diff -u --recursive --new-file v2.4.0-test1/linux/CREDITS linux/CREDITS --- v2.4.0-test1/linux/CREDITS Mon Jun 19 16:31:56 2000 +++ linux/CREDITS Mon Jun 19 12:56:07 2000 @@ -38,10 +38,11 @@ S: Ireland N: Tigran A. Aivazian -E: tigran@ocston.org +E: tigran@veritas.com W: http://www.ocston.org/~tigran D: BFS filesystem D: Intel P6 CPU microcode update support +D: Various kernel patches S: United Kingdom N: Werner Almesberger @@ -291,8 +292,9 @@ D: m68k port to HP9000/300 D: AUN network protocols D: Co-architect of the parallel port sharing system -S: Nexus Electronics Ltd -S: 10 St Barnabas Road, Cambridge CB1 2BY +D: IPv6 netfilter +S: FutureTV Labs Ltd +S: Brunswick House, 61-69 Newmarket Rd, Cambridge CB5 8EG S: United Kingdom N: Thomas Bogendörfer @@ -407,8 +409,8 @@ N: Lennert Buytenhek E: buytenh@gnu.org D: Rewrite of the ethernet bridging code -S: Handelstraat 35 -S: 3131 EK Vlaardingen +S: Ravenhorst 58B +S: 2317 AK Leiden S: The Netherlands N: Michael Callahan @@ -970,7 +972,8 @@ D: Random SMP kernel hacker... D: Uniform Multi-Platform E-IDE driver D: Active-ATA-Chipset maddness.......... -D: Ultra DMA 66/33 +D: Ultra DMA 100/66/33 +D: ATA-Disconnect D: ATA-Smart Kernel Daemon S: Linux ATA Development (LAD) S: Concord, CA @@ -1109,6 +1112,14 @@ S: D-71679 Asperg S: Germany +N: Gareth Hughes +E: gareth@valinux.com +E: gareth@precisioninsight.com +D: Pentium III FXSR, SSE support +S: 11/187 West Street +S: Crows Nest NSW 2065 +S: Australia + N: Kenn Humborg E: kenn@wombat.ie D: Mods to loop device to support sparse backing files @@ -2102,6 +2113,15 @@ S: 9725 GA Groningen S: The Netherlands +N: Pekka Riikonen +E: priikone@poseidon.pspt.fi +E: priikone@ssh.com +D: Random kernel hacking and bug fixes +D: International kernel patch project +S: Kasarmikatu 11 A4 +S: 70110 Kuopio +S: Finland + N: William E. Roadcap E: roadcapw@cfw.com W: http://www.cfw.com/~roadcapw @@ -2155,6 +2175,14 @@ S: The Australian National University, ACT 0200 S: Australia +N: Aristeu Sergio Rozanski Filho +E: aris@conectiva.com.br +D: Support for EtherExpress 10 ISA (i82595) in eepro driver +S: Conectiva S.A. +S: R. Tocantins, 89 - Cristo Rei +S: 80050-430 - Curitiba - Paraná +S: Brazil + N: Alessandro Rubini E: rubini@ipvvis.unipv.it D: the gpm mouse server and kernel support for it @@ -2168,7 +2196,7 @@ N: Paul `Rusty' Russell E: rusty@linuxcare.com -W: http://www.rustcorp.com +W: http://www.samba.org/netfilter D: Ruggedly handsome. D: netfilter, ipchains with Michael Neuling. S: 301/222 City Walk @@ -2779,15 +2807,15 @@ S: The Netherlands N: David Woodhouse -E: David.Woodhouse@mvhi.com -E: Dave@imladris.demon.co.uk -D: Extensive ARCnet rewrite -D: ARCnet COM20020, COM90xx IO-MAP drivers -D: SO_BINDTODEVICE in 2.1.x (from Elliot Poger's code in 2.0.31) -D: Contributed to NCPFS rewrite for 2.1.x dcache -D: Alpha platforms: SX164, LX164 and Ruffian ported to 2.1.x -S: 29, David Bull Way -S: Milton, Cambridge. CB4 6DP +E: dwmw2@infradead.org +E: dwmw2@redhat.com +D: ARCnet stuff, Applicom board driver, SO_BINDTODEVICE, +D: some Alpha platform porting from 2.0, Memory Technology Devices, +D: Acquire watchdog timer, PC speaker driver maintenance, +D: various other stuff that annoyed me by not working. +S: c/o Red Hat UK Limited +S: 35-36 Cambridge Place +S: Cambridge. CB2 1NS S: England N: Frank Xia diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/Changes linux/Documentation/Changes --- v2.4.0-test1/linux/Documentation/Changes Fri May 12 14:18:55 2000 +++ linux/Documentation/Changes Mon Jun 19 12:56:07 2000 @@ -2,7 +2,7 @@ ===== This document is designed to provide a list of the minimum levels of -software necessary to run the 2.3 kernels, as well as provide brief +software necessary to run the 2.4 kernels, as well as provide brief instructions regarding any other "Gotchas" users may encounter when trying life on the Bleeding Edge. If upgrading from a pre-2.2.x kernel, please consult the Changes file included with 2.2.x kernels for @@ -10,861 +10,327 @@ here. Basically, this document assumes that your system is already functional and running at least 2.2.x kernels. - It is originally based on my "Changes" file for 2.2.x kernels and -therefore owes credit to the same people as that file (Jared Mauch, +This document is originally based on my "Changes" file for 2.0.x kernels +and therefore owes credit to the same people as that file (Jared Mauch, Axel Boldt, Alessandro Sigala, and countless other users all over the -'net). Please feel free to submit changes, corrections, gripes, -flames, money, etc. to me (kaboom@gatech.edu). If you do so, you don't -need to bother doing so in the form of a diff, as this is generated by -texinfo so a diff is useless anyway (though I can incorporate one by -hand if you insist upon sending it that way ;-). - - For those of you in Europe, -http://www.datanet.hu/generations/linux/Changes2.html is an -English-language HTML version. - - The most current version should always be available from -http://cyberbuzz.gatech.edu/kaboom/linux/ as well. - - Voir -http://www.linux-france.com/article/sys/Changes-2.2/Changes-2.2.1.html -pour la traduction français. +'net). - Also, don't forget http://www.linuxhq.com/ for all your Linux kernel -needs. +The latest revision of this document, in various formats, can always +be found at http://cyberbuzz.gatech.edu/kaboom/linux/Changes-2.4/ +. -Last updated: Feb 21, 2000 -Current Author: Chris Ricker (kaboom@gatech.edu or chris.ricker@m.cc.utah.edu). +Feel free to translate this document. If you do so, please send me a +URL to your translation for inclusion in future revisions of this +document. + +Last updated: June 11, 2000 + +Chris Ricker (kaboom@gatech.edu or chris.ricker@genetics.utah.edu). Current Minimal Requirements -**************************** +============================ - Upgrade to at *least* these software revisions before thinking you've +Upgrade to at *least* these software revisions before thinking you've encountered a bug! If you're unsure what version you're currently running, the suggested command should tell you. -- Kernel modutils 2.3.10 ; insmod -V -- Gnu C 2.7.2.3 ; gcc --version -- Binutils 2.9.1.0.7 ; ld -v -- Linux libc5 C Library 5.4.46 ; ls -l /lib/libc* -- Linux libc6 C Library 2.0.7pre6 ; ls -l /lib/libc* -- Dynamic Linker (ld.so) 1.9.9 ; ldd --version or ldd -v -- Linux C++ Library 2.7.2.8 ; ls -l /usr/lib/libg++.so.* -- Procps 1.2.9 ; ps --version -- Procinfo 16 ; procinfo -v -- Psmisc 17 ; pstree -V -- Net-tools 1.50 ; hostname -V -- Loadlin 1.6a -- Sh-utils 1.16 ; basename --v -- Autofs 3.1.1 ; automount --version -- NFS (client) 2.2beta40 ; showmount --version -- nfs-utils (server) 0.1.4 -- Bash 1.14.7 ; bash -version -- Ncpfs 2.2.0 ; ncpmount -v -- Pcmcia-cs 3.1.2 ; cardmgr -V -- PPP 2.4.0b1 ; pppd --version -- Util-linux 2.9i ; chsh -v -- isdn4k-utils v3.1beta7 ; isdnctrl 2>&1|grep version - -Upgrade notes -************* - -General Information -=================== - - To use System V shared memory, you have to mount the shm filesystem -somewhere. You can do that automatically by adding this line to /etc/fstab: - -none /var/shm shm defaults 0 0 - -Remember to create the mountpoint directory; it does not have to be /var/shm. - - now performs a cold reboot instead of a warm reboot -for increased hardware compatibility. If you want a warm reboot and -know it works on your hardware, add a "reboot=warm" command line option -in LILO. A small number of machines need "reboot=bios" to reboot via -the BIOS. - - Also, please remember that cua* devices are now obsolete. Switch to -the corresponding ttyS* device instead (e.g., cua0 -> ttyS0, cua1 -> -ttyS1, etc.). - - In addition, some software still works, but needs to be compiled -against 2.2 headers for complete functionality. Fdutils binaries -compiled under 2.0 or earlier kernels should be replaced with ones -compiled under 2.2, for example. - - As of 2.1.115, support for the deprecated major 4 /dev/ttyp* devices -was removed. If necessary (eg, you get "out of pty" error messages when -you obviously are not out of pty's), create major 3 /dev/tty* and major -2 /dev/pty* devices (see Documentation/devices.txt for more -information). In general, you should make sure that your /dev -directory is up-to-date if you are experiencing any problems. - - Optional support for Unix98 pty devices has also been added. If you -want to use the Unix98 ptys, you should be running at least -glibc-2.0.9x, and you must switch completely to Unix98 pty's. The -general procedure for configuring Unix98 pty support is: - -- Compile your kernel with CONFIG_UNIX98_PTYS and CONFIG_DEVPTS_FS. -- mknod /dev/ptmx c 5 2 - chmod 666 /dev/ptmx - mkdir /dev/pts -- Add to /etc/fstab: - - none /dev/pts devpts gid=5,mode=620 0 0 - - (Note: gid=5 is applicable for Red Hat systems for which group "tty" has - gid 5. Adjust according to your distribution. Use mode=600 if you want - "mesg n" to be default.) -- Mount /dev/pts - - Frame buffer consoles ("fbcon") are now in the kernel for all -platforms, not just those non-Intel ones for which VGA text mode is -impossible. VGAcon is still available for those who want it, but fbcon -has the advantage of providing a uniform graphical subsystem across all -Linux ports, and it displays a spiffy penguin logo on boot-up ;-). For -more information, see the files in Documentation/fb/ ; you may also -need to download the fbset utilities. - -Libc (libc5) -============ - - Linux-2.2 is ELF-only. You can still compile a.out apps if you -really want, but your kernel must be compiled ELF. If you can't -currently compile ELF, consult the ELF howto at -http://metalab.unc.edu/mdw/HOWTO/ELF-HOWTO.html and upgrade your system -accordingly. - - For modules to work, you need to be running libc-5.4.x or greater. -Since updates to libc fix other problems as well (security flaws, for -example) and since 5.4.7 is missing a few needed symbols, try to get -the latest 5.4.x you can. Currently, libc-5.4.46 is the latest public -release. - - If you upgrade to libc-5.4.x, you also have to upgrade your dynamic -linker (ld.so) to at least 1.9.9, or all sorts of weirdness will -happen. Actually, ld.so-1.8.2 and later will work, but 1.9.9 is widely -available, so if you need to upgrade, use it. If you get a release -later than 1.8.5, avoid 1.8.10 as it introduces a few bugs that are -fixed in later releases. Please make sure you don't install ld.so-2.x -unless you're running glibc2 / libc6. - - If you upgrade to libc-5.4.x, you may also need to upgrade ypbind if -you're using NIS. For ypbind and glibc, you'll probably need the -ypbind-3.3-glibc5.diff patch available in the same place as the ypbind -source. - - If you upgrade to libc-5.4.46, please read and pay attention to its -accompanying release notes. The section about it breaking make is not a -joke. - -GNU libc (libc6) -================ - - Older versions of GNU libc (libc6) have a bug in the dynamic linker. -/etc/ld.so.cache gets mapped into memory and is never unmapped. If one -of your boot scripts calls ldconfig, /etc/ld.so.cache is deleted. Init, -however, still references that file; as of 2.1.122, the kernel will -consequently not be able to remount the root file system r/o at system -shutdown. To fix this, upgrade to at least the pre6 release of GNU -libc 2.0.7. As a temporary workaround, modify your boot scripts to do -the following before calling ldconfig: - - ln -f /etc/ld.so.cache /etc/ld.so.cache.old - -Modules -======= - - You need to upgrade to the latest version of modutils for the Linux -2.3 kernel. This version can also be built to work with your 2.0 kernel. - - As of 2.1.90-pre1, kerneld has been replaced by a kernel thread, -kmod. See Documentation/kmod.txt for more information. The main -user-level change this requires is modification to your init scripts to -check for the absence of /proc/sys/kernel/modprobe before starting -kerneld. - -Binutils -======== - - If you upgrade binutils, please read its accompanying release notes -to find out the proper way to upgrade it. No, the instruction to "rm -`which encaps`" is not a joke. - - You must use binutils 2.9.1.0.7 or later. Latest release is 2.9.1.0.25. -Beware that binutils 2.9.1 (note the absence of a suffix) from the FSF -does not work. If you are upgrading from earlier versions, you should -consider upgrading to the latest 2.9.5.0.x (beta) release. - -Gnu C -===== - - You need at least GCC 2.7.2 to compile the kernel. If you're -upgrading from an earlier release, you might as well get GCC 2.7.2.3, -the latest stable public release. If you already have GCC 2.7.2 on -your system, you don't have to upgrade just so the kernel will work -(though feel free to upgrade if you want the gcc bug fixes). - - Note that the latest compilers (egcs, pgcc, gcc 2.8) may do Bad -Things while compiling your kernel, particularly if absurd -optimizations (like -O9) are used. Caveat emptor. Currently, the only -C compiler available in a binary distribution is egcs. Version 1.0.3 -seems okay; if you have to have a binary, you may be successful using -that. In general, however, gcc-2.7.2.3 is known to be stable, while -egcs and others have not been as thoroughly tested yet. - -Networking Changes +Again, keep in mind that this list assumes you are already +functionally running a Linux 2.2 kernel. Also, not all tools are +necessary on all systems; obviously, if you don't have any PCMCIA (PC +Card) hardware, for example, you probably needn't concern yourself +with pcmcia-cs. + +o Gnu C 2.7.2.3 # gcc --version +o binutils 2.9.1.0.7 # ld -v +o util-linux 2.10g # chsh -v +o modutils 2.3.10 # insmod -V +o e2fsprogs 1.18 # /sbin/tune2fs --version +o pcmcia-cs 3.1.13 # cardmgr -V +o PPP 2.4.0b1 # pppd --version +o isdn4k-utils 3.1beta7 # isdnctrl 2>&1|grep version + +Kernel compilation ================== - Please read Documentation/networking/routing.txt and -Documentation/networking/policy-routing.txt for more information about -changes in routing code. OSPF classes have been added, and interface -routes are generated automatically. - - If for some reason you need to override this automatic default -routing, you have to specify the complete route specification (netmask, -device, etc.) for the kernel to accept it. Consequently, you need to -either remove interface routes from your init scripts or add missing -information to them if you need to replace the automatic routes. - - Also note that some routes, such as loopback routes, do not show up -in some standard tools. Check in /proc/net/rt_local to verify their -presence. - - To turn on IP forwarding, issue the following command: echo 1 > -/proc/sys/net/ipv4/ip_forward - - Similar procedures are necessary to turn on other features. If -something appears broken, check the /proc/sys/net/ipv4/ directory. "1" -generally denotes enabled, while "0" generally denotes disabled. - - If you're experiencing reports of lots of network errors, chances -are you need to upgrade to a more recent net-tools that understands the -new /proc/net/dev format. This will also provide support for new -features like IPv6. - - The IP firewalling and NAT code has been replaced again. The -userspace tool `iptables' is distributed at: - http://antarctica.penguincomputing.com/~netfilter/ - http://www.samba.org/netfilter/ - http://netfilter.kernelnotes.org - - DHCP clients for 2.0 do not work with the new networking code in the -2.2 kernel. You will need to upgrade your dhcpcd / dhcpclient. - - In 2.0.x the kernel could be configured to drop source routed IP -packets via a compile time configuration option. In 2.2.x, this has -been replaced by a sysctl. See Documentation/networking/ip-sysctl.txt -for more information. - -Memory -====== - - As of 2.1.41, the format of /proc/meminfo has changed. This broke -many memory utils, which have to be upgraded. Get the new procps-1.2 -and you should be set. - -Network File System -=================== - - The NFS code in the kernel is currently being revised, resulting in -much-improved performance. Also, amd is being phased out in favor of -the much better autofs. You'll also have to get the appropriate utils -to use autofs as well as the new NFS utils. In addition, you have the -choice of user-land NFS or kernel-level NFS (knfs). - -Util-linux (including mount) -============================ - - Among other changes made in the development of Linux kernel 2.2, the -128 meg limit on IA32 swap partition sizes has been eliminated. To use -larger swap spaces, you need the new mkswap found in util-linux. You -also need to upgrade util-linux to get the latest version of mount. +GCC +--- - Partitions on 2048 byte sectored media (certain magneto opticals -most prominently) were broken throughout the whole of 2.1 kernel -series, meaning that you will be unable to use 2.1-partitioned media on -Linux 2.2. This is not a 2.2 bug - 2.2 finally does the right thing! -[If you have to interchange media between Linux 2.1 and 2.2, your best -bet is to not use partitions at all but create the filesystem on the -raw device (e.g. /dev/sda) instead. This is also known as the -superfloppy format.] +You will need at least gcc 2.7.2 to compile the kernel. You currently +have several options for gcc-derived compilers: gcc 2.7.2.3, various +versions of egcs, the new gcc 2.95 and upcoming gcc 3.0, and experimental +compilers like pgcc. For absolute stability, it is still recommended +that gcc 2.7.2.3 be used to compile your kernel. egcs 1.12 should also +work. gcc 2.95 is known to have problems, and using pgcc for your kernel +is just asking for trouble. + +In addition, please pay attention to compiler optimization. Anything +greater than -O2 may not be wise. Similarly, if you choose to use gcc-2.95 +or derivatives, be sure not to use -fstrict-aliasing (which, depending on +your version of gcc 2.95, may necessitate using -fno-strict-aliasing). - To properly create partitions on 2048 byte sectored media with Linux -2.2, be sure to use no less than fdisk version 2.9i and invoke fdisk -using '-b 2048' as an option. - - -RPM -=== +Binutils +-------- - If you run Red Hat Linux or any other distribution that uses RPM, -you need to upgrade RPM to a 2.5.x or later version. +Linux on IA/32 has recently switched from using as86 to using gas for +assembling the 16-bit boot code, removing the need for as86 to compile +your kernel. This change does, however, mean that you need a recent +release of binutils. + +If you can, upgrade to the latest 2.9.5 binutils release. Older +releases such as 2.8, 2.8.xx, and the FSF's 2.9.1 should be avoided if +at all possible. The later releases of 2.9.1.0.x (anything where x >= 7) +can and do compile the kernel properly, but there are many benefits +to upgrading to 2.9.5 if you're up to it. -DOSEMU -====== +System utils +============ - A new "stable" version of DOSEMU is available for 2.2 kernels. -Upgrade to 0.98.4 or later. +Architectural changes +--------------------- -Loadlin -======= +DevFS is now in the kernel. See Documentation/filesystems/devfs/* in +the kernel source tree for all the gory details. - Linux 2.1.22 and later releases use a new method of memory size -detection, requiring loadlin users to upgrade to loadlin-1.6a. +System V shared memory is now implemented via a virtual filesystem. +You do not have to mount it to use it as long as you can live with the +default maxima for shared memory and segments. If you wish to change +these variables, you have to mount it with the options nr_blocks +and/or nr_inodes. POSIX shared memory is also now implemented via a +virtual filesystem. If you want to use it, you'll need to mount the +filesystem. The recommended mount location is /dev/shm, and adding the +following line to /etc/fstab should take care of things: + +none /dev/shm shm defaults 0 0 + +Remember to create the directory that you intend to mount shm on if +necessary. + +The Logical Volume Manager (LVM) is now in the kernel. If you want to +use this, you'll need to install the necessary LVM toolset. + +32-bit UID support is now in place. Have fun! + +Linux documentation for functions is transitioning to inline +documentation via specially-formatted comments near their +definitions in the source. These comments can be combined with the +SGML templates in the Documentation/DocBook directory to make DocBook +files, which can then be converted by DocBook stylesheets to PostScript, +HTML, PDF files, and several other formats. In order to convert from +DocBook format to a format of your choice, you'll need to install Jade as +well as the desired DocBook stylesheets. -Sh-utils -======== +Util-linux +---------- - As of Linux-2.1.26, the Configure script ("make config") has been -updated to be POSIX-compliant. As a result, your expr needs to be -updated. Use sh-utils 1.16 or later. +New versions of util-linux provide *fdisk support for larger disks, +support new options to mount, recognize more supported partition +types, and similar goodies. You'll probably want to upgrade. -Parallel Ports -============== +Ksymoops +-------- - As of 2.1.33, parallel port support can now by handled by the parport -driver. Be aware that your parallel port may no longer be where you -expect it; for example, LPT1 (under DOS) was sometimes /dev/lp1 in -Linux, but will probably be /dev/lp0 with the new parport driver. If -printing breaks with the new driver, try checking your lpd -configuration. A good source of more information is the -Documentation/parport.txt file included with the kernel. +If the unthinkable happens and your kernel oopses, you'll need a 2.3 +version of ksymoops to decode the report; see REPORTING-BUGS in the +root of the Linux source for more information. -Setserial -========= +Modutils +-------- - If you experience random problems (stuck lines, lost characters, -etc.) with serial lines under recent kernels, upgrading setserial -should help. +Upgrade to recent modutils to fix various outstanding bugs which are +seen more frequently under 2.3.x, and to enable auto-loading of USB +modules. -Syncookies -========== +E2fsprogs +--------- - When you build your kernel with Syncookie support -(CONFIG_SYN_COOKIES) the syncookie code still defaults to off (unlike -the 2.0.30+ behavior). You have to explicitly enable it by issuing the -following command: echo 1 > /proc/sys/net/ipv4/tcp_syncookies - -Bash -==== - - Old versions of Bash fail to properly handle symlinks, which can -cause problems when compiling modules. Upgrade to at least 1.14 to fix -this problem. - -Sysklogd -======== - - Older versions of sysklogd sometimes segfault under 2.2 kernels. -Upgrading to the latest release fixes that problem as well as adding -support for new features like system power-off on halt (with -appropriate incantations of halt; see the man page) and automatic -decoding of kernel oopses. - -Ncpfs -===== - - To mount NetWare shares, you'll need to upgrade to a more recent -version of the ncpfs utils. - -SMBfs -===== - - To mount SMB (Samba / Windows) shares, you'll need to use the -smbmount utility included with release 2.0 of Samba. -Documentation/filesystems/smbfs.txt has more information about this. -Note that smbmount must have been built against 2.2 headers to work -with 2.2; if all else fails, recompile it and hope it works ;-). In -addition, Mike Warfield has a script and some information at -http://www.wittsend.com/mhw/smbmount.html that you will probably find -useful. +The latest version of e2fsprogs fixes several bugs in fsck and +debugfs. Obviously, it's a good idea to upgrade. Pcmcia-cs -========= - - If you use pcmcia cards, you'll need to upgrade the daemon and -support utils to the latest release of pcmcia-cs. - -PPP -=== - - The PPP driver has been restructured to support multilink and -to enable it to operate over diverse kinds of media. Those of you -using PPP networking will need to upgrade your pppd to at least -version 2.4.0b1. See ftp://linuxcare.com.au/pub/ppp/ for the latest -version. - - If you are not using devfs, you must make sure that the special -device file /dev/ppp exists. It can be made by executing this command -as root: - - mknod /dev/ppp c 108 0 - - If you have built ppp support as modules, you should put the lines -below in your /etc/modules.conf file. - - alias char-major-108 ppp_generic - alias /dev/ppp ppp_generic - alias tty-ldisc-3 ppp_async - alias tty-ldisc-14 ppp_synctty - alias ppp-compress-21 bsd_comp - alias ppp-compress-24 ppp_deflate - alias ppp-compress-26 ppp_deflate - -If you are using devfsd and you have ppp_generic as a module, put the -following line in your /etc/devfsd.conf: - - LOOKUP ppp MODLOAD - -iBCS -==== - - A new version of iBCS is necessary for 2.2 kernels. - -AppleTalk -========= - - Use the Asun version of netatalk for AppleTalk support, as Umich's -version is not compatible with 2.2 kernels. +--------- -Psmisc -====== +PCMCIA (PC Card) support is now partially implemented in the main +kernel source. Pay attention when you recompile your kernel ;-). +Also, be sure to upgrade to the latest pcmcia-cs release. - fuser, which comes with psmisc, reads /proc/*/fd/* to do its job. -Upgrade psmisc if 2.2 changes to /proc broke the version you're using. +Intel P6 microcode +------------------ -PCI utils -========= +A driver has been added to allow updating of Intel P6 microcode, +accessible as both a devfs regular file and as a normal (misc) +character device. If you are not using devfs you may need to: - Linux PCI utils are available; these include lspci, which displays -detailed information about your system's PCI devices (much more than -the basic things in /proc/pci), and setpci, which allows you to read -and write PCI configuration registers of your devices. +mkdir /dev/cpu +mknod /dev/cpu/microcode c 10 184 +chmod 0644 /dev/cpu/microcode -Powertweak -========== - - The PCI Bridge Optimization has been removed from the kernel. If you -think your BIOS does a poor job when setting up your chipset, there -is a utility called PowerTweak whose job is to tune chipset parameters. - -Xosview -======= +as root before you can use this. You'll probably also want to +get the user-space microcode_ctl utility to use with this. - Changes to the /proc interface require a recent xosview. - -RealPlayer +Networking ========== - Current releases of Real Player 5.0 depend on a bug in the sound -sub-system which is no longer there. Consequently, they don't work. -Real is aware of the problem and should have an updated version of the -software available shortly. In the mean time, you can always try -backing up your copy of rvplayer, and then editing it by: - - dd if=/dev/zero of=rvplayer bs=1 count=1 seek=657586 conv=notrunc - dd if=/dev/zero of=rvplayer bs=1 count=1 seek=665986 conv=notrunc - - If you're lucky, you'll then have sound.... - - You may also need to edit it with - - dd if=/dev/zero of=rvplayer bs=1 count=1 seek=702554 conv=notrunc - - as well. Alternately, download rpopen from -http://onramp.i2k.com/~jeffd/rpopen/ and pre-load it before you run -rvplayer (it's a shared object which blocks rvplayer from doing the -NONBLOCKing open of /dev/dsp). - -Quotas -====== - - If you are using large quotas, you should upgrade your quota utils; -newer versions count file sizes in blocks instead of bytes, providing -an upper limit of terabytes instead of 4 GB. - -Ping -==== - - Most distributed ping clients are buggy. Get an updated one from the -iputils package. - -Patch -===== - - Really old versions of patch cannot delete files. This can be a -problem if you try to upgrade via patches. If, for example, you are -unable to compile Linux 2.2, you may have an outdated version of patch. -Upgrade, re-patch the kernel, and try again. - -Process accounting -================== +General changes +--------------- - If you use process accounting, you need to recompile the package -against 2.2 kernel includes for it to work properly. Furthermore, when -you do so, watch out for a quirky configure script. Your generated -config.h file needs to +The IP firewalling and NAT code has been replaced again. The new +netfilter software (including ipfwadm and ipchains backwards- +compatible modules) is currently distributed separately. - #define HAVE_LINUX_ACCT_H - - but instead it often has - - /* #undef HAVE_LINUX_ACCT_H */ - - so be sure to check that when you recompile. - -ISDN4Linux -========== -Since 2.3.27 here is a new length of the phonenumber field, old utils -have to recompile, a upgrade to isdn4k-utils.v3.1beta7 or later is -recomented. -Older isdn4k-utils versions don't support EXTRAVERSION into kernel version -string. - -Logical Volume Manager -====================== -Since 2.3.47 the kernel contains the Logical Volume Manager aka LVM. To use it, -you need to install the LVM tools. More information can be found at the home page -of the LVM project at http://linux.msede.com/lvm/. - -Inline Documentation -==================== -Many of the functions available for modules to use are now documented -with specially-formatted comments near their definitions. These -comments can be combined with the SGML templates in the -Documentation/DocBook directory to make DocBook files, which can then -be combined with DocBook stylesheets to make PostScript documents, -HTML pages, PDF files, and so on. In order to convert from DocBook -format to a format of your choice, you'll need to install jade, as -well as some stylesheets. +If you have advanced network configuration needs, you should probably +consider using the network tools from ip-route2. +PPP +--- -Where to get the files -********************** +The PPP driver has been restructured to support multilink and to +enable it to operate over diverse media layers. If you use PPP, +upgrade pppd to at least 2.4.0b1. + +If you are not using devfs, you must have the device file /dev/ppp +which can be made by: + +mknod /dev/ppp c 108 0 + +as root. + +If you build ppp support as modules, you will need the following in +your /etc/modules.conf file: + +alias char-major-108 ppp_generic +alias /dev/ppp ppp_generic +alias tty-ldisc-3 ppp_async +alias tty-ldisc-14 ppp_synctty +alias ppp-compress-21 bsd_comp +alias ppp-compress-24 ppp_deflate +alias ppp-compress-26 ppp_deflate + +If you use devfsd and build ppp support as modules, you will need +the following in your /etc/devfsd.conf file: + +LOOKUP PPP MODLOAD + +Isdn4k-utils +------------ + +Due to changes in the length of the phone number field, isdn4k-utils +needs to be recompiled or (preferably) upgraded. + +Getting updated software +======================== + +Compilers +********* + +gcc 2.7.2.3 +----------- +o ftp://ftp.gnu.org/gnu/gcc/gcc-2.7.2.3.tar.gz + +o ftp://metalab.unc.edu/pub/gnu/gcc-2.7.2.3.tar.gz + + +egcs 1.12 +--------- +o ftp://ftp.varesearch.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-glibc.x86.tar.bz2 + +o ftp://ftp.varesearch.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-libc5.x86.tar.bz2 + +o ftp://ftp.varesearch.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-alpha.tar.bz2 + Binutils -======== - -The 2.9.1.0.25 release: -ftp://ftp.varesearch.com/pub/support/hjl/binutils/2.9.1/binutils-2.9.1.0.25-glibc.x86.tar.gz -ftp://ftp.varesearch.com/pub/support/hjl/binutils/2.9.1/binutils-2.9.1.0.25.tar.gz -Installation notes: -ftp://ftp.varesearch.com/pub/support/hjl/binutils/2.9.1/release.binutils-2.9.1.0.25 - -The 2.9.5.0.22 release: -ftp://ftp.varesearch.com/pub/support/hjl/binutils/binutils-2.9.5.0.22.tar.bz2 -Installation notes: -ftp://ftp.varesearch.com/pub/support/hjl/binutils/release.binutils-2.9.5.0.22 - -Gnu C -===== - -The egcs-1.0.3 release: -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/egcs-1.0.3-glibc.x86.tar.bz2 -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/egcs-1.0.3-libc5.x86.tar.bz2 -ftp://metalab.unc.edu/pub/Linux/GCC/egcs-1.0.3-glibc.x86.tar.bz2 -ftp://metalab.unc.edu/pub/Linux/GCC/egcs-1.0.3-libc5.x86.tar.bz2 -Installation notes: -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.egcs-1.0.3 -ftp://metalab.unc.edu/pub/Linux/GCC/release.egcs-1.0.3 - -Gnu C 2.7.2.3 source: -ftp://ftp.gnu.org/gnu/gcc/gcc-2.7.2.3.tar.gz -ftp://metalab.unc.edu/pub/gnu/gcc-2.7.2.3.tar.gz - -Linux C Library -=============== - -The (libc5) 5.4.46 release: -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/libc-5.4.46.bin.tar.gz -ftp://metalab.unc.edu/pub/Linux/GCC/libc-5.4.46.bin.tar.gz -Installation notes for 5.4.46: -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.libc-5.4.46 -ftp://metalab.unc.edu/pub/Linux/GCC/release.libc-5.4.46 - -The (libc6) GNU libc 2.0.7pre6 release: -ftp://ftp.kernel.org/pub/software/libs/glibc/glibc-2.0.7pre6.tar.gz -ftp://ftp.kernel.org/pub/software/libs/glibc/glibc-2.0.7pre6.tar.bz2 - -Linux C++ Library -================= - -The 2.7.2 release: -ftp://ftp.gnu.org/gnu/libg++/libg++-2.7.2.tar.gz - -Dynamic Linker -============== - -The 1.9.9 release: -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/ld.so-1.9.9.tar.gz -ftp://metalab.unc.edu/pub/Linux/GCC/ld.so-1.9.9.tar.gz - -Modules utilities -================= - -The 2.3.10 release: -ftp://ftp.ocs.com.au/pub/modutils/v2.3/modutils-2.3.10.tar.gz - -Procps utilities -================ - -The 1.2 release: -ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.2.9.tar.gz -ftp://metalab.unc.edu/pub/Linux/system/status/ps/procps-1.2.9.tgz - -Procinfo utilities -================== - -The 16 release: -ftp://ftp.cistron.nl/pub/people/svm/procinfo-16.tar.gz - -Psmisc utilities -================ - -The 17 release: -ftp://lrcftp.epfl.ch/pub/linux/local/psmisc/psmisc-17.tar.gz -ftp://metalab.unc.edu/pub/Linux/system/status/ps/psmisc-17.tar.gz - -RPM utilities -============= - -The 2.5.1 source release: -ftp://ftp.rpm.org/pub/rpm/dist/rpm-2.5.x/rpm-2.5.1-1.src.rpm -ftp://ftp.rpm.org/pub/rpm/dist/rpm-2.5.x/rpm-2.5.1.tar.gz - -DOSEMU -====== - -The 0.98.1 release: -ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/dosemu-0.98.4.tgz -ftp://ftp.dosemu.org/dosemu/dosemu-0.98.4.tgz +******** -Loadlin -======= +2.9.1 series +------------ +o ftp://ftp.varesearch.com/pub/support/hjl/binutils/2.9.1/binutils-2.9.1.0.25.tar.gz + + +2.9.5 series +------------ +o ftp://ftp.varesearch.com/pub/support/hjl/binutils/binutils-2.9.5.0.29.tar.gz + -The 1.6a release: -ftp://ftp.suse.com/pub/loadlin/update-1.6a/loadlin.exe.gz -ftp://elserv.ffm.fgan.de/pub/linux/loadlin-1.6/update-1.6a/loadlin.exe.gz - -Sh-utils -======== - -The 1.16 release: -ftp://metalab.unc.edu/pub/gnu/sh-utils-1.16.tar.gz -ftp://ftp.gnu.org/gnu/sh-utils/sh-utils-1.16.tar.gz +System utilities +**************** Util-linux -========== - -The 2.9 release: -ftp://ftp.win.tue.nl/pub/linux/utils/util-linux/util-linux-2.9i.tar.gz - -Autofs -====== - -The 3.1.3 release: -ftp://ftp.kernel.org/pub/linux/daemons/autofs/autofs-3.1.3.tar.gz - -NFS -=== - -The user-land 2.2beta40 release: -ftp://ftp.mathematik.th-darmstadt.de/pub/linux/okir/dontuse/nfs-server-2.2beta40.tar.gz -ftp://linux.nrao.edu/mirrors/fb0429.mathematik.th-darmstadt.de/pub/linux/okir/dontuse/nfs-server-2.2beta40.tar.gz - -The kernel-level nfs-utils-0.1.4 release: -ftp://nfs.sourceforge.net/pub/nfs/nfs-utils-0.1.4.tar.gz - -Net-tools -========= - -The 1.50 release: -ftp://ftp.cs-ipv6.lancs.ac.uk/pub/Code/Linux/Net_Tools/net-tools-1.50.tar.gz -http://www.tazenda.demon.co.uk/phil/net-tools/net-tools-1.50.tar.gz - -Ypbind -====== - -The 3.3 release: -ftp://ftp.kernel.org/pub/linux/utils/net/NIS/ypbind-3.3.tar.gz - -Sysklogd -======== - -The 1.3-31 release: -ftp://metalab.unc.edu/pub/Linux/system/daemons/sysklogd-1.3-31.tar.gz - -Bash -==== - -The 1.14.7 release: -ftp://ftp.gnu.org/gnu/bash/bash-1.14.7.tar.gz - -The 2.02.1 release: -ftp://ftp.gnu.org/gnu/bash/bash-2.02.1.tar.gz - -Ncpfs -===== - -The 2.2.0 release: -ftp://ftp.gwdg.de/pub/linux/misc/ncpfs/ncpfs-2.2.0.tgz - -SMBfs -===== - -The 2.0.0 release of Samba: -ftp://ftp.samba.org/pub/samba/samba-2.0.0.tar.gz +---------- +o ftp://ftp.cwi.nl/pub/aeb/util-linux/util-linux-2.10g.tar.gz + + +Ksymoops +-------- +o ftp://ftp.kernel.org/pub/linux/utils/kernel/ksymoops/v2.3 + + +Modutils +-------- +o ftp://ftp.kernel.org/pub/linux/utils/kernel/modutils/v2.3/modutils-2.3.9.tar.gz + + +E2fsprogs +--------- +o http://web.mit.edu/tytso/www/linux/dist/e2fsprogs-1.18.tar.gz + +o http://web.mit.edu/tytso/www/linux/dist/e2fsprogs-1.18.src.rpm + + +LVM toolset +----------- +o http://linux.msede.com/lvm/ Pcmcia-cs -========= - -The 3.1.2 release: -ftp://sourceforge.org/pcmcia/pcmcia-cs-3.1.2.tar.gz - -Setserial -========= - -The 2.15 release: -ftp://tsx-11.mit.edu/pub/linux/sources/sbin/setserial-2.15.tar.gz -ftp://metalab.unc.edu/pub/Linux/system/serial/setserial-2.15.tar.gz - -PPP -=== - -The 2.4.0b1 release: -ftp://linuxcare.com.au/pub/ppp/ppp-2.4.0b1.tar.gz - -iptables -========= - -The 1.1.0 release: -http://antarctica.penguincomputing.com/~netfilter/iptables-1.1.0.tar.bz2 -http://www.samba.org/netfilter/iptables-1.1.0.tar.bz2 -http://netfilter.kernelnotes.org/iptables-1.1.0.tar.bz2 - -IP Masq Adm -=========== - -The 0.4.2 release: -http://juanjox.linuxhq.com/ipmasqadm-0.4.2.tar.gz - -DHCP clients -============ - -The 2.0b1p18 ISC dhcpclient release: -ftp://ftp.isc.org/isc/dhcp/test/dhcp-2.0b1pl8.tar.gz - -The 1.3.17-pl2 PhysTech dhcpcd release: -ftp://ftp.phystech.com/pub/dhcpcd-1.3.17-pl2.tar.gz - -iBCS -==== - -The 11/05/98 release: -ftp://tsx-11.mit.edu/pub/linux/BETA/ibcs2/ibcs-2.1-981105-ALPHA.tar.gz - -Asun netatalk -============= - -The 2.0a18.2 release: -ftp://ftp.u.washington.edu/pub/user-supported/asun/netatalk-1.4b2+asun2.0a18.2.tar.gz - -Fbset -===== - -The 11/04/98 release: -http://www.cs.kuleuven.ac.be/~geert/bin/fbset-2.0-pre-19981104.tar.gz - -PCI utils -========= - -The 2.1.5 release: -ftp://atrey.karlin.mff.cuni.cz/pub/linux/pci/pciutils-2.1.5.tar.gz -ftp://metalab.unc.edu/pub/Linux/hardware/pciutils-2.1.5.tar.gz - -Powertweak -========== - -The 0.1.13 release: -http://linux.powertweak.com/files/powertweak-0.1.13.tgz -ftp://atrey.karlin.mff.cuni.cz/pub/linux/pci/powertweak/powertweak-0.1.13.tgz - -Xosview -======= - -The 1.6.1 release: -ftp://metalab.unc.edu/pub/Linux/system/status/xstatus/xosview-1.6.1.tar.gz - -Quota utils -=========== - -The 1.55 release: -ftp://ftp.uk.linux.org/pub/linux/sct/quota/quota-1.55-10.i386.rpm -ftp://ftp.uk.linux.org/pub/linux/sct/quota/quota-1.55-10.src.rpm - -IP utils -======== - -The 03/01/99 release: -ftp://ftp.inr.ac.ru/ip-routing/iproute2-2.1.99-now-ss990301.tar.gz - -Patch -===== - -The 2.5 release: -ftp://ftp.gnu.org/gnu/patch/patch-2.5.tar.gz - -ISDN4Linux -========== - -The v3.1beta7 release: -ftp://ftp.isdn4linux.de/pub/isdn4linux/utils/testing/isdn4k-utils.v3.1beta7.tar.gz - -Logical Volume Manager -====================== - -The 0.7 release: -ftp://linux.msede.com/lvm/v0.7/lvm_0.7.tar.gz +--------- +o ftp://sourceforge.org/pcmcia/pcmcia-cs-3.1.13.tar.gz + Jade -==== - -The 1.2.1 release: -ftp://ftp.jclark.com/pub/jade/jade-1.2.1.tar.gz +---- +o ftp://ftp.jclark.com/pub/jade/jade-1.2.1.tar.gz + + +DocBook Stylesheets +------------------- +o http://nwalsh.com/docbook/dsssl/ + + +Intel P6 microcode +------------------ +o http://www.urbanmyth.org/microcode/ + -DSSSL Stylesheets for the DocBook DTD -===================================== +Network +******* -http://nwalsh.com/docbook/dsssl/ - - -Other Info -========== +PPP +--- +o ftp://linuxcare.com.au/pub/ppp/ppp-2.4.0b1.tar.gz + + +Isdn4k-utils +------------ +o ftp://ftp.isdn4linux.de/pub/isdn4linux/utils/testing/isdn4k- + utils.v3.1beta7.tar.gz + + +Netfilter +--------- +o http://netfilter.filewatcher.org/iptables-1.1.0.tar.bz2 + +o http://www.samba.org/netfilter/iptables-1.1.0.tar.bz2 + +o http://netfilter.kernelnotes.org/iptables-1.1.0.tar.bz2 + + +Ip-route2 +--------- +o ftp://ftp.inr.ac.ru/ip-routing/iproute2-2.2.4-now-ss991023.tar.gz + - Please remember that most of these utils are available on your -favorite local linux mirror. If you can, please get them from a closer -site before checking metalab or tsx-11. - - You may also want to check for updated versions of this software in a -package format for the distribution you use. - - For those of you running Red Hat (or RPM on a different -distribution), most of these are available in RPM format. Check around -your favorite Red Hat mirror site before installing the non-RPM -version. Remember, you might need to use the --force option to get the -upgrade to install. ftp://contrib.redhat.com/ , -ftp://developer.redhat.com/ , or ftp://updates.redhat.com/ will have -almost everything you need, and Red Hat 6.1 ships with most necessary -software. - - Those of you running Debian (or a different distribution that -supports .deb packages) can look in the "unstable" and -"project/experimental" directories of your favorite Debian mirror. The -Debian 2.2 release will ship with most packages you need as well. - -Please send info about any other packages that 2.3 "broke" or about any -new features of 2.3 that require extra or new packages for use to Chris -Ricker (kaboom@gatech.edu or chris.ricker@m.cc.utah.edu). +Suggestions and corrections +=========================== +Please feel free to submit changes, corrections, gripes, flames, +money, etc. to me . Happy Linuxing! diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.4.0-test1/linux/Documentation/Configure.help Mon Jun 19 16:31:56 2000 +++ linux/Documentation/Configure.help Thu Jun 22 07:21:12 2000 @@ -9,8 +9,8 @@ # http://www.linux.or.jp/JF/JFdocs/Configure.help/ # - Russian, by kaf@linux.nevod.perm.su, at # http://nevod.perm.su/service/linux/doc/kernel/Configure.help -# - French, by Tane Pierre (tanep@bigfoot.com), at -# http://www.kernelfr.org +# - French, by Pierre Tane (tanep@bigfoot.com), at +# http://www.traduc.org/kernelfr # - Spanish, by Carlos Perelló Marín (fperllo@ehome.encis.es), at # http://visar.csustan.edu/~carlos/ # - Italian, by Alessandro Rubini (rubini@linux.it), at @@ -125,7 +125,7 @@ used on systems with several CPU's. If you have a single-CPU system which uses APIC, you can say Y here to use it. If you say Y here even though your machine doesn't have APIC, then the kernel will - still run with now slowdown at all. + still run with no slowdown at all. If you have system with several CPU's, you do not need to say Y here: APIC will be used automatically. @@ -161,17 +161,22 @@ If you are compiling a kernel for a NetWinder or EBSA-285, you will be able to select which LEDs are active using the options below. If - you are compiling a kernel for the EBSA-110 however, the red LED - will simply flash regularly to indicate that the system is still - functional. It is safe to say Y here if you have a CATS system, but - the driver will do nothing. + you are compiling a kernel for the EBSA-110 or the LART however, the + red LED will simply flash regularly to indicate that the system is + still functional. It is safe to say Y here if you have a CATS + system, but the driver will do nothing. Timer LED CONFIG_LEDS_TIMER If you say Y here, one of the system LEDs (the green one on the - NetWinder or the amber one on the EBSA285) will flash regularly to - indicate that the system is still operational. This is mainly - useful to kernel hackers who are debugging unstable kernels. + NetWinder, the amber one on the EBSA285, or the red one on the LART) + will flash regularly to indicate that the system is still + operational. This is mainly useful to kernel hackers who are + debugging unstable kernels. + + The LART uses the same LED for both Timer LED and CPU usage LED + functions. You may choose to use both, but the Timer LED function + will overrule the CPU usage LED. CPU usage LED CONFIG_LEDS_CPU @@ -179,6 +184,10 @@ time indication of CPU usage, by lighting whenever the idle task is not currently executing. + The LART uses the same LED for both Timer LED and CPU usage LED + functions. You may choose to use both, but the Timer LED function + will overrule the CPU usage LED. + Kernel FP software completion (EXPERIMENTAL) CONFIG_MATHEMU This option is required for IEEE compliant floating point arithmetic @@ -358,7 +367,7 @@ 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 a subset of the IDE specifications. + 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 @@ -699,6 +708,14 @@ It is normally safe to answer Y to this question unless your motherboard uses a VIA VP2 chipset, in which case you should say N. +IGNORE word93 Validation BITS +CONFIG_IDEDMA_IVB + Since various rules were applied and created ... et al. as it relates + the detection of vaild cable signals. This is a result of unclear terms + in ATA-4 and ATA-5 standards. + + It is normally safe to answer Y; however, the default is N. + Various ATA, Work(s) In Progress (EXPERIMENTAL) CONFIG_IDEDMA_PCI_WIP If you enable this you will be able to use and test highly @@ -733,7 +750,7 @@ If you say Y here, then say Y to "Use DMA by default when available" as well. -AEC62XX Tuning support (WIP) +AEC62XX Tuning support CONFIG_AEC62XX_TUNING Please read the comments at the top of drivers/ide/aec62xx.c If unsure, say N. @@ -763,7 +780,7 @@ SAY NO! -AMD7409 chipset support (EXPERIMENTAL) +AMD7409 chipset support CONFIG_BLK_DEV_AMD7409 This driver ensures (U)DMA support for the AMD756 Viper chipset. @@ -784,12 +801,7 @@ Say Y here if you have an IDE controller which uses any of these chipsets: CMD643, CMD646, or CMD648. -CMD64X chipset RAID support (WIP) -CONFIG_CMD64X_RAID - Work in progress for hardware raid ata-33/66..........rev 7 minimum. - Say N for now. - -CY82C693 chipset support (EXPERIMENTAL) +CY82C693 chipset support CONFIG_BLK_DEV_CY82C693 This driver adds detection and support for the CY82C693 chipset used on Digital's PC-Alpha 164SX boards. @@ -826,11 +838,13 @@ HPT366 chipset support CONFIG_BLK_DEV_HPT366 HPT366 is an Ultra DMA chipset for ATA-66. - + HPT368 is an Ultra DMA chipset for ATA-66 RAID Based. + HPT370 is an Ultra DMA chipset for ATA-100. + This driver adds up to 4 more EIDE devices sharing a single interrupt. - The HPT366 chipset in its current form is non-bootable. One solution + The HPT366 chipset in its current form is bootable. One solution for this problem are special LILO commands for redirecting the reference to device 0x80. The other solution is to say Y to "Boot off-board chipsets first support" (CONFIG_BLK_DEV_OFFBOARD) unless @@ -842,15 +856,6 @@ ide-probe at boot. It is reported to support DVD II drives, by the manufacturer. -HPT366 Fast Interrupts (WIP) -CONFIG_HPT366_FIP - If unsure, say N. - -HPT366 mode three unsupported (EXPERIMENTAL) (WIP) -CONFIG_HPT366_MODE3 - This is an undocumented mode that the HA366 can default to in many - cases. If unsure, say N. - NS87415 support (EXPERIMENTAL) CONFIG_BLK_DEV_NS87415 This driver adds detection and support for the NS87415 chip @@ -877,7 +882,7 @@ If unsure, say N. -PIIXn Tuning support (EXPERIMENTAL) +PIIXn Tuning support CONFIG_PIIX_TUNING This driver extension adds DMA mode setting and tuning for all PIIX IDE controllers by Intel. Since the BIOS can sometimes improperly @@ -889,9 +894,11 @@ If unsure, say N. -PROMISE PDC20246/PDC20262 support +PROMISE PDC20246/PDC20262/PDC20267 support CONFIG_BLK_DEV_PDC202XX Promise Ultra33 or PDC20246 + Promise Ultra66 or PDC20262 + Promise Ultra100 or PDC20267 This driver adds up to 4 more EIDE devices sharing a single interrupt. This add-on card is a bootable PCI UDMA controller. Since @@ -902,14 +909,6 @@ for more than one card. This card may require that you say Y to "Special UDMA Feature (EXPERIMENTAL)". - Promise Ultra66 or PDC20262 - - This driver adds up to 4 more EIDE devices sharing a single - interrupt. This add-on card is a bootable PCI UDMA ATA-66 - controller. The driver attempts to dynamic tuning of the chipset at - boot-time for max-speed. Note tested limits are UDMA-2. Ultra66 BIOS - 1.11 or newer required. - If you say Y here, you need to say Y to "Use DMA by default when available" as well. @@ -919,21 +918,16 @@ Special UDMA Feature (EXPERIMENTAL) CONFIG_PDC202XX_BURST - For PDC20246 and PDC20262 Ultra DMA chipsets. Designed originally - for PDC20246/Ultra33 that has BIOS setup failures when using 3 or - more cards. + For PDC20246, PDC20262 and PDC20267 Ultra DMA chipsets. Designed + originally for PDC20246/Ultra33 that has BIOS setup failures when + using 3 or more cards. + + Unknown for PDC20267 Ultra DMA 100. Please read the comments at the top of drivers/ide/pdc202xx.c If unsure, say N. -Special Mode Feature (WIP) -CONFIG_PDC202XX_MASTER - For PDC20246 and PDC20262 Ultra DMA chipsets. This is reserved for - possible Hardware RAID 0,1 for the FastTrak Series. - - Say N. - SiS5513 chipset support CONFIG_BLK_DEV_SIS5513 This driver ensures (U)DMA support for SIS5513 chipset based @@ -958,7 +952,7 @@ needed for further tweaking and development. Please read the comments at the top of drivers/ide/trm290.c. -VIA82CXXX chipset support (EXPERIMENTAL) +VIA82CXXX chipset support CONFIG_BLK_DEV_VIA82CXXX This allows you to to configure your chipset for a better use while running (U)DMA: it will allow you to enable efficiently the second @@ -1551,11 +1545,19 @@ If unsure, say Y. -Boot support (linear, striped) +RAID Boot support CONFIG_MD_BOOT - To boot with an initial linear or striped md device you have to - answer Y here. For lilo and loadlin options see the file - Documentation/md.txt. + To boot with an initial raid volume (any type) you can select + autodetect, or answer Y here and appropriate options to the kernel + at boot time. + For lilo and loadlin options see the file Documentation/md.txt. + +RAID AutoDetect support +CONFIG_AUTODETECT_RAID + An alternative to "Raid Boot support" is autodetect support. + With this selected, any partitons of type 0xFD will be considered for + inclusion in a RAID array. Information in the RAID-superblock on + the partition will determine how it is included. Support for Acer PICA 1 chipset CONFIG_ACER_PICA_61 @@ -1781,7 +1783,8 @@ Various modules exist for netfilter which replace the previous masquerading (ipmasqadm), packet filtering (ipchains), transparent proxying, and portforwarding mechanisms. Please see - Documentation/Changes for the location of these packages. + Documentation/Changes under "iptables" for the location of these + packages. Make sure to say N to "Fast switching" below if you intend to say Y here, as Fast switching currently bypasses netfilter. @@ -2089,6 +2092,8 @@ SX164 AlphaPC164-SX Sable AS 2000, AS 2100 Takara Takara + Titan Privateer + Wildfire AlphaServer GS 40/80/160/320 If you don't know what to do, choose "generic". @@ -2571,11 +2576,10 @@ http://www.linuxdoc.org/docs.html#guide . Shared memory is now implemented using a new (minimal) virtual file - system, which you need to mount before programs can use shared - memory. To do this automatically at system startup just add the + system. To mount it automatically at system startup just add the following line to your /etc/fstab: - none /var/shm shm defaults 0 0 + none /dev/shm shm defaults 0 0 Saying Y here enlarges your kernel by about 18 KB. Just say Y. @@ -2729,25 +2733,27 @@ all x86 CPU types (albeit not optimally fast), you can specify "386" here. - If you specify one of "486" or "586" or "Pentium" or "PPro" or - "Athlon", then the kernel will not necessarily run on earlier - architectures (e.g. a Pentium optimized kernel will run on a PPro, - but not necessarily on a i486). + The kernel will not necessarily run on earlier architectures than + the one you have chosen, e.g. a Pentium optimized kernel will run on + a PPro, but not necessarily on a i486. Here are the settings recommended for greatest speed: - "386" for the AMD/Cyrix/Intel 386DX/DXL/SL/SLC/SX, Cyrix/TI - 486DLC/DLC2 and UMC 486SX-S. Only "386" kernels will run on a 386 - class machine. + 486DLC/DLC2, UMC 486SX-S and NexGen Nx586. Only "386" kernels will + run on a 386 class machine. - "486" for the AMD/Cyrix/IBM/Intel 486DX/DX2/DX4 or - SL/SLC/SLC2/SLC3/SX/SX2, AMD/Cyrix 5x86, NexGen Nx586 and - UMC U5D or U5S. + SL/SLC/SLC2/SLC3/SX/SX2 and UMC U5D or U5S. - "586" for generic Pentium CPUs, possibly lacking the TSC (time stamp counter) register. - - "Pentium" for the Intel Pentium/Pentium MMX, and AMD K5. - - "PPro" for the Cyrix/IBM/National Semiconductor 6x86MX, MII and - Intel Pentium Pro/Celeron/Pentium II/Pentium III. - - "K6/II/III" for the AMD K6, K6-II and K6-III (aka K6-3D). + - "Pentium" for the Intel Pentium/Pentium MMX. + - "Pentium-Pro" for the Intel Pentium Pro/Celeron/Pentium II. + - "Pentium-III" for the Intel Pentium III. + - "K6" for the AMD K6, K6-II and K6-III (aka K6-3D). - "Athlon" for the AMD Athlon (K7). + - "Crusoe" for the Transmeta Crusoe series. + - "Winchip-C6" for original IDT Winchip. + - "Winchip-2" for IDT Winchip 2. + - "Winchip-2A/3" for IDT Winchips with 3dNow! capabilities. If you don't know what to do, choose "386". @@ -3067,7 +3073,7 @@ (XF68_FBDev). HGA monochrome support (EXPERIMENTAL) -CONFIG_FBCON_HGA +CONFIG_FB_HGA Say Y here if you have a Hercules mono graphics card. This driver is also available as a module ( = code which can be @@ -3335,6 +3341,11 @@ bits per pixel packed pixels on Mac. It supports variable font widths for low resolution screens. +HGA monochrome support (EXPERIMENTAL) +CONFIG_FBCON_HGA + This is the low level frame buffer console driver for Hercules mono + graphics cards. + VGA characters/attributes support CONFIG_FBCON_VGA This is the low level frame buffer console driver for VGA text mode; @@ -4609,11 +4620,6 @@ addresses on the local network) small. The ethertap device, which lets user space programs read and write raw Ethernet frames, also needs the network link driver. - - This driver is also available as a module called netlink_dev.o ( = - code which can be inserted in and removed from the running kernel - whenever you want). If you want to compile it as a module, say M - here and read Documentation/modules.txt. If unsure, say Y. @@ -5616,8 +5622,8 @@ synchronous data transfers frequency CONFIG_SCSI_NCR53C8XX_SYNC - The SCSI Parallel Interface-2 Standard defines 4 classes of transfer - rates: FAST-5, FAST-10, FAST-20 and FAST-40. The numbers are + The SCSI Parallel Interface-2 Standard defines 5 classes of transfer + rates: FAST-5, FAST-10, FAST-20, FAST-40 and FAST-80. The numbers are respectively the maximum data transfer rates in mega-transfers per second for each class. For example, a FAST-20 Wide 16 device is able to transfer data at 20 million 16 bit packets per second for a total @@ -5625,9 +5631,9 @@ You may specify 0 if you want to only use asynchronous data transfers. This is the safest and slowest option. Otherwise, specify - a value between 5 and 40, depending on the capability of your SCSI + a value between 5 and 80, depending on the capability of your SCSI controller. The higher the number, the faster the data transfer. - Note that 40 should normally be ok since the driver decreases the + Note that 80 should normally be ok since the driver decreases the value automatically according to the controller's capabilities. Your answer to this question is ignored for controllers with NVRAM, @@ -5638,7 +5644,7 @@ second). The normal answer therefore is not to go with the default but to - select the maximum value 40 allowing the driver to use the maximum + select the maximum value 80 allowing the driver to use the maximum value supported by each controller. If this causes problems with your SCSI devices, you should come back and decrease the value. @@ -8527,9 +8533,10 @@ EtherExpress PRO support CONFIG_EEXPRESS_PRO - If you have a network (Ethernet) card of this type, say Y. Note - however that the EtherExpress PRO/100 Ethernet card has its own - separate driver. Please read the Ethernet-HOWTO, available from + If you have a network (Ethernet) card of this type, say Y. This + driver supports intel i82595{FX,TX} based boards. Note however + that the EtherExpress PRO/100 Ethernet card has its own separate + driver. Please read the Ethernet-HOWTO, available from http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be @@ -8641,6 +8648,22 @@ module, say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. +IBM LAN Adapter/A support +CONFIG_IBMLANA + This is a Micro Channel ethernet adapter. You need to set CONFIG_MCA + to use this driver. It is both available as an in-kernel driver and + as a module ( = code which can be inserted in and removed from the + running kernel whenever you want). If you want to compile it as a module, + say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. If you plan to use more than + one network card under linux, read the Multiple-Ethernet-mini-HOWTO, + available from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. The only + currently supported card is the IBM LAN Adapter/A for Ethernet. It will + both support 16K and 32K memory windows, however a 32K window gives + a better security against packet losses. Usage of multiple boards with + this driver should be possible, but has not been tested up to now due + to lack of hardware. + EISA, VLB, PCI and on board controllers CONFIG_NET_PCI This is another class of network cards which attach directly to the @@ -9584,7 +9607,7 @@ USB Human Interface Device (HID) support CONFIG_USB_HID Say Y here if you want to connect keyboards, mice, joysticks, - graphic tablets, UPS's or any other HID based devices to your + graphic tablets, or any other HID based devices to your computer via USB. More information is available: Documentation/usb/input.txt. @@ -9616,16 +9639,16 @@ 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 usbmouse.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + The module will be called usbmouse.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. If unsure, say N. Wacom Intuos/Graphire tablet support CONFIG_USB_WACOM - Say Y here if you want to use the USB version of the Wacom Intuos or - Graphire tablet. Make sure to say Y to "Mouse support" - (CONFIG_INPUT_MOUSEDEV) and "Event interface support" + Say Y here if you want to use the USB version of the Wacom Intuos + or Graphire tablet. Make sure to say Y to "Mouse support" + (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support" (CONFIG_INPUT_EVDEV) as well. This driver is also available as a module ( = code which can be @@ -9636,7 +9659,7 @@ Logitech WingMan Force joystick support CONFIG_USB_WMFORCE Say Y here if you want to use the Logitech WingMan Force with Linux - on the USB port. No force-feedback support yet, but other than that, + on the USB port. No force-feedback support yet, but other than that it should work like a normal joystick. This driver is also available as a module ( = code which can be @@ -9657,31 +9680,35 @@ Mouse support CONFIG_INPUT_MOUSEDEV Say Y here if you want your USB HID mouse to be accessible as - misc devices 32+ under /dev/, as an emulated PS/2 mouse. That way, - all user space programs will be able to use your mouse. + char devices 13:32+ - /dev/input/mouseX and 13:63 - /dev/input/mice + as an emulated PS/2 mouse. That way, all user space programs will + be able to use your mouse. If unsure, say Y. 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 mousedev.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + The module will be called mousedev.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. Horizontal screen resolution CONFIG_INPUT_MOUSEDEV_SCREEN_X - For the mouse emulation to be correct, the mousedev driver needs to - know the screen resolution you are using (in the X window system). + If you're using a digitizer, or a graphic tablet, and want to use + it as a mouse then the mousedev driver needs to know the X window + screen resolution you are using to correctly scale the data. If + you're not using a digitizer, this value is ignored. Vertical screen resolution CONFIG_INPUT_MOUSEDEV_SCREEN_Y - For the mouse emulation to be correct, the mousedev driver needs to - know the screen resolution you are using (in the X window system). + If you're using a digitizer, or a graphic tablet, and want to use + it as a mouse then the mousedev driver needs to know the X window + screen resolution you are using to correctly scale the data. If + you're not using a digitizer, this value is ignored. Joystick support CONFIG_INPUT_JOYDEV Say Y here if you want your USB HID joystick or gamepad to be - accessible as a /dev/js device. You can't use a normal (non-USB) - joystick if you say Y here. + accessible as char device 13:0+ - /dev/input/jsX device. This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -9691,7 +9718,7 @@ Event interface support CONFIG_INPUT_EVDEV Say Y here if you want your USB HID device events be accessible - under /dev/inputX (misc 64+) in a generic way. + under char device 13:64+ - /dev/inputX in a generic way. This is the future ... USB Scanner support @@ -9943,6 +9970,17 @@ Most users want to say Y here. +USB Bandwidth allocation +CONFIG_USB_BANDWIDTH + If you say Y here, the USB subsystem enforces USB bandwidth + allocation and will prevent some device opens from succeeding + if they would cause USB bandwidth usage to go above 90% of + the bus bandwidth. + + If you say N here, these conditions will cause warning messages + about USB bandwidth usage to be logged and some devices or + drivers may not work correctly. + DABUSB driver CONFIG_USB_DABUSB A Digital Audio Broadcasting (DAB) Receiver for USB and Linux @@ -9998,6 +10036,15 @@ The module will be called dsbr100.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +Microtek USB scanner support +CONFIG_USB_MICROTEK + Say Y here if you want support for the Microtek X6USB and possibly + some other scanners. The scanner will appear as a scsi device to the + rest of the system. A patched version of SANE is necessary to use the + scanner. It's available at + http://fachschaft.cup.uni-muenchen.de/~neukum/scanner.html + This driver can be compiled as a module. + Minix fs support CONFIG_MINIX_FS Minix is a simple operating system used in many classes about OS's. @@ -10438,6 +10485,13 @@ If you would like to include the NFSv3 server as well as the NFSv2 server, say Y here. If unsure, say Y. +Provide NFS over TCP server support DEVELOPER ONLY +CONFIG_NFSD_TCP + If you are a developer and want to work on fixing problems with + NFS server over TCP support, say Y here. If unsure, say N. + + Some problems can be found by looking for FIXME in net/sunrpc/svcsock.c + OS/2 HPFS file system support CONFIG_HPFS_FS OS/2 is IBM's operating system for PC's, the same as Warp, and HPFS @@ -11661,7 +11715,7 @@ If you want kernel messages to be printed out as they occur, you can have a console on the printer. This option adds support for doing that; to actually get it to happen you need to pass the - option "console=lp" to the kernel at boot time. + option "console=lp0" to the kernel at boot time. Note that kernel messages can get lost if the printer is out of paper (or off, or unplugged, or too busy..), but this behaviour @@ -12316,6 +12370,22 @@ If unsure, say N. +Intel Random Number Generator support +CONFIG_INTEL_RNG + This driver provides kernel-side support for the Random Number + Generator hardware found on Intel i8xx-based motherboards. + + Both a character driver, used to read() entropy data, and a timer + function which automatically adds entropy directly into the + kernel pool, are exported by this driver. + + 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 Documentation/modules.txt. The module will be called + i810_rng.o. + + If unsure, say N. + Power Management support CONFIG_PM "Power Management" means that parts of your computer are shut @@ -12640,7 +12710,7 @@ For latest news and information on obtaining all the required ingredients for this driver, check: - http://www.ocston.org/~tigran/patches/microcode . + http://www.urbanmyth.org/microcode/ This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -12731,143 +12801,183 @@ weapon control system or something like that you can say Y here to enable generic support for these controllers. You will also need to say Y or M to at least one of the hardware specific drivers. This - will make the controllers available as /dev/jsX devices. Please read - the file Documentation/joystick.txt which contains more information - and the location of the joystick package that you'll need. + will make the controllers available as /dev/input/jsX devices. + Please read the file Documentation/joystick.txt which contains more + information and the location of the joystick package that you'll + need. + +ns558 gameports +CONFIG_INPUT_NS558 + Say Y here if you have an ISA, ISAPnP or PCI standard gameport. + For more information on how to use the driver please read + Documentation/joystick.txt 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 joystick.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + The module will be called ns558.o. If you want to compile + it as a module, say M here and read Documentation/modules.txt. + +PDPI Lightning 4 gamecard +CONFIG_INPUT_LIGHTNING + Say Y here if you have a PDPI Lightning 4 gamecard. For more + information on how to use the driver please read + Documentation/joystick.txt + + 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 lightning.o. If you want to compile + it as a module, say M here and read Documentation/modules.txt. + +Aureal Vortex and Trident 4DWave gameports +CONFIG_INPUT_PCIGAME + Say Y here if you have a Trident 4DWave DX/NX or Aureal Vortex 1/2 + card. For more information on how to use the driver please read + Documentation/joystick.txt -Classic PC analog -CONFIG_JOY_ANALOG + 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 pcigame.o. If you want to compile + it as a module, say M here and read Documentation/modules.txt. + +Classic PC analog joysticks and gamepads +CONFIG_INPUT_ANALOG Say Y here if you have a controller that connects to the PC gameport. This supports many different types, including joysticks with throttle control, with rudders, or with extensions like additional hats and buttons compatible with CH Flightstick Pro, - ThrustMaster FCS or 6 and 8 button gamepads. For more information on - how to use the driver please read Documentation/joystick.txt + ThrustMaster FCS, 6 and 8 button gamepads, or Saitek Cyborg + joysticks. For more information on how to use the driver please read + Documentation/joystick.txt 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 joy-analog.o. If you want to compile + The module will be called analog.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -FPGaming and MadCatz A3D -CONFIG_JOY_ASSASSIN +Assasin 3D and MadCatz Panther devices +CONFIG_INPUT_A3D Say Y here if you have an FPGaming or MadCatz controller using the A3D protocol over the PC gameport. For more information on how to use the driver please read Documentation/joystick.txt 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 joy-assasin.o. If you want to compile + The module will be called a3d.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -Gravis GrIP -CONFIG_JOY_GRAVIS - Say Y here if you have a Gravis controller using the GrIP protocol - over the PC gameport. For more information on how to use the driver - please read Documentation/joystick.txt +Logitech ADI digital joysticks and gamepads +CONFIG_INPUT_ADI + Say Y here if you have a Logitech controller using the ADI + protocol over the PC gameport. For more information on how to use + the driver please read Documentation/joystick.txt 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 joy-gravis.o. If you want to compile + The module will be called adi.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -Logitech ADI -CONFIG_JOY_LOGITECH - Say Y here if you have a Logitech controller using the ADI - protocol over the PC gameport. For more information on how to use - the driver please read Documentation/joystick.txt +Creative Labs Blaster Cobra gamepad +CONFIG_INPUT_COBRA + Say Y here if you have a Creative Labs Blaster Cobra gamepad. + For more information on how to use the driver please read + Documentation/joystick.txt 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 joy-logitech.o. If you want to compile + The module will be called cobra.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -Microsoft SideWinder -CONFIG_JOY_SIDEWINDER - Say Y here if you have a Microsoft controller using the Digital - Overdrive protocol over PC gameport. For more information on how to - use the driver please read Documentation/joystick.txt +Genius Flight2000 Digital joysticks and gamepads +CONFIG_INPUT_GF2K + Say Y here if you have a Genius Flight2000 or MaxFighter + digitally communicating joystick or gamepad. For more information + on how to use the driver please read Documentation/joystick.txt 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 joy-sidewinder.o. If you want to compile + The module will be called gf2k.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -ThrustMaster DirectConnect -CONFIG_JOY_THRUSTMASTER - Say Y here if you have a ThrustMaster controller using the - DirectConnect (BSP) protocol over the PC gameport. For more - information on how to use the driver please read - Documentation/joystick.txt +Gravis GrIP joysticks and gamepads +CONFIG_INPUT_GRIP + Say Y here if you have a Gravis controller using the GrIP protocol + over the PC gameport. For more information on how to use the driver + please read Documentation/joystick.txt 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 joy-thrustmaster.o. If you want to compile + The module will be called grip.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -Creative Labs Blaster -CONFIG_JOY_CREATIVE - Say Y here if you have a Creative Labs controller using the - Blaster protocol over the PC gameport. For more information on how - to use the driver please read Documentation/joystick.txt +InterAct digital joysticks and gamepads +CONFIG_INPUT_INTERACT + Say Y hereif you have an InterAct gameport or joystick + communicating digitally over the gameport. For more information on + how to use the driver please read Documentation/joystick.txt 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 joy-creative.o. If you want to compile + The module will be called interact.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -PDPI Lightning 4 cards -CONFIG_JOY_LIGHTNING - Say Y here if you have a PDPI Lightning 4 gamecard and an analog - joystick or gamepad connected to it. For more information on how to +ThrustMaster DirectConnect joysticks and gamepads +CONFIG_INPUT_TMDC + Say Y here if you have a ThrustMaster controller using the + DirectConnect (BSP) protocol over the PC gameport. For more + information on how to use the driver please read + Documentation/joystick.txt + + 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 tmdc.o. If you want to compile + it as a module, say M here and read Documentation/modules.txt. + +Microsoft SideWinder digital joysticks and gamepads +CONFIG_INPUT_SIDEWINDER + Say Y here if you have a Microsoft controller using the Digital + Overdrive protocol over PC gameport. For more information on how to use the driver please read Documentation/joystick.txt 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 joy-lightning.o. If you want to compile + The module will be called sidewinder.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -Logitech WingMan Warrior -CONFIG_JOY_WARRIOR - Say Y here if you have a Logitech WingMan Warrior controller - connected to your computer's serial port. For more information on - how to use the driver please read Documentation/joystick.txt +Serial port input line discipline +CONFIG_INPUT_SERPORT + Say Y hereif you plan to use a joystick that communicates over the + serial (COM) port. For more information on how to use the driver + please read Documentation/joystick.txt 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 joy-warrior.o. If you want to compile + The module will be called serport.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -Trident 4DWave and Aureal Vortex gameport -CONFIG_JOY_PCI - Say Y here if you have a Trident 4DWave DX/NX or Aureal Vortex 1/2 - card and want to use its gameport in its enhanced digital mode - with and ordinary analog joystick. For more information on how to - use the driver please read Documentation/joystick.txt +Logitech WingMan Warrior joystick +CONFIG_INPUT_WARRIOR + Say Y here if you have a Logitech WingMan Warrior joystick + connected to your computer's serial port. For more information on + how to use the driver please read Documentation/joystick.txt 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 joy-pci.o. If you want to compile + The module will be called warrior.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -Magellan and Space Mouse -CONFIG_JOY_MAGELLAN +LogiCad3d Magellan/SpaceMouse 6dof controller +CONFIG_INPUT_MAGELLAN Say Y here if you have a Magellan or Space Mouse 6DOF controller connected to your computer's serial port. For more information on how to use the driver please read Documentation/joystick.txt 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 joy-magellan.o. If you want to compile + The module will be called magellan.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -SpaceTec SpaceOrb 360 and SpaceBall Avenger -CONFIG_JOY_SPACEORB +SpaceTec SpaceOrb/Avenger 6dof controller +CONFIG_INPUT_SPACEORB Say Y here if you have a SpaceOrb 360 or SpaceBall Avenger 6DOF controller connected to your computer's serial port. For more information on how to use the driver please read @@ -12875,37 +12985,39 @@ 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 joy-spaceorb.o. If you want to compile + The module will be called spaceorb.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -SpaceTec SpaceBall 4000 FLX -CONFIG_JOY_SPACEBALL - Say Y here if you have a SpaceTec SpaceBall 4000 FLX - controller connected to your computer's serial port. For more - information on how to use the driver please read - Documentation/joystick.txt +SpaceTec SpaceBall 4000 FLX 6dof controller +CONFIG_INPUT_SPACEBALL + Say Y here if you have a SpaceTec SpaceBall 4000 FLX controller + connected to your computer's serial port. For more information on + how to use the driver please read Documentation/joystick.txt + +I-Force joysticks/wheels +CONFIG_INPUT_IFORCE_232 + Say Y here if you have an I-Force joystick or steering wheel + connected to your serial (COM) port. For more information on + how to use the driver please read Documentation/joystick.txt 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 joy-spaceball.o. If you want to compile + The module will be called iforce.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. - -NES, SNES, N64, PSX, Multi -CONFIG_JOY_CONSOLE - Say Y here if you have a Nintendo Entertainment System gamepad, - Super Nintendo Entertainment System gamepad, Nintendo 64 gamepad, - Sony PlayStation gamepad or a Multisystem -- Atari, Amiga, - Commodore, Amstrad CPC joystick connected to your parallel port. - For more information on how to use the driver please read - Documentation/joystick.txt and Documentation/joystick-parport.txt + +I-Force joysticks/wheels +CONFIG_INPUT_IFORCE_USB + Say Y here if you have an I-Force joystick or steering wheel + connected to your USB port. For more information on how to use the + driver please read Documentation/joystick.txt 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 joy-console.o. If you want to compile + The module will be called iforce.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. - -Sega, Multi -CONFIG_JOY_DB9 + +Multisystem, Sega Genesis, Saturn joysticks and gamepads +CONFIG_INPUT_DB9 Say Y here if you have a Sega Master System gamepad, Sega Genesis gamepad, Sega Saturn gamepad, or a Multisystem -- Atari, Amiga, Commodore, Amstrad CPC joystick connected to your parallel port. @@ -12914,24 +13026,38 @@ 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 joy-db9.o. If you want to compile + The module will be called db9.o. If you want to compile + it as a module, say M here and read Documentation/modules.txt. + +Multisystem, NES, SNES, N64, PSX joysticks and gamepads +CONFIG_INPUT_GAMECON + Say Y here if you have a Nintendo Entertainment System gamepad, + Super Nintendo Entertainment System gamepad, Nintendo 64 gamepad, + Sony PlayStation gamepad or a Multisystem -- Atari, Amiga, + Commodore, Amstrad CPC joystick connected to your parallel port. + For more information on how to use the driver please read + Documentation/joystick.txt and Documentation/joystick-parport.txt + + 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 gamecon.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -TurboGraFX Multisystem interface -CONFIG_JOY_TURBOGRAFX - Say Y here if you have the TurboGraFX interface by Steffen Schwenke, - and want to use it with Multiststem -- Atari, Amiga, Commodore, - Amstrad CPC joystick. For more information on how to use the driver - please read Documentation/joystick.txt and +Multisystem joysticks via TurboGraFX device +CONFIG_INPUT_TURBOGRAFX + Say Y here if you have the TurboGraFX interface by Steffen + Schwenke, and want to use it with Multiststem -- Atari, Amiga, + Commodore, Amstrad CPC joystick. For more information on how to use + the driver please read Documentation/joystick.txt and Documentation/joystick-parport.txt 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 joy-turbografx.o. If you want to compile + The module will be called turbografx.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. Amiga joysticks -CONFIG_JOY_AMIGA +CONFIG_INPUT_AMIJOY Say Y here if you have an Amiga with a digital joystick connected to it. For more information on how to use the driver please read Documentation/joystick.txt @@ -13525,16 +13651,19 @@ differs slightly from OSS/Free, so PLEASE READ Documentation/sound/sonicvibes. -Trident 4DWave DX/NX or SiS 7018 PCI Audio Core +Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core CONFIG_SOUND_TRIDENT Say Y or M if you have a PCI sound card utilizing the Trident 4DWave-DX/NX chipset or your mother board chipset has SiS 7018 - built-in. The SiS 7018 PCI Audio Core is embedded in SiS960 - Super South Bridge and SiS540/630 Single Chipset. + or ALi 5451 built-in. The SiS 7018 PCI Audio Core is embedded + in SiS960 Super South Bridge and SiS540/630 Single Chipset. + The ALi 5451 PCI Audio Core is embedded in ALi M1535, M1535D, + M1535+ or M1535D+ South Bridge. Use lspci -n to find out if your sound card or chipset uses Trident 4DWave or SiS 7018. PCI ID 1023:2000 or 1023:2001 stands - for Trident 4Dwave. PCI ID 1039:7018 stands for SiS7018. + for Trident 4Dwave. PCI ID 1039:7018 stands for SiS7018. PCI ID + 10B9:5451 stands for ALi5451. This driver differs slightly from OSS/Free, so PLEASE READ the comments at the top of driver/sound/trident.c @@ -13598,7 +13727,9 @@ 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). The + 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 Documentation/sysrq.txt. Don't say Y unless you really know what this hack does. @@ -14159,7 +14290,7 @@ The OpenBoot PROM on Ultra systems is flashable. If you want to be able to upgrade the OBP firmware, say Y here. -JavaStation OS Flash SIMM (EXPERIMENTAL) +JavaStation OS Flash SIMM CONFIG_SUN_JSFLASH If you say Y here, you will be able to boot from your JavaStation's Flash memory. @@ -14724,11 +14855,19 @@ Processor Type CONFIG_6xx - There are three types of PowerPC chips supported. The more common + There are four types of PowerPC chips supported. The more common types (601, 603, 604, 740, 750), the Motorola embedded versions - (821, 823, 850, 855, 860), and the IBM embedded versions (403 and - 405). Unless you are building a kernel for one of the embedded - processor systems, choose 6xx. + (821, 823, 850, 855, 860), the IBM embedded versions (403 and + 405) and the high end 64 bit Power processors (Power 3, Power 4). + Unless you are building a kernel for one of the embedded + processor systems, or a 64 bit IBM RS/6000, choose 6xx. + +CONFIG_PPC64BRIDGE + Currently there is not a 64 bit PowerPC Linux kernel. As a result + if you choose the CONFIG_POWER3 or CONFIG_POWER4 options you + must choose this option as well. This enables gcc to emit + both 32 and 64 bit instructions as well as cause your kernel + to be built as a 32 bit kernel. Machine Type CONFIG_PMAC @@ -14740,6 +14879,22 @@ only supports one type or the other. However, there is very early work on support for CHRP, PReP and PowerMac's from a single binary. +Power management support for PowerBooks +CONFIG_PMAC_PBOOK + This provides support for putting a PowerBook to sleep; it also + enables media bay support. Power management works on the + PB2400/3400/3500, Wallstreet, Lombard, and Bronze PowerBook G3. You + must get the power management daemon, pmud, to make it work and you + must have the /dev/pmu device (see the pmud README). + + Get pmud from ftp://linuxcare.com.au/pub/ppclinux/pmud/ + + If you have a PowerBook, you should say Y. + + You may also want to compile the dma sound driver as a module and + have it autoloaded. The act of removing the module shuts down the + sound hardware for more power savings. + Support for Open Firmware device tree in /proc CONFIG_PROC_DEVICETREE This option adds a device-tree directory under /proc which contains @@ -15213,6 +15368,11 @@ from the running kernel whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. +SAB3036 tuner support +CONFIG_TUNER_3036 + Say Y here to include support for Philips SAB3036 compatible tuners. + If in doubt, say N. + Compaq SMART2 support CONFIG_BLK_CPQ_DA This is the driver for Compaq Smart Array controllers. @@ -15231,15 +15391,46 @@ to set this option to, please consult any information supplied with your system. +Include support for the CATS +CONFIG_ARCH_CATS + Say Y here if you intend to run this kernel on the CATS. + + Saying N will reduce the size of the Footbridge kernel. + +Include support for the EBSA285 +CONFIG_ARCH_EBSA285 + Say Y here if you intend to run this kernel on the EBSA285 card + in host ("central function") mode. + + Saying N will reduce the size of the Footbridge kernel. + +Include support for the LinkUp Systems L7200 SDB +CONFIG_ARCH_L7200 + Say Y here if you intend to run this kernel on a LinkUp Systems + L7200 Software Development Board which uses an ARM720T processor. + Information on this board can be obtained at: + + http://www.linkupsys.com/ + + If you have any questions or comments about the Linux kernel port + to this board, send e-mail to sjhill@cotw.com + Include support for the NetWinder CONFIG_ARCH_NETWINDER - Say Y here if you intend to run this kernel on the NetWinder. + Say Y here if you intend to run this kernel on the Rebel.COM + NetWinder. Information about this machine can be found at: + + http://www.netwinder.org/ + + Saying N will reduce the size of the Footbridge kernel. Include support for the Compaq Personal Server CONFIG_ARCH_PERSONAL_SERVER Say Y here if you intend to run this kernel on the Compaq Personal Server. + Saying N will reduce the size of the Footbridge kernel. + The Compaq Personal Server is not available for purchase. There are no product plans beyond the current research prototypes at this time. Information is available at: @@ -15249,17 +15440,6 @@ If you have any questions or comments about the Compaq Personal Server, send e-mail to skiff@crl.dec.com -Include support for the LinkUp Systems L7200 SDB -CONFIG_ARCH_L7200 - Say Y here if you intend to run this kernel on a LinkUp Systems - L7200 Software Development Board which uses an ARM720T processor. - Information on this board can be obtained at: - - http://www.linkupsys.com/ - - If you have any questions or comments about the Linux kernel port - to this board, send e-mail to sjhill@cotw.com - Math emulation CONFIG_NWFPE Say Y to include the NWFPE floating point emulator in the kernel. @@ -15411,6 +15591,41 @@ the cylinders/heads/sectors count on your hard drive. WARNING: This sometimes doesn't work and it also does some dodgy stuff which potentially might damage your drive. + +NetWinder /dev/flash support +CONFIG_NWFLASH + If you say Y here and create a character device /dev/flash with + major 10 and minor 160 you can manipulate the flash ROM containing + the NetWinder firmware. Be careful as accidentally overwriting the + flash contents can render your computer unbootable. On no account + allow random users access to this device. :-) + + 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 nwflash.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + + If you're not sure, say N. + +Footbridge internal watchdog +CONFIG_21285_WATCHDOG + The Intel Footbridge chip contains a builtin watchdog circuit. Say Y + here if you wish to use this. Alternatively say M to compile the + driver as a module, which will be called wdt285.o. + + This driver does not work on all machines. In particular, early CATS + boards have hardware problems that will cause the machine to simply + lock up if the watchdog fires. + + "If in doubt, leave it out" - say N. + +NetWinder WB977 watchdog +CONFIG_977_WATCHDOG + Say Y here to include support for the WB977 watchdog included in + NetWinder machines. Alternatively say M to compile the driver as + a module, which will be called wdt977.o. + + Not sure? It's safe to say N. IrDA subsystem support CONFIG_IRDA diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/DocBook/Makefile linux/Documentation/DocBook/Makefile --- v2.4.0-test1/linux/Documentation/DocBook/Makefile Mon Jun 19 16:31:56 2000 +++ linux/Documentation/DocBook/Makefile Mon Jun 19 12:56:07 2000 @@ -1,11 +1,17 @@ -BOOKS := wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml kernel-api.sgml parportbook.sgml kernel-hacking.sgml kernel-locking.sgml +BOOKS := wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml \ + kernel-api.sgml parportbook.sgml kernel-hacking.sgml \ + kernel-locking.sgml via-audio.sgml mousedrivers.sgml PS := $(patsubst %.sgml, %.ps, $(BOOKS)) PDF := $(patsubst %.sgml, %.pdf, $(BOOKS)) +HTML := $(patsubst %.sgml, %, $(BOOKS)) +IMG-parportbook := parport-share.fig parport-multi.fig parport-structure.fig +EPS-parportbook := $(patsubst %.fig, %.eps, $(IMG-parportbook)) +JPG-parportbook := $(patsubst %.fig, %.jpeg, $(IMG-parportbook)) $(BOOKS): $(TOPDIR)/scripts/docproc -.PHONY: books ps pdf clean mrproper db2ps db2pdf +.PHONY: books ps pdf html clean mrproper db2ps db2pdf db2html books: $(BOOKS) @@ -13,7 +19,9 @@ pdf: $(PDF) -db2ps db2pdf: +html: $(HTML) + +db2ps db2pdf db2html: @(which $@ > /dev/null 2>&1) || \ (echo "*** You need to install DocBook stylesheets ***"; \ exit 1) @@ -21,37 +29,45 @@ %.eps: %.fig -fig2dev -Leps $< $@ +%.jpeg: %.fig + -fig2dev -Ljpeg $< $@ + $(TOPDIR)/scripts/docproc: $(MAKE) -C $(TOPDIR)/scripts docproc +mousedrivers.sgml: mousedrivers.tmpl + $(TOPDIR)/scripts/docgen <$< >$@ + kernel-hacking.sgml: kernel-hacking.tmpl $(TOPDIR)/scripts/docgen <$< >$@ kernel-locking.sgml: kernel-locking.tmpl $(TOPDIR)/scripts/docgen <$< >$@ -wanbook.sgml: wanbook.tmpl +wanbook.sgml: wanbook.tmpl $(TOPDIR)/drivers/net/wan/syncppp.c $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/net/wan/syncppp.c \ wanbook.sgml -z8530book.sgml: z8530book.tmpl +z8530book.sgml: z8530book.tmpl $(TOPDIR)/drivers/net/wan/z85230.c $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/net/wan/z85230.c \ z8530book.sgml -mcabook.sgml: mcabook.tmpl +via-audio.sgml: via-audio.tmpl $(TOPDIR)/drivers/sound/via82cxxx_audio.c + $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/sound/via82cxxx_audio.c \ + via-audio.sgml + +mcabook.sgml: mcabook.tmpl $(TOPDIR)/arch/i386/kernel/mca.c $(TOPDIR)/scripts/docgen $(TOPDIR)/arch/i386/kernel/mca.c \ mcabook.sgml -videobook.sgml: videobook.tmpl +videobook.sgml: videobook.tmpl $(TOPDIR)/drivers/char/videodev.c $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/char/videodev.c \ videobook.sgml -kernel-api.sgml: kernel-api.tmpl - $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/char/videodev.c \ +APISOURCES := $(TOPDIR)/drivers/char/videodev.c \ $(TOPDIR)/arch/i386/kernel/mca.c \ $(TOPDIR)/arch/i386/kernel/mtrr.c \ $(TOPDIR)/drivers/char/misc.c \ - $(TOPDIR)/drivers/char/videodev.c \ $(TOPDIR)/drivers/net/net_init.c \ $(TOPDIR)/drivers/net/8390.c \ $(TOPDIR)/drivers/char/serial.c \ @@ -63,10 +79,15 @@ $(TOPDIR)/fs/devfs/base.c \ $(TOPDIR)/kernel/pm.c \ $(TOPDIR)/kernel/ksyms.c \ - $(TOPDIR)/net/netsyms.c \ + $(TOPDIR)/net/netsyms.c + +kernel-api.sgml: kernel-api.tmpl $(APISOURCES) + $(TOPDIR)/scripts/docgen $(APISOURCES) \ kernel-api.sgml -parportbook.sgml: parportbook.tmpl +parportbook: $(JPG-parportbook) +parportbook.ps: $(EPS-parportbook) +parportbook.sgml: parportbook.tmpl $(TOPDIR)/drivers/parport/init.c $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/parport/init.c \ parportbook.sgml @@ -74,23 +95,28 @@ AUX := $(patsubst %.sgml, %.aux, $(BOOKS)) TEX := $(patsubst %.sgml, %.tex, $(BOOKS)) LOG := $(patsubst %.sgml, %.log, $(BOOKS)) +OUT := $(patsubst %.sgml, %.out, $(BOOKS)) clean: -$(RM) core *~ -$(RM) $(BOOKS) - -$(RM) $(DVI) $(AUX) $(TEX) $(LOG) - -$(RM) parport-share.eps parport-multi.eps parport-structure.eps + -$(RM) $(DVI) $(AUX) $(TEX) $(LOG) $(OUT) + -$(RM) $(JPG-parportbook) $(EPS-parportbook) mrproper: clean -$(RM) $(PS) $(PDF) - -parportbook.ps: parport-share.eps parport-multi.eps parport-structure.eps + -$(RM) -r $(HTML) %.ps : %.sgml db2ps db2ps $< -%.pdf : %.sgml +%.pdf : %.sgml db2pdf db2pdf $< + +%: %.sgml db2html + -$(RM) -r $@ + db2html $< + if [ ! -z "$(JPG-$@)" ]; then cp $(JPG-$@) $@; fi include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/DocBook/kernel-api.tmpl linux/Documentation/DocBook/kernel-api.tmpl --- v2.4.0-test1/linux/Documentation/DocBook/kernel-api.tmpl Tue May 23 15:31:32 2000 +++ linux/Documentation/DocBook/kernel-api.tmpl Mon Jun 19 12:56:07 2000 @@ -34,6 +34,20 @@ + + Data Types + Doubly Linked Lists +!Iinclude/linux/list.h + + + + + Memory Management in Linux + The Slab Cache +!Emm/slab.c + + + The Linux VFS The Directory Cache diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/DocBook/kernel-locking.tmpl linux/Documentation/DocBook/kernel-locking.tmpl --- v2.4.0-test1/linux/Documentation/DocBook/kernel-locking.tmpl Tue May 23 15:31:32 2000 +++ linux/Documentation/DocBook/kernel-locking.tmpl Mon Jun 19 12:56:07 2000 @@ -208,7 +208,12 @@ your task will put itself on the queue, and be woken up when the semaphore is released. This means the CPU will do something else while you are waiting, but there are many cases when you - simply can't sleep, and so have to use a spinlock instead. + simply can't sleep (see ), and so + have to use a spinlock instead. + + + Neither type of lock is recursive: see + . @@ -430,7 +435,7 @@ Hardware interrupts usually communicate with a bottom half, - tasklet or softirq. Frequently this involved putting work in a + tasklet or softirq. Frequently this involves putting work in a queue, which the BH/softirq will take out. @@ -522,8 +527,8 @@ There is a coding bug where a piece of code tries to grab a spinlock twice: it will spin forever, waiting for the lock to - be released (spinlocks and writelocks are not re-entrant in - Linux). This is trivial to diagnose: not a + be released (spinlocks, rwlocks and semaphores are not + recursive in Linux). This is trivial to diagnose: not a stay-up-five-nights-talk-to-fluffy-code-bunnies kind of problem. @@ -754,37 +759,15 @@ - Dropping or gaining a spinlock, and any atomic operation are - all defined to act as memory barriers (ie. as per the - mb() macro). - - - - There is a similar, but unrelated, problem with code like the - following: - - - - if (!(ctrack->status & IPS_CONFIRMED)) { - spin_lock_bh(&ip_conntrack_lock); - if (!(ctrack->status & IPS_CONFIRMED)) { - clean_from_lists(h->ctrack); - h->ctrack->status |= IPS_CONFIRMED; - } - spin_unlock_bh(&ip_conntrack_lock); - } - - - - In this case, the author has tried to be tricky: knowing that - the CONFIRMED bit is set and never reset in the status word, - you can test it outside the lock, and frequently avoid - grabbing the lock at all. However, the compiler could cache - the value in a register, rather than rereading it once the - lock is obtained, creating a subtle race. The way to get - around this is to declare the status field `volatile', or use - a temporary volatile pointer to achieve the same effect in - this one place. + Any atomic operation is defined to act as a memory barrier + (ie. as per the mb() macro). Also, + spinlock operations act as partial barriers: operations after + gaining a spinlock will never be moved to precede the + spin_lock() call, and operations before + releasing a spinlock will never be moved after the + spin_unlock() call. + @@ -911,7 +894,8 @@ You can never call the following routines while holding a - spinlock, as they may sleep: + spinlock, as they may sleep. This also means you need to be in + user context. @@ -952,11 +936,19 @@ - printk(), which can be called from - user context, interestingly enough. + down_interruptible() and + down() + + + There is a down_trylock() which can be + used inside interrupt context, as it will not sleep. + up() will also never sleep. + + printk() can be called in + any context, interestingly enough. @@ -1047,9 +1039,11 @@ Another common problem is deleting timers which restart themselves (by calling add_timer() at the end of their timer function). Because this is a fairly common case - which is prone to races, the function del_timer_sync() - (include/linux/timer.h) is - provided to handle this case. It returns the number of times the timer + which is prone to races, you can put a call to + timer_exit() at the very end of your timer function, + and user del_timer_sync() + (include/linux/timer.h) + to handle this case. It returns the number of times the timer had to be deleted before we finally stopped it from adding itself back in. @@ -1093,8 +1087,8 @@ Thanks to Martin Pool, Philipp Rumpf, Stephen Rothwell, Paul - Mackerras, Ruedi Aschwanden, Alan Cox for proofreading, - correcting, flaming, commenting. + Mackerras, Ruedi Aschwanden, Alan Cox, Manfred Spraul and Tim + Waugh for proofreading, correcting, flaming, commenting. diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/DocBook/mousedrivers.tmpl linux/Documentation/DocBook/mousedrivers.tmpl --- v2.4.0-test1/linux/Documentation/DocBook/mousedrivers.tmpl Wed Dec 31 16:00:00 1969 +++ linux/Documentation/DocBook/mousedrivers.tmpl Mon Jun 19 12:56:07 2000 @@ -0,0 +1,1022 @@ + + + + + Mouse Drivers + + + + Alan + Cox + +
+ alan@redhat.com +
+
+
+
+ + + 2000 + Alan Cox + + + + + This documentation is free software; you can redistribute + it and/or modify it under the terms of the GNU 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 + + + + For more details see the file COPYING in the source + distribution of Linux. + + +
+ + + + + Introduction + + Earlier publication + + Parts of this document first appeared in Linux Magazine under a + ninety day exclusivity. + + + + + Mice are conceptually one of the simplest device interfaces in the + Linux operating system. Not all mice are handled by the kernel. + Instead there is a two layer abstraction. + + + + The kernel mouse drivers and userspace drivers for the serial mice are + all managed by a system daemon called gpm + - the general purpose mouse driver. gpm + handles cutting and pasting on the text consoles. It provides a + general library for mouse-aware applications and it handles the + sharing of mouse services with the + X Window System user interface. + + + Sometimes a mouse speaks a sufficiently convoluted protocol that the + protocol is handled by Gpm itself. Most + of the mouse drivers follow a common interface called the bus mouse + protocol. + + + Each read from a bus mouse interface device returns a block of data. + The first three bytes of each read are defined as follows: + + + Mouse Data Encoding + + + + Byte 0 + 0x80 + the buttons currently down. + + + Byte 1 + A signed value for the shift in X position + + + Byte 2 + A signed value for the shift in Y position + + + +
+ + An application can choose to read more than 3 bytes. The rest of the + bytes will be zero, or may optionally return some additional + device-specific information. +
+ + The position values are truncated if they exceed the 8bit range (that + is -127 <= delta <= 127). While the value -128 does fit into a + byte is not allowed. + + + The buttons are numbered left to right as + 0, 1, 2, 3.. and each button sets the relevant bit. So a user pressing + the left and right button of a three button mouse will set bits 0 and 2. + + + All mice are required to support the poll + operation. Indeed pretty much every user of a mouse device uses + poll to wait for mouse events to occur. + + + Finally the mice support asynchronous I/O. This is a topic we have not + yet covered but which I will explain after looking at a simple mouse + driver. + +
+ + + A simple mouse driver + + First we will need the set up functions for our mouse device. To keep + this simple our imaginary mouse device has three I/O ports fixed at I/O + address 0x300 and always lives on interrupt 5. The ports will be the X + position, the Y position and the buttons in that order. + + + +#define OURMOUSE_BASE 0x300 + +static struct miscdevice our_mouse = { + OURMOUSE_MINOR, "ourmouse", &our_mouse_fops +}; + +__init ourmouse_init(void) +{ + + if(check_region(OURMOUSE_BASE, 3)) + return -ENODEV; + request_region(OURMOUSE_BASE, 3, "ourmouse"); + + misc_register(&our_mouse); + return 0; +} + + + + The miscdevice is new here. Linux normally + parcels devices out by major number, and each device has 256 units. + For things like mice this is extremely wasteful so a device exists + which is used to accumulate all the odd individual devices that + computers tend to have. + + + Minor numbers in this space are allocated by a central source, although + you can look in the kernel Documentation/devices.txt + file and pick a free one for development use. This kernel file also + carries instructions for registering a device. This may change over time + so it is a good idea to obtain a current copy of this file first. + + + Our code then is fairly simple. We check nobody else has taken our + address space. Having done so we reserve it to ensure nobody stamps + on our device while probing for other ISA bus devices. Such a probe + might confuse our device. + + + Then we tell the misc driver that we wish to own a minor number. We also + hand it our name (which is used in + /proc/misc) and a set of file + operations that are to be used. The file operations work exactly like the + file operations you would register for a normal character device. The misc + device itself is simply acting as a redirector for requests. + + + Next, in order to be able to use and test our code we need to add some + module code to support it. This too is fairly simple: + + +#ifdef MODULE + +int init_module(void) +{ + if(ourmouse_init()<0) + return -ENODEV: + return 0; +} + +void cleanup_module(void) +{ + misc_deregister(&our_mouse); + free_region(OURMOUSE_BASE, 3); +} + + +#endif + + + + The module code provides the normal two functions. The + init_module function is called when the module is + loaded. In our case it simply calls the initialising function we wrote + and returns an error if this fails. This ensures the module will only + be loaded if it was successfully set up. + + + The cleanup_module function is called when the + module is unloaded. We give the miscellaneous device entry back, and + then free our I/O resources. If we didn't free the I/O resources then + the next time the module loaded it would think someone else had its I/O + space. + + + Once the misc_deregister has been called any + attempts to open the mouse device will fail with the error + ENODEV (No such device). + + + Next we need to fill in our file operations. A mouse doesn't need many + of these. We need to provide open, release, read and poll. That makes + for a nice simple structure: + + + +struct file_operations our_mouse_fops = { + NULL, /* Mice don't seek */ + read_mouse, /* You can read a mouse */ + write_mouse, /* This won't do a lot */ + NULL, /* No readdir - not a directory */ + poll_mouse, /* Poll */ + NULL, /* No ioctl calls */ + NULL, /* No mmap */ + open_mouse, /* Called on open */ + NULL, /* Flush - 2.2+ only */ + close_mouse, /* Called on close */ +}; + + + + There is nothing particularly special needed here. We provide functions + for all the relevant or required operations and little else. There is + nothing stopping us providing an ioctl function for this mouse. Indeed + if you have a configurable mouse it may be very appropriate to provide + configuration interfaces via ioctl calls. + + + The open and close routines need to manage enabling and disabling the + interrupts for the mouse as well as stopping the mouse being unloaded + when it is no longer required. + + + +static int mouse_users = 0; /* User count */ +static int mouse_dx = 0; /* Position changes */ +static int mouse_dy = 0; +static int mouse_event = 0; /* Mouse has moved */ + +static int open_mouse(struct inode *inode, struct file *file) +{ + if(mouse_users++) + return 0; + + MOD_INC_USE_COUNT; + + if(request_irq(mouse_intr, OURMOUSE_IRQ, 0, "ourmouse", NULL)) + { + mouse_users--; + MOD_DEC_USE_COUNT; + return -EBUSY; + } + mouse_dx = 0; + mouse_dy = 0; + mouse_event = 0; + mouse_buttons = 0; + return 0; +} + + + The open function has to do a small amount of housework. We keep a count + of the number of times the mouse is open. This is because we do not want + to request the interrupt multiple times. If the mouse has at least one + user then it is set up and we simply add to the user count and return + 0 for success. + + + Firstly we use MOD_INC_USE_COUNT to ensure that + while the mouse is open nobody will unload it and cause a nasty crash. + We must do this before we sleep - and grabbing the interrupt might sleep. + + + We grab the interrupt and thus start mouse interrupts. If the interrupt + has been borrowed by some other driver then request_irq + will fail and we will return an error. If we were capable of sharing an + interrupt line we would specify SA_SHIRQ instead of + zero. Provided that everyone claiming an interrupt + sets this flag, they get to share the line. PCI can + share interrupts, ISA normally however cannot. + + + We do the housekeeping. We make the current mouse position the starting + point for accumulated changes and declare that nothing has happened + since the mouse driver was opened. + + + The release function needs to unwind all these: + + +static int close_mouse(struct inode *inode, struct file *file) +{ + if(--mouse_users) + return 0; + free_irq(OURMOUSE_IRQ, NULL); + MOD_DEC_USE_COUNT; + return 0; +} + + + We count off a user and provided that there are still other users need + take no further action. The last person closing the mouse causes us to + free up the interrupt. This stopps interrupts from the mouse from using + our CPU time, and lets us use MOD_DEC_USE_COUNT so + that the mouse can now be unloaded. + + + We can fill in the write handler at this point as the write function for + our mouse simply declines to allow writes: + + + +static ssize_t write_mouse(struct file *file, const char *buffer, size_t + count, loff_t *ppos) +{ + return -EINVAL; +} + + + + This is pretty much self-explanatory. Whenever you write you get told + it was an invalid function. + + + To make the poll and read functions work we have to consider how we + handle the mouse interrupt. + + + +static struct wait_queue *mouse_wait; +static spinlock_t mouse_lock = SPIN_LOCK_UNLOCKED; + +static void ourmouse_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + char delta_x; + char delta_y; + unsigned char new_buttons; + + delta_x = inb(OURMOUSE_BASE); + delta_y = inb(OURMOUSE_BASE+1); + new_buttons = inb(OURMOUSE_BASE+2); + + if(delta_x || delta_y || new_buttons != mouse_buttons) + { + /* Something happened */ + + spin_lock(&mouse_lock); + mouse_event = 1; + mouse_dx += delta_x; + mouse_dy += delta_y; + mouse_buttons = new_buttons; + spin_unlock(&mouse_lock); + + wake_up_interruptible(&mouse_wait); + } +} + + + + The interrupt handler reads the mouse status. The next thing we do is + to check whether something has changed. If the mouse was smart it would + only interrupt us if something had changed, but let's assume our mouse + is stupid as most mice actually tend to be. + + + If the mouse has changed we need to update the status variables. What we + don't want is the mouse functions reading these variables to read them + during a change. We add a spinlock that protects these variables while we + play with them. + + + If a change has occured we also need to wake sleeping processes, so we + add a wakeup call and a wait_queue to use when + we wish to await a mouse event. + + + Now we have the wait queue we can implement the poll function for the + mouse relatively easily: + + + +static unsigned int mouse_poll(struct file *file, poll_table *wait) +{ + poll_wait(file, &mouse_wait, wait); + if(mouse_event) + return POLLIN | POLLRDNORM; + return 0; +} + + + + This is fairly standard poll code. First we add the wait queue to the + list of queues we want to monitor for an event. Secondly we check if an + event has occured. We only have one kind of event - the + mouse_event flag tells us that something happened. + We know that this something can only be mouse data. We return the flags + indicating input and normal reading will succeed. + + + You may be wondering what happens if the function returns saying 'no + event yet'. In this case the wake up from the wait queue we added to + the poll table will cause the function to be called again. Eventually + we will be woken up and have an event ready. At this point the + poll call will exit back to the user. + + + After the poll completes the user will want to read the data. We now + need to think about how our mouse_read function + will work: + + +static ssize_t mouse_read(struct file *file, char *buffer, + size_t count, loff_t *pos) +{ + int dx, dy; + unsigned char button; + unsigned long flags; + int n; + + if(count<3) + return -EINVAL; + + /* + * Wait for an event + */ + + while(!mouse_event) + { + if(file->f_flags&O_NDELAY) + return -EAGAIN; + interruptible_sleep_on(&mouse_wait); + if(signal_pending(current)) + return -ERESTARTSYS; + } + + + + We start by validating that the user is reading enough data. We could + handle partial reads if we wanted but it isn't terribly useful and the + mouse drivers don't bother to try. + + + Next we wait for an event to occur. The loop is fairly standard event + waiting in Linux. Having checked that the event has not yet occured, we + then check if an event is pending and if not we need to sleep. + + + A user process can set the O_NDELAY flag on a file + to indicate that it wishes to be told immediately if no event is + pending. We check this and give the appropriate error if so. + + + Next we sleep until the mouse or a signal awakens us. A signal will + awaken us as we have used wakeup_interruptible. + This is important as it means a user can kill processes waiting for + the mouse - clearly a desireable property. If we are interrupted we + exit the call and the kernel will then process signals and maybe + restart the call again - from the beginning. + + + This code contains a classic Linux bug. All will be revealed later in this + article as well as explanations for how to avoid it. + + + /* Grab the event */ + + spinlock_irqsave(&mouse_lock, flags); + + dx = mouse_dx; + dy = mouse_dy; + button = mouse_buttons; + + if(dx<=-127) + dx=-127; + if(dx>=127) + dx=127; + if(dy<=-127) + dy=-127; + if(dy>=127) + dy=127; + + mouse_dx -= dx; + mouse_dy -= dy; + + if(mouse_dx == 0 && mouse_dy == 0) + mouse_event = 0; + + spin_unlock_irqrestore(&mouse_lock, flags); + + + This is the next stage. Having established that there is an event + going, we capture it. To be sure that the event is not being updated + as we capture it we also take the spinlock and thus prevent parallel + updates. Note here we use spinlock_irqsave. We + need to disable interrupts on the local processor otherwise bad things + will happen. + + + What will occur is that we take the spinlock. While we hold the lock + an interrupt will occur. At this point our interrupt handler will try + and take the spinlock. It will sit in a loop waiting for the read + routine to release the lock. However because we are sitting in a loop + in the interrupt handler we will never release the lock. The machine + hangs and the user gets upset. + + + By blocking the interrupt on this processor we ensure that the lock + holder will always give the lock back without deadlocking. + + + There is a little cleverness in the reporting mechanism too. We can + only report a move of 127 per read. We don't however want to lose + information by throwing away further movement. Instead we keep + returning as much information as possible. Each time we return a + report we remove the amount from the pending movement in + mouse_dx and mouse_dy. Eventually + when these counts hit zero we clear the mouse_event + flag as there is nothing else left to report. + + + + if(put_user(button|0x80, buffer)) + return -EFAULT; + if(put_user((char)dx, buffer+1)) + return -EFAULT; + if(put_user((char)dy, buffer+2)) + return -EFAULT; + + for(n=3; n < count; n++) + if(put_user(0x00, buffer+n)) + return -EFAULT; + + return count; +} + + + + Finally we must put the results in the user supplied buffer. We cannot + do this while holding the lock as a write to user memory may sleep. + For example the user memory may be residing on disk at this instant. + Thus we did our computation beforehand and now copy the data. Each + put_user call is filling in one byte of the buffer. + If it returns an error we inform the program that it passed us an + invalid buffer and abort. + + + Having written the data we blank the rest of the buffer that was read + and report the read as being successful. + + + + + Debugging the mouse driver + + + We now have an almost perfectly usable mouse driver. If you were to + actually try and use it however you would eventually find a couple of + problems with it. A few programs will also not work with as it does not + yet support asynchronous I/O. + + + First let us look at the bugs. The most obvious one isn't really a driver + bug but a failure to consider the consequences. Imagine you bumped the + mouse hard by accident and sent it skittering across the desk. The mouse + interrupt routine will add up all that movement and report it in steps of + 127 until it has reported all of it. Clearly there is a point beyond + which mouse movement isn't worth reporting. We need to add this as a + limit to the interrupt handler: + + + +static void ourmouse_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + char delta_x; + char delta_y; + unsigned char new_buttons; + + delta_x = inb(OURMOUSE_BASE); + delta_y = inb(OURMOUSE_BASE+1); + new_buttons = inb(OURMOUSE_BASE+2); + + if(delta_x || delta_y || new_buttons != mouse_buttons) + { + /* Something happened */ + + spin_lock(&mouse_lock); + mouse_event = 1; + mouse_dx += delta_x; + mouse_dy += delta_y; + + if(mouse_dx < -4096) + mouse_dx = -4096; + if(mouse_dx > 4096) + mouse_dx = 4096; + + if(mouse_dy < -4096) + mouse_dy = -4096; + if(mouse_dy > 4096) + mouse_dy = 4096; + + mouse_buttons = new_buttons; + spin_unlock(&mouse_lock); + + wake_up_interruptible(&mouse_wait); + } +} + + + + By adding these checks we limit the range of accumulated movement to + something sensible. + + + The second bug is a bit more subtle, and that is perhaps why this is + such a common mistake. Remember, I said the waiting loop for the read + handler had a bug in it. Think about what happens when we execute: + + + + while(!mouse_event) + { + + + + and an interrupt occurs at this point here. This causes a mouse movement + and wakes up the queue. + + + + interruptible_sleep_on(&mouse_wait); + + + + Now we sleep on the queue. We missed the wake up and the application + will not see an event until the next mouse event occurs. This will + lead to just the odd instance when a mouse button gets delayed. The + consequences to the user will probably be almost undetectable with a + mouse driver. With other drivers this bug could be a lot more severe. + + + There are two ways to solve this. The first is to disable interrupts + during the testing and the sleep. This works because when a task sleeps + it ceases to disable interrupts, and when it resumes it disables them + again. Our code thus becomes: + + + + save_flags(flags); + cli(); + + while(!mouse_event) + { + if(file->f_flags&O_NDELAY) + { + restore_flags(flags); + return -EAGAIN; + } + interruptible_sleep_on(&mouse_wait); + if(signal_pending(current)) + { + restore_flags(flags); + return -ERESTARTSYS; + } + } + restore_flags(flags); + + + + This is the sledgehammer approach. It works but it means we spend a + lot more time turning interrupts on and off. It also affects + interrupts globally and has bad properties on multiprocessor machines + where turning interrupts off globally is not a simple operation, but + instead involves kicking each processor, waiting for them to disable + interrupts and reply. + + + The real problem is the race between the event testing and the sleeping. + We can avoid that by using the scheduling functions more directly. + Indeed this is the way they generally should be used for an interrupt. + + + + struct wait_queue wait = { current, NULL }; + + add_wait_queue(&mouse_wait, &wait); + current->state = TASK_INTERRUPTIBLE; + + while(!mouse_event) + { + if(file->f_flags&O_NDELAY) + { + remove_wait_queue(&mouse_wait, &wait); + current->state = TASK_RUNNING; + return -EWOULDBLOCK; + } + if(signal_pending(current)) + { + remove_wait_queue(&mouse_wait, &wait); + current->state = TASK_RUNNING; + return -ERESTARTSYS; + } + schedule(); + current->state = TASK_INTERRUPTIBLE; + } + + remove_wait_wait(&mouse_wait, &wait); + current->state = TASK_RUNNING; + + + + At first sight this probably looks like deep magic. To understand how + this works you need to understand how scheduling and events work on + Linux. Having a good grasp of this is one of the keys to writing clean + efficient device drivers. + + + add_wait_queue does what its name suggests. It adds + an entry to the mouse_wait list. The entry in this + case is the entry for our current process (current + is the current task pointer). + + + So we start by adding an entry for ourself onto the + mouse_wait list. This does not put us to sleep + however. We are merely tagged onto the list. + + + Next we set our status to TASK_INTERRUPTIBLE. Again + this does not mean we are now asleep. This flag says what should happen + next time the process sleeps. TASK_INTERRUPTIBLE says + that the process should not be rescheduled. It will run from now until it + sleeps and then will need to be woken up. + + + The wakeup_interruptible call in the interrupt + handler can now be explained in more detail. This function is also very + simple. It goes along the list of processes on the queue it is given and + any that are marked as TASK_INTERRUPTIBLE it changes + to TASK_RUNNING and tells the kernel that new + processes are runnable. + + + Behind all the wrappers in the original code what is happening is this + + + + + + We add ourself to the mouse wait queue + + + + + We mark ourself as sleeping + + + + + We ask the kernel to schedule tasks again + + + + + The kernel sees we are asleep and schedules someone else. + + + + + The mouse interrupt sets our state to TASK_RUNNING + and makes a note that the kernel should reschedule tasks + + + + + The kernel sees we are running again and continues our execution + + + + + This is why the apparent magic works. Because we mark ourself as + TASK_INTERRUPTIBLE and as we add ourselves + to the queue before we check if there are events pending, the race + condition is removed. + + + Now if an interrupt occurs after we check the queue status and before + we call the schedule function in order to sleep, + things work out. Instead of missing an event, we are set back to + TASK_RUNNING by the mouse interrupt. We still call + schedule but it will continue running our task. + We go back around the loop and this time there may be an event. + + + There will not always be an event. Thus we set ourselves back to + TASK_INTERRUPTIBLE before resuming the loop. + Another process doing a read may already have cleared the event flag, + and if so we will need to go back to sleep again. Eventually we will + get our event and escape. + + + Finally when we exit the loop we remove ourselves from the + mouse_wait queue as we are no longer interested + in mouse events, and we set ourself back to + TASK_RUNNABLE as we do not wish to go to sleep + again just yet. + + + Note + + This isn't an easy topic. Don't be afraid to reread the description a + few times and also look at other device drivers to see how it works. + Finally if you can't grasp it just yet, you can use the code as + boilerplate to write other drivers and trust me instead. + + + + + + Asynchronous I/O + + This leaves the missing feature - Asynchronous I/O. Normally UNIX + programs use the poll call (or its variant form + select) to wait for an event to occur on one of + multiple input or output devices. This model works well for most tasks + but because poll and select + wait for an event isn't suitable for tasks that are also continually + doing computation work. Such programs really want the kernel to kick + them when something happens rather than watch for events. + + + Poll is akin to having a row of lights in front of you. You can see at a + glance which ones if any are lit. You cannot however get anything useful + done while watching them. Asynchronous I/O uses signals which work more + like a door bell. Instead of you watching, it tells you that something + is up. + + + Asynchronous I/O sends the signal SIGIO to a user process when the I/O + events occur. In this case that means when people move the mouse. The + SIGIO signal causes the user process to jump to its signal handler and + execute code in that handler before returning to whatever was going on + previously. It is the application equivalent of an interrupt handler. + + + Most of the code needed for this operation is common to all its users. + The kernel provides a simple set of functions for managing asynchronous + I/O. + + + Our first job is to allow users to set asynchronous I/O on file handles. + To do that we need to add a new function to the file operations table for + our mouse: + + + +struct file_operations our_mouse_fops = { + NULL, /* Mice don't seek */ + read_mouse, /* You can read a mouse */ + write_mouse, /* This won't do a lot */ + NULL, /* No readdir - not a directory */ + poll_mouse, /* Poll */ + NULL, /* No ioctl calls */ + NULL, /* No mmap */ + open_mouse, /* Called on open */ + NULL, /* Flush */ + close_mouse, /* Called on close */ + NULL, /* No fsync on a mouse */ + fasync_mouse, /* Asynchronous I/O */ +}; + + + + Once we have installed this entry the kernel knows we support + asynchronous I/O and will allow all the relevant operations on the + device. Whenever a user adds or removes asynchronous I/O notification + on a file handle it calls our fasync_mouse routine + we just added. This routine uses the helper functions to keep the queue + of handles up to date: + + + +static struct fasync_struct *mouse_fasync = NULL; + +static int fasync_mouse(int fd, struct file *filp, int on) +{ + int retval = fasync_helper(fd, filp, on, &mouse_fasync); + + if (retval < 0) + return retval; + return 0; +} + + + + The fasync helper adds and deletes entries by managing the supplied + list. We also need to remove entries from this list when the file is + closed. This requires we add one line to our close function: + + + +static int close_mouse(struct inode *inode, struct file *file) +{ + fasync_mouse(-1, file, 0) + if(--mouse_users) + return 0; + free_irq(OURMOUSE_IRQ, NULL); + MOD_DEC_USE_COUNT; + return 0; +} + + + + When we close the file we now call our own fasync handler as if the + user had requested that this file cease to be used for asynchronous + I/O. This rather neatly cleans up any loose ends. We certainly don't + wait to deliver a signal for a file that no longer exists. + + + At this point the mouse driver supports all the asynchronous I/O + operations, and applications using them will not error. They won't + however work yet. We need to actually send the signals. Again the + kernel provides a function for handling this. + + + We update our interrupt handler a little: + + + +static void ourmouse_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + char delta_x; + char delta_y; + unsigned char new_buttons; + + delta_x = inb(OURMOUSE_BASE); + delta_y = inb(OURMOUSE_BASE+1); + new_buttons = inb(OURMOUSE_BASE+2); + + if(delta_x || delta_y || new_buttons != mouse_buttons) + { + /* Something happened */ + + spin_lock(&mouse_lock); + mouse_event = 1; + mouse_dx += delta_x; + mouse_dy += delta_y; + + if(mouse_dx < -4096) + mouse_dx = -4096; + if(mouse_dx > 4096) + mouse_dx = 4096; + + if(mouse_dy < -4096) + mouse_dy = -4096; + if(mouse_dy > 4096) + mouse_dy = 4096; + + mouse_buttons = new_buttons; + spin_unlock(&mouse_lock); + + /* Now we do asynchronous I/O */ + kill_fasync(&mouse_fasync, SIGIO); + + wake_up_interruptible(&mouse_wait); + } +} + + + + The new code simply calls the kill_fasync routine + provided by the kernel if the queue is non-empty. This sends the + required signal (SIGIO in this case) to the process each file handle + says should be informed about the exciting new mouse movement that + just happened. + + + With this in place and the bugs in the original version fixed, you now + have a fully functional mouse driver using the bus mouse protocol. It + will work with the X window system, will work + with GPM and should work with every other + application you need. Doom is of course the + ideal way to test your new mouse driver is functioning properly. Be sure + to test it thoroughly. + + +
+ diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/DocBook/via-audio.tmpl linux/Documentation/DocBook/via-audio.tmpl --- v2.4.0-test1/linux/Documentation/DocBook/via-audio.tmpl Wed Dec 31 16:00:00 1969 +++ linux/Documentation/DocBook/via-audio.tmpl Mon Jun 19 12:56:07 2000 @@ -0,0 +1,383 @@ + + + + + Via 686 Audio Driver for Linux + + + + Jeff + Garzik + +
+ jgarzik@mandrakesoft.com +
+
+
+
+ + + 2000 + Jeff Garzik + + + + + This documentation is free software; you can redistribute + it and/or modify it under the terms of the GNU 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 + + + + For more details see the file COPYING in the source + distribution of Linux. + + +
+ + + + + Introduction + + The Via VT82C686A and VT82C686A "super southbridge" chips contain + AC97-compatible audio logic which features dual full-duplex 16-bit stereo + PCM sound channels, plus a third PCM channel intended for use + in hardware-assisted FM synthesis. + + + The current Linux kernel audio driver for this family of chips + supports audio playback, but recording and hardware-assisted + FM support features are not yet available. + + + This driver supports any Linux kernel version after 2.3.50. + + + Please send bug reports to the mailing list linux-via@gtf.org. + To subscribe, e-mail majordomo@gtf.org with + + + subscribe linux-via + + + in the body of the message. + + + + + Driver Installation + + To use this audio driver, select the + CONFIG_SOUND_VIA82CXXX option in the section Sound during kernel configuration. + Follow the usual kernel procedures for rebuilding the kernel, + or building and installing driver modules. + + + To make this driver the default audio driver, you can add the + following to your /etc/conf.modules file: + + + alias sound via82cxxx_audio + + + Note that soundcore and ac97_codec support modules + are also required for working audio, in addition to + the via82cxxx_audio module itself. + + + + + Submitting a bug report + Description of problem + + Describe the application you were using to play/record sound, and how + to reproduce the problem. + + + Diagnostic output + + Obtain the via-audio-diag diagnostics program from + http://gtf.org/garzik/drivers/via82cxxx/ and provide a dump of the + audio chip's registers while the problem is occurring. Sample command line: + + + ./via-audio-diag -aps > diag-output.txt + + + Driver debug output + + Define VIA_DEBUG at the beginning of the driver, then capture and email + the kernel log output. This can be viewed in the system kernel log (if + enabled), or via the dmesg program. Sample command line: + + + dmesg > /tmp/dmesg-output.txt + + + Bigger kernel message buffer + + If you wish to increase the size of the buffer displayed by dmesg, then + change the LOG_BUF_LEN macro at the top of linux/kernel/printk.c, recompile + your kernel, and pass the LOG_BUF_LEN value to dmesg. Sample command line with + LOG_BUF_LEN == 32768: + + + dmesg -s 32768 > /tmp/dmesg-output.txt + + + + + + Known Bugs And Assumptions + + + Recording support + + + Recording support is currently missing. + + + + MMAP support + + + MMAP support is currently missing. Make sure to + test with Quake. + + + + AC97 codec timeout during init + + + A warning message "via82cxxx: timeout while reading AC97 + codec" is printed during driver initialization. This + message can safely be ignored. + + + + Low volume + + + Volume too low on many systems. Workaround: use mixer program + such as xmixer to increase volume. + + + + RealPlayer trouble + + + RealPlayer output very scratchy. Workaround: use esd, and + configure RealPlayer to output to esd. + + + + Broken apps + + + Applications which attempt to open the sound device in read/write + mode (O_RDWR) will fail. This is incorrect OSS behavior, but since + this driver will eventually support recording as well as playback, + we will be able to (in the future) support even broken programs which + unconditionally use O_RDWR. + + + + + + + + + + Thanks + + Via for providing e-mail support, specs, and NDA'd source code. + + + MandrakeSoft for providing hacking time. + + + AC97 mixer interface fixes and debugging by Ron Cemer roncemer@gte.net. + + + + + Random Notes + + Two /proc pseudo-files provide diagnostic information. This is generally + not useful to most users. Power users can disable VIA_PROC_FS macro in the + driver source code, and remove the /proc support code. In any case, once + version 2.0.0 is released, the /proc support code will be disabled by + default. Available /proc pseudo-files: + + + /proc/driver/via/0/info + /proc/driver/via/0/ac97 + + + This driver by default supports all PCI audio devices which report + a vendor id of 0x1106, and a device id of 0x3058. Subsystem vendor + and device ids are not examined. + + + Only supports a single sound chip, as this is a motherboard chipset. + Some architecture remains for multiple cards, feel free to submit + a patch to clean some of that up. + + + No consideration for SMP, this chipset is not known to be found on + any SMP motherboards. However, spin_locks must be used anyway in order + to handle interrupts correctly. + + + GNU indent formatting options: -kr -i8 -pcs + + + Via has graciously donated e-mail support and source code to help further + the development of this driver. Their assistance has been invaluable + in the design and coding of the next major version of this driver. + + + The Via audio chip apparently provides a second PCM scatter-gather + DMA channel just for FM data, but does not have a full hardware MIDI + processor. I haven't put much thought towards a solution here, but it + might involve using SoftOSS midi wave table, or simply disabling MIDI + support altogether and using the FM PCM channel as a second (input? output?) + + + + + Driver ChangeLog + + +Version 1.1.8 + + + + + Clean up interrupt handler output. Fixes the following kernel error message: + + + unhandled interrupt ... + + + + + + Convert documentation to DocBook, so that PDF, HTML and PostScript (.ps) output is readily + available. + + + + + + + +Version 1.1.7 + + + + + Fix module unload bug where mixer device left registered + after driver exit + + + + + + +Version 1.1.6 + + + + + Rewrite via_set_rate to mimic ALSA basic AC97 rate setting + + + + + Remove much dead code + + + + + Complete spin_lock_irqsave -> spin_lock_irq conversion in via_dsp_ioctl + + + + + Fix build problem in via_dsp_ioctl + + + + + Optimize included headers to eliminate headers found in linux/drivers/sound + + + + + + +Version 1.1.5 + + + + + Disable some overly-verbose debugging code + + + + + Remove unnecessary sound locks + + + + + Fix some ioctls for better time resolution + + + + + Begin spin_lock_irqsave -> spin_lock_irq conversion in via_dsp_ioctl + + + + + + +Version 1.1.4 + + + + + Completed rewrite of driver. Eliminated SoundBlaster compatibility + completely, and now uses the much-faster scatter-gather DMA engine. + + + + + + + + + Internal Functions +!Idrivers/sound/via82cxxx_audio.c + + +
diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/arm/README linux/Documentation/arm/README --- v2.4.0-test1/linux/Documentation/arm/README Sun May 2 09:51:16 1999 +++ linux/Documentation/arm/README Mon Jun 19 17:59:33 2000 @@ -1,9 +1,7 @@ - ARM Linux 2.2.3 - =============== + ARM Linux 2.4.0test1 + ==================== - * NOTE * The ARM support in the mainstream Linux kernel sources - is not up to date. Please check ftp.arm.uk.linux.org:/pub/armlinux - for latest updates. + Please check ftp.arm.linux.org.uk:/pub/armlinux for latest updates. Compilation of kernel --------------------- @@ -13,10 +11,10 @@ and EGCS are good compilers. Note that GCC-2.7.2.2 ELF is rare, and you probably don't have it. - To build ARM Linux natively, you shouldn't have to alter the ARCH = line in - the top level Makefile. However, if you don't have the ARM Linux ELF tools - installed as default, then you should change the CROSS_COMPILE line as - detailed below. + To build ARM Linux natively, you shouldn't have to alter the ARCH = line + in the top level Makefile. However, if you don't have the ARM Linux ELF + tools installed as default, then you should change the CROSS_COMPILE + line as detailed below. If you wish to cross-compile, then alter the following lines in the top level make file: @@ -41,27 +39,28 @@ Bug reports etc --------------- - Please send patches, bug reports and code for the ARM Linux project - to linux@arm.linux.org.uk Patches will not be included into future - kernels unless they come to me (or the relevant person concerned). + Please send patches to the patch system. For more information, see + http://www.arm.linux.org.uk/patches/info.html Always include some + explanation as to what the patch does and why it is needed. + + Bug reports should be sent to linux-arm-kernel@lists.arm.linux.org.uk, + or submitted through the web form at + http://www.arm.linux.org.uk/forms/solution.shtml When sending bug reports, please ensure that they contain all relevant information, eg. the kernel messages that were printed before/during the problem, what you were doing, etc. - For patches, please include some explanation as to what the patch does - and why (if relevant). - Modules ------- Although modularisation is supported (and required for the FP emulator), - each module on an arm2/arm250/arm3 machine when is loaded will take - memory up to the next 32k boundary due to the size of the pages. Hence is - modularisation on these machines really worth it? + each module on an ARM2/ARM250/ARM3 machine when is loaded will take + memory up to the next 32k boundary due to the size of the pages. + Therefore, modularisation on these machines really worth it? - However, arm6 and up machines allow modules to take multiples of 4k, and + However, ARM6 and up machines allow modules to take multiples of 4k, and as such Acorn RiscPCs and other architectures using these processors can make good use of modularisation. @@ -124,7 +123,7 @@ The initial entry into the kernel made via head-armv.S uses architecture independent code. The architecture is selected by the value of 'r1' on entry, which must be kept unique. You can register a new architecture - by mailing the following details to rmk@arm.uk.linux.org. Please give + by mailing the following details to rmk@arm.linux.org.uk Please give the mail a subject of 'Register new architecture': Name: @@ -133,7 +132,7 @@ Please follow this format - it is an automated system. You should - receive a reply the next day. + receive a reply within one day. --- -Russell King (27/03/1999) +Russell King (12/06/2000) diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/arm/SA1100/LART linux/Documentation/arm/SA1100/LART --- v2.4.0-test1/linux/Documentation/arm/SA1100/LART Fri May 12 14:18:55 2000 +++ linux/Documentation/arm/SA1100/LART Mon Jun 19 17:59:33 2000 @@ -10,6 +10,5 @@ is under development, with plenty of others in different stages of planning. -The designs for this board have been released under a GPL-like license; - -For lot more info, see the LART page at http://www.lart.tudelft.nl. +The hardware designs for this board have been released under an open license; +see the LART page at http://www.lart.tudelft.nl/ for more information. diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/cpqarray.txt linux/Documentation/cpqarray.txt --- v2.4.0-test1/linux/Documentation/cpqarray.txt Mon Jul 5 19:52:13 1999 +++ linux/Documentation/cpqarray.txt Fri Jun 23 21:04:36 2000 @@ -1,11 +1,5 @@ This driver is for Compaq's SMART2 Intellegent Disk Array Controllers. -WARNING: --------- - -This driver comes with NO WARRANTY. It is not officially supported by -Compaq. Do not call technical support. Use at your own risk. - Supported Cards: ---------------- @@ -22,6 +16,7 @@ * Integrated Smart Array Controller * SA 4200 * SA 4250ES + * SA 431 It should also work with some really old Disk array adapters, but I am unable to test against these cards: diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/filesystems/bfs.txt linux/Documentation/filesystems/bfs.txt --- v2.4.0-test1/linux/Documentation/filesystems/bfs.txt Thu Feb 10 17:11:02 2000 +++ linux/Documentation/filesystems/bfs.txt Mon Jun 19 12:56:07 2000 @@ -54,4 +54,4 @@ If you have any patches, questions or suggestions regarding this BFS implementation please contact the author: -Tigran A. Aivazian . +Tigran A. Aivazian diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/filesystems/devfs/ChangeLog linux/Documentation/filesystems/devfs/ChangeLog --- v2.4.0-test1/linux/Documentation/filesystems/devfs/ChangeLog Thu May 11 15:30:05 2000 +++ linux/Documentation/filesystems/devfs/ChangeLog Wed Jun 21 22:30:59 2000 @@ -1533,3 +1533,46 @@ - Updated Documentation/filesystems/devfs/README - Updated sample modules.conf +=============================================================================== +Changes for patch v168 + +Work sponsored by SGI + +- Disabled multi-mount capability (use VFS bindings instead) + +- Updated README from master HTML file +=============================================================================== +Changes for patch v169 + +Work sponsored by SGI + +- Removed multi-mount code + +- Removed compatibility macros: VFS has changed too much +=============================================================================== +Changes for patch v170 + +Work sponsored by SGI + +- Updated README from master HTML file + +- Merged devfs inode into devfs entry +=============================================================================== +Changes for patch v171 + +Work sponsored by SGI + +- Updated sample modules.conf + +- Removed dead code in which used to call + + +- Ported to kernel 2.4.0-test2-pre3 +=============================================================================== +Changes for patch v172 + +Work sponsored by SGI + +- Changed interface to + +- Changed interface to diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/filesystems/devfs/README linux/Documentation/filesystems/devfs/README --- v2.4.0-test1/linux/Documentation/filesystems/devfs/README Thu May 11 15:30:05 2000 +++ linux/Documentation/filesystems/devfs/README Wed Jun 21 08:29:00 2000 @@ -3,7 +3,7 @@ Linux Devfs (Device File System) FAQ Richard Gooch -1-MAY-2000 +14-JUN-2000 ----------------------------------------------------------------------------- @@ -797,13 +797,15 @@ mount devfs and then create the named pipe *before* init starts. -The default behaviour now is not to mount devfs onto /dev at boot time. -You can correct this with the "devfs=mount" boot option. This solves -any problems with init, and also prevents the dreaded: +The default behaviour now is not to mount devfs onto /dev at boot time +for 2.3.x and later kernels. You can correct this with the +"devfs=mount" boot option. This solves any problems with init, +and also prevents the dreaded: Cannot open initial console -message. +message. For 2.2.x kernels where you need to apply the devfs patch, +the default is to mount. If you have automatic mounting of devfs onto /dev then you may need to create /dev/initctl in your boot scripts. The following lines should @@ -1460,9 +1462,19 @@ Douglas Gilbert has written a useful document at http://www.torque.net/sg/devfs_scsi.html which -explores the SCSI subsystem and how it interacts with devfs. +explores the SCSI subsystem and how it interacts with devfs +Douglas Gilbert has written another useful document at + +http://www.torque.net/scsi/scsihosts.html which +discusses the scsihosts= boot option + + +Douglas Gilbert has written yet another useful document at + +http://www.torque.net/scsi/linux_scsi_24 which +discusses the Linux SCSI subsystem in 2.4. diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/filesystems/devfs/modules.conf linux/Documentation/filesystems/devfs/modules.conf --- v2.4.0-test1/linux/Documentation/filesystems/devfs/modules.conf Thu May 11 15:30:05 2000 +++ linux/Documentation/filesystems/devfs/modules.conf Wed Jun 21 08:29:00 2000 @@ -1,7 +1,7 @@ # Sample entries for /etc/modules.conf for devfs ############################################################################### -# Configuration section: change to suit +# Configuration section: change to suit your hardware # alias /dev/sound sb alias /dev/v4l bttv diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/floppy.txt linux/Documentation/floppy.txt --- v2.4.0-test1/linux/Documentation/floppy.txt Sat Feb 26 22:31:37 2000 +++ linux/Documentation/floppy.txt Mon Jun 19 12:56:07 2000 @@ -201,11 +201,10 @@ The latest version can be found at fdutils homepage: http://fdutils.linux.lu -The fdutils-5.3 release can be found at: - http://fdutils.linux.lu/fdutils-5.3.src.tar.gz - http://www.tux.org/pub/knaff/fdutils/fdutils-5.3.src.tar.gz - ftp://tsx-11.mit.edu/pub/linux/sources/sbin/fdutils-5.3.src.tar.gz - ftp://metalab.unc.edu/pub/Linux/utils/disk-management/fdutils-5.3.src.tar.gz +The fdutils-5.4 release can be found at: + http://fdutils.linux.lu/fdutils-5.4.src.tar.gz + http://www.tux.org/pub/knaff/fdutils/fdutils-5.4.src.tar.gz + ftp://metalab.unc.edu/pub/Linux/utils/disk-management/fdutils-5.4.src.tar.gz Reporting problems about the floppy driver ========================================== diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt --- v2.4.0-test1/linux/Documentation/ioctl-number.txt Thu May 11 15:30:05 2000 +++ linux/Documentation/ioctl-number.txt Mon Jun 19 12:56:07 2000 @@ -74,6 +74,8 @@ 0x22 all scsi/sg.h '1' 00-1F PPS kit from Ulrich Windl +'6' 00-10 Intel P6 microcode update driver + '8' all SNP8023 advanced NIC card 'A' 00-1F linux/apm_bios.h @@ -101,6 +103,7 @@ 'V' all linux/vt.h 'W' 00-1F linux/watchdog.h conflict! 'W' 00-1F linux/wanrouter.h conflict! +'X' all linux/xfs_fs.h 'Y' all linux/cyclades.h 'a' all ATM on linux diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/joystick-parport.txt linux/Documentation/joystick-parport.txt --- v2.4.0-test1/linux/Documentation/joystick-parport.txt Wed Dec 8 14:11:24 1999 +++ linux/Documentation/joystick-parport.txt Wed Jun 21 08:22:21 2000 @@ -1,5 +1,5 @@ - Linux Joystick parport drivers v1.2 BETA - (c) 1998-1999 Vojtech Pavlik + Linux Joystick parport drivers v2.0 + (c) 1998-2000 Vojtech Pavlik (c) 1998 Andree Borrmann Sponsored by SuSE ---------------------------------------------------------------------------- @@ -39,7 +39,7 @@ lines of the parallel port are shared, while one of 5 available input lines is assigned to each gamepad. - This protocol is handled by the joy-console.c driver, so that's the one + This protocol is handled by the gamecon.c driver, so that's the one you'll use for NES and SNES gamepads. The main problem with PC parallel ports is that they don't have +5V power @@ -199,9 +199,9 @@ And there were many others. -2.2.1 Multisystem joysticks using joy-db9.c -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - For the Multisystem joysticks, and their derivatives, the joy-db9.c driver +2.2.1 Multisystem joysticks using db9.c +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + For the Multisystem joysticks, and their derivatives, the db9.c driver was written. It allows only one joystick / gamepad per parallel port, but the interface is easy to build and works with almost anything. @@ -236,25 +236,25 @@ And that's it. On a side note, if you have already built a different adapter for use with -the digital joystick driver 0.8.0.2, this is also supported by the joy-db9.c +the digital joystick driver 0.8.0.2, this is also supported by the db9.c driver, as device type 8. (See section 3.2) -2.2.2 Multisystem joysticks using joy-console.c -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +2.2.2 Multisystem joysticks using gamecon.c +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ For some people just one joystick per parallel port is not enough, and/or -want to use them on one parallel port together with NES/SNES/PSX pads. This -is possible using the joy-console.c. It supports up to 5 devices of the -above types, including 1 and 2 buttons Multisystem joysticks. +want to use them on one parallel port together with NES/SNES/PSX pads. This is +possible using the gamecon.c. It supports up to 5 devices of the above types, +including 1 and 2 buttons Multisystem joysticks. However, there is nothing for free. To allow more sticks to be used at once, you need the sticks to be purely switch based (that is non-TTL), and not to need power. Just a plain simple six switches inside. If your joystick can do more (eg. turbofire) you'll need to disable it totally first -if you want to use joy-console.c. +if you want to use gamecon.c. Also, the connection is a bit more complex. You'll need a bunch of diodes, and one pullup resistor. First, you connect the Directions and the button -the same as for joy-db9, however with the diodes inbetween. +the same as for db9, however with the diodes inbetween. Diodes (pin 2) -----|<|----> Up @@ -278,17 +278,17 @@ And that's all, here we go! -2.2.3 Multisystem joysticks using joy-turbografx.c -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +2.2.3 Multisystem joysticks using turbografx.c +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The TurboGraFX interface, designed by Steffen Schwenke allows up to 7 Multisystem joysticks connected to the parallel port. In -Steffen's version, there is support for up to 5 buttons per joystick. -However, since this doesn't work reliably on all parallel ports, the -joy-turbografx.c driver supports only one button per joystick. For more -information on how to build the interface, see +Steffen's version, there is support for up to 5 buttons per joystick. However, +since this doesn't work reliably on all parallel ports, the turbografx.c driver +supports only one button per joystick. For more information on how to build the +interface, see http://www2.burg-halle.de/~schwenke/parport.html @@ -298,7 +298,7 @@ WARNING: PSX support is experimental, and at the moment doesn't seem to work for most people. If you like adventure, you can try yourself. - The PSX controller is supported by the joy-console.c. + The PSX controller is supported by the gamecon.c. Pinout of the PSX controller (compatible with DirectPadPro): @@ -328,7 +328,7 @@ ~~~~~~~~ All the Sega controllers are more or less based on the standard 2-button Multisystem joystick. However, since they don't use switches and use TTL -logic, the only driver useable with them is the joy-db9.c driver. +logic, the only driver useable with them is the db9.c driver. 2.4.1 Sega Master System ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -377,13 +377,13 @@ (pin 14) -----> Select - The rest is the same as for Multi2 joysticks using joy-db9.c + The rest is the same as for Multi2 joysticks using db9.c 2.4.3 Sega Saturn ~~~~~~~~~~~~~~~~~ Sega Saturn has eight buttons, and to transfer that, without hacks like Genesis 6 pads use, it needs one more select pin. Anyway, it is still -handled by the joy-db9.c driver. Its pinout is very different from anything +handled by the db9.c driver. Its pinout is very different from anything else. Use this schematic: +-----------> Select 1 @@ -409,7 +409,7 @@ (pin 16) -----> Select 2 The other pins (Up, Down, Right, Left, Power, Ground) are the same as for -Multi joysticks using joy-db9.c +Multi joysticks using db9.c 3. The drivers ~~~~~~~~~~~~~~ @@ -417,16 +417,14 @@ described above, allows to connect a different group of joysticks and pads. Here are described their command lines: -3.1 joy-console.c -~~~~~~~~~~~~~~~~~ - Using joy-console.c you can connect up to five devices to one parallel -port. It uses the following kernel/module command line: +3.1 gamecon.c +~~~~~~~~~~~~~ + Using gamecon.c you can connect up to five devices to one parallel port. It +uses the following kernel/module command line: - js_console=port,pad1,pad2,pad3,pad4,pad5 + gc=port,pad1,pad2,pad3,pad4,pad5 - Where 'port' is either the address of the parallel port the joystick/pad -is connected to (eg. 0x378), or, if you are using the parport driver of 2.1+ -Linux kernels, the number of the parport interface (eg. 0 for parport0). + Where 'port' the number of the parport interface (eg. 0 for parport0). And 'pad1' to 'pad5' are pad types connected to different data input pins (10,11,12,13,15), as described in section 2.1 of this file. @@ -442,47 +440,22 @@ 5 | Multisystem 2-button joystick 6 | Sony PSX controller 7 | N64 pad - 8 | N64 pad with direction pad as buttons (DirectPadPro style) The exact type of the PSX controller type is autoprobed, so you must have your controller plugged in before initializing. - Should you want to use more than one of parallel ports at once, you can -use js_console_2 and js_console_3 as additional command line parameters for -two more parallel ports. - - Changes: - v0.1 : First version (SNES only) - v0.2 : X/Y directions were exchanged... - v0.3 : Adaptation for kernel 2.1 - v0.4 : Adaptation for joystick-1.2.6 - - added open/close callbacks - v0.5 : Renamed to "joy-console" because I have added - PSX controller support. - v0.6 : NES support - v0.7V : Added "multi system" support - v0.8 : Bugfixed PSX driver... - v0.9V : Changed multi system support - Added Multi2 support - Fixed parport handling - Cleaned up - v0.10 : Fixed PSX buttons 8 and 9 - v0.11V: Switched to EXCL mode - Removed wakeup - v0.12V: Added N64 support - v0.13V: Updated N64 support - v0.14V: Fixed N64 axis/button counts + Should you want to use more than one of parallel ports at once, you can use +gc_2 and gc_3 as additional command line parameters for two more parallel +ports. -3.2 joy-db9.c -~~~~~~~~~~~~~ +3.2 db9.c +~~~~~~~~~ Apart from making an interface, there is nothing difficult on using the -joy-db9.c driver. It uses the following kernel/module command line: +db9.c driver. It uses the following kernel/module command line: - js_db9=port,type + db9=port,type - Where 'port' is either the address of the parallel port the joystick/pad -is connected to (eg. 0x378), or, if you are using the parport driver of 2.1+ -Linux kernels, the number of the parport interface (eg. 0 for parport0). + Where 'port' is the number of the parport interface (eg. 0 for parport0). Caveat here: This driver only works on bidirectional parallel ports. If your parallel port is recent enough, you should have no trouble with this. @@ -500,39 +473,26 @@ 6 | Genesis pad (6+2 buttons) 7 | Saturn pad (8 buttons) 8 | Multisystem 1-button joystick (v0.8.0.2 pin-out) - 9 | Two Multiststem 1-button joysticks (v0.8.0.2 pin-out) + 9 | Two Multisystem 1-button joysticks (v0.8.0.2 pin-out) + 10 | Amiga CD32 pad Should you want to use more than one of these joysticks/pads at once, you -can use js_db9_2 and js_db9_3 as additional command line parameters for two +can use db9_2 and db9_3 as additional command line parameters for two more joysticks/pads. - Changes: - v0.1 : First version - v0.2 : Changed kernel parameter format - v0.3V: Added Sega Saturn support - Fixed parport and PS/2 mode handling - Cleaned up - v0.4V: Switched to EXCL mode - Removed wakeup - v0.5V: Added 0.8.0.2 HW compatibility for Multi sticks - v0.6V: Better timing for Genesis 6 - v0.7V: Added 0.8.0.2 second joystick support - -3.3 joy-turbografx.c -~~~~~~~~~~~~~~~~~~~~ - The joy-turbografx.c driver uses a very simple kernel/module command line: +3.3 turbografx.c +~~~~~~~~~~~~~~~~ + The turbografx.c driver uses a very simple kernel/module command line: - js_tg=port,js1,js2,js3,js4,js5,js6,js7 + tgfx=port,js1,js2,js3,js4,js5,js6,js7 - Where 'port' is either the address of the parallel port the interface is -connected to (eg. 0x378), or, if you are using the parport driver of 2.1+ -Linux kernels, the number of the parport interface (eg. 0 for parport0). + Where 'port' is the number of the parport interface (eg. 0 for parport0). 'jsX' is the number of buttons the Multisystem joysticks connected to the interface ports 1-7 have. For a standard multisystem joystick, this is 1. Should you want to use more than one of these interfaces at once, you can -use js_tg_2 and js_tg_3 as additional command line parameters for two more +use tgfx_2 and tgfx_3 as additional command line parameters for two more interfaces. 3.4 PC parallel port pinout diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/joystick.txt linux/Documentation/joystick.txt --- v2.4.0-test1/linux/Documentation/joystick.txt Wed Dec 8 14:11:24 1999 +++ linux/Documentation/joystick.txt Wed Jun 21 08:22:21 2000 @@ -1,5 +1,5 @@ - Linux Joystick driver v1.2.15 - (c) 1996-1999 Vojtech Pavlik + Linux Joystick driver v2.0.0 + (c) 1996-2000 Vojtech Pavlik Sponsored by SuSE ---------------------------------------------------------------------------- @@ -29,45 +29,17 @@ 1. Intro ~~~~~~~~ The joystick driver for Linux provides support for a variety of joysticks -and similar devices. - - These currently include various analog joysticks and gamepads (both -variable resistor based and microswitch+resistor based), following IBM PC -joystick standard, with extensions like additional hats and buttons -compatible with CH Flightstick Pro, ThrustMaster FCS or 6 and 8 button -gamepads. - - In addition to these it also supports some of the new PC joysticks that -use proprietary digital protocols to communicate over the gameport, -currently by FPGaming, Gravis, Logitech, MadCatz, Microsoft, Creative and -ThrustMaster. Saitek protocol support is still to be done. - - The driver also includes support for many gamepads and joysticks that were -used by various non-PC computers and game consoles. These include Multi -system joysticks (Atari, Amiga, Commodore, Amstrad), Sega gamepads (Master -System, Genesis, Saturn), Nintendo gamepads (NES, SNES, N64), Sony gamepads -(PSX). Support for Atari Jaguar, Atari 2600, NES FourScore, SNES MultiTap -and others might be added later. - - Last, but not least there is also native Amiga joystick support for the -Amiga Linux port. +and similar devices. It is based on a larger project aiming to support all +input devices in Linux. Should you encounter any problems while using the driver, or joysticks this driver can't make complete use of, I'm very interested in hearing about them. Bug reports and success stories are also welcome. - The joystick package is available at the following FTP sites: + The input project website is at: - ftp://ftp.suse.cz/pub/development/joystick/ - ftp://atrey.karlin.mff.cuni.cz/pub/linux/joystick/ - ftp://ftp.gts.cz/pub/linux/joystick/ - - And a homepage of the driver is at: - - http://www.suse.cz/development/joystick/ - http://atrey.karlin.mff.cuni.cz/~vojtech/joystick/ - http://www.trylinux.com/projects/joystick/ - http://www.linuxgames.com/joystick/ + http://www.suse.cz/development/input/ + http://atrey.karlin.mff.cuni.cz/~vojtech/input/ There is also a mailing list for the driver at: @@ -77,114 +49,70 @@ 2. Usage ~~~~~~~~ - You could have obtained this driver in two different ways - either in the -joystick package or in the kernel. Because, for successful usage of the -joysticks, the utilities in the package are useful, maybe necessary, and -definitely recommended, I suggest you getting the package at some of the -above mentioned locations. The rest of this file assumes you have it. - -2.1 Compiling the driver package -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - To compile the utilities in the joystick package, and the driver itself, -as a standalone module, you first unpack the package, and then edit the -Makefile to meet your needs (namely whether are you using versioned -modules). You will also need an unpacked and configured - - make config - -kernel in - - /usr/src/linux - -Furthermore, if you're using versioned modules, you'll also need - - make dep - -done on the kernel, to create some needed files. - -After that, you compile the joystick driver - - make - - And after that you install it - - make install - - In case you have not used the driver before, you'll need to create the -joystick device files in /dev so that applications can use them: + For basic usage you just choose the right options in kernel config and +you should be set. - make devs +2.1 inpututils +~~~~~~~~~~~~~~ +For testing and other purposes (for example serial devices), a set of +utilities is available at the abovementioned website. I suggest you download +and install it before going on. - For manual creation of the joystick devices, check the -Documentation/devices.txt file in the Linux source tree. - - Should you not want to mess with the kernel, and just use the driver -standalone, as modules, skip the next two sections, proceeding right to 2.4, -because all you need is already done. - -2.2 Patching the kernel -~~~~~~~~~~~~~~~~~~~~~~~ - If you already have the most recent joystick driver in your kernel, skip -this section. If not, you need to patch the kernel, so that it contains the -current driver version. You do that with a command: - - patch -Esp1 < /usr/src/joystick-1.2.x/kernel-2.x.y.diff - -in - - /usr/src/linux - -2.3 Compiling the kernel -~~~~~~~~~~~~~~~~~~~~~~~~ - To compile joystick support into the kernel, use the kernel configuration -scripts, and answer 'Y' to Joystick support and also to at least one of the -hardware specific options. After doing something like - - make bzlilo - - you are done with the driver installation. Just reboot and the driver -should find all the connected joysticks. Read the notes about the hardware -specific drivers later in this file, though. - - You can also compile the driver as modules, answering 'M' to all joystick -support you want to have modules for. It is possible to have the main -joystick driver compiled into the kernel and the hardware dependent drivers -as modules. After you compile the modules - - make modules - - And install them +2.2 Device nodes +~~~~~~~~~~~~~~~~ +For applications to be able to use the joysticks, in you don't use devfs, +you'll have to manually create these nodes in /dev: - make modules_install +cd /dev +rm js* +mkdir input +mknod input/js0 c 13 0 +mknod input/js1 c 13 1 +mknod input/js2 c 13 2 +mknod input/js3 c 13 3 +ln -s input/js0 js0 +ln -s input/js1 js1 +ln -s input/js2 js2 +ln -s input/js3 js3 + +For testing with inpututils it's also convenient to create these: + +mknod input/event0 c 13 64 +mknod input/event1 c 13 65 +mknod input/event2 c 13 66 +mknod input/event3 c 13 67 - you're set, and can proceed to the next step. +2.4 Modules needed +~~~~~~~~~~~~~~~~~~ + For all joystick drivers to function, you'll need the userland interface +module in kernel, either loaded or compiled in: -2.4 Inserting the modules into the kernel -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - After installing the modules you'll first need to insert the generic -joystick driver module into the kernel + modprobe joydev - insmod joystick + For gameport joysticks, you'll have to load the gameport driver as well; - and then one or more of the hardware specific modules + modprove ns558 - insmod joy-something + And for serial port joysticks, you'll need the serial input line +discipline module loaded and the inputattach utility started: - where 'something' is the type of your joystick. See below for more precise -explanation. + modprobe serport + inputattach -xxx /dev/tts/X & - Alternately you can add the lines + In addition to that, you'll need the joystick driver module itself, most +usually you'll have an analog joystick: - alias char-major-15 joy-something - options joy-something js_xx=x,x,x,x,... + modprobe analog + + For automatic module loading, something like this might work: - to the /etc/conf.modules file, so that the joystick module will be loaded -automatically when the /dev/js devices are accessed. + alias tty-ldisc-2 serport + alias char-major-13 joydev ns558 analog 2.5 Verifying that it works ~~~~~~~~~~~~~~~~~~~~~~~~~~~ For testing the joystick driver functionality, there is the jstest -program. You run it by typing: +program in the utilities package. You run it by typing: jstest /dev/js0 @@ -231,109 +159,95 @@ 3.1 Analog joysticks ~~~~~~~~~~~~~~~~~~~~ - The joy-analog.c uses the standard analog inputs of the gameport, and thus -supports all standard joysticks and gamepads. It also supports extensions -like additional hats and buttons compatible with CH Flightstick Pro, -ThrustMaster FCS or 6 and 8 button gamepads. + The analog.c uses the standard analog inputs of the gameport, and thus +supports all standard joysticks and gamepads. It uses a very advanced +routine for this, allowing for data precision that can't be found on any +other system. + + It also supports extensions like additional hats and buttons compatible +with CH Flightstick Pro, ThrustMaster FCS or 6 and 8 button gamepads. Saitek +Cyborg 'digital' joysticks are also supportted by this driver, because +they're basically souped up CHF sticks. However the only types that can be autodetected are: * 2-axis, 4-button joystick * 3-axis, 4-button joystick * 4-axis, 4-button joystick +* Saitek Cyborg 'digital' joysticks For other joystick types (more/less axes, hats, and buttons) support you'll need to specify the types either on the kernel command line or on the -module command line, when inserting joy-analog.o into the kernel. The +module command line, when inserting analog.o into the kernel. The parameters are: - js_an=p0,m0,n0,p1,m1,n1 ... - - Where 'p' is the port number, eg. 0x201, which is the standard address. -'m' and 'n' are joystick 0 and joystick 1 bitmasks for the specified -joystick port. The bits in the bitmasks mean: - - Bit | 2^n | Meaning - ---------------------------------- - 0 | 1 | Axis X1 - 1 | 2 | Axis Y1 - 2 | 4 | Axis X2 - 3 | 8 | Axis Y2 - 4 | 16 | Button A - 5 | 32 | Button B - 6 | 64 | Button C - 7 | 128 | Button D - 8 | 256 | CHF Buttons X and Y - 9 | 512 | CHF Hat 1 - 10 | 1024 | CHF Hat 2 - 11 | 2048 | FCS Hat - 12 | 4096 | Pad Button X - 13 | 8192 | Pad Button Y - 14 | 16384 | Pad Button U - 15 | 32768 | Pad Button V - -(CHF = CH Flightstick Pro, FCS = ThrustMaster FCS) - - Following is a table of joysticks for which the 'm' values are known. If -you have any additions/corrections to it, e-mail me. - - Joystick | 'm' value - ---------------------------------------------------- - Simple 2-button 2-axis joystick | 0x0033 - Second simple joystick on Y-cable | 0x00cc - Genius Flight2000 F-12 | 0x00f3 - Genius Flight2000 F-21 | 0x08f7 - Genius Flight2000 F-22 | 0x02ff - Genius GameHunter G-06 | 0xf0f3 - Genius MaxFire G-07 | 0xf0f3 - Genius PowerStation | 0xf0f3 - Laing #1 PC SuperPad | 0xf0f3 - Logitech Wingman | 0x003b - Microsoft SideWinder Standard | 0x003b - QuickShot QS-201 SuperWarrior | 0x00fb - Saitek Megapad XII | 0x30f3 - PC Powerpad Pro | 0x30f3 - - In case you have one of the joystick in the table below, and it doesn't -work with a specific driver in digital mode for some reason, you can use -them in analog mode with the joy-analog driver as well. However, digital -operation is always better. - - Joystick | 'm' value - ---------------------------------------------------- - Gravis GamePad Pro - analog mode | 0x00f3 - Genius Flight2000 F-23 | 0x02ff - Microsoft SideWinder 3D Pro - CHF mode | 0x02ff - Microsoft SideWinder 3D Pro - FCS mode | 0x08f7 - - An example that would configure the driver to use two two axis, two button -joysticks connected to port 0x201, a single four button four axis joystick -connected to port 0x202, a four axis, six button and two hat CHF compatible -joystick on 0x203, and a two axis four button FCS compatible joystick with a -single hat on 0x207: - - js_an=0x201,0x33,0xcc,0x202,0xff,0,0x203,0x7ff,0,0x207,0x8f3,0 - - If you can't sum bits into hex numbers in your head easily, you can simply -sum the values in the 2^n column decimally and use that number instead. -Using this method you'd get a command line: + js=type,type,type,.... - js_an=0x201,51,204,0x202,255,0,0x203,2047,0,0x207,2291,0 - - And it would do the same as the above explained command line. Use -whichever way you like best. + 'type' is type of the joystick from the table below, defining joysticks +present on gameports in the system, starting with gameport0, second 'type' +entry defining joystick on gameport1 and so on. + + Type | Meaning + ----------------------------------- + none | No analog joystick on that port + auto | Autodetect joystick + 2btn | 2-button n-axis joystick + y-joy | Two 2-button 2-axis joysticks on an Y-cable + y-pad | Two 2-button 2-axis gamepads on an Y-cable + fcs | Thrustmaster FCS compatible joystick + chf | Joystick with a CH Flightstick compatible hat + fullchf | CH Flightstick compatible with two hats and 6 buttons + gamepad | 4/6-button n-axis gamepad + gamepad8 | 8-button 2-axis gamepad + + In case your joystick doesn't fit in any of the above categories, you can +specify the type as a number by combining the bits in the table below. This +is not recommended unless you really know what are you doing. It's not +dangerous, but not simple either. + + Bit | Meaning + -------------------------- + 0 | Axis X1 + 1 | Axis Y1 + 2 | Axis X2 + 3 | Axis Y2 + 4 | Button A + 5 | Button B + 6 | Button C + 7 | Button D + 8 | CHF Buttons X and Y + 9 | CHF Hat 1 + 10 | CHF Hat 2 + 11 | FCS Hat + 12 | Pad Button X + 13 | Pad Button Y + 14 | Pad Button U + 15 | Pad Button V + 16 | Saitek F1-F4 Buttons + 17 | Saitek Digital Mode + 19 | GamePad + 20 | Joy2 Axis X1 + 21 | Joy2 Axis Y1 + 22 | Joy2 Axis X2 + 23 | Joy2 Axis Y2 + 24 | Joy2 Button A + 25 | Joy2 Button B + 26 | Joy2 Button C + 27 | Joy2 Button D + 31 | Joy2 GamePad 3.2 Microsoft SideWinder joysticks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Microsoft 'Digital Overdrive' protocol is supported by the -joy-sidewinder.c module. All currently supported joysticks: + Microsoft 'Digital Overdrive' protocol is supported by the sidewinder.c +module. All currently supported joysticks: -* SideWinder 3D Pro -* SideWinder Force Feedback Pro -* SideWinder Force Feedback Wheel -* SideWinder FreeStyle Pro -* SideWinder GamePad (up to four, chained together) -* SideWinder Precision Pro +* Microsoft SideWinder 3D Pro +* Microsoft SideWinder Force Feedback Pro +* Microsoft SideWinder Force Feedback Wheel +* Microsoft SideWinder FreeStyle Pro +* Microsoft SideWinder GamePad (up to four, chained) +* Microsoft SideWinder Precision Pro +* Microsoft SideWinder Precision Pro USB are autodetected, and thus no module parameters are needed. @@ -349,9 +263,9 @@ 3.3 Logitech ADI devices ~~~~~~~~~~~~~~~~~~~~~~~~ - Logitech ADI protocol is supported by the joy-logitech.c module. It should -support any Logitech device using this protocol. This includes, but is not -limited to: + Logitech ADI protocol is supported by the adi.c module. It should support +any Logitech device using this protocol. This includes, but is not limited +to: * Logitech CyberMan 2 * Logitech ThunderPad Digital @@ -370,48 +284,48 @@ Logitech WingMan Joystick, Logitech WingMan Attack, Logitech WingMan Extreme and Logitech WingMan ThunderPad are not digital joysticks and are handled by the analog driver described above. Logitech WingMan Warrior and -Logitech Magellan are supported by serial drivers described below. Logitech -CyberMan, Logitech WingMan Force and Logitech WingMan Formula Force are not -supported yet. +Logitech Magellan are supported by serial drivers described below. Logitech +WingMan Force and Logitech WingMan Formula Force are supported by the +I-Force driver described below. Logitech CyberMan is not supported yet. 3.4 Gravis GrIP ~~~~~~~~~~~~~~~ - Gravis GrIP protocol is supported by the joy-gravis.c module. It -currently supports: + Gravis GrIP protocol is supported by the grip.c module. It currently +supports: * Gravis GamePad Pro -* Gravis Xterminator * Gravis BlackHawk Digital +* Gravis Xterminator +* Gravis Xterminator DualControl All these devices are autodetected, and you can even use any combination of up to two of these pads either chained together or using an Y-cable on a single gameport. -GrIP MultiPort and Gravis Xterminator DualControl aren't supported yet. -Gravis Stinger is a serial device and hopefully will be supported in the -future. Other Gravis joysticks are supported by the joy-analog driver. +GrIP MultiPort isn't supported yet. Gravis Stinger is a serial device and +hopefully will be supported soon. Other Gravis joysticks are supported by +the analog driver. 3.5 FPGaming A3D and MadCatz A3D ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Assassin 3D protocol created by FPGaming, is used both by FPGaming themselves and is licensed to MadCatz. A3D devices are supported by the -joy-assassin.c module. It currently supports: +a3d.c module. It currently supports: * FPGaming Assassin 3D * MadCatz Panther * MadCatz Panther XL All these devices are autodetected. Because the Assassin 3D and the Panther -allow connecting analog joysticks to them, these are supported in this -driver, too. The driver uses the js_as parameter for the analog joysticks, -which has the same syntax as js_an for the analog driver. +allow connecting analog joysticks to them, you'll need to load the analog +driver as well to handle the attached joysticks. - The trackball support is far from perfect at this stage of development, -but should be well usable. + The trackball should work with USB mousedev module as a normal mouse. See +the USB documentation for how to setup an USB mouse. 3.6 ThrustMaster DirectConnect (BSP) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - The TM DirectConnect (BSP) protocol is supported by the joy-thrustmaster.c + The TM DirectConnect (BSP) protocol is supported by the tmdc.c module. This includes, but is not limited to: * ThrustMaster Millenium 3D Inceptor @@ -426,96 +340,62 @@ If you have one of these, contact me. BSP devices are autodetected, and thus no parameters to the module -are needed. +are needed. Up to two TMDC devices can be connected to one gameport, using +an Y-cable. 3.7 Creative Labs Blaster ~~~~~~~~~~~~~~~~~~~~~~~~~ - The Blaster protocol is supported by the joy-creative.c module. It -currently supports only the: + The Blaster protocol is supported by the cobra.c module. It supports only +the: * Creative Blaster GamePad Cobra Up to two of these can be used on a single gameport, using an Y-cable. -3.8 PDPI Lightning 4 gamecards -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - PDPI Lightning 4 gamecards are supported by the joy-lightning.c module. -This driver is only for analog joysticks connected to the card - if you want -to use some of the digital devices, you need to use its specific driver. The -card will work in legacy mode with them, though. - - Since all features of analog joysticks can't be detected, this driver -needs a command line: - - js_l4=p0,m0,n0,p1,m1,n1,.... - - As you can see, it's very similar to the analog drivers command line. -Actually it is the same except for the meaning of p0. p0 in this case is the -port the joystick is attached to: - - p | Port - ---------------------------- - 0 | Primary card, port 1 - 1 | Primary card, port 2 - 2 | Primary card, port 3 - 3 | Primary card, port 4 - 4 | Secondary card, port 1 - 5 | Secondary card, port 2 - 6 | Secondary card, port 3 - 7 | Secondary card, port 4 +3.8 Genius Digital joysticks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + The Genius digitally communicating joysticks are supported by the gf2k.c +module. This includes: - Two cards maximum are allowed in one system, because of the card's design. +* Genius Flight2000 F-23 joystick +* Genius Flight2000 F-31 joystick +* Genius G-09D gamepad - See the description of analog joystick driver for explanations of m0 and -n0 values. + Other Genius digital joysticks are not supported yet, but support can be +added fairly easily. -3.9 Trident 4DWave / Aureal Vortex -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Soundcards with a Trident 4DWave DX/NX or Aureal Vortex chipset provide an -"Enhanced Game Port" mode where the soundcard handles polling the joystick. -This mode is supported by the joy-pci module. - - If no module parameters are given, the joy-pci module will set all the -soundcards it finds to "enhanced" mode, and will try to autodetect the type -of attached joystick. It can only detect the same types of joysticks that -the joy-analog module can. - - This module accepts parameters in the form: - - js_pci=t0,i0,m0,n0,t1,i1,m1,n1,.... - - The "t" value specifies the type of card, as follows: - - t | Card Type - ---------------------------- - 0 | Trident 4DWave DX - 1 | Trident 4DWave NX - 2 | Aureal Vortex1 (Au8820 chipset) - 3 | Aureal Vortex2 (Au8830 chipset) - - If you have more than one card of the same type, the "i" parameter lets -you choose which card to apply the "m" and "n" values to. It counts from -"0". (The driver detects cards in the order listed in the above table.) - - The "m" and "n" values have the same meaning as for the analog module, -with the exception that the value m=0, n=0 indicates that joy-pci should -completely ignore that port. This can be useful to reserve a certain port -for purely MIDI operation. - - For example, let's say you have 3 sound cards - a 4Dwave DX, a 4DWave NX, -and a Vortex 2. You have a three-axis, four-button, one-hat CHF- compatible -joystick on the DX. You use the NX to interface to an external MIDI device. -Finally, you have two two-axis, two-button joysticks on the Vortex. Your -command line might look like: +3.9 InterAct Digital joysticks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + The InterAct digitally communicating joysticks are supported by the +interact.c module. This includes: + +* InterAct HammerHead/FX gamepad +* InterAct ProPad8 gamepad + + Other InterAct digital joysticks are not supported yet, but support can be +added fairly easily. - js_pci=0,0,0x207,0,1,1,0,0,3,0,0x33,0xcc +3.10 PDPI Lightning 4 gamecards +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + PDPI Lightning 4 gamecards are supported by the lightning.c module. +Once the module is loaded, the analog driver can be used to handle the +joysticks. Digitally communicating joystick will work only on port 0, while +using Y-cables, you can connect up to 8 analog joysticks to a single L4 +card, 16 in case you have two in your system. + +3.11 Trident 4DWave / Aureal Vortex +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Soundcards with a Trident 4DWave DX/NX or Aureal Vortex/Vortex2 chipsets +provide an "Enhanced Game Port" mode where the soundcard handles polling the +joystick. This mode is supported by the pcigame.c module. Once loaded the +analog driver can use the enhanced features of these gameports.. -3.10 Amiga +3.12 Amiga ~~~~~~~~~~ - Amiga joysticks, connected to an Amiga, are supported by the joy-amiga.c + Amiga joysticks, connected to an Amiga, are supported by the amijoy.c driver. Since they can't be autodetected, the driver has a command line. - js_am=a,b + amijoy=a,b a and b define the joysticks connected to the JOY0DAT and JOY1DAT ports of the Amiga. @@ -528,32 +408,32 @@ No more joystick types are supported now, but that should change in the future if I get an Amiga in the reach of my fingers. -3.11 Game console and 8-bit pads and joysticks +3.13 Game console and 8-bit pads and joysticks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ See joystick-parport.txt for more info. -3.12 SpaceTec/LabTec devices +3.14 SpaceTec/LabTec devices ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SpaceTec serial devices communicate using the SpaceWare protocol. It is -supported by the joy-spaceorb and joy-spaceball drivers. The devices currently -supported by joy-spaceorb are: +supported by the spaceorb.c and spaceball.c drivers. The devices currently +supported by spaceorb.c are: * SpaceTec SpaceBall Avenger * SpaceTec SpaceOrb 360 -Devices currently supported by joy-spaceball are: +Devices currently supported by spaceball.c are: * SpaceTec SpaceBall 4000 FLX - In addition to having the joy-spaceorb/spaceball module in the kernel, you -also need to attach a serial port to it. to do that, run the jsattach -program: + In addition to having the spaceorb/spaceball and serport modules in the +kernel, you also need to attach a serial port to it. to do that, run the +jsattach program: - jsattach --spaceorb /dev/ttySx & + inputattach --spaceorb /dev/tts/x & or - jsattach --sball4 /dev/ttySx & + jsattach --spaceball /dev/tts/x & -where /dev/ttySx is the serial port which the device is connected to. After +where /dev/tts/x is the serial port which the device is connected to. After doing this, the device will be reported and will start working. There is one caveat with the SpaceOrb. The button #6, the on the bottom @@ -564,9 +444,9 @@ SpaceTec SpaceBall 2003 FLX and 3003 FLX are not supported yet. -3.13 Logitech SWIFT devices +3.15 Logitech SWIFT devices ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - The SWIFT serial protocol is supported by the joy-warrior module. It + The SWIFT serial protocol is supported by the warrior.c module. It currently supports only the: * Logitech WingMan Warrior @@ -575,11 +455,11 @@ supported as well. To use the module, you need to run jsattach after you insert/compile the module into your kernel: - jsattach --warrior /dev/ttySx & + inputattach --warrior /dev/tts/x & -ttySx is the serial port your Warrior is attached to. +/dev/tts/x is the serial port your Warrior is attached to. -3.14 Magellan / Space Mouse +3.16 Magellan / Space Mouse ~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Magellan (or Space Mouse), manufactured by LogiCad3d (formerly Space Systems), for many other companies (Logitech, HP, ...) is supported by the @@ -592,10 +472,29 @@ To use it, you need to attach the serial port to the driver using the - jsattach --magellan /dev/ttySx & + inputattach --magellan /dev/tts/x & command. After that the Magellan will be detected, initialized, will beep, -and the /dev/jsX device should become useable. +and the /dev/input/jsX device should become useable. + +3.17 I-Force devices +~~~~~~~~~~~~~~~~~~~~ + All I-Force devices ale supported by the iforce.c module. This includes, +but is not limited to: + +* Logitech WingMan Force +* Logitech WingMan Force Wheel +* Guillemot Race Leader wheel + + To use it, you need to attach the serial port to the driver using the + + inputattach --iforce /dev/tts/x & + +command. After that the I-Force device will be detected, and the +/dev/input/jsX device should become useable. + + In case you're using the device via the USB port, the inputattach command +isn't needed. 4. Troubleshooting ~~~~~~~~~~~~~~~~~~ @@ -604,80 +503,20 @@ some of its modes. The most useful modes are "normal" - for the 1.x interface, and "old" for the "0.x" interface. You run it by typing: - jstest --normal /dev/js0 - jstest --old /dev/js0 - - If your trouble stems from the fact the drivers can't detect the joystick -attached to your gameport, and you decide you need my help (which I will -gladly provide), please use the joydump utility first. It's created just by -typing - - make joydump.o + jstest --normal /dev/input/js0 + jstest --old /dev/input/js0 - in the directory where you unpacked the joystick package. It is run then -by typing + Additionally you can do a test with the evtest utility: - insmod joydump.o - - in the same directory. It will return a 'device busy' or 'initialization -failed' error. This is perfectly okay. It has already done it's job. The -results can be found in the system log or in the output of the - - dmesg - -command. Please send me the results along with your problem report. + evtest /dev/input/event0 Oh, and read the FAQ! :) 5. FAQ ~~~~~~ -Q: The driver doesn't find any joysticks connected to my soundcard with the - message "joy-something: no joysticks found" and "joy-something.o: - init_module: Device or resource busy." or "Initialization of joy-something - failed" What could be the cause? -A: The most common cause is that the joystick port on your soundcard is - not enabled. If it is an ISA PnP card, you'll need isapnptools to configure - the gameport. Non-PnP cards usually use some option to the sound driver - - see the sound driver docs and source and enable the port. Note that in case - of a PnP card you have to load the joystick driver as a module after running - the isapnp command, it will not work in the opposite order. - -Q: Any access to the joystick devices gives me "Operation not supported by - device". What am I doing wrong? -A: You're running a 2.0 kernel and you forgot to insmod the hardware - specific module. You not only need the joystick.o, but also one of the other - joy-*.o files (most usually joy-analog.o), as described in this document, - section 2. If you are not using modules, then you didn't say 'Y' to any of - the hardware-specific questions. Again, see section 2. If you did select - the specific support, and you still get this message, check that you - selected the right one, and if it still doesn't work, go to the previous - FAQ. - -Q: Everything is fine, except I get "No such device" error when I try to - do anything with /dev/js0. What's the cause? -A: You're running a 2.1 or 2.2. kernel and you want to read the previous FAQ. - -Q: Upon 'insmod joystick.o' I get a LOT of unresolved symbols, including - 'printk' and others. Why? -A: You either don't have your kernel compiled with module support. If - that's the cause, re-compile your kernel with module support switched on. - Or, you use versioned symbols, and don't have -DMODVERSIONS in the joystick - driver Makefile, or vice versa. Correct the situation by either removing or - adding -DMODVERSIONS to the Makefile. - -Q: Upon 'insmod joy-something' I get a bunch of unresolved symbols, like - 'js_register_port, js_unregister device' and others. What's wrong? -A: You need to 'insmod joystick.o' first. - -Q: Running 'jstest 1' or 'jscal 1' doesn't work, and returns with "File - not found" error. What is the problem? -A: The command line interface for these tools is different from what - version 0.8.0 used. You have to specify the whole device name, eg. 'jstest - /dev/js0'. - Q: Running 'jstest /dev/js0' results in "File not found" error. What's the cause? -A: The device files don't exist. Run 'make devs'. +A: The device files don't exist. Create them (see section 2.2). Q: Is it possible to connect my old Atari/Commodore/Amiga/console joystick or pad that uses a 9-pin D-type cannon connector to the serial port of my @@ -741,47 +580,3 @@ If you think you should be in this list and are not, it's possible that I forgot to include you - contact me and I'll correct the error. :) - - Thanks to KYE Systems Europe, who provided me with driver sources for the -Genius Flight2000 Digital F-23, which happens to be identical (in software) -to Microsoft SideWinder 3D Pro. - - Thanks to ThrustMaster Inc. who provided me with docs for their digital -protocol specifications, and to Trystan A Larey-Williams , -who wrote an attempt of a driver for them. - - Thanks to Creative Labs Europe, and Ifor Powell , -who provided me with docs for their first generation Blaster GamePad. - - Special thanks go to FP-Gaming, Inc. and James C Barnes , -who provided me with help and detailed information about the Assassin 3D -protocol and devices, and even sent me a Panther and Panther XL for testing, -along with cool T-shirts. - - Special thanks to PDPI, Mike Pelkey and Brand Kvavle -, for providing me with documentation and example -code for their L4 gamecard, and sending me the card to test my driver with -it. - - Thanks to LogiCad3D for their support, for having the specifications -online and for the nice music on their telephone. - - Special thanks to Logitech, Jerry de Raad , -Thomas Burgel , Avinash Shinde - for providing me with a lot of documentation -for their devices, and also for a big box, containing a CyberMan2, Wingman -Extreme, Magellan, Wingman Warrior, two MouseMan mice, and a NewTouch -keyboard. - - Thanks to everyone else who helped me develop this package of drivers! - - No thanks to Microsoft and Gravis, who don't release a word about their -hardware .... :( - -8. ChangeLog -~~~~~~~~~~~~ - See the ChangeLog file for the log of changes. - -9. To do -~~~~~~~~ - See the TODO file for the list of things planned. diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/kernel-doc-nano-HOWTO.txt linux/Documentation/kernel-doc-nano-HOWTO.txt --- v2.4.0-test1/linux/Documentation/kernel-doc-nano-HOWTO.txt Tue May 23 15:31:32 2000 +++ linux/Documentation/kernel-doc-nano-HOWTO.txt Mon Jun 19 12:56:07 2000 @@ -57,7 +57,7 @@ If you want to see man pages instead, you can do this: $ cd linux -$ scripts/kernel-doc -man $(find -name '*.c') | split-man.pl /tmp/man +$ scripts/kernel-doc -man $(find -name '*.c' '*.h') | split-man.pl /tmp/man Here is split-man.pl: @@ -122,6 +122,25 @@ '%CONST' - name of a constant. Take a look around the source tree for examples. + + +How to make new SGML template files +----------------------------------- + +SGML template files (*.tmpl) are like normal SGML files, except that +they can contain escape sequences where extracted documentation should +be inserted. + +!E is replaced by the documentation, in , for +functions that are exported using EXPORT_SYMBOL: the function list is +collected from files listed in Documentation/DocBook/Makefile. + +!I is replaced by the documentation for functions that are +_not_ exported using EXPORT_SYMBOL. + +!F is replaced by the +documentation, in , for the functions listed. + Tim. */ diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/kernel-parameters.txt linux/Documentation/kernel-parameters.txt --- v2.4.0-test1/linux/Documentation/kernel-parameters.txt Fri Jan 21 18:19:15 2000 +++ linux/Documentation/kernel-parameters.txt Mon Jun 19 12:56:07 2000 @@ -1,8 +1,8 @@ -June 1999 Kernel Parameters v2.2.9 +June 2000 Kernel Parameters v2.4.0 ~~~~~~~~~~~~~~~~~ -The following is a consolidated list of the kernel parameters as defined -in the file init/main.c and sorted into English Dictionary order (defined +The following is a consolidated list of the kernel parameters as implemented +by the __setup() macro and sorted into English Dictionary order (defined as ignoring all punctuation and sorting digits before letters in a case insensitive manner), and with descriptions where known. @@ -10,10 +10,13 @@ restrictions on the kernel for the said kernel parameter to be valid. The restrictions referred to are that the relevant option is valid if: + ACPI ACPI support is enabled. APIC APIC support is enabled. APM Advanced Power Management support is enabled. AX25 Appropriate AX.25 support is enabled. CD Appropriate CD support is enabled. + DEVFS devfs support is enabled. + DRM Direct Rendering Management support is enabled. EIDE EIDE/ATAPI support is enabled. FB The frame buffer device is enabled. HW Appropriate hardware is enabled. @@ -21,6 +24,7 @@ JOY Appropriate joystick support is enabled. LP Printer support is enabled. LOOP Loopback device support is enabled. + M68k M68k architecture is enabled. MCA MCA bus support is enabled. MDA MDA console support is enabled. MOUSE Appropriate mouse support is enabled. @@ -54,10 +58,20 @@ 53c7xx= [HW,SCSI] Amiga SCSI controllers. + acpi= [HW,ACPI] Advanced Configuration and Power Interface + + ad1816= [HW,SOUND] + + ad1848= [HW,SOUND] + adb_buttons= [HW,MOUSE] + adlib= [HW,SOUND] + advansys= [HW,SCSI] + aedsp16= [HW,SOUND] + aha152x= [HW,SCSI] aha1542= [HW,SCSI] @@ -68,16 +82,22 @@ apm= [APM] Advanced Power Management. + applicom= [HW] + arcrimi= [HW,NET] - ataflop= [HW, M68k] + ataflop= [HW,M68k] - atamouse= [HW,MOUSE] Atari Mouse. + atarimouse= [HW,MOUSE] Atari Mouse. atascsi= [HW,SCSI] Atari SCSI. + awe= [HW,SOUND] + aztcd= [HW,CD] Aztec CD driver. + baycom_epp= [HW,AX25] + baycom_par= [HW,AX25] BayCom Parallel Port AX.25 Modem. baycom_ser_fdx= [HW,AX25] BayCom Serial Port AX.25 Modem in Full @@ -92,6 +112,8 @@ cdu31a= [HW,CD] + chandev= [HW,NET] + cm206= [HW,CD] com20020= [HW,NET] @@ -100,15 +122,29 @@ com90xx= [HW,NET] + condev= [HW] + console= [KNL] output console + comm spec (speed, control, parity). + cpia_pp= [HW,PPT] + + cs4232= [HW,SOUND] + + cs89x0_dma= [HW,NET] + + ctc= [HW,NET] + cyclades= [HW,SERIAL] Cyclades multi-serial port adapter. + + dasd= [HW,NET] debug [KNL] Enable kernel debugging (events log level). decnet= [HW,NET] + devfs= [DEVFS] + digi= [HW,SERIAL] io parameters + enable/disable command. digiepca= [HW,SERIAL] @@ -126,6 +162,12 @@ edb= [HW,PS2] + eicon= [HW,ISDN] + + es1370= [HW,SOUND] + + es1371= [HW,SOUND] + ether= [HW,NET] Ethernet cards parameters (iomem, irq, dev_name). @@ -141,6 +183,8 @@ gscd= [HW,CD] + gus= [HW,SOUND] + gvp11= [HW,SCSI] hd= [EIDE] (E)IDE hard drive subsystem geometry @@ -148,8 +192,6 @@ hfmodem= [HW,AX25] - HiSax= [HW,ISDN] - hisax= [HW,ISDN] in2000= [HW,SCSI] @@ -166,15 +208,11 @@ idebus= [HW] (E)IDE subsystem : VLB/PCI bus speed. - in2000= [HW,SCSI] - - init= [KNL] Default init level. - ip= [PNP] isp16= [HW,CD] - js_14= [HW,JOY] + iucv= [HW,NET] js_am= [HW,JOY] @@ -194,6 +232,10 @@ js_db9_3= [HW,JOY] + js_l4= [HW,JOY] + + js_pci= [HW,JOY,PCI] + js_tg= [HW,JOY] js_tg_2= [HW,JOY] @@ -204,6 +246,8 @@ load_ramdisk= [RAM] List of ramdisks to load from floppy. + logi_busmouse= [HW, MOUSE] + lp=0 [LP] Specify parallel ports to use, e.g, lp=port[,port...] lp=none,parport0 (lp0 not configured, lp1 uses lp=reset first parallel port). 'lp=0' disables the @@ -224,6 +268,12 @@ mac5380= [HW,SCSI] + mac53c9x= [HW,SCSI] + + mad16= [HW,SOUND] + + maui= [HW,SOUND] + max_loop=[0-255] [LOOP] Set the maximum number of loopback devices that can be mounted. @@ -240,11 +290,19 @@ md= [HW] RAID subsystems devices and level. + mdisk= [HW] + mdacon= [MDA] + megaraid= [HW,SCSI] + mem= [KNL] force use XX Mb of memory when the kernel is not able to see the whole system memory or for test. + memfrac= [KNL] + + mpu401= [HW,SOUND] + msmouse= [HW,MOUSE] Microsoft Mouse. ncr5380= [HW,SCSI] @@ -257,35 +315,53 @@ ncr53c8xx= [HW,SCSI] + netdev= [NET] + nfsaddrs= [NFS] nfsroot= [NFS] nfs root filesystem for disk-less boxes. - nmi_watchdog= [KNL, BUGS=ix86] debugging features for SMP kernels. + nmi_watchdog= [KNL,BUGS=ix86] debugging features for SMP kernels. no387 [BUGS=ix86] Tells the kernel to use the 387 maths emulation library even if a 387 maths coprocessor is present. + noalign [KNL,ARM] + noapic [SMP,APIC] Tells the kernel not to make use of any APIC that may be present on the system. noasync [HW, M68K] Disables async and sync negotiation for all devices. + nocache [ARM] + nodisconnect [HW,SCSI, M68K] Disables SCSI disconnects. - no-halt [BUGS=ix86] + nohlt [BUGS=ARM] + + no-hlt [BUGS=ix86] noinitrd [RAM] Tells the kernel not to load any configured initial RAM disk. + nointroute [IA-64] + no-scroll [VGA] nosmp [SMP] Tells an SMP kernel to act as a UP kernel. nosync [HW, M68K] Disables sync negotiation for all devices. + nowb [ARM] + + opl3= [HW,SOUND] + + opl3sa= [HW,SOUND] + + opl3sa2= [HW,SOUND] + optcd= [HW,CD] panic= [KNL] kernel behaviour on panic. @@ -305,6 +381,8 @@ order they are specified on the command line, starting with parport0. + pas2= [HW,SOUND] + pas16= [HW,SCSI] pcbit= [HW,ISDN] @@ -329,10 +407,17 @@ prompt_ramdisk= [RAM] List of RAM disks to prompt for floppy disk before loading. + pss= [HW,SOUND] + pt. [PARIDE] + quiet= [KNL] Disable log messages. + ramdisk= [RAM] Sizes of RAM disks in kilobytes [deprecated]. + ramdisk_blocksize= + [RAM] + ramdisk_size= [RAM] New name for the ramdisk parameter. ramdisk_start= [RAM] Starting block of RAM disk image (so you can @@ -352,12 +437,27 @@ S [KNL] run init in single mode. + sb= [HW,SOUND] + sbpcd= [HW,CD] Soundblaster CD adapter. scsi_logging= [SCSI] + scsihosts= [SCSI] + + sg_def_reserved_size= + [SCSI] + + sgalaxy= [HW,SOUND] + + sim710= [SCSI,HW] + sjcd= [HW,CD] + smart2= [HW] + + sonicvibes= [HW,SOUND] + sonycd535= [HW,CD] sound= [SOUND] @@ -366,7 +466,9 @@ specialix= [HW,SERIAL] Specialix multi-serial port adapter. - st= [HW] SCSI tape parameters (buffers, etc.). + sscape= [HW,SOUND] + + st= [HW,SCSI] SCSI tape parameters (buffers, etc.). st0x= [HW,SCSI] @@ -380,19 +482,35 @@ t128= [HW,SCSI] + tdfx= [HW,DRM] + tmc8xx= [HW,SCSI] tmscsim= [HW,SCSI] tp720= [HW,PS2] + trix= [HW,SOUND] + u14-34f= [HW,SCSI] + uart401= [HW,SOUND] + + uart6850= [HW,SOUND] + + usbfix [BUGS=IA-64] + video= [FB] frame buffer configuration. vga= [KNL] on ix386, enable to choose a peculiar video mode (use vga=ask for menu). + vmhalt= [KNL,S390] + + vmpoff= [KNL,S390] + + waveartist= [HW,SOUND] + wd33c93= [HW,SCSI] wd7000= [HW,SCSI] diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/md.txt linux/Documentation/md.txt --- v2.4.0-test1/linux/Documentation/md.txt Mon Feb 2 13:07:47 1998 +++ linux/Documentation/md.txt Tue Jun 20 07:24:52 2000 @@ -1,15 +1,17 @@ -Tools that manage md devices can be found at sweet-smoke.ufr-info-p7.ibp.fr -in public/Linux/md035.tar.gz. +Tools that manage md devices can be found at + http://www..kernel.org/pub/linux/daemons/raid/.... - Marc ZYNGIER --- You can boot (if you selected boot support in the configuration) with your md -device with the following kernel command line: +device with the following kernel command lines: -md=,,,,dev0,dev1,...,devn +for old raid arrays without persistant superblocks: + md=,,,,dev0,dev1,...,devn +for raid arrays with persistant superblocks + md=,dev0,dev1,...,devn + md device no. = the number of the md device ... 0 means md0, 1 md1, @@ -19,19 +21,16 @@ raid level = -1 linear mode 0 striped mode - other modes are currently unsupported. + other modes are only supported with persistant super blocks chunk size factor = (raid-0 and raid-1 only) - Set the chunk size as PAGE_SIZE << n. + Set the chunk size as 4k << n. -fault level = (raid-1 only) - Set the maximum fault number as n. - Currently unsupported due to lack of boot support for raid1. +fault level = totally ignored dev0-devn: e.g. /dev/hda1,/dev/hdc1,/dev/sda1,/dev/sdb1 -my loadlin line looks like this: +A possible loadlin line (Harald Hoyer ) looks like this: e:\loadlin\loadlin e:\zimage root=/dev/md0 md=0,0,4,0,/dev/hdb2,/dev/hdc3 ro - Harald Hoyer diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/networking/8139too.txt linux/Documentation/networking/8139too.txt --- v2.4.0-test1/linux/Documentation/networking/8139too.txt Tue May 23 15:31:32 2000 +++ linux/Documentation/networking/8139too.txt Mon Jun 19 17:59:32 2000 @@ -181,11 +181,25 @@ 11) RTL8139C support untested. +12) 10base-T support flaky or slow + Change History -------------- +Version 0.9.7 - June 11, 2000 + +* Fix support for older chips (RTL8139 early chips should now work again) + + +Version 0.9.6 - May 30, 2000 + +* Fix 4-extra-bytes bug + (thanks to Markus Westergren, via Santiago Garcia Mantinan) +* Yet more improved chip recognition + + Version 0.9.5 - May 17, 2000 * Improved chip version recognition diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/networking/shaper.txt linux/Documentation/networking/shaper.txt --- v2.4.0-test1/linux/Documentation/networking/shaper.txt Tue Apr 28 14:22:04 1998 +++ linux/Documentation/networking/shaper.txt Mon Jun 19 17:59:32 2000 @@ -1,6 +1,6 @@ Traffic Shaper For Linux -This is the current ALPHA release of the traffic shaper for Linux. It works +This is the current BETA release of the traffic shaper for Linux. It works within the following limits: o Minimum shaping speed is currently about 9600 baud (it can only @@ -37,13 +37,12 @@ mrouted tunnels via a traffic shaper to control bandwidth usage. The shaper is device/route based. This makes it very easy to use -with any setup BUT less flexible. You may well want to combine this patch -with Mike McLagan 's patch to allow routes to be -specified by source/destination pairs. +with any setup BUT less flexible. You may need to use iproute2 to set up +multiple route tables to get the flexibility. There is no "borrowing" or "sharing" scheme. This is a simple -traffic limiter. I'd like to implement Van Jacobson and Sally Floyd's CBQ -architecture into Linux one day (maybe in 2.1 sometime) and do this with -style. +traffic limiter. We implement Van Jacobson and Sally Floyd's CBQ +architecture into Linux 2.2. THis is the preferred solution. Shaper is +for simple or back compatible setups. Alan diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/networking/sk98lin.txt linux/Documentation/networking/sk98lin.txt --- v2.4.0-test1/linux/Documentation/networking/sk98lin.txt Tue Nov 23 22:42:20 1999 +++ linux/Documentation/networking/sk98lin.txt Mon Jun 19 17:59:32 2000 @@ -3,7 +3,7 @@ sk98lin.txt created 11-Nov-1999 -Readme File for sk98lin.o v3.02 +Readme File for sk98lin.o v3.04 SK-NET Gigabit Ethernet Adapter SK-98xx Driver for Linux This file contains @@ -24,8 +24,8 @@ ============ The sk98lin driver supports the SysKonnect SK-NET Gigabit Ethernet -Adapter SK-98xx family on Linux 2.2.x. -It has been tested with Linux on Intel/x86 and ALPHA machines. +Adapter SK-98xx family on Linux 2.2.x and above. +It has been tested with Linux on Intel/x86, ALPHA and UltraSPARC machines. From v3.02 on, the driver is integrated in the linux kernel source. *** @@ -132,7 +132,8 @@ module with 'insmod'. The configuration tools of some distributions can also give parameters to the driver module. If you use the kernel module loader, you can set driver parameters -in the file /etc/conf.modules. Insert a line of the form: +in the file /etc/modules.conf (or old name: /etc/conf.modules). +Insert a line of the form: options sk98lin ... @@ -281,14 +282,12 @@ the large frames. If one adapter is not set to receive large frames, it will simply drop them. -NOTE: If you look at the statistics (with netstat) in large frame - mode while there is traffic on the net, you will see the - RX error counter go up. This is because the adapter hardware - counts received large frames as errors, although they are - received correctly. So ignore this counter in that case. - You can switch back to the standard ethernet frame size with: ifconfig eth0 mtu 1500 + +To make this setting persitent, add a script with the 'ifconfig' +line to the system startup sequence (named something like "S99sk98lin" +in /etc/rc.d/rc2.d). *** @@ -374,15 +373,27 @@ (8) HISTORY =========== -VERSION 3.02 +VERSION 3.04 (In-Kernel version) +Problems fixed: +- Driver start failed on UltraSPARC +- Rx checksum calculation for big endian machines did not work +- Jumbo frames were counted as input-errors in netstat + +VERSION 3.03 (Standalone version) +Problems fixed: +- Compilation did not find script "printver.sh" if "." not in PATH +Known limitations: +- None + +VERSION 3.02 (In-Kernel version) Problems fixed: - None New Features: -- Integration in linux kernel source. +- Integration in Linux kernel source (2.2.14 and 2.3.29) Known limitations: - None -VERSION 3.02 +VERSION 3.01 Problems fixed: - None New Features: diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/networking/tlan.txt linux/Documentation/networking/tlan.txt --- v2.4.0-test1/linux/Documentation/networking/tlan.txt Mon Mar 27 08:08:20 2000 +++ linux/Documentation/networking/tlan.txt Mon Jun 19 12:56:07 2000 @@ -2,7 +2,10 @@ (C) 1998 James Banks (C) 1999-2000 Torben Mathiasen -TLAN driver for Linux, version 1.5 +For driver information/updates visit http://tlan.kernel.dk + + +TLAN driver for Linux, version 1.8a README @@ -65,12 +68,15 @@ if a card which only supports 10Mbs is forced into 100Mbs mode.) - 5. If the driver is built into the kernel, you can use the 3rd + 5. You have to use speed=X duplex=Y together now. If you just + do "insmod tlan.o speed=100" the driver will do Auto-Neg. + To force a 10Mbps Half-Duplex link do "insmod tlan.o speed=10 + duplex=1". + + 6. If the driver is built into the kernel, you can use the 3rd and 4th parameters to set aui and debug respectively. For example: -/* kernel-parameters are currently not supported. I will fix this asap. */ - ether=0,0,0x1,0x7,eth0 This sets aui to 0x1 and debug to 0x7, assuming eth0 is a @@ -79,11 +85,14 @@ The bits in the third byte are assigned as follows: 0x01 = aui - 0x04 = use half duplex - 0x08 = use full duplex - 0x10 = use 10BaseT - 0x20 = use 100BaseTx - + 0x02 = use half duplex + 0x04 = use full duplex + 0x08 = use 10BaseT + 0x10 = use 100BaseTx + + You also need to set both speed and duplex settings when forcing + speeds with kernel-parameters. + ether=0,0,0x12,0,eth0 will force link to 100Mbps Half-Duplex. III. Things to try if you have problems. 1. Make sure your card's PCI id is among those listed in @@ -94,5 +103,5 @@ There is also a tlan mailing list which you can join by sending "subscribe tlan" in the body of an email to majordomo@vuser.vu.union.edu. - +There is also a tlan website at http://tlan.kernel.dk diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/networking/tulip.txt linux/Documentation/networking/tulip.txt --- v2.4.0-test1/linux/Documentation/networking/tulip.txt Wed Apr 26 16:34:06 2000 +++ linux/Documentation/networking/tulip.txt Mon Jun 19 17:59:32 2000 @@ -142,6 +142,24 @@ Version history =============== +0.9.6 (May 31, 2000): +* Revert 21143-related support flag patch +* Add HPPA/media-table debugging printk + +0.9.5 (May 30, 2000): +* HPPA support (willy@puffingroup) +* CSR6 bits and tulip.h cleanup (Chris Smith) +* Improve debugging messages a bit +* Add delay after CSR13 write in t21142_start_nway +* Remove unused ETHER_STATS code +* Convert 'extern inline' to 'static inline' in tulip.h (Chris Smith) +* Update DS21143 support flags in tulip_chip_info[] +* Use spin_lock_irq, not _irqsave/restore, in tulip_start_xmit() +* Add locking to set_rx_mode() +* Fix race with chip setting DescOwned bit (Hal Murray) +* Request 100% of PIO and MMIO resource space assigned to card +* Remove error message from pci_enable_device failure + 0.9.4.3 (April 14, 2000): * mod_timer fix (Hal Murray) * PNIC2 resusitation (Chris Smith) diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/networking/vortex.txt linux/Documentation/networking/vortex.txt --- v2.4.0-test1/linux/Documentation/networking/vortex.txt Thu May 11 15:30:05 2000 +++ linux/Documentation/networking/vortex.txt Mon Jun 19 17:59:32 2000 @@ -156,7 +156,12 @@ "Variables to work-around the Compaq PCI BIOS32 problem".... +watchdog=N + Sets the time duration (in milliseconds) after which the kernel + decides that the transmitter has become stuck and needs to be reset. + This is mainly for debugging purposes. The default value is 400 (0.4 + seconds). Additional resources -------------------- diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/parport.txt linux/Documentation/parport.txt --- v2.4.0-test1/linux/Documentation/parport.txt Fri Jan 21 18:19:15 2000 +++ linux/Documentation/parport.txt Mon Jun 19 17:59:32 2000 @@ -109,7 +109,10 @@ | | |-- active | | `-- lp | | `-- timeslice -| |-- hardware +| |-- base-addr +| |-- irq +| |-- dma +| |-- modes | `-- spintime `-- parport1 |-- autoprobe @@ -121,7 +124,10 @@ | |-- active | `-- ppa | `-- timeslice - |-- hardware + |-- base-addr + |-- irq + |-- dma + |-- modes `-- spintime @@ -133,7 +139,28 @@ string "none" means that there are no device drivers using that port. -hardware Parallel port's base address, IRQ line and DMA channel. +base-addr Parallel port's base address, or addresses if the port + has more than one in which case they are separated + with tabs. These values might not have any sensible + meaning for some ports. + +irq Parallel port's IRQ, or -1 if none is being used. + +dma Parallel port's DMA channel, or -1 if none is being + used. + +modes Parallel port's hardware modes, comma-separated, + meaning: + + PCSPP PC-style SPP registers are available. + TRISTATE Port is bidirectional. + COMPAT Hardware acceleration for printers is + available and will be used. + EPP Hardware acceleration for EPP protocol + is available and will be used. + ECP Hardware acceleration for ECP protocol + is available and will be used. + DMA DMA is available and will be used. autoprobe Any IEEE-1284 device ID information that has been acquired from the (non-IEEE 1284.3) device. diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/powerpc/00-INDEX linux/Documentation/powerpc/00-INDEX --- v2.4.0-test1/linux/Documentation/powerpc/00-INDEX Sat Oct 10 09:53:24 1998 +++ linux/Documentation/powerpc/00-INDEX Tue Jun 20 07:24:52 2000 @@ -1,7 +1,7 @@ Index of files in Documentation/powerpc. If you think something about Linux/PPC needs an entry here, needs correction or you've written one please mail me. - Cort Dougan (cort@cs.nmt.edu) + Cort Dougan (cort@fsmlabs.com) 00-INDEX - this file @@ -9,6 +9,8 @@ - info about the Linux/PPC /proc/ppc_htab entry smp.txt - use and state info about Linux/PPC on MP machines +SBC8260_memory_mapping.txt + - EST SBC8260 board info sound.txt - info on sound support under Linux/PPC zImage_layout.txt diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/powerpc/SBC8260_memory_mapping.txt linux/Documentation/powerpc/SBC8260_memory_mapping.txt --- v2.4.0-test1/linux/Documentation/powerpc/SBC8260_memory_mapping.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/powerpc/SBC8260_memory_mapping.txt Mon Jun 19 17:59:35 2000 @@ -0,0 +1,197 @@ +Please mail me (Jon Diekema, diekema_jon@si.com or diekema@cideas.com) +if you have questions, comments or corrections. + + * EST SBC8260 Linux memory mapping rules + + http://www.estc.com/ + http://www.estc.com/products/boards/SBC8260-8240_ds.html + + Initial conditions: + ------------------- + + Tasks that need to be perform by the boot ROM before control is + transferred to zImage (compressed Linux kernel): + + - Define the IMMR to 0xf0000000 + + - Initialize the memory controller so that RAM is available at + physical address 0x00000000. On the SBC8260 is this 16M (64M) + SDRAM. + + - The boot ROM should only clear the RAM that it is using. + + The reason for doing this is to enhances the chances of a + successful post mortem on a Linux panic. One of the first + items to examine is the 16k (LOG_BUF_LEN) circular console + buffer called log_buf which is defined in kernel/printk.c. + + - To enhance boot ROM performance, the I-cache can be enabled. + + Date: Mon, 22 May 2000 14:21:10 -0700 + From: Neil Russell + + LiMon (LInux MONitor) runs with and starts Linux with MMU + off, I-cache enabled, D-cache disabled. The I-cache doesn't + need hints from the MMU to work correctly as the D-cache + does. No D-cache means no special code to handle devices in + the presence of cache (no snooping, etc). The use of the + I-cache means that the monitor can run acceptably fast + directly from ROM, rather than having to copy it to RAM. + + - Build the board information structure (see + include/asm-ppc/est8260.h for its definition) + + - The compressed Linux kernel (zImage) contains a bootstrap loader + that is position independent; you can load it into any RAM, + ROM or FLASH memory address >= 0x00500000 (above 5 MB), or + at its link address of 0x00400000 (4 MB). + + Note: If zImage is loaded at its link address of 0x00400000 (4 MB), + then zImage will skip the step of moving itself to + its link address. + + - Load R3 with the address of the board information structure + + - Transfer control to zImage + + - The Linux console port is SMC1, and the baud rate is controlled + from the bi_baudrate field of the board information structure. + On thing to keep in mind when picking the baud rate, is that + there is no flow control on the SMC ports. I would stick + with something safe and standard like 19200. + + On the EST SBC8260, the SMC1 port is on the COM1 connector of + the board. + + + EST SBC8260 defaults: + --------------------- + + Chip + Memory Sel Bus Use + --------------------- --- --- ---------------------------------- + 0x00000000-0x03FFFFFF CS2 60x (16M or 64M)/64M SDRAM + 0x04000000-0x04FFFFFF CS4 local 4M/16M SDRAM (soldered to the board) + 0x21000000-0x21000000 CS7 60x 1B/64K Flash present detect (from the flash SIMM) + 0x21000001-0x21000001 CS7 60x 1B/64K Switches (read) and LEDs (write) + 0x22000000-0x2200FFFF CS5 60x 8K/64K EEPROM + 0xFC000000-0xFCFFFFFF CS6 60x 2M/16M flash (8 bits wide, soldered to the board) + 0xFE000000-0xFFFFFFFF CS0 60x 4M/16M flash (SIMM) + + Notes: + ------ + + - The chip selects can map 32K blocks and up (powers of 2) + + - The SDRAM machine can handled up to 128Mbytes per chip select + + - Linux uses the 60x bus memory (the SDRAM DIMM) for the + communications buffers. + + - BATs can map 128K-256Mbytes each. There are four data BATs and + four instruction BATs. Generally the data and instruction BATs + are mapped the same. + + - The IMMR must be set above the kernel virtual memory addresses, + which start at 0xC0000000. Otherwise, the kernel may crash as + soon as you start any threads or processes due to VM collisions + in the kernel or user process space. + + + Details from Dan Malek on 10/29/1999: + + The user application virtual space consumes the first 2 Gbytes + (0x00000000 to 0x7FFFFFFF). The kernel virtual text starts at + 0xC0000000, with data following. There is a "protection hole" + between the end of kernel data and the start of the kernel + dynamically allocated space, but this space is still within + 0xCxxxxxxx. + + Obviously the kernel can't map any physical addresses 1:1 in + these ranges. + + + Details from Dan Malek on 5/19/2000: + + During the early kernel initialization, the kernel virtual + memory allocator is not operational. Prior to this KVM + initialization, we choose to map virtual to physical addresses + 1:1. That is, the kernel virtual address exactly matches the + physical address on the bus. These mappings are typically done + in arch/ppc/kernel/head.S, or arch/ppc/mm/init.c. Only + absolutely necessary mappings should be done at this time, for + example board control registers or a serial uart. Normal device + driver initialization should map resources later when necessary. + + Although platform dependent, and certainly the case for embedded + 8xx, traditionally memory is mapped at physical address zero, + and I/O devices above phsical address 0x80000000. The lowest + and highest (above 0xf0000000) I/O addresses are traditionally + used for devices or registers we need to map during kernel + initialization and prior to KVM operation. For this reason, + and since it followed prior PowerPC platform examples, I chose + to map the embedded 8xx kernel to the 0xc0000000 virtual address. + This way, we can enable the MMU to map the kernel for proper + operation, and still map a few windows before the KVM is operational. + + On some systems, you could possibly run the kernel at the + 0x80000000 or any other virtual address. It just depends upon + mapping that must be done prior to KVM operational. You can never + map devices or kernel spaces that overlap with the user virtual + space. This is why default IMMR mapping used by most BDM tools + won't work. They put the IMMR at something like 0x10000000 or + 0x02000000 for example. You simply can't map these addresses early + in the kernel, and continue proper system operation. + + The embedded 8xx/82xx kernel is mature enough that all you should + need to do is map the IMMR someplace at or above 0xf0000000 and it + should boot far enough to get serial console messages and KGDB + connected on any platform. There are lots of other subtle memory + management design features that you simply don't need to worry + about. If you are changing functions related to MMU initialization, + you are likely breaking things that are known to work and are + heading down a path of disaster and frustration. Your changes + should be to make the flexibility of the processor fit Linux, + not force arbitrary and non-workable memory mappings into Linux. + + - You don't want to change KERNELLOAD or KERNELBASE, otherwise the + virtual memory and MMU code will get confused. + + arch/ppc/Makefile:KERNELLOAD = 0xc0000000 + + include/asm-ppc/page.h:#define PAGE_OFFSET 0xc0000000 + include/asm-ppc/page.h:#define KERNELBASE PAGE_OFFSET + + - RAM is at physical address 0x00000000, and gets mapped to + virtual address 0xC0000000 for the kernel. + + + Physical addresses used by the Linux kernel: + -------------------------------------------- + + 0x00000000-0x3FFFFFFF 1GB reserved for RAM + 0xF0000000-0xF001FFFF 128K IMMR 64K used for dual port memory, + 64K for 8260 registers + + + Logical addresses used by the Linux kernel: + ------------------------------------------- + + 0xF0000000-0xFFFFFFFF 256M BAT0 (IMMR: dual port RAM, registers) + 0xE0000000-0xEFFFFFFF 256M BAT1 (I/O space for custom boards) + 0xC0000000-0xCFFFFFFF 256M BAT2 (RAM) + 0xD0000000-0xDFFFFFFF 256M BAT3 (if RAM > 256MByte) + + + EST SBC8260 Linux mapping: + -------------------------- + + DBAT0, IBAT0, cache inhibited: + + Chip + Memory Sel Use + --------------------- --- --------------------------------- + 0xF0000000-0xF001FFFF n/a IMMR: dual port RAM, registers + + DBAT1, IBAT1, cache inhibited: + diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/serial-console.txt linux/Documentation/serial-console.txt --- v2.4.0-test1/linux/Documentation/serial-console.txt Mon Dec 20 18:48:21 1999 +++ linux/Documentation/serial-console.txt Mon Jun 19 12:56:07 2000 @@ -1,5 +1,10 @@ Linux Serial Console +To use a serial port as console you need to compile the support into your +kernel - by default it is not compiled in. For PC style serial ports +it's the config option next to "Standard/generic (dumb) serial support". +You must compile serial support into the kernel and not as a module. + It is possible to specify multiple devices for console output. You can define a new kernel command line option to select which device(s) to use for console output. @@ -62,14 +67,20 @@ append = "console=ttyS1,9600" -4. Init and /etc/ioctl.save +4. Make sure a getty runs on the serial port so that you can login to + it once the system is done booting. This is done by adding a line + like this to /etc/inittab (exact syntax depends on your getty): + + S1:23:respawn:/sbin/getty -L ttyS1 9600 vt100 + +5. Init and /etc/ioctl.save Sysvinit remembers its stty settings in a file in /etc, called `/etc/ioctl.save'. REMOVE THIS FILE before using the serial console for the first time, because otherwise init will probably set the baudrate to 38400 (baudrate of the virtual console). -5. /dev/console and X +6. /dev/console and X Programs that want to do something with the virtual console usually open /dev/console. If you have created the new /dev/console device, and your console is NOT the virtual console some programs will fail. @@ -78,18 +89,16 @@ Xfree86, svgalib, gpm, SVGATextMode - I have binary patched the above mentioned programs to use "tty0" - instead of "console". This will be reported to the maintainers of - said programs. + It should be fixed in modern versions of these programs though. Note that if you boot without a console= option (or with console=/dev/tty0), /dev/console is the same as /dev/tty0. In that case everything will still work. -6. Thanks +7. Thanks Thanks to Geert Uytterhoeven for porting the patches from 2.1.4x to 2.1.6x for taking care of the integration of these patches into m68k, ppc and alpha. -Miquel van Smoorenburg , 21-Mar-1998 +Miquel van Smoorenburg , 11-Jun-2000 diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/sound/Maestro linux/Documentation/sound/Maestro --- v2.4.0-test1/linux/Documentation/sound/Maestro Thu May 11 15:30:05 2000 +++ linux/Documentation/sound/Maestro Mon Jun 19 12:56:07 2000 @@ -6,7 +6,7 @@ ------------------------------ The most recent version of this driver will hopefully always be available at - http://people.redhat.com/zab/maestro/ + http://www.zabbo.net/maestro/ I will try and maintain the most recent stable version of the driver in both the stable and development kernel lines. diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/sound/README.ymfsb linux/Documentation/sound/README.ymfsb --- v2.4.0-test1/linux/Documentation/sound/README.ymfsb Wed Dec 31 16:00:00 1969 +++ linux/Documentation/sound/README.ymfsb Tue Jun 20 07:52:36 2000 @@ -0,0 +1,107 @@ +Legacy audio driver for YMF7xx PCI cards. + + +FIRST OF ALL +============ + + This code references YAMAHA's sample codes and data sheets. + I respect and thank for all people they made open the informations + about YMF7xx cards. + + And this codes heavily based on Jeff Garzik 's + old VIA 82Cxxx driver (via82cxxx.c). I also respect him. + + +DISCLIMER +========= + + This driver is currently at early ALPHA stage. It may cause serious + damage to your computer when used. + PLEASE USE IT AT YOUR OWN RISK. + + +ABOUT THIS DRIVER +================= + + This code enables you to use your YMF724[A-F], YMF740[A-C], YMF744, YMF754 + cards. When enabled, your card acts as "SoundBlaster Pro" compatible card. + It can only play 22.05kHz / 8bit / Stereo samples, control external MIDI + port. + If you want to use your card as recent "16-bit" card, you should use + Alsa or OSS/Linux driver. Ofcource you can write native PCI driver for + your cards :) + + +USAGE +===== + + # modprobe ymfsb (options) + + +OPTIONS FOR MODULE +================== + + io : SB base address (0x220, 0x240, 0x260, 0x280) + synth_io : OPL3 base address (0x388, 0x398, 0x3a0, 0x3a8) + dma : DMA number (0,1,3) + master_volume: AC'97 PCM out Vol (0-100) + spdif_out : SPDIF-out flag (0:disable 1:enable) + + These options will change in future... + + +FREQUENCY +========= + + When playing sounds via this driver, you will hear its pitch is slightly + lower than original sounds. Since this driver recognizes your card acts + with 21.739kHz sample rates rather than 22.050kHz (I think it must be + hardware restriction). So many players become tone deafness. + To prevent this, you should express some options to your sound player + that specify correct sample frequency. For example, to play your MP3 file + correctly with mpg123, specify the frequency like following: + + % mpg123 -r 21739 foo.mp3 + + +SPDIF OUT +========= + + With installing modules with option 'spdif_out=1', you can enjoy your + sounds from SPDIF-out of your card (if it had). + Its Fs is fixed to 48kHz (It never means the sample frequency become + up to 48kHz. All sounds via SPDIF-out also 22kHz samples). So your + digital-in capable components has to be able to handle 48kHz Fs. + + +COPYING +======= + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + +TODO +==== + * support for multiple cards + (set the different SB_IO,MPU_IO,OPL_IO for each cards) + + * support for OPL (dmfm) : There will be no requirements... :-< + + +AUTHOR +====== + + Daisuke Nagano + diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/sound/via82cxxx.txt linux/Documentation/sound/via82cxxx.txt --- v2.4.0-test1/linux/Documentation/sound/via82cxxx.txt Thu May 11 15:30:05 2000 +++ linux/Documentation/sound/via82cxxx.txt Tue Jun 20 07:52:36 2000 @@ -48,6 +48,15 @@ Driver notes ------------------------------------------------------------------------ +Two /proc pseudo-files provide diagnostic information. This is generally +not useful to most users. Power users can disable VIA_PROC_FS macro in the +driver source code, and remove the /proc support code. In any case, once +version 2.0.0 is released, the /proc support code will be disabled by +default. Available /proc pseudo-files: + + /proc/driver/via/0/info + /proc/driver/via/0/ac97 + This driver by default supports all PCI audio devices which report a vendor id of 0x1106, and a device id of 0x3058. Subsystem vendor and device ids are not examined. @@ -110,7 +119,8 @@ 1) Volume too low on many systems. Workaround: use mixer program such as xmixer to increase volume. -2) RealPlayer output very scratchy. +2) RealPlayer output very scratchy. Workaround: use esd, and +configure RealPlayer to output to esd. 3) Applications which attempt to open the sound device in read/write mode (O_RDWR) will fail. This is incorrect OSS behavior, but since @@ -137,5 +147,30 @@ If you wish to increase the size of the buffer displayed by 'dmesg', then change the LOG_BUF_LEN macro at the top of linux/kernel/printk.c, recompile your kernel, and pass the "-s " option to 'dmesg'. + + + +Change history +------------------------------------------------------------------------ +Version 1.1.7: +* Fix module unload bug where mixer device left registered + after driver exit + +Version 1.1.6: +* Rewrite via_set_rate to mimic ALSA basic AC97 rate setting +* Remove much dead code +* Complete spin_lock_irqsave -> spin_lock_irq conversion in via_dsp_ioctl +* Fix build problem in via_dsp_ioctl +* Optimize included headers to eliminate headers found in linux/drivers/sound + +Version 1.1.5: +* Disable some overly-verbose debugging code +* Remove unnecessary sound locks +* Fix some ioctls for better time resolution +* Begin spin_lock_irqsave -> spin_lock_irq conversion in via_dsp_ioctl + +Version 1.1.4: +* Completed rewrite of driver. Eliminated SoundBlaster compatibility + completely, and now uses the much-faster scatter-gather DMA engine. diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/sysrq.txt linux/Documentation/sysrq.txt --- v2.4.0-test1/linux/Documentation/sysrq.txt Tue Apr 11 15:09:11 2000 +++ linux/Documentation/sysrq.txt Mon Jun 19 12:56:07 2000 @@ -25,6 +25,10 @@ On SPARC - You press 'ALT-STOP-', I believe. +On the serial console (PC style standard serial ports only) - + You send a BREAK, then within 5 seconds a command key. Sending + BREAK twice is interpreted as a normal BREAK. + On other - If you know of the key combos for other architectures, please let me know so I can add them to this section. diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/usb/input.txt linux/Documentation/usb/input.txt --- v2.4.0-test1/linux/Documentation/usb/input.txt Thu May 11 15:30:05 2000 +++ linux/Documentation/usb/input.txt Mon Jun 19 17:59:32 2000 @@ -1,6 +1,7 @@ - Linux Input drivers v0.9 - (c) 1999 Vojtech Pavlik + Linux Input drivers v1.0 + (c) 1999-2000 Vojtech Pavlik Sponsored by SuSE + $Id: input.txt,v 1.4 2000/05/28 17:57:22 vojtech Exp $ ---------------------------------------------------------------------------- 0. Disclaimer @@ -62,27 +63,27 @@ hid.o After this, the USB keyboard will work straight away, and the USB mouse -will be available as a character device on major 13, minor 32: +will be available as a character device on major 13, minor 63: - crw-r--r-- 1 root root 13, 32 Mar 28 22:45 mouse0 + crw-r--r-- 1 root root 13, 63 Mar 28 22:45 mice This device, has to be created, unless you use devfs, in which case it's created automatically. The commands to do that are: cd /dev mkdir input - mknod input/mouse0 c 13 32 + mknod input/mice c 13 63 After that you have to point GPM (the textmode mouse cut&paste tool) and XFree to this device to use it - GPM should be called like: - gpm -t ps2 -m /dev/input/mouse0 + gpm -t ps2 -m /dev/input/mice And in X: Section "Pointer" Protocol "ImPS/2" - Device "/dev/input/mouse0" + Device "/dev/input/mice" ZAxisMapping 4 5 EndSection @@ -199,10 +200,11 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_[XY] in the kernel configuration are the size of your screen (in pixels) in XFree86. This is needed if you want to use your digitizer in X, because it's movement is sent to X via a virtual PS/2 -mouse. These values won't be used if you use a mouse only. +mouse and thus needs to be scaled accordingly. These values won't be used if +you use a mouse only. - Mousedev.c will generate either PS/2, ImPS/2 (microsoft intellimouse) or -GenPS/2 (genius netmouse/netscroll) protocols, depending on what the program + Mousedev will generate either PS/2, ImPS/2 (Microsoft IntelliMouse) or +GenPS/2 (Genius NetMouse/NetScroll) protocols, depending on what the program reading the data wishes. You can set GPM and X to any of these. You'll need ImPS/2 if you want to make use of a wheel on a USB mouse and GenPS/2 if you want to use extra (up to 5) buttons. I'm not sure how much is GenPS/2 supported @@ -249,8 +251,12 @@ http://www.suse.cz/development/input/ -You'll find both the latest HID driver and the complete Input driver there. -There is also a mailing list for this: +You'll find both the latest HID driver and the complete Input driver there +as well as information how to access the CVS repository for latest revisions +of the drivers. + + + There is also a mailing list for this: majordomo@atrey.karlin.mff.cuni.cz @@ -278,8 +284,8 @@ to be extended, but not changed incompatibly as time goes: You can use blocking and nonblocking reads, also select() on the -/dev/inputX devices, and you'll always get a whole number of input events on -a read. Their layout is: +/dev/input/eventX devices, and you'll always get a whole number of input +events on a read. Their layout is: struct input_event { struct timeval time; diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/usb/ov511.txt linux/Documentation/usb/ov511.txt --- v2.4.0-test1/linux/Documentation/usb/ov511.txt Mon Jun 19 16:31:56 2000 +++ linux/Documentation/usb/ov511.txt Mon Jun 19 17:59:32 2000 @@ -6,21 +6,16 @@ Homepage: http://alpha.dyndns.org/ov511 NEW IN THIS VERSION: - o 384x288 and 448x336 modes - o better /proc/video support + o Race conditions and other bugs fixed INTRODUCTION: -This is a preliminary version of my OV511 Linux device driver. Currently, it can -grab a frame in color (YUV420) at 640x480 or 320x240 using either vidcat or -xawtv. Other utilities may work but have not yet been tested. - -Any camera using the OV511/OV511+ and the OV7610/20/20AE CCD should work. The -driver only detects known cameras though, based on their custom id number. If -you have a currently unsupported camera, the ID number should be reported to you -in the kernel logs. Please send me the model, manufacturer and ID number and I -will add it to the detection code. In the meantime, you can add to the code -yourself in the function ov511_probe(). +This is a driver for the OV511, a USB-only chip used in many "webcam" devices. +Any camera using the OV511/OV511+ and the OV7610/20/20AE CCD should work.It +supports streaming and capture of color or monochrome video via the Video4Linux +API. Most V4L apps are compatible with it, but a few videoconferencing programs +do not work yet. The following resolutions are supported: 640x480, 448x336, +384x288, 352x288, and 320x240. WHAT YOU NEED: @@ -93,7 +88,8 @@ bit flaky right now. This message means that the I2C bus never got initialized properly, and the camera will most likely not work even if you disable this warning. Try unloading/reloading the driver or unplugging/re- - plugging the camera if this happens. + plugging the camera if this happens. Also try increasing the i2c_detect_tries + parameter (see below). Q: "Why do you bother with this phony camera detection crap? It doesn't do anything useful!" @@ -200,9 +196,6 @@ would like them to release their specifications to the Linux community. o Get 160x120 working o YUV422 (and other color modes) - o Fix read(). It only works right now if you run an mmap() based app like xawtv - or vidcat after loading the module and before using read(). Apparently there - are some initialization issues. o Get snapshot mode working with mmap(). o Fix fixFrameRGBoffset(). It is not stable yet with streaming video. o Get hue (red/blue channel balance) adjustment working (in ov511_get_picture() diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/video4linux/bttv/CARDLIST linux/Documentation/video4linux/bttv/CARDLIST --- v2.4.0-test1/linux/Documentation/video4linux/bttv/CARDLIST Tue May 23 15:31:32 2000 +++ linux/Documentation/video4linux/bttv/CARDLIST Tue Jun 20 07:52:36 2000 @@ -42,6 +42,8 @@ card=40 - STB2 card=41 - AVerMedia TVPhone 98 card=42 - ProVideo PV951 + card=43 - Little OnAir TV + card=44 - Sigma TVII-FM tuner.o type=0 - Temic PAL diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/video4linux/bttv/Insmod-options linux/Documentation/video4linux/bttv/Insmod-options --- v2.4.0-test1/linux/Documentation/video4linux/bttv/Insmod-options Tue Mar 7 14:32:25 2000 +++ linux/Documentation/video4linux/bttv/Insmod-options Tue Jun 20 07:52:36 2000 @@ -3,7 +3,7 @@ the bt848 (grabber chip) driver insmod args: - card=n card type, see cardlist for a list. + card=n card type, see CARDLIST for a list. radio=0/1 card supports radio pll=0/1/2 pll settings 0: don't use PLL @@ -31,6 +31,29 @@ remap, card, radio and pll accept up to four comma-separated arguments (for multiple boards). +tuner.o + The tuner driver. You need this unless you want to use only + with a camera or external tuner ... + + insmod args: + debug=1 print some debug info to the syslog + type=n type of the tuner chip. n as follows: + see CARDLIST for a complete list. + +tvmixer.o + registers a mixer device for the TV card's volume/bass/treble + controls (requires a i2c audio control chip like the msp3400). + + insmod args: + debug=1 print some debug info to the syslog. + devnr=n allocate device #n (0 == /dev/mixer, + 1 = /dev/mixer1, ...), default is to + use the first free one. + +tvaudio.o + new, experimental module which is supported to provide a single + driver for all simple i2c audio control chips (tda/tea*). + msp3400.o The driver for the msp34xx sound processor chips. If you have a stereo card, you probably want to insmod this one. @@ -47,8 +70,6 @@ amsound=1 Audio carrier is AM/NICAM at 6.5 Mhz. This should improve things for french people, the carrier autoscan seems to work with FM only... - mixer=n allocate mixer device #n. Default is the - first free slot. tea6300.o The driver for the tea6300 fader chip. If you have a stereo @@ -73,20 +94,3 @@ insmod args: debug=1 print some debug info to the syslog. chip=9850/9855 set the chip type. - -tuner.o - The tuner driver. You need this unless you want to use only - with a camera or external tuner ... - - insmod args: - debug=1 print some debug info to the syslog - type=n type of the tuner chip. n as follows: - 0: Temic PAL tuner - 1: Philips PAL_I tuner - 2: Philips NTSC tuner - 3: Philips SECAM tuner - 4: no tuner - 5: Philips PAL tuner - 6: Temic NTSC tuner - 7: Temic PAL tuner - diff -u --recursive --new-file v2.4.0-test1/linux/Documentation/watchdog.txt linux/Documentation/watchdog.txt --- v2.4.0-test1/linux/Documentation/watchdog.txt Tue Aug 31 17:29:12 1999 +++ linux/Documentation/watchdog.txt Mon Jun 19 12:56:07 2000 @@ -77,17 +77,23 @@ Contact Information People keep asking about the WDT watchdog timer hardware: The phone contacts -for ICS Advent are: +for Industrial Computer Source are: -US: 619 677 0877 (sales) 0895 (fax) -UK: 01243 533900 -France (1) 69.18.74.30 +Industrial Computer Source +http://www.indcompsrc.com +ICS Advent, San Diego +6260 Sequence Dr. +San Diego, CA 92121-4371 +Phone (858) 677-0877 +FAX: (858) 677-0895 +> +ICS Advent Europe, UK +Oving Road +Chichester, +West Sussex, +PO19 4ET, UK +Phone: 00.44.1243.533900 -ICS Advent -9950 Barnes Canyon Road -San Diego, CA - -http://www.icsadvent.com and please mention Linux when enquiring. diff -u --recursive --new-file v2.4.0-test1/linux/MAINTAINERS linux/MAINTAINERS --- v2.4.0-test1/linux/MAINTAINERS Mon Jun 19 16:31:56 2000 +++ linux/MAINTAINERS Fri Jun 23 21:04:36 2000 @@ -178,7 +178,7 @@ BFS FILE SYSTEM P: Tigran A. Aivazian -M: tigran@ocston.org +M: tigran@veritas.com L: linux-kernel@vger.rutgers.edu W: http://www.ocston.org/~tigran/patches/bfs S: Maintained @@ -199,8 +199,9 @@ COMPAQ SMART2 RAID DRIVER P: Charles White M: Charles White -L: compaqandlinux@yps.org -S: Maintained +L: compaqandlinux@cpqlin.van-dijk.net +W: ftp.compaq.com/pub/products/drivers/linux +S: Supported COMPUTONE INTELLIPORT MULTIPORT CARD P: Doug McNash @@ -234,6 +235,11 @@ W: http://www.fi.muni.cz/~kas/cosa/ S: Maintained +CPUID/MSR DRIVER +P: H. Peter Anvin +M: hpa@zytor.com +S: Maintained + CREDITS FILE P: John A. Martin M: jam@acm.org @@ -300,11 +306,19 @@ DIGI RIGHTSWITCH NETWORK DRIVER P: Rick Richardson -M: rick@dgii.com +M: rick@remotepoint.com L: linux-net@vger.rutgers.edu W: http://www.dgii.com/linux/ S: Maintained +DISK GEOMETRY AND PARTITION HANDLING +P: Andries Brouwer +M: aeb@veritas.com +W: http://www.win.tue.nl/~aeb/linux/Large-Disk.html +W: http://www.win.tue.nl/~aeb/linux/zip/zip-1.html +W: http://www.win.tue.nl/~aeb/partitions/partition_types-1.html +S: Maintained + DISKQUOTA: P: Marco van Wieringen M: mvw@planets.elm.net @@ -476,7 +490,7 @@ IBM ServeRAID RAID DRIVER P: Keith Mitchell M: ipslinux@us.ibm.com -W: http://www.developer.ibm.com/welcome/netfinity/serveraid_beta.html +W: http://www.developer.ibm.com/welcome/netfinity/serveraid.html S: Supported IDE DRIVER [GENERAL] @@ -540,7 +554,7 @@ INTEL P6 MICROCODE UPDATE SUPPORT P: Tigran Aivazian -M: tigran@sco.com +M: tigran@veritas.com S: Maintained IP MASQUERADING: @@ -580,6 +594,13 @@ W: http://www.isdn4linux.de S: Maintained +ISDN SUBSYSTEM (Eicon active card driver) +P: Armin Schindler +M: mac@melware.de +L: isdn4linux@listserv.isdn4linux.de +W: http://www.melware.de +S: Maintained + JOYSTICK DRIVER P: Vojtech Pavlik M: vojtech@suse.cz @@ -659,7 +680,8 @@ MISCELLANEOUS MCA-SUPPORT P: David Weinehall -M: tao@acc.umu.se (personal) +M: Project MCA Team +M: David Weinehall W: http://www.acc.umu.se/~tao/ W: http://www.acc.umu.se/~mcalinux/ L: linux-kernel@vger.rutgers.edu @@ -699,12 +721,12 @@ NETFILTER P: Rusty Russell -M: Rusty.Russell@rustcorp.com.au +M: rusty@linuxcare.com P: Marc Boucher M: marc@mbsi.ca W: http://www.samba.org/netfilter/ W: http://netfilter.kernelnotes.org -W: http://antarctica.penguincomputing.com/~netfilter/ +W: http://netfilter.filewatcher.org L: netfilter@lists.samba.org S: Supported @@ -744,8 +766,8 @@ NI5010 NETWORK DRIVER P: Jan-Pascal van Best and Andreas Mohr -M: jvbest@qv3pluto.leidenuniv.nl (Best) -M: 100.30936@germany.net (Mohr) +M: Jan-Pascal van Best +M: Andreas Mohr <100.30936@germany.net> L: linux-net@vger.rutgers.edu S: Maintained @@ -793,12 +815,12 @@ P: Andrea Arcangeli M: andrea@e-mind.com L: linux-parport@torque.net -W: http://www.cyberelk.demon.co.uk/parport.html +W: http://people.redhat.com/twaugh/parport/ S: Maintained PARIDE DRIVERS FOR PARALLEL PORT IDE DEVICES -P: Grant Guenther -M: grant@torque.net +P: Tim Waugh +M: tim@cyberelk.demon.co.uk L: linux-parport@torque.net W: http://www.torque.net/linux-pp.html S: Maintained @@ -1051,6 +1073,8 @@ M: torben.mathiasen@compaq.com M: tmm@image.dk L: tlan@vuser.vu.union.edu +L: linux-net@vger.rutgers.edu +W: http://tlan.kernel.dk S: Maintained TOKEN-RING NETWORK DRIVER diff -u --recursive --new-file v2.4.0-test1/linux/Makefile linux/Makefile --- v2.4.0-test1/linux/Makefile Mon Jun 19 16:31:56 2000 +++ linux/Makefile Tue Jun 20 14:28:05 2000 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 0 -EXTRAVERSION = -test1 +EXTRAVERSION = -test2 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -118,8 +118,8 @@ #export RAMDISK = -DRAMDISK=512 CORE_FILES =kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o -NETWORKS =net/network.a -DRIVERS =drivers/block/block.a \ +NETWORKS =net/network.o +DRIVERS =drivers/block/block.o \ drivers/char/char.o \ drivers/misc/misc.o \ drivers/net/net.o \ @@ -142,8 +142,8 @@ DRIVERS-$(CONFIG_WAN) += drivers/net/wan/wan.a DRIVERS-$(CONFIG_ARCNET) += drivers/net/arcnet/arcnet.a DRIVERS-$(CONFIG_ATM) += drivers/atm/atm.o -DRIVERS-$(CONFIG_IDE) += drivers/ide/ide.a -DRIVERS-$(CONFIG_SCSI) += drivers/scsi/scsi.a +DRIVERS-$(CONFIG_IDE) += drivers/ide/idedriver.o +DRIVERS-$(CONFIG_SCSI) += drivers/scsi/scsidrv.o DRIVERS-$(CONFIG_IEEE1394) += drivers/ieee1394/ieee1394.a ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR)$(CONFIG_PARIDE_PCD),) @@ -168,9 +168,9 @@ DRIVERS-$(CONFIG_HAMRADIO) += drivers/net/hamradio/hamradio.o DRIVERS-$(CONFIG_TC) += drivers/tc/tc.a DRIVERS-$(CONFIG_USB) += drivers/usb/usbdrv.o -DRIVERS-$(CONFIG_I2O) += drivers/i2o/i2o.a +DRIVERS-$(CONFIG_I2O) += drivers/i2o/i2o.o DRIVERS-$(CONFIG_IRDA) += drivers/net/irda/irda_drivers.a -DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.a +DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.a DRIVERS += $(DRIVERS-y) @@ -421,7 +421,10 @@ pdfdocs: sgmldocs $(MAKE) -C Documentation/DocBook pdf - + +htmldocs: sgmldocs + $(MAKE) -C Documentation/DocBook html + sums: find . -type f -print | sort | xargs sum > .SUMS diff -u --recursive --new-file v2.4.0-test1/linux/Rules.make linux/Rules.make --- v2.4.0-test1/linux/Rules.make Tue Apr 11 15:09:11 2000 +++ linux/Rules.make Thu Jun 22 07:09:44 2000 @@ -291,9 +291,12 @@ )) # A kludge: .S files don't get flag dependencies (yet), -# because that will involve changing a lot of Makefiles. +# because that will involve changing a lot of Makefiles. Also +# suppress object files explicitly listed in $(IGNORE_FLAGS_OBJS). +# This allows handling of assembly files that get translated into +# multiple object files (see arch/ia64/lib/idiv.S, for example). FILES_FLAGS_CHANGED := $(strip \ - $(filter-out $(patsubst %.S, %.o, $(wildcard *.S)), \ + $(filter-out $(patsubst %.S, %.o, $(wildcard *.S) $(IGNORE_FLAGS_OBJS)), \ $(FILES_FLAGS_CHANGED))) ifneq ($(FILES_FLAGS_CHANGED),) diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/boot/bootp.c linux/arch/alpha/boot/bootp.c --- v2.4.0-test1/linux/arch/alpha/boot/bootp.c Tue Nov 23 22:42:20 1999 +++ linux/arch/alpha/boot/bootp.c Mon Jun 19 17:59:32 2000 @@ -93,7 +93,7 @@ i = switch_to_osf_pal(2, pcb_va, pcb_pa, VPTB); if (i) { srm_printk("failed, code %ld\n", i); - halt(); + __halt(); } percpu = (struct percpu_struct *) @@ -171,8 +171,7 @@ srm_printk("Initrd positioned at %#lx\n", initrd_start); #endif - nbytes = srm_dispatch(CCB_GET_ENV, ENV_BOOTED_OSFLAGS, - envval, sizeof(envval)); + nbytes = callback_getenv(ENV_BOOTED_OSFLAGS, envval, sizeof(envval)); if (nbytes < 0 || nbytes >= sizeof(envval)) { nbytes = 0; } @@ -181,18 +180,17 @@ /* NOTE: *no* callbacks or printouts from here on out!!! */ - /* - * This is a hack, as some consoles seem to get virtual 20000000 - * (ie where the SRM console puts the kernel bootp image) memory - * overlapping physical 310000 memory, which causes real problems - * when attempting to copy the former to the latter... :-( + /* This is a hack, as some consoles seem to get virtual 20000000 (ie + * where the SRM console puts the kernel bootp image) memory + * overlapping physical memory where the kernel wants to be put, + * which causes real problems when attempting to copy the former to + * the latter... :-( * * So, we first move the kernel virtual-to-physical way above where * we physically want the kernel to end up, then copy it from there * to its final resting place... ;-} * - * Sigh... - */ + * Sigh... */ #ifdef INITRD_SIZE load(initrd_start, KERNEL_ORIGIN+KERNEL_SIZE, INITRD_SIZE); diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/boot/main.c linux/arch/alpha/boot/main.c --- v2.4.0-test1/linux/arch/alpha/boot/main.c Tue Nov 23 22:42:20 1999 +++ linux/arch/alpha/boot/main.c Mon Jun 19 17:59:32 2000 @@ -90,7 +90,7 @@ i = switch_to_osf_pal(2, pcb_va, pcb_pa, VPTB); if (i) { srm_printk("failed, code %ld\n", i); - halt(); + __halt(); } percpu = (struct percpu_struct *) @@ -107,15 +107,15 @@ char bootdev[256]; long result; - result = srm_dispatch(CCB_GET_ENV, ENV_BOOTED_DEV, bootdev, 255); + result = callback_getenv(ENV_BOOTED_DEV, bootdev, 255); if (result < 0) return result; - return srm_dispatch(CCB_OPEN, bootdev, result & 255); + return callback_open(bootdev, result & 255); } static inline long close(long dev) { - return srm_dispatch(CCB_CLOSE, dev); + return callback_close(dev); } static inline long load(long dev, unsigned long addr, unsigned long count) @@ -124,7 +124,7 @@ extern char _end; long result, boot_size = &_end - (char *) BOOT_ADDR; - result = srm_dispatch(CCB_GET_ENV, ENV_BOOTED_FILE, bootfile, 255); + result = callback_getenv(ENV_BOOTED_FILE, bootfile, 255); if (result < 0) return result; result &= 255; @@ -132,7 +132,7 @@ if (result) srm_printk("Boot file specification (%s) not implemented\n", bootfile); - return srm_dispatch(CCB_READ, dev, count, addr, boot_size/512 + 1); + return callback_read(dev, count, addr, boot_size/512 + 1); } /* @@ -176,8 +176,7 @@ return; } - nbytes = srm_dispatch(CCB_GET_ENV, ENV_BOOTED_OSFLAGS, - envval, sizeof(envval)); + nbytes = callback_getenv(ENV_BOOTED_OSFLAGS, envval, sizeof(envval)); if (nbytes < 0) { nbytes = 0; } @@ -188,5 +187,5 @@ runkernel(); for (i = 0 ; i < 0x100000000 ; i++) /* nothing */; - halt(); + __halt(); } diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v2.4.0-test1/linux/arch/alpha/config.in Tue Apr 11 15:09:11 2000 +++ linux/arch/alpha/config.in Mon Jun 19 17:59:32 2000 @@ -1,6 +1,6 @@ # # For a description of the syntax of this configuration file, -# see the Configure script. +# see Documentation/kbuild/config-language.txt. # define_bool CONFIG_UID16 n @@ -51,7 +51,9 @@ RX164 CONFIG_ALPHA_RX164 \ SX164 CONFIG_ALPHA_SX164 \ Sable CONFIG_ALPHA_SABLE \ - Takara CONFIG_ALPHA_TAKARA" Generic + Takara CONFIG_ALPHA_TAKARA \ + Titan CONFIG_ALPHA_TITAN \ + Wildfire CONFIG_ALPHA_WILDFIRE" Generic # clear all implied options (don't want default values for those): unset CONFIG_ALPHA_EV4 CONFIG_ALPHA_EV5 CONFIG_ALPHA_EV6 @@ -131,6 +133,16 @@ define_bool CONFIG_ALPHA_EV6 y define_bool CONFIG_ALPHA_TSUNAMI y fi +if [ "$CONFIG_ALPHA_WILDFIRE" = "y" ] +then + define_bool CONFIG_PCI y + define_bool CONFIG_ALPHA_EV6 y +fi +if [ "$CONFIG_ALPHA_TITAN" = "y" ] +then + define_bool CONFIG_PCI y + define_bool CONFIG_ALPHA_EV6 y +fi if [ "$CONFIG_ALPHA_RAWHIDE" = "y" ] then define_bool CONFIG_ALPHA_EV5 y @@ -151,18 +163,23 @@ define_bool CONFIG_ALPHA_IRONGATE y fi +if [ "$CONFIG_ALPHA_JENSEN" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \ + -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" \ + -o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" \ + -o "$CONFIG_ALPHA_EIGER" = "y" -o "$CONFIG_ALPHA_WILDFIRE" = "y" \ + -o "$CONFIG_ALPHA_TITAN" = "y" ] +then + define_bool CONFIG_ALPHA_SRM y +fi if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \ - -o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_JENSEN" = "y" \ + -o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \ -o "$CONFIG_ALPHA_TAKARA" = "y" -o "$CONFIG_ALPHA_EB164" = "y" \ - -o "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_ALCOR" = "y" \ - -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_MIATA" = "y" \ - -o "$CONFIG_ALPHA_NORITAKE" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \ - -o "$CONFIG_ALPHA_LX164" = "y" -o "$CONFIG_ALPHA_SX164" = "y" \ - -o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" \ - -o "$CONFIG_ALPHA_EIGER" = "y" ] + -o "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_MIATA" = "y" \ + -o "$CONFIG_ALPHA_LX164" = "y" -o "$CONFIG_ALPHA_SX164" = "y" ] then bool 'Use SRM as bootloader' CONFIG_ALPHA_SRM fi + if [ "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \ -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" \ -o "$CONFIG_ALPHA_RAWHIDE" = "y" ] @@ -179,7 +196,8 @@ fi if [ "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" \ - -o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_GENERIC" = "y" ] + -o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_WILDFIRE" = "y" \ + -o "$CONFIG_ALPHA_TITAN" = "y" -o "$CONFIG_ALPHA_GENERIC" = "y" ] then bool 'Symmetric multi-processing support' CONFIG_SMP fi @@ -286,6 +304,12 @@ mainmenu_option next_comment comment 'Console drivers' bool 'VGA text console' CONFIG_VGA_CONSOLE +# if [ "$CONFIG_PCI" = "y" -a "$CONFIG_VGA_CONSOLE" = "y" ]; then +# bool ' Allow VGA on any bus?' CONFIG_VGA_HOSE +# if [ "$CONFIG_VGA_HOSE" = "y" ]; then +# define_bool CONFIG_DUMMY_CONSOLE y +# fi +# fi source drivers/video/Config.in if [ "$CONFIG_FB" = "y" ]; then define_bool CONFIG_PCI_CONSOLE y diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/defconfig linux/arch/alpha/defconfig --- v2.4.0-test1/linux/arch/alpha/defconfig Thu May 11 15:30:05 2000 +++ linux/arch/alpha/defconfig Mon Jun 19 17:59:32 2000 @@ -45,6 +45,8 @@ # CONFIG_ALPHA_SX164 is not set # CONFIG_ALPHA_SABLE is not set # CONFIG_ALPHA_TAKARA is not set +# CONFIG_ALPHA_TITAN is not set +# CONFIG_ALPHA_WILDFIRE is not set CONFIG_ISA=y # CONFIG_SBUS is not set CONFIG_PCI=y @@ -83,10 +85,6 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_DEV_DAC960 is not set - -# -# Additional Block Devices -# # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile --- v2.4.0-test1/linux/arch/alpha/kernel/Makefile Tue Apr 11 15:09:11 2000 +++ linux/arch/alpha/kernel/Makefile Mon Jun 19 17:59:32 2000 @@ -26,17 +26,22 @@ endif ifdef CONFIG_PCI -L_OBJS += pci.o pci_iommu.o +O_OBJS += pci.o pci_iommu.o +endif + +ifdef CONFIG_VGA_HOSE +L_OBJS += console.o endif ifdef CONFIG_ALPHA_GENERIC O_OBJS += core_apecs.o core_cia.o core_irongate.o core_lca.o core_mcpcia.o \ - core_polaris.o core_t2.o core_tsunami.o \ + core_polaris.o core_t2.o core_tsunami.o core_titan.o \ sys_alcor.o sys_cabriolet.o sys_dp264.o sys_eb64p.o sys_eiger.o \ - sys_jensen.o sys_miata.o sys_mikasa.o sys_nautilus.o \ + sys_jensen.o sys_miata.o sys_mikasa.o sys_nautilus.o sys_titan.o \ sys_noritake.o sys_rawhide.o sys_ruffian.o sys_rx164.o \ - sys_sable.o sys_sio.o sys_sx164.o sys_takara.o sys_rx164.o + sys_sable.o sys_sio.o sys_sx164.o sys_takara.o sys_rx164.o \ + sys_wildfire.o core_wildfire.o else @@ -62,9 +67,15 @@ ifdef CONFIG_ALPHA_TSUNAMI O_OBJS += core_tsunami.o endif +ifdef CONFIG_ALPHA_TITAN +O_OBJS += core_titan.o +endif ifdef CONFIG_ALPHA_POLARIS O_OBJS += core_polaris.o endif +ifdef CONFIG_ALPHA_WILDFIRE +O_OBJS += core_wildfire.o +endif # Board support ifneq ($(CONFIG_ALPHA_ALCOR)$(CONFIG_ALPHA_XLT),) @@ -76,6 +87,9 @@ ifdef CONFIG_ALPHA_DP264 O_OBJS += sys_dp264.o endif +ifdef CONFIG_ALPHA_TITAN +O_OBJS += sys_titan.o +endif ifneq ($(CONFIG_ALPHA_EB64P)$(CONFIG_ALPHA_EB66),) O_OBJS += sys_eb64p.o endif @@ -117,6 +131,9 @@ endif ifdef CONFIG_ALPHA_TAKARA O_OBJS += sys_takara.o +endif +ifdef CONFIG_ALPHA_WILDFIRE +O_OBJS += sys_wildfire.o endif endif # GENERIC diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/kernel/console.c linux/arch/alpha/kernel/console.c --- v2.4.0-test1/linux/arch/alpha/kernel/console.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/kernel/console.c Mon Jun 19 17:59:32 2000 @@ -0,0 +1,66 @@ +/* + * linux/arch/alpha/kernel/console.c + * + * Architecture-specific specific support for VGA device on + * non-0 I/O hose + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_VGA_HOSE + +/* + * Externally-visible vga hose bases + */ +unsigned long __vga_hose_io_base = 0; /* base for default hose */ +unsigned long __vga_hose_mem_base = 0; /* base for default hose */ + +static struct pci_controler * __init +default_vga_hose_select(struct pci_controler *h1, struct pci_controler *h2) +{ + if (h2->index < h1->index) + return h2; + + return h1; +} + +void __init +set_vga_hose(struct pci_controler *hose) +{ + if (hose) { + __vga_hose_io_base = hose->io_space->start; + __vga_hose_mem_base = hose->mem_space->start; + } +} + +void __init +locate_and_init_vga(void *(*sel_func)(void *, void *)) +{ + struct pci_controler *hose = NULL; + struct pci_dev *dev = NULL; + + if (!sel_func) sel_func = (void *)default_vga_hose_select; + + for(dev=NULL; (dev=pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, dev));) { + if (!hose) hose = dev->sysdata; + else hose = sel_func(hose, dev->sysdata); + } + + /* Did we already inititialize the correct one? */ + if (conswitchp == &vga_con && + __vga_hose_io_base == hose->io_space->start && + __vga_hose_mem_base == hose->mem_space->start) + return; + + /* Set the VGA hose and init the new console */ + set_vga_hose(hose); + take_over_console(&vga_con, 0, MAX_NR_CONSOLES-1, 1); +} + +#endif diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/kernel/core_mcpcia.c linux/arch/alpha/kernel/core_mcpcia.c --- v2.4.0-test1/linux/arch/alpha/kernel/core_mcpcia.c Mon Mar 27 08:08:21 2000 +++ linux/arch/alpha/kernel/core_mcpcia.c Wed Jun 21 22:30:59 2000 @@ -308,6 +308,7 @@ mb(); draina(); wrmces(7); + mcheck_expected(cpu) = 2; /* indicates probing */ mcheck_taken(cpu) = 0; mcheck_extra(cpu) = mid; @@ -409,19 +410,19 @@ * Window 2 is direct access 2GB at 2GB * ??? We ought to scale window 1 with memory. */ - hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0); hose->sg_pci = iommu_arena_new(hose, 0x40000000, 0x08000000, 0); + __direct_map_base = 0x80000000; __direct_map_size = 0x80000000; *(vuip)MCPCIA_W0_BASE(mid) = hose->sg_isa->dma_base | 3; *(vuip)MCPCIA_W0_MASK(mid) = (hose->sg_isa->size - 1) & 0xfff00000; - *(vuip)MCPCIA_T0_BASE(mid) = virt_to_phys(hose->sg_isa->ptes) >> 2; + *(vuip)MCPCIA_T0_BASE(mid) = virt_to_phys(hose->sg_isa->ptes) >> 8; *(vuip)MCPCIA_W1_BASE(mid) = hose->sg_pci->dma_base | 3; *(vuip)MCPCIA_W1_MASK(mid) = (hose->sg_pci->size - 1) & 0xfff00000; - *(vuip)MCPCIA_T1_BASE(mid) = virt_to_phys(hose->sg_pci->ptes) >> 2; + *(vuip)MCPCIA_T1_BASE(mid) = virt_to_phys(hose->sg_pci->ptes) >> 8; *(vuip)MCPCIA_W2_BASE(mid) = __direct_map_base | 1; *(vuip)MCPCIA_W2_MASK(mid) = (__direct_map_size - 1) & 0xfff00000; @@ -464,9 +465,11 @@ mcpcia_init_hoses(void) { struct pci_controler *hose; - int h, hose_count = 0; + int hose_count; + int h; /* First, find how many hoses we have. */ + hose_count = 0; for (h = 0; h < MCPCIA_MAX_HOSES; ++h) { if (mcpcia_probe_hose(h)) { if (h != 0) @@ -554,6 +557,65 @@ frame->ld_lock); } +static void +mcpcia_print_system_area(unsigned long la_ptr) +{ + struct el_common *frame; + struct pci_controler *hose; + + struct IOD_subpacket { + unsigned long base; + unsigned int whoami; + unsigned int rsvd1; + unsigned int pci_rev; + unsigned int cap_ctrl; + unsigned int hae_mem; + unsigned int hae_io; + unsigned int int_ctl; + unsigned int int_reg; + unsigned int int_mask0; + unsigned int int_mask1; + unsigned int mc_err0; + unsigned int mc_err1; + unsigned int cap_err; + unsigned int rsvd2; + unsigned int pci_err1; + unsigned int mdpa_stat; + unsigned int mdpa_syn; + unsigned int mdpb_stat; + unsigned int mdpb_syn; + unsigned int rsvd3; + unsigned int rsvd4; + unsigned int rsvd5; + } *iodpp; + + frame = (struct el_common *)la_ptr; + iodpp = (struct IOD_subpacket *) (la_ptr + frame->sys_offset); + + for (hose = hose_head; hose; hose = hose->next, iodpp++) { + + printk("IOD %d Register Subpacket - Bridge Base Address %16lx\n", + hose->index, iodpp->base); + printk(" WHOAMI = %8x\n", iodpp->whoami); + printk(" PCI_REV = %8x\n", iodpp->pci_rev); + printk(" CAP_CTRL = %8x\n", iodpp->cap_ctrl); + printk(" HAE_MEM = %8x\n", iodpp->hae_mem); + printk(" HAE_IO = %8x\n", iodpp->hae_io); + printk(" INT_CTL = %8x\n", iodpp->int_ctl); + printk(" INT_REG = %8x\n", iodpp->int_reg); + printk(" INT_MASK0 = %8x\n", iodpp->int_mask0); + printk(" INT_MASK1 = %8x\n", iodpp->int_mask1); + printk(" MC_ERR0 = %8x\n", iodpp->mc_err0); + printk(" MC_ERR1 = %8x\n", iodpp->mc_err1); + printk(" CAP_ERR = %8x\n", iodpp->cap_err); + printk(" PCI_ERR1 = %8x\n", iodpp->pci_err1); + printk(" MDPA_STAT = %8x\n", iodpp->mdpa_stat); + printk(" MDPA_SYN = %8x\n", iodpp->mdpa_syn); + printk(" MDPB_STAT = %8x\n", iodpp->mdpb_stat); + printk(" MDPB_SYN = %8x\n", iodpp->mdpb_syn); + } +} + void mcpcia_machine_check(unsigned long vector, unsigned long la_ptr, struct pt_regs * regs) @@ -594,6 +656,8 @@ mb(); process_mcheck_info(vector, la_ptr, regs, "MCPCIA", expected != 0); - if (!expected && vector != 0x620 && vector != 0x630) + if (!expected && vector != 0x620 && vector != 0x630) { mcpcia_print_uncorrectable(mchk_logout); + mcpcia_print_system_area(la_ptr); + } } diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/kernel/core_titan.c linux/arch/alpha/kernel/core_titan.c --- v2.4.0-test1/linux/arch/alpha/kernel/core_titan.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/kernel/core_titan.c Wed Jun 21 22:30:59 2000 @@ -0,0 +1,490 @@ +/* + * linux/arch/alpha/kernel/core_titan.c + * + * Code common to all TITAN core logic chips. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define __EXTERN_INLINE inline +#include +#include +#undef __EXTERN_INLINE + +#include "proto.h" +#include "pci_impl.h" + +unsigned TITAN_agp = 0; + +static struct +{ + unsigned long wsba[4]; + unsigned long wsm[4]; + unsigned long tba[4]; +} saved_pachip_port[4]; + +/* + * BIOS32-style PCI interface: + */ + +#define DEBUG_MCHECK 0 /* 0 = minimum, 1 = debug, 2 = dump+dump */ +#define DEBUG_CONFIG 0 + +#if DEBUG_CONFIG +# define DBG_CFG(args) printk args +#else +# define DBG_CFG(args) +#endif + +/* + * Given a bus, device, and function number, compute resulting + * configuration space address + * accordingly. It is therefore not safe to have concurrent + * invocations to configuration space access routines, but there + * really shouldn't be any need for this. + * + * Note that all config space accesses use Type 1 address format. + * + * Note also that type 1 is determined by non-zero bus number. + * + * Type 1: + * + * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 + * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * 31:24 reserved + * 23:16 bus number (8 bits = 128 possible buses) + * 15:11 Device number (5 bits) + * 10:8 function number + * 7:2 register number + * + * Notes: + * The function number selects which function of a multi-function device + * (e.g., SCSI and Ethernet). + * + * The register selects a DWORD (32 bit) register offset. Hence it + * doesn't get shifted by 2 bits as we want to "drop" the bottom two + * bits. + */ + +static int +mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr, + unsigned char *type1) +{ + struct pci_controler *hose = dev->sysdata; + unsigned long addr; + u8 bus = dev->bus->number; + u8 device_fn = dev->devfn; + + DBG_CFG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, " + "pci_addr=0x%p, type1=0x%p)\n", + bus, device_fn, where, pci_addr, type1)); + + if (hose->first_busno == dev->bus->number) + bus = 0; + *type1 = (bus != 0); + + addr = (bus << 16) | (device_fn << 8) | where; + addr |= hose->config_space_base; + + *pci_addr = addr; + DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr)); + return 0; +} + +static int +titan_read_config_byte(struct pci_dev *dev, int where, u8 *value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = __kernel_ldbu(*(vucp)addr); + return PCIBIOS_SUCCESSFUL; +} + +static int +titan_read_config_word(struct pci_dev *dev, int where, u16 *value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = __kernel_ldwu(*(vusp)addr); + return PCIBIOS_SUCCESSFUL; +} + +static int +titan_read_config_dword(struct pci_dev *dev, int where, u32 *value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = *(vuip)addr; + return PCIBIOS_SUCCESSFUL; +} + +static int +titan_write_config_byte(struct pci_dev *dev, int where, u8 value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + __kernel_stb(value, *(vucp)addr); + mb(); + __kernel_ldbu(*(vucp)addr); + return PCIBIOS_SUCCESSFUL; +} + +static int +titan_write_config_word(struct pci_dev *dev, int where, u16 value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + __kernel_stw(value, *(vusp)addr); + mb(); + __kernel_ldwu(*(vusp)addr); + return PCIBIOS_SUCCESSFUL; +} + +static int +titan_write_config_dword(struct pci_dev *dev, int where, u32 value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *(vuip)addr = value; + mb(); + *(vuip)addr; + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops titan_pci_ops = +{ + read_byte: titan_read_config_byte, + read_word: titan_read_config_word, + read_dword: titan_read_config_dword, + write_byte: titan_write_config_byte, + write_word: titan_write_config_word, + write_dword: titan_write_config_dword +}; + + +void +titan_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end) +{ + titan_pachip *pachip = + (hose->index & 1) ? TITAN_pachip1 : TITAN_pachip0; + titan_pachip_port *port; + volatile unsigned long *csr; + unsigned long value; + + /* Get the right hose */ + port = &pachip->g_port; + if (hose->index & 2) + port = &pachip->a_port; + + /* We can invalidate up to 8 tlb entries in a go. The flush + matches against <31:16> in the pci address. */ + csr = &port->port_specific.g.gtlbia.csr; + if (((start ^ end) & 0xffff0000) == 0) + csr = &port->port_specific.g.gtlbiv.csr; + + /* For TBIA, it doesn't matter what value we write. For TBI, + it's the shifted tag bits. */ + value = (start & 0xffff0000) >> 12; + + wmb(); + *csr = value; + mb(); + *csr; +} + +#define FN __FUNCTION__ + +static int __init +titan_query_agp(titan_pachip_port *port) +{ + union TPAchipPCTL pctl; + + /* set up APCTL */ + pctl.pctl_q_whole = port->pctl.csr; + + return pctl.pctl_r_bits.apctl_v_agp_present; + +} +static void __init +titan_init_agp(titan_pachip_port *port, struct pci_controler *hose) +{ + union TPAchipPCTL pctl; + + if (!titan_query_agp(port)) + return; + + printk("AGP present on hose %d\n", hose->index); + + /* get APCTL */ + pctl.pctl_q_whole = port->pctl.csr; + + + pctl.pctl_r_bits.apctl_v_agp_en = 1; /* enable AGP */ + pctl.pctl_r_bits.apctl_v_agp_lp_rd = 0; + pctl.pctl_r_bits.apctl_v_agp_hp_rd = 0; + + port->pctl.csr = pctl.pctl_q_whole; + + TITAN_agp |= 1 << hose->index; + +#ifdef CONFIG_VGA_HOSE + /* is a graphics card on the AGP? (always device 5) */ + if (hose != NULL && + __kernel_ldwu(*(vusp)(hose->config_space_base + 0x280a)) == + PCI_CLASS_DISPLAY_VGA) + set_vga_hose(hose); +#endif +} + +static void __init +titan_init_one_pachip_port(titan_pachip_port *port, int index) +{ + struct pci_controler *hose; + + hose = alloc_pci_controler(); + if (index == 0) + pci_isa_hose = hose; + hose->io_space = alloc_resource(); + hose->mem_space = alloc_resource(); + + hose->config_space_base = TITAN_CONF(index); + hose->index = index; + + hose->io_space->start = TITAN_IO(index) - TITAN_IO_BIAS; + hose->io_space->end = hose->io_space->start + TITAN_IO_SPACE - 1; + hose->io_space->name = pci_io_names[index]; + hose->io_space->flags = IORESOURCE_IO; + + hose->mem_space->start = TITAN_MEM(index) - TITAN_MEM_BIAS; + hose->mem_space->end = hose->mem_space->start + 0xffffffff; + hose->mem_space->name = pci_mem_names[index]; + hose->mem_space->flags = IORESOURCE_MEM; + + if (request_resource(&ioport_resource, hose->io_space) < 0) + printk(KERN_ERR "Failed to request IO on hose %d\n", index); + if (request_resource(&iomem_resource, hose->mem_space) < 0) + printk(KERN_ERR "Failed to request MEM on hose %d\n", index); + + /* It's safe to call this for both G-Ports and A-Ports */ + titan_init_agp(port, hose); + + /* + * Save the existing PCI window translations. SRM will + * need them when we go to reboot. + */ + saved_pachip_port[index].wsba[0] = port->wsba[0].csr; + saved_pachip_port[index].wsm[0] = port->wsm[0].csr; + saved_pachip_port[index].tba[0] = port->tba[0].csr; + + saved_pachip_port[index].wsba[1] = port->wsba[1].csr; + saved_pachip_port[index].wsm[1] = port->wsm[1].csr; + saved_pachip_port[index].tba[1] = port->tba[1].csr; + + saved_pachip_port[index].wsba[2] = port->wsba[2].csr; + saved_pachip_port[index].wsm[2] = port->wsm[2].csr; + saved_pachip_port[index].tba[2] = port->tba[2].csr; + + saved_pachip_port[index].wsba[3] = port->wsba[3].csr; + saved_pachip_port[index].wsm[3] = port->wsm[3].csr; + saved_pachip_port[index].tba[3] = port->tba[3].csr; + + /* + * Set up the PCI to main memory translation windows. + * + * Note: Window 3 on Titan is Scatter-Gather ONLY + * + * Window 0 is scatter-gather 8MB at 8MB (for isa) + * Window 1 is direct access 1GB at 1GB + * Window 2 is direct access 1GB at 2GB + * Window 3 is scatter-gather 128MB at 3GB + * ??? We ought to scale window 3 memory. + * + * We must actually use 2 windows to direct-map the 2GB space, + * because of an idiot-syncrasy of the CYPRESS chip. It may + * respond to a PCI bus address in the last 1MB of the 4GB + * address range. + */ + hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0); + hose->sg_isa->align_entry = 8; /* 64KB for ISA */ + + hose->sg_pci = iommu_arena_new(hose, 0xc0000000, 0x08000000, 0); + hose->sg_pci->align_entry = 4; /* Titan caches 4 PTEs at a time */ + + __direct_map_base = 0x40000000; + __direct_map_size = 0x80000000; + + port->wsba[0].csr = hose->sg_isa->dma_base | 3; + port->wsm[0].csr = (hose->sg_isa->size - 1) & 0xfff00000; + port->tba[0].csr = virt_to_phys(hose->sg_isa->ptes); + + port->wsba[1].csr = 0x40000000 | 1; + port->wsm[1].csr = (0x40000000 - 1) & 0xfff00000; + port->tba[1].csr = 0; + + port->wsba[2].csr = 0x80000000 | 1; + port->wsm[2].csr = (0x40000000 - 1) & 0xfff00000; + port->tba[2].csr = 0x40000000; + + port->wsba[3].csr = hose->sg_pci->dma_base | 3; + port->wsm[3].csr = (hose->sg_pci->size - 1) & 0xfff00000; + port->tba[3].csr = virt_to_phys(hose->sg_pci->ptes); + + titan_pci_tbi(hose, 0, -1); +} + +static void __init +titan_init_pachips(titan_pachip *pachip0, titan_pachip *pachip1) +{ + int pchip1_present = TITAN_cchip->csc.csr & 1L<<14; + + /* Init the ports in hose order... */ + titan_init_one_pachip_port(&pachip0->g_port, 0); /* hose 0 */ + if (pchip1_present) + titan_init_one_pachip_port(&pachip1->g_port, 1);/* hose 1 */ + titan_init_one_pachip_port(&pachip0->a_port, 2); /* hose 2 */ + if (pchip1_present) + titan_init_one_pachip_port(&pachip1->a_port, 3);/* hose 3 */ +} + +void __init +titan_init_arch(void) +{ +#if 0 + printk("%s: titan_init_arch()\n", FN); + printk("%s: CChip registers:\n", FN); + printk("%s: CSR_CSC 0x%lx\n", FN, TITAN_cchip->csc.csr); + printk("%s: CSR_MTR 0x%lx\n", FN, TITAN_cchip->mtr.csr); + printk("%s: CSR_MISC 0x%lx\n", FN, TITAN_cchip->misc.csr); + printk("%s: CSR_DIM0 0x%lx\n", FN, TITAN_cchip->dim0.csr); + printk("%s: CSR_DIM1 0x%lx\n", FN, TITAN_cchip->dim1.csr); + printk("%s: CSR_DIR0 0x%lx\n", FN, TITAN_cchip->dir0.csr); + printk("%s: CSR_DIR1 0x%lx\n", FN, TITAN_cchip->dir1.csr); + printk("%s: CSR_DRIR 0x%lx\n", FN, TITAN_cchip->drir.csr); + + printk("%s: DChip registers:\n", FN); + printk("%s: CSR_DSC 0x%lx\n", FN, TITAN_dchip->dsc.csr); + printk("%s: CSR_STR 0x%lx\n", FN, TITAN_dchip->str.csr); + printk("%s: CSR_DREV 0x%lx\n", FN, TITAN_dchip->drev.csr); +#endif + + boot_cpuid = __hard_smp_processor_id(); + + /* With multiple PCI busses, we play with I/O as physical addrs. */ + ioport_resource.end = ~0UL; + iomem_resource.end = ~0UL; + + /* Init the PA chip(s) */ + titan_init_pachips(TITAN_pachip0, TITAN_pachip1); +} + +static void +titan_kill_one_pachip_port(titan_pachip_port *port, int index) +{ + port->wsba[0].csr = saved_pachip_port[index].wsba[0]; + port->wsm[0].csr = saved_pachip_port[index].wsm[0]; + port->tba[0].csr = saved_pachip_port[index].tba[0]; + + port->wsba[1].csr = saved_pachip_port[index].wsba[1]; + port->wsm[1].csr = saved_pachip_port[index].wsm[1]; + port->tba[1].csr = saved_pachip_port[index].tba[1]; + + port->wsba[2].csr = saved_pachip_port[index].wsba[2]; + port->wsm[2].csr = saved_pachip_port[index].wsm[2]; + port->tba[2].csr = saved_pachip_port[index].tba[2]; + + port->wsba[3].csr = saved_pachip_port[index].wsba[3]; + port->wsm[3].csr = saved_pachip_port[index].wsm[3]; + port->tba[3].csr = saved_pachip_port[index].tba[3]; +} + +static void +titan_kill_pachips(titan_pachip *pachip0, titan_pachip *pachip1) +{ + int pchip1_present = TITAN_cchip->csc.csr & 1L<<14; + + if (pchip1_present) { + titan_kill_one_pachip_port(&pachip0->g_port, 1); + titan_kill_one_pachip_port(&pachip0->a_port, 3); + } + titan_kill_one_pachip_port(&pachip0->g_port, 0); + titan_kill_one_pachip_port(&pachip0->a_port, 2); +} + +void +titan_kill_arch(int mode) +{ + titan_kill_pachips(TITAN_pachip0, TITAN_pachip1); +} + +static inline void +titan_pci_clr_err_1(titan_pachip *pachip) +{ + unsigned int jd; + + jd = pachip->g_port.port_specific.g.gperror.csr; + pachip->g_port.port_specific.g.gperror.csr = jd; + mb(); + pachip->g_port.port_specific.g.gperror.csr; +} + +static inline void +titan_pci_clr_err(void) +{ + titan_pci_clr_err_1(TITAN_pachip0); + + if (TITAN_cchip->csc.csr & 1L<<14) + titan_pci_clr_err_1(TITAN_pachip1); +} + +void +titan_machine_check(unsigned long vector, unsigned long la_ptr, + struct pt_regs * regs) +{ + /* clear error before any reporting. */ + mb(); + draina(); + titan_pci_clr_err(); + wrmces(0x7); + mb(); + + process_mcheck_info(vector, la_ptr, regs, "TITAN", + mcheck_expected(smp_processor_id())); +} + diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/kernel/core_tsunami.c linux/arch/alpha/kernel/core_tsunami.c --- v2.4.0-test1/linux/arch/alpha/kernel/core_tsunami.c Mon Mar 27 08:08:21 2000 +++ linux/arch/alpha/kernel/core_tsunami.c Mon Jun 19 17:59:32 2000 @@ -344,11 +344,13 @@ /* * Set up the PCI to main memory translation windows. * + * Note: Window 3 is scatter-gather only + * * Window 0 is scatter-gather 8MB at 8MB (for isa) - * Window 1 is scatter-gather 128MB at 3GB - * Window 2 is direct access 1GB at 1GB - * Window 3 is direct access 1GB at 2GB - * ??? We ought to scale window 1 memory. + * Window 1 is direct access 1GB at 1GB + * Window 2 is direct access 1GB at 2GB + * Window 3 is scatter-gather 128MB at 3GB + * ??? We ought to scale window 3 memory. * * We must actually use 2 windows to direct-map the 2GB space, * because of an idiot-syncrasy of the CYPRESS chip. It may @@ -364,17 +366,17 @@ pchip->wsm[0].csr = (hose->sg_isa->size - 1) & 0xfff00000; pchip->tba[0].csr = virt_to_phys(hose->sg_isa->ptes); - pchip->wsba[1].csr = hose->sg_pci->dma_base | 3; - pchip->wsm[1].csr = (hose->sg_pci->size - 1) & 0xfff00000; - pchip->tba[1].csr = virt_to_phys(hose->sg_pci->ptes); + pchip->wsba[1].csr = 0x40000000 | 1; + pchip->wsm[1].csr = (0x40000000 - 1) & 0xfff00000; + pchip->tba[1].csr = 0; - pchip->wsba[2].csr = 0x40000000 | 1; + pchip->wsba[2].csr = 0x80000000 | 1; pchip->wsm[2].csr = (0x40000000 - 1) & 0xfff00000; - pchip->tba[2].csr = 0; + pchip->tba[2].csr = 0x40000000; - pchip->wsba[3].csr = 0x80000000 | 1; - pchip->wsm[3].csr = (0x40000000 - 1) & 0xfff00000; - pchip->tba[3].csr = 0x40000000; + pchip->wsba[3].csr = hose->sg_pci->dma_base | 3; + pchip->wsm[3].csr = (hose->sg_pci->size - 1) & 0xfff00000; + pchip->tba[3].csr = virt_to_phys(hose->sg_pci->ptes); tsunami_pci_tbi(hose, 0, -1); } diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/kernel/core_wildfire.c linux/arch/alpha/kernel/core_wildfire.c --- v2.4.0-test1/linux/arch/alpha/kernel/core_wildfire.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/kernel/core_wildfire.c Mon Jun 19 17:59:32 2000 @@ -0,0 +1,668 @@ +/* + * linux/arch/alpha/kernel/core_wildfire.c + * + * Wildfire support. + * + * Copyright (C) 2000 Andrea Arcangeli SuSE + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define __EXTERN_INLINE inline +#include +#include +#undef __EXTERN_INLINE + +#include "proto.h" +#include "pci_impl.h" + +#define DEBUG_MCHECK 0 /* 0 = minimal, 1 = debug, 2 = debug+dump. */ +#define DEBUG_CONFIG 0 +#define DEBUG_DUMP_REGS 0 +#define DEBUG_DUMP_CONFIG 1 + +#if DEBUG_CONFIG +# define DBG_CFG(args) printk args +#else +# define DBG_CFG(args) +#endif + +#if DEBUG_DUMP_REGS +static void wildfire_dump_pci_regs(int qbbno, int hoseno); +static void wildfire_dump_pca_regs(int qbbno, int pcano); +static void wildfire_dump_qsa_regs(int qbbno); +static void wildfire_dump_qsd_regs(int qbbno); +static void wildfire_dump_iop_regs(int qbbno); +static void wildfire_dump_gp_regs(int qbbno); +#endif +#if DEBUG_DUMP_CONFIG +static void wildfire_dump_hardware_config(void); +#endif + +unsigned char wildfire_hard_qbb_map[WILDFIRE_MAX_QBB]; +unsigned char wildfire_soft_qbb_map[WILDFIRE_MAX_QBB]; +#define QBB_MAP_EMPTY 0xff + +unsigned long wildfire_hard_qbb_mask; +unsigned long wildfire_soft_qbb_mask; +unsigned long wildfire_gp_mask; +unsigned long wildfire_hs_mask; +unsigned long wildfire_iop_mask; +unsigned long wildfire_ior_mask; +unsigned long wildfire_pca_mask; +unsigned long wildfire_cpu_mask; +unsigned long wildfire_mem_mask; + +void __init +wildfire_init_hose(int qbbno, int hoseno) +{ + struct pci_controler *hose; + wildfire_pci *pci; + + hose = alloc_pci_controler(); + hose->io_space = alloc_resource(); + hose->mem_space = alloc_resource(); + + /* This is for userland consumption. */ + hose->sparse_mem_base = 0; + hose->sparse_io_base = 0; + hose->dense_mem_base = WILDFIRE_MEM(qbbno, hoseno); + hose->dense_io_base = WILDFIRE_IO(qbbno, hoseno); + + hose->config_space_base = WILDFIRE_CONF(qbbno, hoseno); + hose->index = (qbbno << 3) + hoseno; + + hose->io_space->start = WILDFIRE_IO(qbbno, hoseno) - WILDFIRE_IO_BIAS; + hose->io_space->end = hose->io_space->start + WILDFIRE_IO_SPACE - 1; + hose->io_space->name = pci_io_names[hoseno]; + hose->io_space->flags = IORESOURCE_IO; + + hose->mem_space->start = WILDFIRE_MEM(qbbno, hoseno)-WILDFIRE_MEM_BIAS; + hose->mem_space->end = hose->mem_space->start + 0xffffffff; + hose->mem_space->name = pci_mem_names[hoseno]; + hose->mem_space->flags = IORESOURCE_MEM; + + if (request_resource(&ioport_resource, hose->io_space) < 0) + printk(KERN_ERR "Failed to request IO on qbb %d hose %d\n", + qbbno, hoseno); + if (request_resource(&iomem_resource, hose->mem_space) < 0) + printk(KERN_ERR "Failed to request MEM on qbb %d hose %d\n", + qbbno, hoseno); + +#if DEBUG_DUMP_REGS + wildfire_dump_pci_regs(qbbno, hoseno); +#endif + + /* + * Set up the PCI to main memory translation windows. + * + * Note: Window 3 is scatter-gather only + * + * Window 0 is scatter-gather 8MB at 8MB (for isa) + * Window 1 is direct access 1GB at 1GB + * Window 2 is direct access 1GB at 2GB + * Window 3 is scatter-gather 128MB at 3GB + * ??? We ought to scale window 3 memory. + * + */ + hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0); + hose->sg_pci = iommu_arena_new(hose, 0xc0000000, 0x08000000, 0); + + pci = WILDFIRE_pci(qbbno, hoseno); + + pci->pci_window[0].wbase.csr = hose->sg_isa->dma_base | 3; + pci->pci_window[0].wmask.csr = (hose->sg_isa->size - 1) & 0xfff00000; + pci->pci_window[0].tbase.csr = virt_to_phys(hose->sg_isa->ptes); + + pci->pci_window[1].wbase.csr = 0x40000000 | 1; + pci->pci_window[1].wmask.csr = (0x40000000 -1) & 0xfff00000; + pci->pci_window[1].tbase.csr = 0; + + pci->pci_window[2].wbase.csr = 0x80000000 | 1; + pci->pci_window[2].wmask.csr = (0x40000000 -1) & 0xfff00000; + pci->pci_window[2].tbase.csr = 0x40000000; + + pci->pci_window[3].wbase.csr = hose->sg_pci->dma_base | 3; + pci->pci_window[3].wmask.csr = (hose->sg_pci->size - 1) & 0xfff00000; + pci->pci_window[3].tbase.csr = virt_to_phys(hose->sg_pci->ptes); + + wildfire_pci_tbi(hose, 0, 0); /* Flush TLB at the end. */ +} + +void __init +wildfire_init_pca(int qbbno, int pcano) +{ + + /* Test for PCA existence first. */ + if (!WILDFIRE_PCA_EXISTS(qbbno, pcano)) + return; + +#if DEBUG_DUMP_REGS + wildfire_dump_pca_regs(qbbno, pcano); +#endif + + /* Do both hoses of the PCA. */ + wildfire_init_hose(qbbno, (pcano << 1) + 0); + wildfire_init_hose(qbbno, (pcano << 1) + 1); +} + +void __init +wildfire_init_qbb(int qbbno) +{ + int pcano; + + /* Test for QBB existence first. */ + if (!WILDFIRE_QBB_EXISTS(qbbno)) + return; + +#if DEBUG_DUMP_REGS + wildfire_dump_qsa_regs(qbbno); + wildfire_dump_qsd_regs(qbbno); + wildfire_dump_iop_regs(qbbno); + wildfire_dump_gp_regs(qbbno); +#endif + + /* Init all PCAs here. */ + for (pcano = 0; pcano < WILDFIRE_PCA_PER_QBB; pcano++) { + wildfire_init_pca(qbbno, pcano); + } +} + +void __init +wildfire_hardware_probe(void) +{ + unsigned long temp; + unsigned int hard_qbb, soft_qbb; + wildfire_fast_qsd *fast = WILDFIRE_fast_qsd(); + wildfire_qsd *qsd; + wildfire_qsa *qsa; + wildfire_iop *iop; + wildfire_gp *gp; + wildfire_ne *ne; + wildfire_fe *fe; + int i; + + temp = fast->qsd_whami.csr; +#if 0 + printk(KERN_ERR "fast QSD_WHAMI at base %p is 0x%lx\n", fast, temp); +#endif + + hard_qbb = (temp >> 8) & 7; + soft_qbb = (temp >> 4) & 7; + + /* Init the HW configuration variables. */ + wildfire_hard_qbb_mask = (1 << hard_qbb); + wildfire_soft_qbb_mask = (1 << soft_qbb); + + wildfire_gp_mask = 0; + wildfire_hs_mask = 0; + wildfire_iop_mask = 0; + wildfire_ior_mask = 0; + wildfire_pca_mask = 0; + + wildfire_cpu_mask = 0; + wildfire_mem_mask = 0; + + memset(wildfire_hard_qbb_map, QBB_MAP_EMPTY, WILDFIRE_MAX_QBB); + memset(wildfire_soft_qbb_map, QBB_MAP_EMPTY, WILDFIRE_MAX_QBB); + + /* First, determine which QBBs are present. */ + qsa = WILDFIRE_qsa(soft_qbb); + + temp = qsa->qsa_qbb_id.csr; +#if 0 + printk(KERN_ERR "QSA_QBB_ID at base %p is 0x%lx\n", qsa, temp); +#endif + + if (temp & 0x40) /* Is there an HS? */ + wildfire_hs_mask = 1; + + if (temp & 0x20) { /* Is there a GP? */ + gp = WILDFIRE_gp(soft_qbb); + temp = 0; + for (i = 0; i < 4; i++) { + temp |= gp->gpa_qbb_map[i].csr << (i * 8); +#if 0 + printk(KERN_ERR "GPA_QBB_MAP[%d] at base %p is 0x%lx\n", + i, gp, temp); +#endif + } + + for (hard_qbb = 0; hard_qbb < WILDFIRE_MAX_QBB; hard_qbb++) { + if (temp & 8) { /* Is there a QBB? */ + soft_qbb = temp & 7; + wildfire_hard_qbb_mask |= (1 << hard_qbb); + wildfire_soft_qbb_mask |= (1 << soft_qbb); + } + temp >>= 4; + } + wildfire_gp_mask = wildfire_soft_qbb_mask; + } + + /* Next determine each QBBs resources. */ + for (soft_qbb = 0; soft_qbb < WILDFIRE_MAX_QBB; soft_qbb++) { + if (WILDFIRE_QBB_EXISTS(soft_qbb)) { + qsd = WILDFIRE_qsd(soft_qbb); + temp = qsd->qsd_whami.csr; +#if 0 + printk(KERN_ERR "QSD_WHAMI at base %p is 0x%lx\n", qsd, temp); +#endif + hard_qbb = (temp >> 8) & 7; + wildfire_hard_qbb_map[hard_qbb] = soft_qbb; + wildfire_soft_qbb_map[soft_qbb] = hard_qbb; + + qsa = WILDFIRE_qsa(soft_qbb); + temp = qsa->qsa_qbb_pop[0].csr; +#if 0 + printk(KERN_ERR "QSA_QBB_POP_0 at base %p is 0x%lx\n", qsa, temp); +#endif + wildfire_cpu_mask |= ((temp >> 0) & 0xf) << (soft_qbb << 2); + wildfire_mem_mask |= ((temp >> 4) & 0xf) << (soft_qbb << 2); + + temp = qsa->qsa_qbb_pop[1].csr; +#if 0 + printk(KERN_ERR "QSA_QBB_POP_1 at base %p is 0x%lx\n", qsa, temp); +#endif + wildfire_iop_mask |= (1 << soft_qbb); + wildfire_ior_mask |= ((temp >> 4) & 0xf) << (soft_qbb << 2); + + temp = qsa->qsa_qbb_id.csr; +#if 0 + printk(KERN_ERR "QSA_QBB_ID at %p is 0x%lx\n", qsa, temp); +#endif + if (temp & 0x20) + wildfire_gp_mask |= (1 << soft_qbb); + + /* Probe for PCA existence here. */ + for (i = 0; i < WILDFIRE_PCA_PER_QBB; i++) { + iop = WILDFIRE_iop(soft_qbb); + ne = WILDFIRE_ne(soft_qbb, i); + fe = WILDFIRE_fe(soft_qbb, i); + + if ((iop->iop_hose[i].init.csr & 1) == 1 && + ((ne->ne_what_am_i.csr & 0xf00000300) == 0x100000300) && + ((fe->fe_what_am_i.csr & 0xf00000300) == 0x100000200)) + { + wildfire_pca_mask |= 1 << ((soft_qbb << 2) + i); + } + } + + } + } +#if DEBUG_DUMP_CONFIG + wildfire_dump_hardware_config(); +#endif +} + +void __init +wildfire_init_arch(void) +{ + int qbbno; + + /* With multiple PCI buses, we play with I/O as physical addrs. */ + ioport_resource.end = ~0UL; + iomem_resource.end = ~0UL; + + + /* Probe the hardware for info about configuration. */ + wildfire_hardware_probe(); + + /* Now init all the found QBBs. */ + for (qbbno = 0; qbbno < WILDFIRE_MAX_QBB; qbbno++) { + wildfire_init_qbb(qbbno); + } + + /* Normal direct PCI DMA mapping. */ + __direct_map_base = 0x40000000UL; + __direct_map_size = 0x80000000UL; +} + +void +wildfire_machine_check(unsigned long vector, unsigned long la_ptr, + struct pt_regs * regs) +{ + mb(); + mb(); /* magic */ + draina(); + /* FIXME: clear pci errors */ + wrmces(0x7); + mb(); + + process_mcheck_info(vector, la_ptr, regs, "WILDFIRE", + mcheck_expected(smp_processor_id())); +} + +void +wildfire_kill_arch(int mode) +{ +} + +void +wildfire_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end) +{ + int qbbno = hose->index >> 3; + int hoseno = hose->index & 7; + wildfire_pci *pci = WILDFIRE_pci(qbbno, hoseno); + + mb(); + pci->pci_flush_tlb.csr; /* reading does the trick */ +} + +static int +mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr, + unsigned char *type1) +{ + struct pci_controler *hose = dev->sysdata; + unsigned long addr; + u8 bus = dev->bus->number; + u8 device_fn = dev->devfn; + + DBG_CFG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, " + "pci_addr=0x%p, type1=0x%p)\n", + bus, device_fn, where, pci_addr, type1)); + + if (hose->first_busno == dev->bus->number) + bus = 0; + *type1 = (bus != 0); + + addr = (bus << 16) | (device_fn << 8) | where; + addr |= hose->config_space_base; + + *pci_addr = addr; + DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr)); + return 0; +} + +static int +wildfire_read_config_byte(struct pci_dev *dev, int where, u8 *value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = __kernel_ldbu(*(vucp)addr); + return PCIBIOS_SUCCESSFUL; +} + +static int +wildfire_read_config_word(struct pci_dev *dev, int where, u16 *value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = __kernel_ldwu(*(vusp)addr); + return PCIBIOS_SUCCESSFUL; +} + +static int +wildfire_read_config_dword(struct pci_dev *dev, int where, u32 *value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = *(vuip)addr; + return PCIBIOS_SUCCESSFUL; +} + +static int +wildfire_write_config_byte(struct pci_dev *dev, int where, u8 value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + __kernel_stb(value, *(vucp)addr); + mb(); + __kernel_ldbu(*(vucp)addr); + return PCIBIOS_SUCCESSFUL; +} + +static int +wildfire_write_config_word(struct pci_dev *dev, int where, u16 value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + __kernel_stw(value, *(vusp)addr); + mb(); + __kernel_ldwu(*(vusp)addr); + return PCIBIOS_SUCCESSFUL; +} + +static int +wildfire_write_config_dword(struct pci_dev *dev, int where, u32 value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *(vuip)addr = value; + mb(); + *(vuip)addr; + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops wildfire_pci_ops = +{ + read_byte: wildfire_read_config_byte, + read_word: wildfire_read_config_word, + read_dword: wildfire_read_config_dword, + write_byte: wildfire_write_config_byte, + write_word: wildfire_write_config_word, + write_dword: wildfire_write_config_dword +}; + +#if DEBUG_DUMP_REGS + +static void __init +wildfire_dump_pci_regs(int qbbno, int hoseno) +{ + wildfire_pci *pci = WILDFIRE_pci(qbbno, hoseno); + int i; + + printk(KERN_ERR "PCI registers for QBB %d hose %d (%p)\n", + qbbno, hoseno, pci); + + printk(KERN_ERR " PCI_IO_ADDR_EXT: 0x%16lx\n", + pci->pci_io_addr_ext.csr); + printk(KERN_ERR " PCI_CTRL: 0x%16lx\n", pci->pci_ctrl.csr); + printk(KERN_ERR " PCI_ERR_SUM: 0x%16lx\n", pci->pci_err_sum.csr); + printk(KERN_ERR " PCI_ERR_ADDR: 0x%16lx\n", pci->pci_err_addr.csr); + printk(KERN_ERR " PCI_STALL_CNT: 0x%16lx\n", pci->pci_stall_cnt.csr); + printk(KERN_ERR " PCI_PEND_INT: 0x%16lx\n", pci->pci_pend_int.csr); + printk(KERN_ERR " PCI_SENT_INT: 0x%16lx\n", pci->pci_sent_int.csr); + + printk(KERN_ERR " DMA window registers for QBB %d hose %d (%p)\n", + qbbno, hoseno, pci); + for (i = 0; i < 4; i++) { + printk(KERN_ERR " window %d: 0x%16lx 0x%16lx 0x%16lx\n", i, + pci->pci_window[i].wbase.csr, + pci->pci_window[i].wmask.csr, + pci->pci_window[i].tbase.csr); + } + printk(KERN_ERR "\n"); +} + +static void __init +wildfire_dump_pca_regs(int qbbno, int pcano) +{ + wildfire_pca *pca = WILDFIRE_pca(qbbno, pcano); + int i; + + printk(KERN_ERR "PCA registers for QBB %d PCA %d (%p)\n", + qbbno, pcano, pca); + + printk(KERN_ERR " PCA_WHAT_AM_I: 0x%16lx\n", pca->pca_what_am_i.csr); + printk(KERN_ERR " PCA_ERR_SUM: 0x%16lx\n", pca->pca_err_sum.csr); + printk(KERN_ERR " PCA_PEND_INT: 0x%16lx\n", pca->pca_pend_int.csr); + printk(KERN_ERR " PCA_SENT_INT: 0x%16lx\n", pca->pca_sent_int.csr); + printk(KERN_ERR " PCA_STDIO_EL: 0x%16lx\n", + pca->pca_stdio_edge_level.csr); + + printk(KERN_ERR " PCA target registers for QBB %d PCA %d (%p)\n", + qbbno, pcano, pca); + for (i = 0; i < 4; i++) { + printk(KERN_ERR " target %d: 0x%16lx 0x%16lx\n", i, + pca->pca_int[i].target.csr, + pca->pca_int[i].enable.csr); + } + + printk(KERN_ERR "\n"); +} + +static void __init +wildfire_dump_qsa_regs(int qbbno) +{ + wildfire_qsa *qsa = WILDFIRE_qsa(qbbno); + int i; + + printk(KERN_ERR "QSA registers for QBB %d (%p)\n", qbbno, qsa); + + printk(KERN_ERR " QSA_QBB_ID: 0x%16lx\n", qsa->qsa_qbb_id.csr); + printk(KERN_ERR " QSA_PORT_ENA: 0x%16lx\n", qsa->qsa_port_ena.csr); + printk(KERN_ERR " QSA_REF_INT: 0x%16lx\n", qsa->qsa_ref_int.csr); + + for (i = 0; i < 5; i++) + printk(KERN_ERR " QSA_CONFIG_%d: 0x%16lx\n", + i, qsa->qsa_config[i].csr); + + for (i = 0; i < 2; i++) + printk(KERN_ERR " QSA_QBB_POP_%d: 0x%16lx\n", + i, qsa->qsa_qbb_pop[0].csr); + + printk(KERN_ERR "\n"); +} + +static void __init +wildfire_dump_qsd_regs(int qbbno) +{ + wildfire_qsd *qsd = WILDFIRE_qsd(qbbno); + + printk(KERN_ERR "QSD registers for QBB %d (%p)\n", qbbno, qsd); + + printk(KERN_ERR " QSD_WHAMI: 0x%16lx\n", qsd->qsd_whami.csr); + printk(KERN_ERR " QSD_REV: 0x%16lx\n", qsd->qsd_rev.csr); + printk(KERN_ERR " QSD_PORT_PRESENT: 0x%16lx\n", + qsd->qsd_port_present.csr); + printk(KERN_ERR " QSD_PORT_ACTUVE: 0x%16lx\n", + qsd->qsd_port_active.csr); + printk(KERN_ERR " QSD_FAULT_ENA: 0x%16lx\n", + qsd->qsd_fault_ena.csr); + printk(KERN_ERR " QSD_CPU_INT_ENA: 0x%16lx\n", + qsd->qsd_cpu_int_ena.csr); + printk(KERN_ERR " QSD_MEM_CONFIG: 0x%16lx\n", + qsd->qsd_mem_config.csr); + printk(KERN_ERR " QSD_ERR_SUM: 0x%16lx\n", + qsd->qsd_err_sum.csr); + + printk(KERN_ERR "\n"); +} + +static void __init +wildfire_dump_iop_regs(int qbbno) +{ + wildfire_iop *iop = WILDFIRE_iop(qbbno); + int i; + + printk(KERN_ERR "IOP registers for QBB %d (%p)\n", qbbno, iop); + + printk(KERN_ERR " IOA_CONFIG: 0x%16lx\n", iop->ioa_config.csr); + printk(KERN_ERR " IOD_CONFIG: 0x%16lx\n", iop->iod_config.csr); + printk(KERN_ERR " IOP_SWITCH_CREDITS: 0x%16lx\n", + iop->iop_switch_credits.csr); + printk(KERN_ERR " IOP_HOSE_CREDITS: 0x%16lx\n", + iop->iop_hose_credits.csr); + + for (i = 0; i < 4; i++) + printk(KERN_ERR " IOP_HOSE_%d_INIT: 0x%16lx\n", + i, iop->iop_hose[i].init.csr); + for (i = 0; i < 4; i++) + printk(KERN_ERR " IOP_DEV_INT_TARGET_%d: 0x%16lx\n", + i, iop->iop_dev_int[i].target.csr); + + printk(KERN_ERR "\n"); +} + +static void __init +wildfire_dump_gp_regs(int qbbno) +{ + wildfire_gp *gp = WILDFIRE_gp(qbbno); + int i; + + printk(KERN_ERR "GP registers for QBB %d (%p)\n", qbbno, gp); + for (i = 0; i < 4; i++) + printk(KERN_ERR " GPA_QBB_MAP_%d: 0x%16lx\n", + i, gp->gpa_qbb_map[i].csr); + + printk(KERN_ERR " GPA_MEM_POP_MAP: 0x%16lx\n", + gp->gpa_mem_pop_map.csr); + printk(KERN_ERR " GPA_SCRATCH: 0x%16lx\n", gp->gpa_scratch.csr); + printk(KERN_ERR " GPA_DIAG: 0x%16lx\n", gp->gpa_diag.csr); + printk(KERN_ERR " GPA_CONFIG_0: 0x%16lx\n", gp->gpa_config_0.csr); + printk(KERN_ERR " GPA_INIT_ID: 0x%16lx\n", gp->gpa_init_id.csr); + printk(KERN_ERR " GPA_CONFIG_2: 0x%16lx\n", gp->gpa_config_2.csr); + + printk(KERN_ERR "\n"); +} +#endif /* DUMP_REGS */ + +#if DEBUG_DUMP_CONFIG +static void __init +wildfire_dump_hardware_config(void) +{ + int i; + + printk(KERN_ERR "Probed Hardware Configuration\n"); + + printk(KERN_ERR " hard_qbb_mask: 0x%16lx\n", wildfire_hard_qbb_mask); + printk(KERN_ERR " soft_qbb_mask: 0x%16lx\n", wildfire_soft_qbb_mask); + + printk(KERN_ERR " gp_mask: 0x%16lx\n", wildfire_gp_mask); + printk(KERN_ERR " hs_mask: 0x%16lx\n", wildfire_hs_mask); + printk(KERN_ERR " iop_mask: 0x%16lx\n", wildfire_iop_mask); + printk(KERN_ERR " ior_mask: 0x%16lx\n", wildfire_ior_mask); + printk(KERN_ERR " pca_mask: 0x%16lx\n", wildfire_pca_mask); + + printk(KERN_ERR " cpu_mask: 0x%16lx\n", wildfire_cpu_mask); + printk(KERN_ERR " mem_mask: 0x%16lx\n", wildfire_mem_mask); + + printk(" hard_qbb_map: "); + for (i = 0; i < WILDFIRE_MAX_QBB; i++) + if (wildfire_hard_qbb_map[i] == QBB_MAP_EMPTY) + printk("--- "); + else + printk("%3d ", wildfire_hard_qbb_map[i]); + printk("\n"); + + printk(" soft_qbb_map: "); + for (i = 0; i < WILDFIRE_MAX_QBB; i++) + if (wildfire_soft_qbb_map[i] == QBB_MAP_EMPTY) + printk("--- "); + else + printk("%3d ", wildfire_soft_qbb_map[i]); + printk("\n"); +} +#endif /* DUMP_CONFIG */ diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S --- v2.4.0-test1/linux/arch/alpha/kernel/entry.S Wed Apr 26 16:34:06 2000 +++ linux/arch/alpha/kernel/entry.S Mon Jun 19 17:59:32 2000 @@ -34,11 +34,12 @@ #define TASK_EXEC_DOMAIN 32 #define TASK_NEED_RESCHED 40 #define TASK_PROCESSOR 100 +#define TASK_PTRACE 104 /* * task flags (must match include/linux/sched.h): */ -#define PF_PTRACED 0x00000010 +#define PT_PTRACED 0x00000001 #define CLONE_VM 0x00000100 @@ -557,10 +558,10 @@ lda $5,sys_call_table lda $27,sys_ni_syscall cmpult $0,$4,$4 - ldq $3,TASK_FLAGS($8) + ldq $3,TASK_PTRACE($8) stq $17,SP_OFF+32($30) s8addq $0,$5,$5 - and $3,PF_PTRACED,$3 + and $3,PT_PTRACED,$3 stq $18,SP_OFF+40($30) bne $3,strace beq $4,1f diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c --- v2.4.0-test1/linux/arch/alpha/kernel/irq.c Wed Apr 26 16:34:06 2000 +++ linux/arch/alpha/kernel/irq.c Wed Jun 21 22:30:59 2000 @@ -240,7 +240,7 @@ return; while (((cpu_present_mask >> cpu) & 1) == 0) - cpu = (cpu < NR_CPUS ? cpu + 1 : 0); + cpu = (cpu < (NR_CPUS-1) ? cpu + 1 : 0); last_cpu = cpu; irq_affinity[irq] = 1UL << cpu; @@ -520,8 +520,10 @@ p += sprintf(p, " "); for (i = 0; i < smp_num_cpus; i++) p += sprintf(p, "CPU%d ", i); +#ifdef DO_BROADCAST_INTS for (i = 0; i < smp_num_cpus; i++) p += sprintf(p, "TRY%d ", i); +#endif *p++ = '\n'; #endif @@ -536,9 +538,11 @@ for (j = 0; j < smp_num_cpus; j++) p += sprintf(p, "%10u ", kstat.irqs[cpu_logical_map(j)][i]); +#ifdef DO_BROADCAST_INTS for (j = 0; j < smp_num_cpus; j++) p += sprintf(p, "%10lu ", irq_attempt(cpu_logical_map(j), i)); +#endif #endif p += sprintf(p, " %14s", irq_desc[i].handler->typename); p += sprintf(p, " %c%s", diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/kernel/irq_alpha.c linux/arch/alpha/kernel/irq_alpha.c --- v2.4.0-test1/linux/arch/alpha/kernel/irq_alpha.c Sun Mar 19 18:35:30 2000 +++ linux/arch/alpha/kernel/irq_alpha.c Mon Jun 19 17:59:32 2000 @@ -105,8 +105,18 @@ void __init init_IRQ(void) { - alpha_mv.init_irq(); + /* Uh, this really MUST come first, just in case + * the platform init_irq() causes interrupts/mchecks + * (as is the case with RAWHIDE, at least). + */ wrent(entInt, 0); + + alpha_mv.init_irq(); + + /* If we had wanted SRM console printk echoing early, undo it now. */ + if (alpha_using_srm && srmcons_output) { + unregister_srm_console(); + } } /* diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/kernel/irq_i8259.c linux/arch/alpha/kernel/irq_i8259.c --- v2.4.0-test1/linux/arch/alpha/kernel/irq_i8259.c Tue Apr 11 15:09:11 2000 +++ linux/arch/alpha/kernel/irq_i8259.c Mon Jun 19 17:59:32 2000 @@ -126,6 +126,8 @@ # define IACK_SC CIA_IACK_SC #elif defined(CONFIG_ALPHA_PYXIS) # define IACK_SC PYXIS_IACK_SC +#elif defined(CONFIG_ALPHA_TITAN) +# define IACK_SC TITAN_IACK_SC #elif defined(CONFIG_ALPHA_TSUNAMI) # define IACK_SC TSUNAMI_IACK_SC #elif defined(CONFIG_ALPHA_POLARIS) diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/kernel/machvec_impl.h linux/arch/alpha/kernel/machvec_impl.h --- v2.4.0-test1/linux/arch/alpha/kernel/machvec_impl.h Sun Mar 19 18:35:30 2000 +++ linux/arch/alpha/kernel/machvec_impl.h Wed Jun 21 22:30:59 2000 @@ -9,12 +9,14 @@ #include #include -/* Whee. IRONGATE, POLARIS and TSUNAMI don't have an HAE. Fix things up for - the GENERIC kernel by defining the HAE address to be that of the cache. - Now we can read and write it as we like. ;-) */ +/* Whee. IRONGATE, POLARIS, TSUNAMI, TITAN, and WILDFIRE don't have an HAE. + Fix things up for the GENERIC kernel by defining the HAE address + to be that of the cache. Now we can read and write it as we like. ;-) */ #define IRONGATE_HAE_ADDRESS (&alpha_mv.hae_cache) #define POLARIS_HAE_ADDRESS (&alpha_mv.hae_cache) #define TSUNAMI_HAE_ADDRESS (&alpha_mv.hae_cache) +#define TITAN_HAE_ADDRESS (&alpha_mv.hae_cache) +#define WILDFIRE_HAE_ADDRESS (&alpha_mv.hae_cache) #if CIA_ONE_HAE_WINDOW #define CIA_HAE_ADDRESS (&alpha_mv.hae_cache) @@ -28,6 +30,7 @@ seems like such a pain. Define this to get things to compile. */ #define JENSEN_IACK_SC 1 #define T2_IACK_SC 1 +#define WILDFIRE_IACK_SC 1 /* FIXME */ /* @@ -91,6 +94,8 @@ #define DO_POLARIS_IO IO(POLARIS,polaris) #define DO_T2_IO IO(T2,t2) #define DO_TSUNAMI_IO IO(TSUNAMI,tsunami) +#define DO_TITAN_IO IO(TITAN,titan) +#define DO_WILDFIRE_IO IO(WILDFIRE,wildfire) #define DO_PYXIS_IO IO_LITE(CIA,cia_bwx), \ pci_ops: &CAT(cia,_pci_ops) @@ -107,6 +112,8 @@ #define DO_POLARIS_BUS BUS(polaris) #define DO_T2_BUS BUS(t2) #define DO_TSUNAMI_BUS BUS(tsunami) +#define DO_TITAN_BUS BUS(titan) +#define DO_WILDFIRE_BUS BUS(wildfire) /* @@ -114,7 +121,7 @@ * all but one of which we want to go away. In a non-GENERIC kernel, * we want only one, ever. * - * Accomplish this in the GENERIC kernel by puting all of the vectors + * Accomplish this in the GENERIC kernel by putting all of the vectors * in the .init.data section where they'll go away. We'll copy the * one we want to the real alpha_mv vector in setup_arch. * diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c --- v2.4.0-test1/linux/arch/alpha/kernel/osf_sys.c Tue May 23 15:31:32 2000 +++ linux/arch/alpha/kernel/osf_sys.c Mon Jun 19 17:59:32 2000 @@ -230,7 +230,6 @@ struct file *file = NULL; unsigned long ret = -EBADF; - down(¤t->mm->mmap_sem); lock_kernel(); #if 0 if (flags & (_MAP_HASSEMAPHORE | _MAP_INHERIT | _MAP_UNALIGNED)) @@ -243,12 +242,13 @@ goto out; } flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + down(¤t->mm->mmap_sem); ret = do_mmap(file, addr, len, prot, flags, off); + up(¤t->mm->mmap_sem); if (file) fput(file); out: unlock_kernel(); - up(¤t->mm->mmap_sem); return ret; } diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/kernel/pci.c linux/arch/alpha/kernel/pci.c --- v2.4.0-test1/linux/arch/alpha/kernel/pci.c Wed Apr 26 16:34:06 2000 +++ linux/arch/alpha/kernel/pci.c Wed Jun 21 22:30:59 2000 @@ -25,11 +25,13 @@ */ const char *const pci_io_names[] = { - "PCI IO bus 0", "PCI IO bus 1", "PCI IO bus 2", "PCI IO bus 3" + "PCI IO bus 0", "PCI IO bus 1", "PCI IO bus 2", "PCI IO bus 3", + "PCI IO bus 4", "PCI IO bus 5", "PCI IO bus 6", "PCI IO bus 7" }; const char *const pci_mem_names[] = { - "PCI mem bus 0", "PCI mem bus 1", "PCI mem bus 2", "PCI mem bus 3" + "PCI mem bus 0", "PCI mem bus 1", "PCI mem bus 2", "PCI mem bus 3", + "PCI mem bus 4", "PCI mem bus 5", "PCI mem bus 6", "PCI mem bus 7" }; const char pci_hae0_name[] = "HAE0"; @@ -266,6 +268,7 @@ struct pci_controler *hose = (struct pci_controler *) bus->sysdata; struct list_head *ln; + /* ???? */ bus->resource[0] = hose->io_space; bus->resource[1] = hose->mem_space; @@ -291,15 +294,14 @@ u32 reg; if (resource < PCI_ROM_RESOURCE) - where = PCI_BASE_ADDRESS_0 + (resource * 4); + where = PCI_BASE_ADDRESS_0 + (resource * 4); else if (resource == PCI_ROM_RESOURCE) where = dev->rom_base_reg; else { - /* Don't update non-standard resources here */ - return; + return; /* Don't update non-standard resources here. */ } - /* Point root at the hose root */ + /* Point root at the hose root. */ if (res->flags & IORESOURCE_IO) root = hose->io_space; if (res->flags & IORESOURCE_MEM) @@ -424,12 +426,17 @@ inner.mem_end -= inner.mem_start; /* Align the sizes up by bridge rules */ - inner.io_end = ROUND_UP(inner.io_end, 4*1024); - inner.mem_end = ROUND_UP(inner.mem_end, 1*1024*1024); + inner.io_end = ROUND_UP(inner.io_end, 4*1024) - 1; + inner.mem_end = ROUND_UP(inner.mem_end, 1*1024*1024) - 1; /* Adjust the bridge's allocation requirements */ bridge->resource[0].end = bridge->resource[0].start + inner.io_end; bridge->resource[1].end = bridge->resource[1].start + inner.mem_end; + + bridge->resource[PCI_BRIDGE_RESOURCES].end = + bridge->resource[PCI_BRIDGE_RESOURCES].start + inner.io_end; + bridge->resource[PCI_BRIDGE_RESOURCES+1].end = + bridge->resource[PCI_BRIDGE_RESOURCES+1].start + inner.mem_end; /* adjust parent's resource requirements */ if (outer) { diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/kernel/pci_iommu.c linux/arch/alpha/kernel/pci_iommu.c --- v2.4.0-test1/linux/arch/alpha/kernel/pci_iommu.c Sun Mar 19 18:35:30 2000 +++ linux/arch/alpha/kernel/pci_iommu.c Wed Jun 21 22:30:59 2000 @@ -97,8 +97,8 @@ } if (i < n) { - /* Reached the end. Flush the TLB and restart the - search from the beginning. */ + /* Reached the end. Flush the TLB and restart the + search from the beginning. */ alpha_mv.mv_pci_tbi(arena->hose, 0, -1); p = 0, i = 0; @@ -139,7 +139,7 @@ p[i] = 0; } -/* Map a single buffer of the indicate size for PCI DMA in streaming +/* Map a single buffer of the indicated size for PCI DMA in streaming mode. The 32-bit PCI bus mastering address to use is returned. Once the device is given the dma address, the device owns this memory until either pci_unmap_single or pci_dma_sync_single is performed. */ @@ -250,9 +250,12 @@ npages = calc_npages((dma_addr & ~PAGE_MASK) + size); iommu_arena_free(arena, dma_ofs, npages); - /* If we're freeing ptes above the `next_entry' pointer, they - may have snuck back into the TLB since the last wrap flush. - We need to flush the TLB before reallocating these. */ + + /* + If we're freeing ptes above the `next_entry' pointer (they + may have snuck back into the TLB since the last wrap flush), + we need to flush the TLB before reallocating the latter. + */ if (dma_ofs >= arena->next_entry) alpha_mv.mv_pci_tbi(hose, dma_addr, dma_addr + size - 1); @@ -574,9 +577,11 @@ if (fend < tend) fend = tend; } - /* If we're freeing ptes above the `next_entry' pointer, they - may have snuck back into the TLB since the last wrap flush. - We need to flush the TLB before reallocating these. */ + /* + If we're freeing ptes above the `next_entry' pointer (they + may have snuck back into the TLB since the last wrap flush), + we need to flush the TLB before reallocating the latter. + */ if ((fend - arena->dma_base) >> PAGE_SHIFT >= arena->next_entry) alpha_mv.mv_pci_tbi(hose, fbeg, fend); diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/kernel/proto.h linux/arch/alpha/kernel/proto.h --- v2.4.0-test1/linux/arch/alpha/kernel/proto.h Wed Apr 26 16:34:06 2000 +++ linux/arch/alpha/kernel/proto.h Mon Jun 19 17:59:32 2000 @@ -61,6 +61,13 @@ extern void t2_machine_check(u64, u64, struct pt_regs *); #define t2_pci_tbi ((void *)0) +/* core_titan.c */ +extern struct pci_ops titan_pci_ops; +extern void titan_init_arch(void); +extern void titan_kill_arch(int); +extern void titan_machine_check(u64, u64, struct pt_regs *); +extern void titan_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t); + /* core_tsunami.c */ extern struct pci_ops tsunami_pci_ops; extern void tsunami_init_arch(void); @@ -68,9 +75,19 @@ extern void tsunami_machine_check(u64, u64, struct pt_regs *); extern void tsunami_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t); +/* core_wildfire.c */ +extern struct pci_ops wildfire_pci_ops; +extern void wildfire_init_arch(void); +extern void wildfire_kill_arch(int); +extern void wildfire_machine_check(u64, u64, struct pt_regs *); +extern void wildfire_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t); + /* setup.c */ extern unsigned long srm_hae; extern int boot_cpuid; +extern int srmcons_output; +extern void register_srm_console(void); +extern void unregister_srm_console(void); /* smp.c */ extern void setup_smp(void); @@ -129,7 +146,8 @@ extern void die_if_kernel(char *, struct pt_regs *, long, unsigned long *); /* ../mm/init.c */ -void srm_paging_stop(void); +extern void switch_to_system_map(void); +extern void srm_paging_stop(void); /* irq.c */ diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/kernel/ptrace.c linux/arch/alpha/kernel/ptrace.c --- v2.4.0-test1/linux/arch/alpha/kernel/ptrace.c Mon Mar 27 08:08:21 2000 +++ linux/arch/alpha/kernel/ptrace.c Mon Jun 19 17:59:32 2000 @@ -246,18 +246,23 @@ ret = -EPERM; if (request == PTRACE_TRACEME) { /* are we already being traced? */ - if (current->flags & PF_PTRACED) - goto out; - /* set the ptrace bit in the process flags. */ - current->flags |= PF_PTRACED; + if (current->ptrace & PT_PTRACED) + goto out_notsk; + /* set the ptrace bit in the process ptrace flags. */ + current->ptrace |= PT_PTRACED; ret = 0; - goto out; + goto out_notsk; } if (pid == 1) /* you may not mess with init */ - goto out; + goto out_notsk; ret = -ESRCH; - if (!(child = find_task_by_pid(pid))) - goto out; + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + if (child) + get_task_struct(child); + read_unlock(&tasklist_lock); + if (!child) + goto out_notsk; if (request == PTRACE_ATTACH) { ret = -EPERM; if (child == current) @@ -273,20 +278,22 @@ && !capable(CAP_SYS_PTRACE)) goto out; /* the same process cannot be attached many times */ - if (child->flags & PF_PTRACED) + if (child->ptrace & PT_PTRACED) goto out; - child->flags |= PF_PTRACED; + child->ptrace |= PT_PTRACED; + write_lock_irq(&tasklist_lock); if (child->p_pptr != current) { REMOVE_LINKS(child); child->p_pptr = current; SET_LINKS(child); } + write_unlock_irq(&tasklist_lock); send_sig(SIGSTOP, child, 1); ret = 0; goto out; } ret = -ESRCH; - if (!(child->flags & PF_PTRACED)) { + if (!(child->ptrace & PT_PTRACED)) { DBG(DBG_MEM, ("child not traced\n")); goto out; } @@ -343,9 +350,9 @@ if ((unsigned long) data > _NSIG) goto out; if (request == PTRACE_SYSCALL) - child->flags |= PF_TRACESYS; + child->ptrace |= PT_TRACESYS; else - child->flags &= ~PF_TRACESYS; + child->ptrace &= ~PT_TRACESYS; child->exit_code = data; wake_up_process(child); /* make sure single-step breakpoint is gone. */ @@ -373,7 +380,7 @@ if ((unsigned long) data > _NSIG) goto out; child->thread.bpt_nsaved = -1; /* mark single-stepping */ - child->flags &= ~PF_TRACESYS; + child->ptrace &= ~PT_TRACESYS; wake_up_process(child); child->exit_code = data; /* give it a chance to run. */ @@ -384,12 +391,14 @@ ret = -EIO; if ((unsigned long) data > _NSIG) goto out; - child->flags &= ~(PF_PTRACED|PF_TRACESYS); + child->ptrace &= ~(PT_PTRACED|PT_TRACESYS); wake_up_process(child); child->exit_code = data; + write_lock_irq(&tasklist_lock); REMOVE_LINKS(child); child->p_pptr = child->p_opptr; SET_LINKS(child); + write_unlock_irq(&tasklist_lock); /* make sure single-step breakpoint is gone. */ ptrace_cancel_bpt(child); ret = 0; @@ -400,6 +409,8 @@ goto out; } out: + free_task_struct(child); + out_notsk: unlock_kernel(); return ret; } @@ -407,8 +418,8 @@ asmlinkage void syscall_trace(void) { - if ((current->flags & (PF_PTRACED|PF_TRACESYS)) - != (PF_PTRACED|PF_TRACESYS)) + if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) + != (PT_PTRACED|PT_TRACESYS)) return; current->exit_code = SIGTRAP; current->state = TASK_STOPPED; diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c --- v2.4.0-test1/linux/arch/alpha/kernel/setup.c Wed Apr 26 16:34:06 2000 +++ linux/arch/alpha/kernel/setup.c Mon Jun 19 17:59:32 2000 @@ -34,6 +34,15 @@ #include #endif +#include +extern struct notifier_block *panic_notifier_list; +static int alpha_panic_event(struct notifier_block *, unsigned long, void *); +static struct notifier_block alpha_panic_block = { + alpha_panic_event, + NULL, + INT_MAX /* try to do it first */ +}; + #include #include #include @@ -42,6 +51,7 @@ #include #include #include +#include #include "proto.h" #include "pci_impl.h" @@ -53,6 +63,17 @@ /* Which processor we booted from. */ int boot_cpuid; +/* Using SRM callbacks for initial console output. This works from + setup_arch() time through the end of init_IRQ(), as those places + are under our control. + + By default, OFF; set it with a bootcommand arg of "srmcons". +*/ +int srmcons_output = 0; + +/* Enforce a memory size limit; useful for testing. By default, none. */ +unsigned long mem_size_limit = 0; + #ifdef CONFIG_ALPHA_GENERIC struct alpha_machine_vector alpha_mv; int alpha_using_srm; @@ -139,6 +160,7 @@ WEAK(noritake_primo_mv); WEAK(p2k_mv); WEAK(pc164_mv); +WEAK(privateer_mv); WEAK(rawhide_mv); WEAK(ruffian_mv); WEAK(rx164_mv); @@ -147,6 +169,7 @@ WEAK(sx164_mv); WEAK(takara_mv); WEAK(webbrick_mv); +WEAK(wildfire_mv); WEAK(xl_mv); WEAK(xlt_mv); @@ -202,14 +225,33 @@ for ((cluster) = (memdesc)->cluster, (i) = 0; \ (i) < (memdesc)->numclusters; (i)++, (cluster)++) +static unsigned long __init +get_mem_size_limit(char *s) +{ + unsigned long end = 0; + char *from = s; + + end = simple_strtoul(from, &from, 0); + if ( *from == 'K' || *from == 'k' ) { + end = end << 10; + from++; + } else if ( *from == 'M' || *from == 'm' ) { + end = end << 20; + from++; + } else if ( *from == 'G' || *from == 'g' ) { + end = end << 30; + from++; + } + return end >> PAGE_SHIFT; /* Return the PFN of the limit. */ +} + static void __init -setup_memory(void) +setup_memory(void * kernel_end) { struct memclust_struct * cluster; struct memdesc_struct * memdesc; unsigned long start_pfn, bootmap_size, bootmap_pages, bootmap_start; unsigned long start, end; - extern char _end[]; int i; /* Find free clusters, and init and free the bootmem accordingly. */ @@ -232,15 +274,23 @@ max_low_pfn = end; } - /* Find the end of the kernel memory. */ - start_pfn = PFN_UP(virt_to_phys(_end)); + if (mem_size_limit && max_low_pfn >= mem_size_limit) + { + printk("setup: forcing memory size to %ldK (from %ldK).\n", + mem_size_limit << (PAGE_SHIFT - 10), + max_low_pfn << (PAGE_SHIFT - 10)); + max_low_pfn = mem_size_limit; + } + + /* Find the end of the memory used by the kernel. */ + start_pfn = PFN_UP(virt_to_phys(kernel_end)); bootmap_start = -1; try_again: if (max_low_pfn <= start_pfn) panic("not enough memory to boot"); - /* We need to know how many physically contigous pages + /* We need to know how many physically contiguous pages we'll need for the bootmap. */ bootmap_pages = bootmem_bootmap_pages(max_low_pfn); @@ -307,14 +357,14 @@ printk("Initial ramdisk at: 0x%p (%lu bytes)\n", (void *) initrd_start, INITRD_SIZE); - if (initrd_end > phys_to_virt(PFN_PHYS(max_low_pfn))) { + if ((void *)initrd_end > phys_to_virt(PFN_PHYS(max_low_pfn))) { printk("initrd extends beyond end of memory " - "(0x%08lx > 0x%08lx)\ndisabling initrd\n", + "(0x%08lx > 0x%p)\ndisabling initrd\n", initrd_end, phys_to_virt(PFN_PHYS(max_low_pfn))); initrd_start = initrd_end = 0; } else { - reserve_bootmem(virt_to_phys(initrd_start), + reserve_bootmem(virt_to_phys((void *)initrd_start), INITRD_SIZE); } } @@ -346,20 +396,98 @@ #undef PFN_PHYS #undef PFN_MAX +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM) +/* + * Manage the SRM callbacks as a "console". + */ +static struct console srmcons; + +void __init register_srm_console(void) +{ + register_console(&srmcons); +} + +void __init unregister_srm_console(void) +{ + unregister_console(&srmcons); +} + +static void srm_console_write(struct console *co, const char *s, + unsigned count) +{ + srm_printk(s); +} + +static kdev_t srm_console_device(struct console *c) +{ + /* Huh? */ + return MKDEV(TTY_MAJOR, 64 + c->index); +} + +static int srm_console_wait_key(struct console *co) +{ + /* Huh? */ + return 1; +} + +static int __init srm_console_setup(struct console *co, char *options) +{ + return 1; +} + +static struct console srmcons = { + "srm0", + srm_console_write, + NULL, + srm_console_device, + srm_console_wait_key, + NULL, + srm_console_setup, + CON_PRINTBUFFER | CON_ENABLED, /* fake it out */ + -1, + 0, + NULL +}; + +#else +void __init register_srm_console(void) +{ +} +void __init unregister_srm_console(void) +{ +} +#endif + void __init setup_arch(char **cmdline_p) { struct alpha_machine_vector *vec = NULL; struct percpu_struct *cpu; char *type_name, *var_name, *p; + extern char _end; + void * kernel_end = &_end; /* end of kernel */ hwrpb = (struct hwrpb_struct*) __va(INIT_HWRPB->phys_addr); boot_cpuid = hard_smp_processor_id(); + /* Register a call for panic conditions. */ + notifier_chain_register(&panic_notifier_list, &alpha_panic_block); + +#ifdef CONFIG_ALPHA_GENERIC + /* Assume that we've booted from SRM if we havn't booted from MILO. + Detect the later by looking for "MILO" in the system serial nr. */ + alpha_using_srm = strncmp((const char *)hwrpb->ssn, "MILO", 4) != 0; +#endif + + /* If we are using SRM, we want to allow callbacks + as early as possible, so do this NOW, and then + they should work immediately thereafter. + */ + kernel_end = callback_init(kernel_end); + /* * Locate the command line. */ - /* Hack for Jensen... since we're restricted to 8 or 16 chars for boot flags depending on the boot mode, we need some shorthand. This should do for installation. */ @@ -375,7 +503,6 @@ /* * Process command-line arguments. */ - for (p = strtok(command_line, " \t"); p ; p = strtok(NULL, " \t")) { if (strncmp(p, "alpha_mv=", 9) == 0) { vec = get_sysvec_byname(p+9); @@ -385,15 +512,27 @@ est_cycle_freq = simple_strtol(p+6, NULL, 0); continue; } + if (strncmp(p, "mem=", 4) == 0) { + mem_size_limit = get_mem_size_limit(p+4); + continue; + } + if (strncmp(p, "srmcons", 7) == 0) { + srmcons_output = 1; + continue; + } } - /* Replace the command line, not that we've killed it with strtok. */ + /* Replace the command line, now that we've killed it with strtok. */ strcpy(command_line, saved_command_line); + /* If we want SRM console printk echoing early, do it now. */ + if (alpha_using_srm && srmcons_output) { + register_srm_console(); + } + /* * Indentify and reconfigure for the current system. */ - get_sysnames(hwrpb->sys_type, hwrpb->sys_variation, &type_name, &var_name); if (*var_name == '0') @@ -415,12 +554,6 @@ alpha_mv = *vec; } -#ifdef CONFIG_ALPHA_GENERIC - /* Assume that we've booted from SRM if we havn't booted from MILO. - Detect the later by looking for "MILO" in the system serial nr. */ - alpha_using_srm = strncmp((const char *)hwrpb->ssn, "MILO", 4) != 0; -#endif - printk("Booting " #ifdef CONFIG_ALPHA_GENERIC "GENERIC " @@ -433,10 +566,9 @@ printk("Command line: %s\n", command_line); /* - * Sync with the HAE + * Sync up the HAE. + * Save the SRM's current value for restoration. */ - - /* Save the SRM's current value for restoration. */ srm_hae = *alpha_mv.hae_register; __set_hae(alpha_mv.hae_cache); @@ -444,7 +576,7 @@ wrmces(0x7); /* Find our memory. */ - setup_memory(); + setup_memory(kernel_end); /* Initialize the machine. Usually has to do with setting up DMA windows and the like. */ @@ -499,7 +631,7 @@ "Mikasa", "EB64", "EB66", "EB64+", "AlphaBook1", "Rawhide", "K2", "Lynx", "XL", "EB164", "Noritake", "Cortex", "29", "Miata", "XXM", "Takara", "Yukon", - "Tsunami", "Wildfire", "CUSCO", "Eiger" + "Tsunami", "Wildfire", "CUSCO", "Eiger", "Titan" }; static char unofficial_names[][8] = {"100", "Ruffian"}; @@ -523,6 +655,11 @@ }; static int rawhide_indices[] = {0,0,0,1,1,2,2,3,3,4,4}; +static char titan_names[][16] = { + "0", "Privateer" +}; +static int titan_indices[] = {0,1}; + static char tsunami_names[][16] = { "0", "DP264", "Warhol", "Windjammer", "Monet", "Clipper", "Goldrush", "Webbrick", "Catamaran" @@ -569,9 +706,10 @@ &takara_mv, NULL, /* Yukon */ NULL, /* Tsunami -- see variation. */ - NULL, /* Wildfire */ + &wildfire_mv, /* Wildfire */ NULL, /* CUSCO */ &eiger_mv, /* Eiger */ + NULL, /* Titan */ }; static struct alpha_machine_vector *unofficial_vecs[] __initlocaldata = @@ -609,6 +747,12 @@ &eb66p_mv }; + static struct alpha_machine_vector *titan_vecs[] __initlocaldata = + { + NULL, + &privateer_mv, /* privateer */ + }; + static struct alpha_machine_vector *tsunami_vecs[] __initlocaldata = { NULL, @@ -665,6 +809,10 @@ if (member < N(eb66_indices)) vec = eb66_vecs[eb66_indices[member]]; break; + case ST_DEC_TITAN: + if (member < N(titan_indices)) + vec = titan_vecs[titan_indices[member]]; + break; case ST_DEC_TSUNAMI: if (member < N(tsunami_indices)) vec = tsunami_vecs[tsunami_indices[member]]; @@ -723,6 +871,7 @@ &noritake_primo_mv, &p2k_mv, &pc164_mv, + &privateer_mv, &rawhide_mv, &ruffian_mv, &rx164_mv, @@ -731,6 +880,7 @@ &sx164_mv, &takara_mv, &webbrick_mv, + &wildfire_mv, &xl_mv, &xlt_mv }; @@ -801,6 +951,10 @@ if (member < N(rawhide_indices)) *variation_name = rawhide_names[rawhide_indices[member]]; break; + case ST_DEC_TITAN: + if (member < N(titan_indices)) + *variation_name = titan_names[titan_indices[member]]; + break; case ST_DEC_TSUNAMI: if (member < N(tsunami_indices)) *variation_name = tsunami_names[tsunami_indices[member]]; @@ -873,7 +1027,7 @@ static char cpu_names[][8] = { "EV3", "EV4", "Simulate", "LCA4", "EV5", "EV45", "EV56", - "EV6", "PCA56", "PCA57", "EV67" + "EV6", "PCA56", "PCA57", "EV67", "EV68CB", "EV68AL" }; struct percpu_struct *cpu; @@ -935,4 +1089,17 @@ #endif return len; +} + +static int alpha_panic_event(struct notifier_block *this, + unsigned long event, + void *ptr) +{ +#if 1 + /* FIXME FIXME FIXME */ + /* If we are using SRM and serial console, just hard halt here. */ + if (alpha_using_srm && srmcons_output) + __halt(); +#endif + return NOTIFY_DONE; } diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/kernel/signal.c linux/arch/alpha/kernel/signal.c --- v2.4.0-test1/linux/arch/alpha/kernel/signal.c Mon Jun 19 16:31:56 2000 +++ linux/arch/alpha/kernel/signal.c Mon Jun 19 17:59:32 2000 @@ -651,7 +651,7 @@ if (!signr) break; - if ((current->flags & PF_PTRACED) && signr != SIGKILL) { + if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { /* Let the debugger run. */ current->exit_code = signr; current->state = TASK_STOPPED; diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/kernel/smc37c669.c linux/arch/alpha/kernel/smc37c669.c --- v2.4.0-test1/linux/arch/alpha/kernel/smc37c669.c Sun Feb 21 19:06:36 1999 +++ linux/arch/alpha/kernel/smc37c669.c Mon Jun 19 17:59:32 2000 @@ -2588,6 +2588,9 @@ ); SMC37c669_enable_device( FLOPPY_0 ); + /* Wake up sometimes forgotten floppy, especially on DP264. */ + outb(0xc, 0x3f2); + SMC37c669_disable_device( IDE_0 ); #if SMC_DEBUG diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c --- v2.4.0-test1/linux/arch/alpha/kernel/smp.c Sun Mar 19 18:35:30 2000 +++ linux/arch/alpha/kernel/smp.c Mon Jun 19 17:59:32 2000 @@ -212,8 +212,19 @@ freq = hwrpb->cycle_freq ? : est_cycle_freq; +#if 0 /* Magic estimation stolen from x86 port. */ - cacheflush_time = freq / 1024 * on_chip_cache / 5000; + cacheflush_time = freq / 1024L * on_chip_cache / 5000L; + + printk("Using heuristic of %d cycles.\n", + cacheflush_time); +#else + /* Magic value to force potential preemption of other CPUs. */ + cacheflush_time = INT_MAX; + + printk("Using heuristic of %d cycles.\n", + cacheflush_time); +#endif } /* @@ -325,8 +336,8 @@ } } - printk(KERN_INFO "recv_secondary_console_msg: on %d " - "message is '%s'\n", mycpu, buf); + DBGS((KERN_INFO "recv_secondary_console_msg: on %d " + "message is '%s'\n", mycpu, buf)); } hwrpb->txrdy = 0; @@ -361,8 +372,10 @@ hwpcb->flags = idle->thread.pal_flags; hwpcb->res1 = hwpcb->res2 = 0; +#if 0 DBGS(("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx UNIQUE 0x%lx\n", hwpcb->ksp, hwpcb->ptbr, hwrpb->vptb, hwcpb->unique)); +#endif DBGS(("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n", cpuid, idle->state, idle->thread.pal_flags)); @@ -738,8 +751,10 @@ unsigned long *pending_ipis = &ipi_data[this_cpu].bits; unsigned long ops; - DBGS(("handle_ipi: on CPU %d ops 0x%x PC 0x%lx\n", +#if 0 + DBGS(("handle_ipi: on CPU %d ops 0x%lx PC 0x%lx\n", this_cpu, *pending_ipis, regs->pc)); +#endif mb(); /* Order interrupt and bit testing. */ while ((ops = xchg(pending_ipis, 0)) != 0) { diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/kernel/sys_dp264.c linux/arch/alpha/kernel/sys_dp264.c --- v2.4.0-test1/linux/arch/alpha/kernel/sys_dp264.c Sun Mar 19 18:35:30 2000 +++ linux/arch/alpha/kernel/sys_dp264.c Wed Jun 21 22:30:59 2000 @@ -36,7 +36,7 @@ /* Note mask bit is true for ENABLED irqs. */ static unsigned long cached_irq_mask; /* dp264 boards handle at max four CPUs */ -static unsigned long cpu_irq_affinity[4] = { ~0UL, ~0UL, ~0UL, ~0UL }; +static unsigned long cpu_irq_affinity[4] = { 0UL, 0UL, 0UL, 0UL }; spinlock_t dp264_irq_lock = SPIN_LOCK_UNLOCKED; @@ -52,6 +52,7 @@ volatile unsigned long *dim0, *dim1, *dim2, *dim3; unsigned long mask0, mask1, mask2, mask3, dummy; + mask &= ~isa_enable; mask0 = mask & cpu_irq_affinity[0]; mask1 = mask & cpu_irq_affinity[1]; mask2 = mask & cpu_irq_affinity[2]; @@ -170,7 +171,6 @@ aff &= ~(1UL << irq); cpu_irq_affinity[cpu] = aff; } - } static void @@ -275,7 +275,7 @@ irq = (vector - 0x800) >> 4; - /* +/* * The SRM console reports PCI interrupts with a vector calculated by: * * 0x900 + (0x10 * DRIR-bit) diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/kernel/sys_mikasa.c linux/arch/alpha/kernel/sys_mikasa.c --- v2.4.0-test1/linux/arch/alpha/kernel/sys_mikasa.c Sun Mar 19 18:35:30 2000 +++ linux/arch/alpha/kernel/sys_mikasa.c Mon Jun 19 17:59:32 2000 @@ -185,8 +185,8 @@ mikasa_apecs_machine_check(unsigned long vector, unsigned long la_ptr, struct pt_regs * regs) { -#define MCHK_NO_DEVSEL 0x205L -#define MCHK_NO_TABT 0x204L +#define MCHK_NO_DEVSEL 0x205U +#define MCHK_NO_TABT 0x204U struct el_common *mchk_header; unsigned int code; diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/kernel/sys_titan.c linux/arch/alpha/kernel/sys_titan.c --- v2.4.0-test1/linux/arch/alpha/kernel/sys_titan.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/kernel/sys_titan.c Mon Jun 19 17:59:32 2000 @@ -0,0 +1,393 @@ +/* + * linux/arch/alpha/kernel/sys_titan.c + * + * Copyright (C) 1995 David A Rusling + * Copyright (C) 1996, 1999 Jay A Estabrook + * Copyright (C) 1998, 1999 Richard Henderson + * Copyright (C) 1999, 2000 Jeff Wiedemeier + * + * Code supporting TITAN systems (EV6+TITAN), currently: + * Privateer + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "proto.h" +#include "irq_impl.h" +#include "pci_impl.h" +#include "machvec_impl.h" + +/* Note mask bit is true for ENABLED irqs. */ +static unsigned long cached_irq_mask; +/* Titan boards handle at most four CPUs. */ +static unsigned long cpu_irq_affinity[4] = { ~0UL, ~0UL, ~0UL, ~0UL }; + +spinlock_t titan_irq_lock = SPIN_LOCK_UNLOCKED; + +static void +titan_update_irq_hw(unsigned long mask) +{ + register titan_cchip *cchip = TITAN_cchip; + unsigned long isa_enable = 1UL << 55; + register int bcpu = boot_cpuid; + +#ifdef CONFIG_SMP + register unsigned long cpm = cpu_present_mask; + volatile unsigned long *dim0, *dim1, *dim2, *dim3; + unsigned long mask0, mask1, mask2, mask3, dummy; + + mask &= ~isa_enable; + mask0 = mask & cpu_irq_affinity[0]; + mask1 = mask & cpu_irq_affinity[1]; + mask2 = mask & cpu_irq_affinity[2]; + mask3 = mask & cpu_irq_affinity[3]; + + if (bcpu == 0) mask0 |= isa_enable; + else if (bcpu == 1) mask1 |= isa_enable; + else if (bcpu == 2) mask2 |= isa_enable; + else mask3 |= isa_enable; + + dim0 = &cchip->dim0.csr; + dim1 = &cchip->dim1.csr; + dim2 = &cchip->dim2.csr; + dim3 = &cchip->dim3.csr; + if ((cpm & 1) == 0) dim0 = &dummy; + if ((cpm & 2) == 0) dim1 = &dummy; + if ((cpm & 4) == 0) dim2 = &dummy; + if ((cpm & 8) == 0) dim3 = &dummy; + + *dim0 = mask0; + *dim1 = mask1; + *dim2 = mask2; + *dim3 = mask3; + mb(); + *dim0; + *dim1; + *dim2; + *dim3; +#else + volatile unsigned long *dimB; + if (bcpu == 0) dimB = &cchip->dim0.csr; + else if (bcpu == 1) dimB = &cchip->dim1.csr; + else if (bcpu == 2) dimB = &cchip->dim2.csr; + else if (bcpu == 3) dimB = &cchip->dim3.csr; + + *dimB = mask | isa_enable; + mb(); + *dimB; +#endif +} + +static inline void +privateer_enable_irq(unsigned int irq) +{ + spin_lock(&titan_irq_lock); + cached_irq_mask |= 1UL << (irq - 16); + titan_update_irq_hw(cached_irq_mask); + spin_unlock(&titan_irq_lock); +} + +static inline void +privateer_disable_irq(unsigned int irq) +{ + spin_lock(&titan_irq_lock); + cached_irq_mask &= ~(1UL << (irq - 16)); + titan_update_irq_hw(cached_irq_mask); + spin_unlock(&titan_irq_lock); +} + +static unsigned int +privateer_startup_irq(unsigned int irq) +{ + privateer_enable_irq(irq); + return 0; /* never anything pending */ +} + +static void +privateer_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + privateer_enable_irq(irq); +} + +static void +cpu_set_irq_affinity(unsigned int irq, unsigned long affinity) +{ + int cpu; + + for (cpu = 0; cpu < 4; cpu++) { + if (affinity & (1UL << cpu)) + cpu_irq_affinity[cpu] |= 1UL << irq; + else + cpu_irq_affinity[cpu] &= ~(1UL << irq); + } + +} + +static void +privateer_set_affinity(unsigned int irq, unsigned long affinity) +{ + spin_lock(&titan_irq_lock); + cpu_set_irq_affinity(irq - 16, affinity); + titan_update_irq_hw(cached_irq_mask); + spin_unlock(&titan_irq_lock); +} + +static struct hw_interrupt_type privateer_irq_type = { + typename: "PRIVATEER", + startup: privateer_startup_irq, + shutdown: privateer_disable_irq, + enable: privateer_enable_irq, + disable: privateer_disable_irq, + ack: privateer_disable_irq, + end: privateer_end_irq, + set_affinity: privateer_set_affinity, +}; + +static void +privateer_device_interrupt(unsigned long vector, struct pt_regs * regs) +{ + printk("privateer_device_interrupt: NOT IMPLEMENTED YET!! \n"); +} + +static void +privateer_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) +{ + int irq; + + irq = (vector - 0x800) >> 4; + handle_irq(irq, regs); +} + + +static void __init +init_titan_irqs(struct hw_interrupt_type * ops, int imin, int imax) +{ + long i; + for(i = imin; i <= imax; ++i) { + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[i].handler = ops; + } +} + +static void __init +privateer_init_irq(void) +{ + extern asmlinkage void entInt(void); + int cpu; + + outb(0, DMA1_RESET_REG); + outb(0, DMA2_RESET_REG); + outb(DMA_MODE_CASCADE, DMA2_MODE_REG); + outb(0, DMA2_MASK_REG); + + if (alpha_using_srm) + alpha_mv.device_interrupt = privateer_srm_device_interrupt; + + titan_update_irq_hw(0UL); + + init_i8259a_irqs(); + init_titan_irqs(&privateer_irq_type, 16, 63 + 16); +} + +/* + * Privateer PCI Fixup configuration. + * + * PCHIP 0 BUS 0 (Hose 0) + * + * IDSEL Dev What + * ----- --- ---- + * 18 7 Embedded Southbridge + * 19 8 Slot 0 + * 20 9 Slot 1 + * 21 10 Slot 2 + * 22 11 Slot 3 + * 23 12 Embedded HotPlug controller + * 27 16 Embedded Southbridge IDE + * 29 18 Embedded Southbridge PMU + * 31 20 Embedded Southbridge USB + * + * PCHIP 1 BUS 0 (Hose 1) + * + * IDSEL Dev What + * ----- --- ---- + * 12 1 Slot 0 + * 13 2 Slot 1 + * 17 6 Embedded hotPlug controller + * + * PCHIP 0 BUS 1 (Hose 2) + * + * IDSEL What + * ----- ---- + * NONE AGP + * + * PCHIP 1 BUS 1 (Hose 3) + * + * IDSEL Dev What + * ----- --- ---- + * 12 1 Slot 0 + * 13 2 Slot 1 + * 17 6 Embedded hotPlug controller + * + * Summary @ TITAN_CSR_DIM0: + * Bit Meaning + * 0-7 Unused + * 8 PCHIP 0 BUS 1 YUKON (if present) + * 9 PCHIP 1 BUS 1 YUKON + * 10 PCHIP 1 BUS 0 YUKON + * 11 PCHIP 0 BUS 0 YUKON + * 12 PCHIP 0 BUS 0 SLOT 2 INT A + * 13 PCHIP 0 BUS 0 SLOT 2 INT B + * 14 PCHIP 0 BUS 0 SLOT 2 INT C + * 15 PCHIP 0 BUS 0 SLOT 2 INT D + * 16 PCHIP 0 BUS 0 SLOT 3 INT A + * 17 PCHIP 0 BUS 0 SLOT 3 INT B + * 18 PCHIP 0 BUS 0 SLOT 3 INT C + * 19 PCHIP 0 BUS 0 SLOT 3 INT D + * 20 PCHIP 0 BUS 0 SLOT 0 INT A + * 21 PCHIP 0 BUS 0 SLOT 0 INT B + * 22 PCHIP 0 BUS 0 SLOT 0 INT C + * 23 PCHIP 0 BUS 0 SLOT 0 INT D + * 24 PCHIP 0 BUS 0 SLOT 1 INT A + * 25 PCHIP 0 BUS 0 SLOT 1 INT B + * 26 PCHIP 0 BUS 0 SLOT 1 INT C + * 27 PCHIP 0 BUS 0 SLOT 1 INT D + * 28 PCHIP 1 BUS 0 SLOT 0 INT A + * 29 PCHIP 1 BUS 0 SLOT 0 INT B + * 30 PCHIP 1 BUS 0 SLOT 0 INT C + * 31 PCHIP 1 BUS 0 SLOT 0 INT D + * 32 PCHIP 1 BUS 0 SLOT 1 INT A + * 33 PCHIP 1 BUS 0 SLOT 1 INT B + * 34 PCHIP 1 BUS 0 SLOT 1 INT C + * 35 PCHIP 1 BUS 0 SLOT 1 INT D + * 36 PCHIP 1 BUS 1 SLOT 0 INT A + * 37 PCHIP 1 BUS 1 SLOT 0 INT B + * 38 PCHIP 1 BUS 1 SLOT 0 INT C + * 39 PCHIP 1 BUS 1 SLOT 0 INT D + * 40 PCHIP 1 BUS 1 SLOT 1 INT A + * 41 PCHIP 1 BUS 1 SLOT 1 INT B + * 42 PCHIP 1 BUS 1 SLOT 1 INT C + * 43 PCHIP 1 BUS 1 SLOT 1 INT D + * 44 AGP INT A + * 45 AGP INT B + * 46-47 Unused + * 49 Reserved for Sleep mode + * 50 Temperature Warning (optional) + * 51 Power Warning (optional) + * 52 Reserved + * 53 South Bridge NMI + * 54 South Bridge SMI INT + * 55 South Bridge ISA Interrupt + * 56-58 Unused + * 59 PCHIP1_C_ERROR + * 60 PCHIP0_C_ERROR + * 61 PCHIP1_H_ERROR + * 62 PCHIP0_H_ERROR + * 63 Reserved + * + */ +static int __init +privateer_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + u8 irq; + + pcibios_read_config_byte(dev->bus->number, + dev->devfn, + PCI_INTERRUPT_LINE, + &irq); + + /* is it routed through ISA? */ + if ((irq & 0xF0) == 0xE0) + return (int)irq; + + return (int)irq + 16; /* HACK -- this better only be called once */ +} + +#ifdef CONFIG_VGA_HOSE +static struct pci_controler * __init +privateer_vga_hose_select(struct pci_controler *h1, struct pci_controler *h2) +{ + struct pci_controler *hose = h1; + int agp1, agp2; + + /* which hose(s) are agp? */ + agp1 = (0 != (TITAN_agp & (1 << h1->index))); + agp2 = (0 != (TITAN_agp & (1 << h2->index))); + + hose = h1; /* default to h1 */ + if (agp1 ^ agp2) { + if (agp2) hose = h2; /* take agp if only one */ + } else if (h2->index < h1->index) + hose = h2; /* first hose if 2xpci or 2xagp */ + + return hose; +} +#endif + +static void __init +privateer_init_pci(void) +{ + common_init_pci(); + SMC669_Init(0); +#ifdef CONFIG_VGA_HOSE + locate_and_init_vga(privateer_vga_hose_select); +#endif +} + +void +privateer_machine_check(unsigned long vector, unsigned long la_ptr, + struct pt_regs * regs) +{ + /* only handle system events here */ + if (vector != SCB_Q_SYSEVENT) + return titan_machine_check(vector, la_ptr, regs); + + /* it's a system event, handle it here */ + printk("PRIVATEER 680 Machine Check on CPU %d\n", smp_processor_id()); +} + + +/* + * The System Vectors + */ + +struct alpha_machine_vector privateer_mv __initmv = { + vector_name: "PRIVATEER", + DO_EV6_MMU, + DO_DEFAULT_RTC, + DO_TITAN_IO, + DO_TITAN_BUS, + machine_check: privateer_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: DEFAULT_MEM_BASE, + + nr_irqs: 80, /* 64 + 16 */ + device_interrupt: privateer_device_interrupt, + + init_arch: titan_init_arch, + init_irq: privateer_init_irq, + init_rtc: common_init_rtc, + init_pci: privateer_init_pci, + kill_arch: titan_kill_arch, + pci_map_irq: privateer_map_irq, + pci_swizzle: common_swizzle, +}; +ALIAS_MV(privateer) diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/kernel/sys_wildfire.c linux/arch/alpha/kernel/sys_wildfire.c --- v2.4.0-test1/linux/arch/alpha/kernel/sys_wildfire.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/kernel/sys_wildfire.c Mon Jun 19 17:59:32 2000 @@ -0,0 +1,361 @@ +/* + * linux/arch/alpha/kernel/sys_wildfire.c + * + * Wildfire support. + * + * Copyright (C) 2000 Andrea Arcangeli SuSE + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "proto.h" +#include "irq_impl.h" +#include "pci_impl.h" +#include "machvec_impl.h" + +static unsigned long cached_irq_mask[WILDFIRE_NR_IRQS/(sizeof(long)*8)]; + +spinlock_t wildfire_irq_lock = SPIN_LOCK_UNLOCKED; + +static int doing_init_irq_hw = 0; + +static void +wildfire_update_irq_hw(unsigned int irq) +{ + int qbbno = (irq >> 8) & (WILDFIRE_MAX_QBB - 1); + int pcano = (irq >> 6) & (WILDFIRE_PCA_PER_QBB - 1); + wildfire_pca *pca; + volatile unsigned long * enable0; + + if (!WILDFIRE_PCA_EXISTS(qbbno, pcano)) { + if (!doing_init_irq_hw) { + printk(KERN_ERR "wildfire_update_irq_hw:" + " got irq %d for non-existent PCA %d" + " on QBB %d.\n", + irq, pcano, qbbno); + } + return; + } + + pca = WILDFIRE_pca(qbbno, pcano); + enable0 = (unsigned long *) &pca->pca_int[0].enable; /* ??? */ + + *enable0 = cached_irq_mask[qbbno * WILDFIRE_PCA_PER_QBB + pcano]; + mb(); + *enable0; +} + +static void __init +wildfire_init_irq_hw(void) +{ +#if 0 + register wildfire_pca * pca = WILDFIRE_pca(0, 0); + volatile unsigned long * enable0, * enable1, * enable2, *enable3; + volatile unsigned long * target0, * target1, * target2, *target3; + + enable0 = (unsigned long *) &pca->pca_int[0].enable; + enable1 = (unsigned long *) &pca->pca_int[1].enable; + enable2 = (unsigned long *) &pca->pca_int[2].enable; + enable3 = (unsigned long *) &pca->pca_int[3].enable; + + target0 = (unsigned long *) &pca->pca_int[0].target; + target1 = (unsigned long *) &pca->pca_int[1].target; + target2 = (unsigned long *) &pca->pca_int[2].target; + target3 = (unsigned long *) &pca->pca_int[3].target; + + *enable0 = *enable1 = *enable2 = *enable3 = 0; + + *target0 = (1UL<<8) | WILDFIRE_QBB(0); + *target1 = *target2 = *target3 = 0; + + mb(); + + *enable0; *enable1; *enable2; *enable3; + *target0; *target1; *target2; *target3; + +#else + int i; + + doing_init_irq_hw = 1; + + /* Need to update only once for every possible PCA. */ + for (i = 0; i < WILDFIRE_NR_IRQS; i+=WILDFIRE_IRQ_PER_PCA) + wildfire_update_irq_hw(i); + + doing_init_irq_hw = 0; +#endif +} + +static void +wildfire_enable_irq(unsigned int irq) +{ + if (irq < 16) + i8259a_enable_irq(irq); + + spin_lock(&wildfire_irq_lock); + set_bit(irq, &cached_irq_mask); + wildfire_update_irq_hw(irq); + spin_unlock(&wildfire_irq_lock); +} + +static void +wildfire_disable_irq(unsigned int irq) +{ + if (irq < 16) + i8259a_disable_irq(irq); + + spin_lock(&wildfire_irq_lock); + clear_bit(irq, &cached_irq_mask); + wildfire_update_irq_hw(irq); + spin_unlock(&wildfire_irq_lock); +} + +static void +wildfire_mask_and_ack_irq(unsigned int irq) +{ + if (irq < 16) + i8259a_mask_and_ack_irq(irq); + + spin_lock(&wildfire_irq_lock); + clear_bit(irq, &cached_irq_mask); + wildfire_update_irq_hw(irq); + spin_unlock(&wildfire_irq_lock); +} + +static unsigned int +wildfire_startup_irq(unsigned int irq) +{ + wildfire_enable_irq(irq); + return 0; /* never anything pending */ +} + +static void +wildfire_end_irq(unsigned int irq) +{ +#if 0 + if (!irq_desc[irq].action) + printk("got irq %d\n", irq); +#endif + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + wildfire_enable_irq(irq); +} + +static struct hw_interrupt_type wildfire_irq_type = { + typename: "WILDFIRE", + startup: wildfire_startup_irq, + shutdown: wildfire_disable_irq, + enable: wildfire_enable_irq, + disable: wildfire_disable_irq, + ack: wildfire_mask_and_ack_irq, + end: wildfire_end_irq, +}; + +static void __init +wildfire_init_irq_per_pca(int qbbno, int pcano) +{ + int i, irq_bias; + unsigned long io_bias; + static struct irqaction isa_enable = { + handler: no_action, + name: "isa_enable", + }; + + irq_bias = qbbno * (WILDFIRE_PCA_PER_QBB * WILDFIRE_IRQ_PER_PCA) + + pcano * WILDFIRE_IRQ_PER_PCA; + + /* Only need the following for first PCI bus per PCA. */ + io_bias = WILDFIRE_IO(qbbno, pcano<<1) - WILDFIRE_IO_BIAS; + +#if 0 + outb(0, DMA1_RESET_REG + io_bias); + outb(0, DMA2_RESET_REG + io_bias); + outb(DMA_MODE_CASCADE, DMA2_MODE_REG + io_bias); + outb(0, DMA2_MASK_REG + io_bias); +#endif + +#if 0 + /* ??? Not sure how to do this, yet... */ + init_i8259a_irqs(); /* ??? */ +#endif + + for (i = 0; i < 16; ++i) { + if (i == 2) + continue; + irq_desc[i+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[i+irq_bias].handler = &wildfire_irq_type; + } + + irq_desc[36+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[36+irq_bias].handler = &wildfire_irq_type; + for (i = 40; i < 64; ++i) { + irq_desc[i+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[i+irq_bias].handler = &wildfire_irq_type; + } + + setup_irq(32+irq_bias, &isa_enable); +} + +static void __init +wildfire_init_irq(void) +{ + int qbbno, pcano; + +#if 1 + wildfire_init_irq_hw(); + init_i8259a_irqs(); +#endif + + for (qbbno = 0; qbbno < WILDFIRE_MAX_QBB; qbbno++) { + if (WILDFIRE_QBB_EXISTS(qbbno)) { + for (pcano = 0; pcano < WILDFIRE_PCA_PER_QBB; pcano++) { + if (WILDFIRE_PCA_EXISTS(qbbno, pcano)) { + wildfire_init_irq_per_pca(qbbno, pcano); + } + } + } + } +} + +static void +wildfire_device_interrupt(unsigned long vector, struct pt_regs * regs) +{ + int irq; + + irq = (vector - 0x800) >> 4; + + /* + * bits 10-8: source QBB ID + * bits 7-6: PCA + * bits 5-0: irq in PCA + */ + + handle_irq(irq, regs); + return; +} + +/* + * PCI Fixup configuration. + * + * Summary per PCA (2 PCI or HIPPI buses): + * + * Bit Meaning + * 0-15 ISA + * + *32 ISA summary + *33 SMI + *34 NMI + *36 builtin QLogic SCSI (or slot 0 if no IO module) + *40 Interrupt Line A from slot 2 PCI0 + *41 Interrupt Line B from slot 2 PCI0 + *42 Interrupt Line C from slot 2 PCI0 + *43 Interrupt Line D from slot 2 PCI0 + *44 Interrupt Line A from slot 3 PCI0 + *45 Interrupt Line B from slot 3 PCI0 + *46 Interrupt Line C from slot 3 PCI0 + *47 Interrupt Line D from slot 3 PCI0 + * + *48 Interrupt Line A from slot 4 PCI1 + *49 Interrupt Line B from slot 4 PCI1 + *50 Interrupt Line C from slot 4 PCI1 + *51 Interrupt Line D from slot 4 PCI1 + *52 Interrupt Line A from slot 5 PCI1 + *53 Interrupt Line B from slot 5 PCI1 + *54 Interrupt Line C from slot 5 PCI1 + *55 Interrupt Line D from slot 5 PCI1 + *56 Interrupt Line A from slot 6 PCI1 + *57 Interrupt Line B from slot 6 PCI1 + *58 Interrupt Line C from slot 6 PCI1 + *50 Interrupt Line D from slot 6 PCI1 + *60 Interrupt Line A from slot 7 PCI1 + *61 Interrupt Line B from slot 7 PCI1 + *62 Interrupt Line C from slot 7 PCI1 + *63 Interrupt Line D from slot 7 PCI1 + * + * + * IdSel + * 0 Cypress Bridge I/O (ISA summary interrupt) + * 1 64 bit PCI 0 option slot 1 (SCSI QLogic builtin) + * 2 64 bit PCI 0 option slot 2 + * 3 64 bit PCI 0 option slot 3 + * 4 64 bit PCI 1 option slot 4 + * 5 64 bit PCI 1 option slot 5 + * 6 64 bit PCI 1 option slot 6 + * 7 64 bit PCI 1 option slot 7 + */ + +static int __init +wildfire_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + static char irq_tab[8][5] __initlocaldata = { + /*INT INTA INTB INTC INTD */ + { -1, -1, -1, -1, -1}, /* IdSel 0 ISA Bridge */ + { 36, 36, 36+1, 36+2, 36+3}, /* IdSel 1 SCSI builtin */ + { 40, 40, 40+1, 40+2, 40+3}, /* IdSel 2 PCI 0 slot 2 */ + { 44, 44, 44+1, 44+2, 44+3}, /* IdSel 3 PCI 0 slot 3 */ + { 48, 48, 48+1, 48+2, 48+3}, /* IdSel 4 PCI 1 slot 4 */ + { 52, 52, 52+1, 52+2, 52+3}, /* IdSel 5 PCI 1 slot 5 */ + { 56, 56, 56+1, 56+2, 56+3}, /* IdSel 6 PCI 1 slot 6 */ + { 60, 60, 60+1, 60+2, 60+3}, /* IdSel 7 PCI 1 slot 7 */ + }; + const long min_idsel = 0, max_idsel = 7, irqs_per_slot = 5; + + struct pci_controler *hose = dev->sysdata; + int irq = COMMON_TABLE_LOOKUP; + + if (irq > 0) { + int qbbno = hose->index >> 3; + int pcano = (hose->index >> 1) & 3; + irq += (qbbno << 8) + (pcano << 6); + } + return irq; +} + +static void __init +wildfire_init_pci(void) +{ + common_init_pci(); +} + +/* + * The System Vectors + */ + +struct alpha_machine_vector wildfire_mv __initmv = { + vector_name: "WILDFIRE", + DO_EV6_MMU, + DO_DEFAULT_RTC, + DO_WILDFIRE_IO, + DO_WILDFIRE_BUS, + machine_check: wildfire_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: DEFAULT_MEM_BASE, + + nr_irqs: WILDFIRE_NR_IRQS, + device_interrupt: wildfire_device_interrupt, + + init_arch: wildfire_init_arch, + init_irq: wildfire_init_irq, + init_rtc: common_init_rtc, + init_pci: wildfire_init_pci, + kill_arch: wildfire_kill_arch, + pci_map_irq: wildfire_map_irq, + pci_swizzle: common_swizzle, +}; +ALIAS_MV(wildfire) diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c --- v2.4.0-test1/linux/arch/alpha/kernel/traps.c Wed Apr 26 16:34:06 2000 +++ linux/arch/alpha/kernel/traps.c Mon Jun 19 17:59:33 2000 @@ -27,30 +27,234 @@ { printk("pc = [<%016lx>] ra = [<%016lx>] ps = %04lx\n", regs->pc, regs->r26, regs->ps); - printk("r0 = %016lx r1 = %016lx r2 = %016lx\n", + printk("v0 = %016lx t0 = %016lx t1 = %016lx\n", regs->r0, regs->r1, regs->r2); - printk("r3 = %016lx r4 = %016lx r5 = %016lx\n", + printk("t2 = %016lx t3 = %016lx t4 = %016lx\n", regs->r3, regs->r4, regs->r5); - printk("r6 = %016lx r7 = %016lx r8 = %016lx\n", + printk("t5 = %016lx t6 = %016lx t7 = %016lx\n", regs->r6, regs->r7, regs->r8); if (r9_15) { - printk("r9 = %016lx r10= %016lx r11= %016lx\n", + printk("s0 = %016lx s1 = %016lx s2 = %016lx\n", r9_15[9], r9_15[10], r9_15[11]); - printk("r12= %016lx r13= %016lx r14= %016lx\n", + printk("s3 = %016lx s4 = %016lx s5 = %016lx\n", r9_15[12], r9_15[13], r9_15[14]); - printk("r15= %016lx\n", r9_15[15]); + printk("s6 = %016lx\n", r9_15[15]); } - printk("r16= %016lx r17= %016lx r18= %016lx\n", + printk("a0 = %016lx a1 = %016lx a2 = %016lx\n", regs->r16, regs->r17, regs->r18); - printk("r19= %016lx r20= %016lx r21= %016lx\n", + printk("a3 = %016lx a4 = %016lx a5 = %016lx\n", regs->r19, regs->r20, regs->r21); - printk("r22= %016lx r23= %016lx r24= %016lx\n", + printk("t8 = %016lx t9 = %016lx t10= %016lx\n", regs->r22, regs->r23, regs->r24); - printk("r25= %016lx r27= %016lx r28= %016lx\n", + printk("t11= %016lx pv = %016lx at = %016lx\n", regs->r25, regs->r27, regs->r28); printk("gp = %016lx sp = %p\n", regs->gp, regs+1); +#if 0 +__halt(); +#endif +} + +static char * ireg_name[] = {"v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6", + "t7", "s0", "s1", "s2", "s3", "s4", "s5", "s6", + "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9", + "t10", "t11", "ra", "pv", "at", "gp", "sp", "zero"}; + +static char * inst_name[] = {"call_pal", "", "", "", "", "", "", "", + "lda", "ldah", "ldbu", "ldq_u", "ldwu", "stw", "stb", "stq_u", + "ALU", "ALU", "ALU", "ALU", "SQRT", "FVAX", "FIEEE", "FLOAT", + "MISC", "PAL19", "JMP", "PAL1B", "GRAPH", "PAL1D", "PAL1E", "PAL1F", + "ldf", "ldg", "lds", "ldt", "stf", "stg", "sts", "stt", + "ldl", "ldq", "ldl_l", "ldq_l", "stl", "stq", "stl_c", "stq_c", + "br", "fbeq", "fblt", "fble", "bsr", "fbne", "fbge", "fbgt" + "blbc", "beq", "blt", "ble", "blbs", "bne", "bge", "bgt" +}; + +static char * jump_name[] = {"jmp", "jsr", "ret", "jsr_coroutine"}; + +typedef struct {int func; char * text;} alist; + +static alist inta_name[] = {{0, "addl"}, {2, "s4addl"}, {9, "subl"}, + {0xb, "s4subl"}, {0xf, "cmpbge"}, {0x12, "s8addl"}, {0x1b, "s8subl"}, + {0x1d, "cmpult"}, {0x20, "addq"}, {0x22, "s4addq"}, {0x29, "subq"}, + {0x2b, "s4subq"}, {0x2d, "cmpeq"}, {0x32, "s8addq"}, {0x3b, "s8subq"}, + {0x3d, "cmpule"}, {0x40, "addl/v"}, {0x49, "subl/v"}, {0x4d, "cmplt"}, + {0x60, "addq/v"}, {0x69, "subq/v"}, {0x6d, "cmple"}, {-1, 0}}; + +static alist intl_name[] = {{0, "and"}, {8, "andnot"}, {0x14, "cmovlbs"}, + {0x16, "cmovlbc"}, {0x20, "or"}, {0x24, "cmoveq"}, {0x26, "cmovne"}, + {0x28, "ornot"}, {0x40, "xor"}, {0x44, "cmovlt"}, {0x46, "cmovge"}, + {0x48, "eqv"}, {0x61, "amask"}, {0x64, "cmovle"}, {0x66, "cmovgt"}, + {0x6c, "implver"}, {-1, 0}}; + +static alist ints_name[] = {{2, "mskbl"}, {6, "extbl"}, {0xb, "insbl"}, + {0x12, "mskwl"}, {0x16, "extwl"}, {0x1b, "inswl"}, {0x22, "mskll"}, + {0x26, "extll"}, {0x2b, "insll"}, {0x30, "zap"}, {0x31, "zapnot"}, + {0x32, "mskql"}, {0x34, "srl"}, {0x36, "extql"}, {0x39, "sll"}, + {0x3b, "insql"}, {0x3c, "sra"}, {0x52, "mskwh"}, {0x57, "inswh"}, + {0x5a, "extwh"}, {0x62, "msklh"}, {0x67, "inslh"}, {0x6a, "extlh"}, + {0x72, "mskqh"}, {0x77, "insqh"}, {0x7a, "extqh"}, {-1, 0}}; + +static alist intm_name[] = {{0, "mull"}, {0x20, "mulq"}, {0x30, "umulh"}, + {0x40, "mull/v"}, {0x60, "mulq/v"}, {-1, 0}}; + +static alist * int_name[] = {inta_name, intl_name, ints_name, intm_name}; + +static char * +assoc(int fcode, alist * a) +{ + while ((fcode != a->func) && (a->func != -1)) + ++a; + return a->text; +} + +static char * +iname(unsigned int instr) +{ + int opcode = instr >> 26; + char * name = inst_name[opcode]; + + switch (opcode) { + default: + break; + + case 0x10: + case 0x11: + case 0x12: + case 0x13: { + char * specific_name + = assoc((instr >> 5) & 0x3f, int_name[opcode - 0x10]); + if (specific_name) + name = specific_name; + break; + } + + case 0x1a: + name = jump_name[(instr >> 14) & 3]; + break; + } + + return name; +} + +static enum {NOT_INST, PAL, BRANCH, MEMORY, JUMP, OPERATE, FOPERATE, MISC} +iformat(int opcode) +{ + if (opcode >= 0x30) + return BRANCH; + if (opcode >= 0x20) + return MEMORY; + if (opcode == 0) + return PAL; + if (opcode < 8) + return NOT_INST; + if (opcode < 0x10) + return MEMORY; + if (opcode < 0x14) + return OPERATE; + if (opcode < 0x18) + return FOPERATE; + switch (opcode) { + case 0x18: + return MISC; + case 0x1A: + return JUMP; + case 0x1C: + return OPERATE; + default: + return NOT_INST; + } +} + +/* + * The purpose here is to provide useful clues about a kernel crash, so + * less likely instructions, e.g. floating point, aren't fully decoded. + */ +static void +disassemble(unsigned int instr) +{ + int optype = instr >> 26; + char buf[40], *s = buf; + + s += sprintf(buf, "%08x %s ", instr, iname(instr)); + switch (iformat(optype)) { + default: + case NOT_INST: + case MISC: + break; + + case PAL: + s += sprintf(s, "%d", instr); + break; + + case BRANCH: { + int reg = (instr >> 21) & 0x1f; + int offset = instr & 0x1fffff; + + if (offset >= 0x100000) + offset -= 0x200000; + if (((optype & 3) == 0) || (optype >= 0x38)) { + if ((optype != 0x30) || (reg != 0x1f)) + s += sprintf(s, "%s,", ireg_name[reg]); + } else + s += sprintf(s, "f%d,", reg); + s += sprintf(s, ".%+d", (offset + 1) << 2); + break; + } + + case MEMORY: { + int addr_reg = (instr >> 16) & 0x1f; + int value_reg = (instr >> 21) & 0x1f; + int offset = instr & 0xffff; + + if (offset >= 0x8000) + offset -= 0x10000; + if ((optype >= 0x20) && (optype < 0x28)) + s += sprintf(s, "f%d", value_reg); + else + s += sprintf(s, "%s", ireg_name[value_reg]); + + s += sprintf(s, ",%d(%s)", offset, ireg_name[addr_reg]); + break; + } + + case JUMP: { + int target_reg = (instr >> 16) & 0x1f; + int return_reg = (instr >> 21) & 0x1f; + + s += sprintf(s, "%s,", ireg_name[return_reg]); + s += sprintf(s, "(%s)", ireg_name[target_reg]); + break; + } + + case OPERATE: { + int areg = (instr >> 21) & 0x1f; + int breg = (instr >> 16) & 0x1f; + int creg = instr & 0x1f; + int litflag = instr & (1<<12); + int lit = (instr >> 13) & 0xff; + + s += sprintf(s, "%s,", ireg_name[areg]); + if (litflag) + s += sprintf(s, "%d", lit); + else + s += sprintf(s, "%s", ireg_name[breg]); + s += sprintf(s, ",%s", ireg_name[creg]); + break; + } + + case FOPERATE: { + int areg = (instr >> 21) & 0x1f; + int breg = (instr >> 16) & 0x1f; + int creg = instr & 0x1f; + + s += sprintf(s, "f%d,f%d,f%d", areg, breg, creg); + break; + } + } + buf[s-buf] = 0; + printk("%s\n", buf); } static void @@ -59,11 +263,12 @@ long i; printk("Code:"); - for (i = -3; i < 6; i++) { + for (i = -6; i < 2; i++) { unsigned int insn; if (__get_user(insn, pc+i)) break; - printk("%c%08x%c",i?' ':'<',insn,i?' ':'>'); + printk("%c", i ? ' ' : '*'); + disassemble(insn); } printk("\n"); } @@ -81,8 +286,12 @@ continue; if (tmp >= (unsigned long) &_etext) continue; - printk(" [<%lx>]", tmp); - if (++i > 40) { + /* + * Assume that only the low 24-bits of a kernel text address + * is interesting. + */ + printk("%6x%c", (int)tmp & 0xffffff, (++i % 11) ? ' ' : '\n'); + if (i > 40) { printk(" ..."); break; } @@ -450,7 +659,7 @@ got_exception: /* Ok, we caught the exception, but we don't want it. Is there someone to pass it along to? */ - if ((fixup = search_exception_table(pc)) != 0) { + if ((fixup = search_exception_table(pc, regs.gp)) != 0) { unsigned long newpc; newpc = fixup_exception(una_reg, fixup, pc); diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/lib/Makefile linux/arch/alpha/lib/Makefile --- v2.4.0-test1/linux/arch/alpha/lib/Makefile Mon Dec 20 18:48:21 1999 +++ linux/arch/alpha/lib/Makefile Mon Jun 19 17:59:33 2000 @@ -2,13 +2,18 @@ # Makefile for alpha-specific library files.. # +.S.s: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -E -o $*.s $< +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o $*.o $< + OBJS = __divqu.o __remqu.o __divlu.o __remlu.o memset.o memcpy.o io.o \ checksum.o csum_partial_copy.o strlen.o \ strcat.o strcpy.o strncat.o strncpy.o stxcpy.o stxncpy.o \ strchr.o strrchr.o memchr.o \ copy_user.o clear_user.o strncpy_from_user.o strlen_user.o \ csum_ipv6_magic.o strcasecmp.o semaphore.o fpreg.o \ - srm_dispatch.o srm_fixup.o srm_puts.o srm_printk.o + callback_srm.o callback_init.o srm_puts.o srm_printk.o lib.a: $(OBJS) $(AR) rcs lib.a $(OBJS) diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/lib/callback_init.c linux/arch/alpha/lib/callback_init.c --- v2.4.0-test1/linux/arch/alpha/lib/callback_init.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/lib/callback_init.c Mon Jun 19 17:59:33 2000 @@ -0,0 +1,79 @@ +#include +#include + +#include +#include +#include +#include + +#include "../kernel/proto.h" + +extern struct hwrpb_struct *hwrpb; + +/* This is the SRM version. Maybe there will be a DBM version. */ + +int callback_init_done = 0; + +void * __init callback_init(void * kernel_end) +{ + int i, j; + unsigned long vaddr = CONSOLE_REMAP_START; + struct crb_struct * crb; + pgd_t * pgd = pgd_offset_k(vaddr); + pmd_t * pmd; + unsigned long two_pte_pages; + + if (!alpha_using_srm) { + switch_to_system_map(); + return kernel_end; + } + + /* Allocate some memory for the pages. */ + two_pte_pages = ((unsigned long)kernel_end + ~PAGE_MASK) & PAGE_MASK; + kernel_end = (void *)(two_pte_pages + 2*PAGE_SIZE); + memset((void *)two_pte_pages, 0, 2*PAGE_SIZE); + + /* Starting at the HWRPB, locate the CRB. */ + crb = (struct crb_struct *)((char *)hwrpb + hwrpb->crb_offset); + + /* Tell the console whither the console is to be remapped. */ + if (srm_fixup(vaddr, (unsigned long)hwrpb)) + __halt(); /* "We're boned." --Bender */ + + /* Edit the procedure descriptors for DISPATCH and FIXUP. */ + crb->dispatch_va = (struct procdesc_struct *) + (vaddr + (unsigned long)crb->dispatch_va - crb->map[0].va); + crb->fixup_va = (struct procdesc_struct *) + (vaddr + (unsigned long)crb->fixup_va - crb->map[0].va); + + switch_to_system_map(); + + /* + * Set up the first and second level PTEs for console callbacks. + * There is an assumption here that only one of each is needed, + * and this allows for 8MB. Currently (late 1999), big consoles + * are still under 4MB. + */ + pgd_set(pgd, (pmd_t *)two_pte_pages); + pmd = pmd_offset(pgd, vaddr); + pmd_set(pmd, (pte_t *)(two_pte_pages + PAGE_SIZE)); + + /* + * Set up the third level PTEs and update the virtual addresses + * of the CRB entries. + */ + for (i = 0; i < crb->map_entries; ++i) { + unsigned long paddr = crb->map[i].pa; + crb->map[i].va = vaddr; + for (j = 0; j < crb->map[i].count; ++j) { + set_pte(pte_offset(pmd, vaddr), + mk_pte_phys(paddr, PAGE_KERNEL)); + paddr += PAGE_SIZE; + vaddr += PAGE_SIZE; + } + } + + callback_init_done = 1; + return kernel_end; +} + diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/lib/callback_srm.S linux/arch/alpha/lib/callback_srm.S --- v2.4.0-test1/linux/arch/alpha/lib/callback_srm.S Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/lib/callback_srm.S Mon Jun 19 17:59:33 2000 @@ -0,0 +1,102 @@ +/* + * arch/alpha/lib/callback_srm.S + */ + +#include +#include + +.text +#define HWRPB_CRB_OFFSET 0xc0 + +#if defined(CONFIG_ALPHA_SRM) || defined(CONFIG_ALPHA_GENERIC) +.align 4 +srm_dispatch: +#if defined(CONFIG_ALPHA_GENERIC) + ldl $4,alpha_using_srm + beq $4,nosrm +#endif + ldq $0,hwrpb # gp is set up by CALLBACK macro. + ldl $25,0($25) # Pick up the wrapper data. + mov $20,$21 # Shift arguments right. + mov $19,$20 + ldq $1,HWRPB_CRB_OFFSET($0) + mov $18,$19 + mov $17,$18 + mov $16,$17 + addq $0,$1,$2 # CRB address + ldq $27,0($2) # DISPATCH procedure descriptor (VMS call std) + extwl $25,0,$16 # SRM callback function code + ldq $3,8($27) # call address + extwl $25,2,$25 # argument information (VMS calling std) + jmp ($3) # Return directly to caller of wrapper. + +.align 4 +.globl srm_fixup +.ent srm_fixup +srm_fixup: + ldgp $29,0($27) +#if defined(CONFIG_ALPHA_GENERIC) + ldl $4,alpha_using_srm + beq $4,nosrm +#endif + ldq $0,hwrpb + ldq $1,HWRPB_CRB_OFFSET($0) + addq $0,$1,$2 # CRB address + ldq $27,16($2) # VA of FIXUP procedure descriptor + ldq $3,8($27) # call address + lda $25,2($31) # two integer arguments + jmp ($3) # Return directly to caller of srm_fixup. +.end srm_fixup + +#if defined(CONFIG_ALPHA_GENERIC) +.align 3 +nosrm: + lda $0,-1($31) + ret +#endif + +#define CALLBACK(NAME, CODE, ARG_CNT) \ +.align 4; .globl callback_##NAME; .ent callback_##NAME; callback_##NAME##: \ +ldgp $29,0($27); br $25,srm_dispatch; .word CODE, ARG_CNT; .end callback_##NAME + +#else /* defined(CONFIG_ALPHA_SRM) || defined(CONFIG_ALPHA_GENERIC) */ + +#define CALLBACK(NAME, CODE, ARG_CNT) \ +.align 3; .globl callback_##NAME; .ent callback_##NAME; callback_##NAME##: \ +lda $0,-1($31); ret; .end callback_##NAME + +.align 3 +.globl srm_fixup +.ent srm_fixup +srm_fixup: + lda $0,-1($31) + ret +.end srm_fixup +#endif /* defined(CONFIG_ALPHA_SRM) || defined(CONFIG_ALPHA_GENERIC) */ + +CALLBACK(puts, CCB_PUTS, 4) +CALLBACK(open, CCB_OPEN, 3) +CALLBACK(close, CCB_CLOSE, 2) +CALLBACK(read, CCB_READ, 5) +CALLBACK(getenv, CCB_GET_ENV, 4) +CALLBACK(setenv, CCB_SET_ENV, 4) +CALLBACK(getc, CCB_GETC, 2) +CALLBACK(reset_term, CCB_RESET_TERM, 2) +CALLBACK(term_int, CCB_SET_TERM_INT, 3) +CALLBACK(term_ctl, CCB_SET_TERM_CTL, 3) +CALLBACK(process_keycode, CCB_PROCESS_KEYCODE, 3) +CALLBACK(ioctl, CCB_IOCTL, 6) +CALLBACK(write, CCB_WRITE, 5) +CALLBACK(reset_env, CCB_RESET_ENV, 4) +CALLBACK(save_env, CCB_SAVE_ENV, 1) +CALLBACK(pswitch, CCB_PSWITCH, 3) +CALLBACK(bios_emul, CCB_BIOS_EMUL, 5) + +.data +__alpha_using_srm: # For use by bootpheader + .long 7 # value is not 1 for link debugging + .weak alpha_using_srm; alpha_using_srm = __alpha_using_srm +__callback_init_done: # For use by bootpheader + .long 7 # value is not 1 for link debugging + .weak callback_init_done; callback_init_done = __callback_init_done + diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/lib/srm_dispatch.S linux/arch/alpha/lib/srm_dispatch.S --- v2.4.0-test1/linux/arch/alpha/lib/srm_dispatch.S Mon Oct 12 11:40:12 1998 +++ linux/arch/alpha/lib/srm_dispatch.S Wed Dec 31 16:00:00 1969 @@ -1,43 +0,0 @@ -/* - * arch/alpha/lib/srm_dispatch.S - */ - -.globl srm_dispatch -.ent srm_dispatch -srm_dispatch: - .frame $30,30,$26 - subq $30,80,$30 - stq $26,0($30) - stq $8,8($30) - stq $9,16($30) - stq $10,24($30) - stq $11,32($30) - stq $12,40($30) - stq $13,48($30) - stq $14,56($30) - stq $15,64($30) - stq $29,72($30) - .mask 0x2400FF00, -80 - .prologue 0 - - ldq $1,hwrpb - ldq $2,0xc0($1) /* crb offset */ - addq $2,$1,$2 /* crb */ - ldq $27,0($2) /* dispatch procedure value */ - - ldq $2,8($27) /* dispatch call address */ - jsr $26,($2) /* call it (weird VMS call seq) */ - - ldq $26,0($30) - ldq $8,8($30) - ldq $9,16($30) - ldq $10,24($30) - ldq $11,32($30) - ldq $12,40($30) - ldq $13,48($30) - ldq $14,56($30) - ldq $15,64($30) - ldq $29,72($30) - addq $30,80,$30 - ret $31,($26),1 -.end srm_dispatch diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/lib/srm_fixup.S linux/arch/alpha/lib/srm_fixup.S --- v2.4.0-test1/linux/arch/alpha/lib/srm_fixup.S Mon Oct 12 11:40:12 1998 +++ linux/arch/alpha/lib/srm_fixup.S Wed Dec 31 16:00:00 1969 @@ -1,42 +0,0 @@ -/* - * arch/alpha/lib/srm_fixup.S - */ - -.globl srm_fixup -.ent srm_fixup -srm_fixup: - .frame $30,30,$26 - subq $30,80,$30 - stq $26,0($30) - stq $8,8($30) - stq $9,16($30) - stq $10,24($30) - stq $11,32($30) - stq $12,40($30) - stq $13,48($30) - stq $14,56($30) - stq $15,64($30) - stq $29,72($30) - .mask 0x2400FF00, -80 - .prologue 0 - - ldq $2,0xc0($17) /* crb offset */ - addq $2,$1,$2 /* crb */ - ldq $27,16($2) /* fixup procedure value */ - - ldq $2,8($27) /* dispatch call address */ - jsr $26,($2) /* call it (weird VMS call seq) */ - - ldq $26,0($30) - ldq $8,8($30) - ldq $9,16($30) - ldq $10,24($30) - ldq $11,32($30) - ldq $12,40($30) - ldq $13,48($30) - ldq $14,56($30) - ldq $15,64($30) - ldq $29,72($30) - addq $30,80,$30 - ret $31,($26),1 -.end srm_fixup diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/lib/srm_printk.c linux/arch/alpha/lib/srm_printk.c --- v2.4.0-test1/linux/arch/alpha/lib/srm_printk.c Mon Oct 12 11:40:12 1998 +++ linux/arch/alpha/lib/srm_printk.c Mon Jun 19 17:59:33 2000 @@ -9,13 +9,33 @@ srm_printk(const char *fmt, ...) { static char buf[1024]; - va_list args; - long i; + va_list args; + long len, num_lf; + char *src, *dst; - va_start(args, fmt); - i = vsprintf(buf,fmt,args); - va_end(args); + va_start(args, fmt); + len = vsprintf(buf, fmt, args); + va_end(args); - srm_puts(buf); - return i; + /* count number of linefeeds in string: */ + + num_lf = 0; + for (src = buf; *src; ++src) { + if (*src == '\n') { + ++num_lf; + } + } + + if (num_lf) { + /* expand each linefeed into carriage-return/linefeed: */ + for (dst = src + num_lf; src >= buf; ) { + if (*src == '\n') { + *dst-- = '\r'; + } + *dst-- = *src--; + } + } + + srm_puts(buf, num_lf+len); + return len; } diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/lib/srm_puts.c linux/arch/alpha/lib/srm_puts.c --- v2.4.0-test1/linux/arch/alpha/lib/srm_puts.c Mon Oct 12 11:40:12 1998 +++ linux/arch/alpha/lib/srm_puts.c Mon Jun 19 17:59:33 2000 @@ -5,30 +5,19 @@ #include #include -void -srm_puts(const char *str) +long +srm_puts(const char *str, long len) { - /* Expand \n to \r\n as we go. */ + long remaining, written; - while (*str) { - long len; - const char *e = str; + if (!callback_init_done) + return len; - if (*str == '\n') { - if (srm_dispatch(CCB_PUTS, 0, "\r", 1) < 0) - return; - ++e; - } - - e = strchr(e, '\n') ? : strchr(e, '\0'); - len = e - str; - - while (len > 0) { - long written = srm_dispatch(CCB_PUTS, 0, str, len); - if (written < 0) - return; - len -= written & 0xffffffff; - str += written & 0xffffffff; - } + for (remaining = len; remaining > 0; remaining -= written) + { + written = callback_puts(0, str, remaining); + written &= 0xffffffff; + str += written; } + return len; } diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/mm/extable.c linux/arch/alpha/mm/extable.c --- v2.4.0-test1/linux/arch/alpha/mm/extable.c Thu Jan 23 11:01:28 1997 +++ linux/arch/alpha/mm/extable.c Mon Jun 19 17:59:33 2000 @@ -36,12 +36,12 @@ register unsigned long gp __asm__("$29"); -unsigned -search_exception_table(unsigned long addr) +static unsigned +search_exception_table_without_gp(unsigned long addr) { unsigned ret; -#ifndef CONFIG_MODULE +#ifndef CONFIG_MODULES /* There is only the kernel to search. */ ret = search_one_table(__start___ex_table, __stop___ex_table - 1, addr - gp); @@ -57,6 +57,42 @@ if (ret) return ret; } #endif + + return 0; +} + +unsigned +search_exception_table(unsigned long addr, unsigned long exc_gp) +{ + unsigned ret; + +#ifndef CONFIG_MODULES + ret = search_one_table(__start___ex_table, __stop___ex_table - 1, + addr - exc_gp); + if (ret) return ret; +#else + /* The kernel is the last "module" -- no need to treat it special. */ + struct module *mp; + for (mp = module_list; mp ; mp = mp->next) { + if (!mp->ex_table_start) + continue; + ret = search_one_table(mp->ex_table_start, + mp->ex_table_end - 1, addr - exc_gp); + if (ret) return ret; + } +#endif + + /* + * The search failed with the exception gp. To be safe, try the + * old method before giving up. + */ + ret = search_exception_table_without_gp(addr); + if (ret) { + printk(KERN_ALERT, "%s: [%lx] EX_TABLE search fail with" + "exc frame GP, success with raw GP\n", + current->comm, addr); + return ret; + } return 0; } diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/mm/fault.c linux/arch/alpha/mm/fault.c --- v2.4.0-test1/linux/arch/alpha/mm/fault.c Wed Apr 26 16:34:06 2000 +++ linux/arch/alpha/mm/fault.c Mon Jun 19 17:59:33 2000 @@ -164,11 +164,13 @@ no_context: /* Are we prepared to handle this fault as an exception? */ - if ((fixup = search_exception_table(regs->pc)) != 0) { + if ((fixup = search_exception_table(regs->pc, regs->gp)) != 0) { unsigned long newpc; newpc = fixup_exception(dpf_reg, fixup, regs->pc); - printk("%s: Exception at [<%lx>] (%lx)\n", +#if 1 + printk("%s: Exception at [<%lx>] (%lx) handled successfully\n", current->comm, regs->pc, newpc); +#endif regs->pc = newpc; return; } diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c --- v2.4.0-test1/linux/arch/alpha/mm/init.c Wed Apr 26 16:34:06 2000 +++ linux/arch/alpha/mm/init.c Mon Jun 19 17:59:33 2000 @@ -182,43 +182,15 @@ return __reload_thread(pcb); } -/* - * paging_init() sets up the page tables: in the alpha version this actually - * unmaps the bootup page table (as we're now in KSEG, so we don't need it). - */ +/* switch_to_system_map() sets up some necessary page tables. */ void -paging_init(void) +switch_to_system_map(void) { unsigned long newptbr; unsigned long original_pcb_ptr; - unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; - unsigned long dma_pfn, high_pfn; - - dma_pfn = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; - high_pfn = max_low_pfn; - -#define ORDER_MASK (~((1 << (MAX_ORDER-1))-1)) -#define ORDER_ALIGN(n) (((n) + ~ORDER_MASK) & ORDER_MASK) - - dma_pfn = ORDER_ALIGN(dma_pfn); - high_pfn = ORDER_ALIGN(high_pfn); - -#undef ORDER_MASK -#undef ORDER_ALIGN - - if (dma_pfn > high_pfn) - zones_size[ZONE_DMA] = high_pfn; - else { - zones_size[ZONE_DMA] = dma_pfn; - zones_size[ZONE_NORMAL] = high_pfn - dma_pfn; - } - - /* Initialize mem_map[]. */ - free_area_init(zones_size); /* Initialize the kernel's page tables. Linux puts the vptb in the last slot of the L1 page table. */ - memset((void *)ZERO_PGE, 0, PAGE_SIZE); memset(swapper_pg_dir, 0, PAGE_SIZE); newptbr = ((unsigned long) swapper_pg_dir - PAGE_OFFSET) >> PAGE_SHIFT; pgd_val(swapper_pg_dir[1023]) = @@ -251,6 +223,41 @@ phys_to_virt(original_pcb_ptr); } original_pcb = *(struct thread_struct *) original_pcb_ptr; +} + +/* + * paging_init() sets up the memory map. + */ +void +paging_init(void) +{ + unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; + unsigned long dma_pfn, high_pfn; + + dma_pfn = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; + high_pfn = max_low_pfn; + +#define ORDER_MASK (~((1L << (MAX_ORDER-1))-1)) +#define ORDER_ALIGN(n) (((n) + ~ORDER_MASK) & ORDER_MASK) + + dma_pfn = ORDER_ALIGN(dma_pfn); + high_pfn = ORDER_ALIGN(high_pfn); + +#undef ORDER_MASK +#undef ORDER_ALIGN + + if (dma_pfn > high_pfn) + zones_size[ZONE_DMA] = high_pfn; + else { + zones_size[ZONE_DMA] = dma_pfn; + zones_size[ZONE_NORMAL] = high_pfn - dma_pfn; + } + + /* Initialize mem_map[]. */ + free_area_init(zones_size); + + /* Initialize the kernel's ZERO_PGE. */ + memset((void *)ZERO_PGE, 0, PAGE_SIZE); } #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM) diff -u --recursive --new-file v2.4.0-test1/linux/arch/alpha/vmlinux.lds linux/arch/alpha/vmlinux.lds --- v2.4.0-test1/linux/arch/alpha/vmlinux.lds Sat Feb 26 22:31:38 2000 +++ linux/arch/alpha/vmlinux.lds Mon Jun 19 17:59:33 2000 @@ -2,7 +2,7 @@ ENTRY(__start) SECTIONS { - . = 0xfffffc0000310000; + . = 0xfffffc0000810000; _text = .; .text : { *(.text) } _etext = .; @@ -50,9 +50,11 @@ .got : { *(.got) } .sdata : { *(.sdata) } _edata = .; - _bss = .; + + __bss_start = .; .sbss : { *(.sbss) *(.scommon) } .bss : { *(.bss) *(COMMON) } + __bss_stop = .; _end = .; .mdebug 0 : { *(.mdebug) } diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/Makefile linux/arch/arm/Makefile --- v2.4.0-test1/linux/arch/arm/Makefile Tue May 23 15:31:32 2000 +++ linux/arch/arm/Makefile Mon Jun 19 17:59:33 2000 @@ -19,7 +19,7 @@ AFLAGS += -mno-fpu CFLAGS_PIPE := -pipe -CFLAGS := $(CFLAGS) $(CFLAGS_PIPE) +CFLAGS := $(CFLAGS) $(CFLAGS_PIPE) -msoft-float ifdef CONFIG_FRAME_POINTER CFLAGS := $(CFLAGS:-fomit-frame-pointer=) @@ -29,11 +29,13 @@ CFLAGS += -g endif +GZFLAGS = -9 + # Ensure this is ld "2.9.4" or later NEW_LINKER := $(shell if $(LD) --gc-sections --version >/dev/null 2>&1; then echo y; else echo n; fi) ifneq ($(NEW_LINKER),y) -dummy:; @echo '*** 2.3 kernels no longer build correctly with old versions of binutils.' +dummy:; @echo '*** ${VERSION}.${PATCHLEVEL} kernels no longer build correctly with old versions of binutils.' @echo '*** Please upgrade your binutils to 2.9.5.' @false endif @@ -45,7 +47,7 @@ # select flags depending on the compiler # ifeq ($(NEW_GCC),y) -CFLAGS += -mshort-load-bytes -msoft-float +CFLAGS += -mshort-load-bytes CFLAGS_PROC_CPU_26 := -mcpu=arm3 -Os CFLAGS_PROC_CPU_32v3 := -march=armv3 CFLAGS_PROC_CPU_32v4 := -march=armv4 @@ -110,7 +112,7 @@ LIBGCC := $(shell $(CC) $(CFLAGS) --print-libgcc-file-name) -export LIBGCC MACHINE PROCESSOR TEXTADDR +export LIBGCC MACHINE PROCESSOR TEXTADDR GZFLAGS ifeq ($(CONFIG_ARCH_A5K),y) MACHINE = a5k diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/boot/compressed/Makefile linux/arch/arm/boot/compressed/Makefile --- v2.4.0-test1/linux/arch/arm/boot/compressed/Makefile Fri May 12 14:18:55 2000 +++ linux/arch/arm/boot/compressed/Makefile Mon Jun 19 17:59:33 2000 @@ -89,7 +89,7 @@ piggy.o: $(SYSTEM) $(OBJCOPY) $(SYSTEM) piggy - gzip -9 < piggy > piggy.gz + gzip $(GZFLAGS) < piggy > piggy.gz $(LD) -r -o $@ -b binary piggy.gz rm -f piggy piggy.gz diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/boot/compressed/head-sa1100.S linux/arch/arm/boot/compressed/head-sa1100.S --- v2.4.0-test1/linux/arch/arm/boot/compressed/head-sa1100.S Fri May 12 14:18:55 2000 +++ linux/arch/arm/boot/compressed/head-sa1100.S Mon Jun 19 17:59:33 2000 @@ -133,6 +133,5 @@ #endif @ Restore initial r0/r1 - @ (r8 preserved) mov r0, r8 mov r1, r9 diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/boot/compressed/head.S linux/arch/arm/boot/compressed/head.S --- v2.4.0-test1/linux/arch/arm/boot/compressed/head.S Fri May 12 14:18:55 2000 +++ linux/arch/arm/boot/compressed/head.S Mon Jun 19 17:59:33 2000 @@ -84,9 +84,7 @@ b 1f .word 0x016f2818 @ Magic numbers to help the loader .word start -1: adr r8, start @ get the start address of the code - @ (used for locating the page tables) - +1: /* * some architecture specific code can be inserted * by the linker here, but it should preserve r0, r1 @@ -178,9 +176,13 @@ .align 5 cache_on: ldr r1, proc_sa110_type eor r1, r1, r6 - movs r1, r1, lsr #5 + movs r1, r1, lsr #5 @ catch SA110 and SA1100 + beq 1f + ldr r1, proc_sa1110_type + eor r1, r1, r6 + movs r1, r1, lsr #4 movne pc, lr - +1: sub r3, r4, #16384 @ Page directory size bic r3, r3, #0xff @ Align the pointer bic r3, r3, #0x3f @@ -259,6 +261,11 @@ .word 0x4401a100 .size proc_sa110_type, . - proc_sa110_type + .type proc_sa1110_type,#object +proc_sa1110_type: + .word 0x6901b110 + .size proc_sa1110_type, . - proc_sa1110_type + /* * Turn off StrongARM cache and MMU. It is safe to * leave the I-cache on. @@ -273,8 +280,13 @@ .align 5 cache_off: ldr r1, proc_sa110_type eor r1, r1, r6 - movs r1, r1, lsr #5 + movs r1, r1, lsr #5 @ catch SA110 and SA1100 + beq 1f + ldr r1, proc_sa1110_type + eor r1, r1, r6 + movs r1, r1, lsr #4 movne pc, lr +1: mrc p15, 0, r0, c1, c0 bic r0, r0, #0x000d mcr p15, 0, r0, c1, c0 @@ -292,11 +304,15 @@ */ .align 5 cache_clean_flush: - ldr r1, proc_sa110_type @ SA-110 or SA-1100? + ldr r1, proc_sa110_type + eor r1, r1, r6 + movs r1, r1, lsr #5 @ catch SA110 and SA1100 + beq 1f + ldr r1, proc_sa1110_type eor r1, r1, r6 - movs r1, r1, lsr #5 + movs r1, r1, lsr #4 movne pc, lr - +1: bic r1, pc, #31 add r2, r1, #32768 1: ldr r12, [r1], #32 @ s/w flush D cache diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/config.in linux/arch/arm/config.in --- v2.4.0-test1/linux/arch/arm/config.in Fri May 12 14:18:55 2000 +++ linux/arch/arm/config.in Mon Jun 19 17:59:33 2000 @@ -1,57 +1,50 @@ # # For a description of the syntax of this configuration file, -# see the Configure script. +# see Documentation/kbuild/config-language.txt. # mainmenu_name "Linux Kernel Configuration" define_bool CONFIG_ARM y - +define_bool CONFIG_SBUS n define_bool CONFIG_UID16 y + mainmenu_option next_comment comment 'Code maturity level options' bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL endmenu + mainmenu_option next_comment -comment 'System and Processor Type' +comment 'System Type' choice 'ARM system type' \ "Archimedes CONFIG_ARCH_ARC \ A5000 CONFIG_ARCH_A5K \ - RiscPC CONFIG_ARCH_RPC \ + Co-EBSA285 CONFIG_ARCH_CO285 \ EBSA-110 CONFIG_ARCH_EBSA110 \ - FootBridge-based CONFIG_FOOTBRIDGE" RiscPC + FootBridge CONFIG_ARCH_FOOTBRIDGE \ + RiscPC CONFIG_ARCH_RPC \ + SA1100-based CONFIG_ARCH_SA1100" RiscPC + # the following are placeholders for when they are fully integrated +# Cirrus CL-PS7500FE CONFIG_ARCH_CLPS7500 \ # LinkUp-L7200 CONFIG_ARCH_L7200 -# SA1100-based CONFIG_ARCH_SA1100 -if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then - bool 'FootBridge in HOST mode' CONFIG_HOST_FOOTBRIDGE - if [ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then - define_bool CONFIG_ADDIN_FOOTBRIDGE n - else - define_bool CONFIG_ADDIN_FOOTBRIDGE y - fi -fi - -if [ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then +if [ "$CONFIG_ARCH_FOOTBRIDGE" = "y" ]; then comment 'Footbridge Implementations' - bool ' Include support for EBSA285' CONFIG_ARCH_EBSA285 - bool ' Include support for CATS' CONFIG_ARCH_CATS - bool ' Include support for NetWinder' CONFIG_ARCH_NETWINDER - bool ' Include support for Compaq Personal Server' CONFIG_ARCH_PERSONAL_SERVER -fi - -if [ "$CONFIG_ADDIN_FOOTBRIDGE" = "y" ]; then - # If we get any other footbridge-based plug-in boards, then - # add your architecture options here - define_bool CONFIG_ARCH_CO285 y + bool ' CATS support' CONFIG_ARCH_CATS + bool ' Compaq Personal Server support' CONFIG_ARCH_PERSONAL_SERVER + bool ' EBSA285 (addin mode) support' CONFIG_ARCH_EBSA285_ADDIN + bool ' EBSA285 (host mode) support' CONFIG_ARCH_EBSA285_HOST + bool ' NetWinder support' CONFIG_ARCH_NETWINDER fi - if [ "$CONFIG_ARCH_SA1100" = "y" ]; then comment 'SA11x0 Implementations' - bool ' Include support for Assabet' CONFIG_SA110_ASSABET + bool ' Include support for Assabet' CONFIG_SA1100_ASSABET + if [ "$CONFIG_SA1100_ASSABET" = "y" ]; then + bool ' Include support for Neponset' CONFIG_ASSABET_NEPONSET + fi bool ' Include support for Bitsy' CONFIG_SA1100_BITSY bool ' Include support for Brutus' CONFIG_SA1100_BRUTUS # bool ' Include support for Empeg' CONFIG_SA1100_EMPEG @@ -62,43 +55,21 @@ bool ' Include support for GraphicsClient' CONFIG_SA1100_GRAPHICSCLIENT bool ' Include support for Victor' CONFIG_SA1100_VICTOR # bool ' Include support for Tifon' CONFIG_SA1100_TIFON - define_bool CONFIG_DISCONTIGMEM y +# bool ' Include support for XP860' CONFIG_SA1100_XP860 fi -# -# Select various configuration options depending on the machine type -# Easy check for Acorn-style architectures -# -if [ "$CONFIG_ARCH_ARC" = "y" -o \ - "$CONFIG_ARCH_A5K" = "y" -o \ - "$CONFIG_ARCH_RPC" = "y" ]; then - define_bool CONFIG_ARCH_ACORN y -else - define_bool CONFIG_ARCH_ACORN n -fi - -# -# Figure out whether this system uses 26-bit or 32-bit CPUs. Nobody has -# ever built a machine that can take both, and now that ARM3 is obsolete -# nobody is likely to either. -# +# Figure out whether this system uses 26-bit or 32-bit CPUs. if [ "$CONFIG_ARCH_ARC" = "y" -o \ "$CONFIG_ARCH_A5K" = "y" ]; then define_bool CONFIG_CPU_32 n define_bool CONFIG_CPU_26 y - - # - # Select memory size - # bool '2MB physical memory' CONFIG_PAGESIZE_16 else define_bool CONFIG_CPU_32 y define_bool CONFIG_CPU_26 n fi -# # Select CPU and optimisation dependent on architecture -# if [ "$CONFIG_ARCH_RPC" = "y" ]; then define_bool CONFIG_CPU_32v3 y bool 'Support ARM610' CONFIG_CPU_ARM6 @@ -113,6 +84,10 @@ define_bool CONFIG_CPU_32v4 y define_bool CONFIG_CPU_SA110 y fi +if [ "$CONFIG_ARCH_CLPS7500" = "y" ]; then + define_bool CONFIG_CPU_32v4 y + define_bool CONFIG_CPU_ARM7 y +fi if [ "$CONFIG_ARCH_L7200" = "y" ]; then define_bool CONFIG_CPU_32v4 y define_bool CONFIG_CPU_ARM720 y @@ -122,20 +97,54 @@ define_bool CONFIG_CPU_SA1100 y fi -# -# These machines always have PCI -# +# Select various configuration options depending on the machine type +if [ "$CONFIG_ARCH_ARC" = "y" -o \ + "$CONFIG_ARCH_A5K" = "y" -o \ + "$CONFIG_ARCH_RPC" = "y" ]; then + define_bool CONFIG_ARCH_ACORN y +else + define_bool CONFIG_ARCH_ACORN n +fi + +if [ "$CONFIG_ARCH_CO285" = "y" -o \ + "$CONFIG_ARCH_FOOTBRIDGE" = "y" ]; then + define_bool CONFIG_FOOTBRIDGE y +else + define_bool CONFIG_FOOTBRIDGE n +fi +if [ "$CONFIG_ARCH_CATS" = "y" -o \ + "$CONFIG_ARCH_EBSA285_HOST" = "y" -o \ + "$CONFIG_ARCH_NETWINDER" = "y" -o \ + "$CONFIG_ARCH_PERSONAL_SERVER" = "y" ]; then + define_bool CONFIG_FOOTBRIDGE_HOST y +else + define_bool CONFIG_FOOTBRIDGE_HOST n +fi +if [ "$CONFIG_ARCH_CO285" = "y" -o \ + "$CONFIG_ARCH_EBSA285_ADDIN" = "y" ]; then + define_bool CONFIG_FOOTBRIDGE_ADDIN y +else + define_bool CONFIG_FOOTBRIDGE_ADDIN n +fi +if [ "$CONFIG_ARCH_EBSA285_HOST" = "y" -o \ + "$CONFIG_ARCH_EBSA285_ADDIN" = "y" ]; then + define_bool CONFIG_ARCH_EBSA285 y +fi + +if [ "$CONFIG_ARCH_SA1100" = "y" ]; then + define_bool CONFIG_DISCONTIGMEM y +else + define_bool CONFIG_DISCONTIGMEM n +fi + +# Now handle the bus types if [ "$CONFIG_ARCH_NEXUSPCI" = "y" -o \ - "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then + "$CONFIG_FOOTBRIDGE_HOST" = "y" ]; then define_bool CONFIG_PCI y - source drivers/pci/Config.in else define_bool CONFIG_PCI n fi -# -# These machines have ISA-DMA -# if [ "$CONFIG_ARCH_CATS" = "y" -o \ "$CONFIG_ARCH_SHARK" = "y" -o \ "$CONFIG_ARCH_NETWINDER" = "y" ]; then @@ -145,15 +154,9 @@ define_bool CONFIG_ISA n define_bool CONFIG_ISA_DMA n fi - -define_bool CONFIG_SBUS n -define_bool CONFIG_PCMCIA n - -if [ "$CONFIG_CPU_32" = "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then - bool 'Kernel-mode alignment trap handler' CONFIG_ALIGNMENT_TRAP -fi endmenu + mainmenu_option next_comment comment 'Loadable module support' bool 'Enable loadable module support' CONFIG_MODULES @@ -163,53 +166,61 @@ fi endmenu + mainmenu_option next_comment comment 'General setup' +source drivers/pci/Config.in +bool 'Support hot-pluggable devices' CONFIG_HOTPLUG +if [ "$CONFIG_HOTPLUG" = "y" ]; then + source drivers/pcmcia/Config.in +else + define_bool CONFIG_PCMCIA n +fi bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL -tristate 'Math emulation' CONFIG_NWFPE -if [ "$CONFIG_PROC_FS" = "y" ]; then - choice 'Kernel core (/proc/kcore) format' \ +tristate 'NWFPE math emulation' CONFIG_NWFPE +choice 'Kernel core (/proc/kcore) format' \ "ELF CONFIG_KCORE_ELF \ A.OUT CONFIG_KCORE_AOUT" ELF -fi 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 if [ "$CONFIG_CPU_32" = "y" ]; then tristate 'RISC OS personality' CONFIG_ARTHUR fi - -source drivers/parport/Config.in - if [ "$CONFIG_ARCH_EBSA110" = "y" -o \ "$CONFIG_ARCH_SA1100" = "y" -o \ - "$CONFIG_ARCH_NETWINDER" = "y" -o \ "$CONFIG_ARCH_PERSONAL_SERVER" = "y" -o \ "$CONFIG_ARCH_CATS" = "y" ]; then - string 'Initial kernel command string' CONFIG_CMDLINE + string 'Default kernel command string' CONFIG_CMDLINE "" fi if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \ "$CONFIG_ARCH_EBSA110" = "y" -o \ "$CONFIG_ARCH_EBSA285" = "y" -o \ - "$CONFIG_ARCH_CO285" = "y" ]; then + "$CONFIG_ARCH_CO285" = "y" -o \ + "$CONFIG_ARCH_SA1100" = "y" ]; then bool 'Timer and CPU usage LEDs' CONFIG_LEDS if [ "$CONFIG_LEDS" = "y" ]; then if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \ "$CONFIG_ARCH_EBSA285" = "y" -o \ - "$CONFIG_ARCH_CO285" = "y" ]; then + "$CONFIG_ARCH_CO285" = "y" -o \ + "$CONFIG_ARCH_SA1100" = "y" ]; then bool ' Timer LED' CONFIG_LEDS_TIMER bool ' CPU usage LED' CONFIG_LEDS_CPU fi fi + if [ "$CONFIG_ARCH_EBSA110" = "y" ]; then + define_bool CONFIG_LEDS_TIMER y + fi +fi +if [ "$CONFIG_CPU_32" = "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then + bool 'Kernel-mode alignment trap handler' CONFIG_ALIGNMENT_TRAP fi endmenu -source drivers/ieee1394/Config.in - -source drivers/i2o/Config.in +source drivers/parport/Config.in source drivers/pnp/Config.in @@ -219,37 +230,9 @@ source drivers/acorn/block/Config.in fi -source drivers/char/Config.in -if [ "$CONFIG_ARCH_ACORN" = "y" ]; then - if [ "$CONFIG_BUSMOUSE" = "y" ]; then - if [ "$CONFIG_ARCH_RPC" != "y" ]; then - define_bool CONFIG_KBDMOUSE y - else - define_bool CONFIG_RPCMOUSE y - fi - fi -fi - -#source drivers/misc/Config.in - -if [ "$CONFIG_VT" = "y" ]; then - mainmenu_option next_comment - comment 'Console drivers' - if [ "$CONFIG_ARCH_ACORN" != "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then - bool 'VGA text console' CONFIG_VGA_CONSOLE - fi - bool 'Support Frame buffer devices' CONFIG_FB - source drivers/video/Config.in - endmenu -fi - if [ "$CONFIG_NET" = "y" ]; then source net/Config.in - source net/ax25/Config.in - - source net/irda/Config.in - mainmenu_option next_comment comment 'Network device support' @@ -258,16 +241,11 @@ source drivers/net/Config.in fi endmenu -fi -# mainmenu_option next_comment -# comment 'ISDN subsystem' -# -# tristate 'ISDN support' CONFIG_ISDN -# if [ "$CONFIG_ISDN" != "n" ]; then -# source drivers/isdn/Config.in -# fi -# endmenu + source net/ax25/Config.in + + source net/irda/Config.in +fi mainmenu_option next_comment comment 'ATA/IDE/MFM/RLL support' @@ -292,6 +270,44 @@ fi endmenu +source drivers/ieee1394/Config.in + +source drivers/i2o/Config.in + +mainmenu_option next_comment +comment 'ISDN subsystem' + +tristate 'ISDN support' CONFIG_ISDN +if [ "$CONFIG_ISDN" != "n" ]; then + source drivers/isdn/Config.in +fi +endmenu + +source drivers/char/Config.in +if [ "$CONFIG_ARCH_ACORN" = "y" -a \ + "$CONFIG_BUSMOUSE" = "y" ]; then + if [ "$CONFIG_ARCH_RPC" != "y" ]; then + define_bool CONFIG_KBDMOUSE y + else + define_bool CONFIG_RPCMOUSE y + fi +fi + +#source drivers/misc/Config.in + +source fs/Config.in + +if [ "$CONFIG_VT" = "y" ]; then + mainmenu_option next_comment + comment 'Console drivers' + if [ "$CONFIG_ARCH_ACORN" != "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then + bool 'VGA text console' CONFIG_VGA_CONSOLE + fi + bool 'Support Frame buffer devices' CONFIG_FB + source drivers/video/Config.in + endmenu +fi + if [ "$CONFIG_ARCH_ACORN" = "y" -o \ "$CONFIG_ARCH_CLPS7500" = "y" -o \ "$CONFIG_ARCH_SHARK" = "y" -o \ @@ -306,10 +322,9 @@ endmenu fi -source fs/Config.in - source drivers/usb/Config.in + mainmenu_option next_comment comment 'Kernel hacking' @@ -317,7 +332,6 @@ bool 'Verbose kernel error messages' CONFIG_DEBUG_ERRORS bool 'Verbose user fault messages' CONFIG_DEBUG_USER bool 'Include debugging information in kernel binary' CONFIG_DEBUG_INFO -#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ if [ "$CONFIG_CPU_26" = "y" ]; then bool 'Disable pgtable cache' CONFIG_NO_PGT_CACHE diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/def-configs/a5k linux/arch/arm/def-configs/a5k --- v2.4.0-test1/linux/arch/arm/def-configs/a5k Thu Feb 10 17:11:02 2000 +++ linux/arch/arm/def-configs/a5k Mon Jun 19 17:59:33 2000 @@ -94,10 +94,6 @@ # CONFIG_BLK_DEV_IDEDMA_ICS is not set # CONFIG_BLK_DEV_IDE_RAPIDE is not set # CONFIG_IDE_CHIPSETS is not set - -# -# Additional Block Devices -# CONFIG_BLK_DEV_LOOP=m # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/def-configs/assabet linux/arch/arm/def-configs/assabet --- v2.4.0-test1/linux/arch/arm/def-configs/assabet Fri May 12 14:18:55 2000 +++ linux/arch/arm/def-configs/assabet Mon Jun 19 17:59:33 2000 @@ -10,25 +10,29 @@ CONFIG_EXPERIMENTAL=y # -# System and processor type +# System and Processor Type # # CONFIG_ARCH_ARC is not set # CONFIG_ARCH_A5K is not set -# CONFIG_ARCH_RPC is not set # CONFIG_ARCH_EBSA110 is not set # CONFIG_FOOTBRIDGE is not set +# CONFIG_ARCH_RPC is not set CONFIG_ARCH_SA1100=y + +# +# SA11x0 Implementations +# CONFIG_SA1100_ASSABET=y -# CONFIG_SA1100_BRUTUS is not set -# CONFIG_SA1100_EMPEG is not set -# CONFIG_SA1100_ITSY is not set +# CONFIG_ASSABET_NEPONSET is not set # CONFIG_SA1100_BITSY is not set +# CONFIG_SA1100_BRUTUS is not set # CONFIG_SA1100_LART is not set -# CONFIG_SA1100_PLEB is not set # CONFIG_SA1100_THINCLIENT is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set # CONFIG_SA1100_VICTOR is not set -# CONFIG_SA1100_TIFON is not set CONFIG_DISCONTIGMEM=y +CONFIG_SA1100_FREQUENCY_SCALE=y +# CONFIG_SA1100_VOLTAGE_SCALE is not set # CONFIG_ARCH_ACORN is not set CONFIG_CPU_32=y # CONFIG_CPU_26 is not set @@ -37,7 +41,8 @@ # CONFIG_PCI is not set # CONFIG_ISA is not set # CONFIG_ISA_DMA is not set -# CONFIG_ALIGNMENT_TRAP is not set +# CONFIG_SBUS is not set +CONFIG_ALIGNMENT_TRAP=y # # Loadable module support @@ -49,14 +54,14 @@ # # General setup # -# CONFIG_NET is not set +CONFIG_NET=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set -# CONFIG_SYSCTL is not set +CONFIG_SYSCTL=y CONFIG_NWFPE=y CONFIG_KCORE_ELF=y # CONFIG_KCORE_AOUT is not set -CONFIG_BINFMT_AOUT=y +# CONFIG_BINFMT_AOUT is not set CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set # CONFIG_ARTHUR is not set @@ -69,13 +74,22 @@ CONFIG_LEDS=y CONFIG_LEDS_TIMER=y CONFIG_LEDS_CPU=y +CONFIG_HOTPLUG=y + +# +# PC Card support +# +CONFIG_PCMCIA=y +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_SA1100_PCMCIA=y +CONFIG_VIRTUAL_BUS=y # # I2O device support # # CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set # CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set # CONFIG_I2O_SCSI is not set # CONFIG_I2O_PROC is not set @@ -91,12 +105,15 @@ # CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE is not set - -# -# Additional Block Devices -# +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_LVM is not set # CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_RAID15_DANGEROUS is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_INITRD=y # CONFIG_BLK_DEV_FLASH is not set @@ -152,6 +169,7 @@ # CONFIG_FTAPE is not set # CONFIG_DRM is not set # CONFIG_DRM_TDFX is not set +# CONFIG_PCMCIA_SERIAL is not set # CONFIG_AGP is not set # @@ -171,6 +189,7 @@ CONFIG_FBCON_CFB2=y CONFIG_FBCON_CFB4=y CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y CONFIG_FBCON_FONTWIDTH8_ONLY=y CONFIG_FBCON_FONTS=y CONFIG_FONT_8x8=y @@ -180,11 +199,176 @@ # CONFIG_FONT_ACORN_8x8 is not set # +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_ALIAS is not set +# CONFIG_SYN_COOKIES is not set + +# +# (it is safe to leave these untouched) +# +CONFIG_SKB_LARGE=y +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_BRIDGE is not set +# CONFIG_LLC is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_FMVJ18X is not set +CONFIG_PCMCIA_PCNET=y +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +# CONFIG_NET_PCMCIA_RADIO is not set +CONFIG_PCMCIA_NETCARD=y + +# # ATA/IDE/MFM/RLL support # -# CONFIG_IDE is not set -# CONFIG_BLK_DEV_IDE_MODES is not set +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set # CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +CONFIG_BLK_DEV_IDECS=y +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_BLK_DEV_IDE_MODES is not set # # SCSI support @@ -192,43 +376,135 @@ # CONFIG_SCSI is not set # +# Sound +# +CONFIG_SOUND=y +CONFIG_SOUND_UDA1341=y +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_SOUND_OSS is not set + +# # File systems # # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS 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_FAT_FS is not set -# CONFIG_MSDOS_FS is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y # CONFIG_UMSDOS_FS is not set # CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set # CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set # CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set # # Partition Types # -# CONFIG_PARTITION_ADVANCED is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set CONFIG_MSDOS_PARTITION=y -# CONFIG_NLS is not set +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set # # USB support diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/def-configs/brutus linux/arch/arm/def-configs/brutus --- v2.4.0-test1/linux/arch/arm/def-configs/brutus Fri May 12 14:18:55 2000 +++ linux/arch/arm/def-configs/brutus Mon Jun 19 17:59:33 2000 @@ -95,10 +95,6 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_DEV_DAC960 is not set - -# -# Additional Block Devices -# # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_LVM is not set @@ -216,10 +212,12 @@ # CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set # CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set @@ -227,11 +225,16 @@ # CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE 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 # # Partition Types diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/def-configs/ebsa110 linux/arch/arm/def-configs/ebsa110 --- v2.4.0-test1/linux/arch/arm/def-configs/ebsa110 Tue May 23 15:31:33 2000 +++ linux/arch/arm/def-configs/ebsa110 Mon Jun 19 17:59:33 2000 @@ -1,7 +1,8 @@ # -# Automatically generated make config: don't edit +# Automatically generated by make menuconfig: don't edit # CONFIG_ARM=y +# CONFIG_SBUS is not set CONFIG_UID16=y # @@ -10,23 +11,27 @@ CONFIG_EXPERIMENTAL=y # -# System and Processor Type +# System Type # # CONFIG_ARCH_ARC is not set # CONFIG_ARCH_A5K is not set -# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_CO285 is not set CONFIG_ARCH_EBSA110=y -# CONFIG_FOOTBRIDGE is not set -# CONFIG_ARCH_ACORN is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set CONFIG_CPU_32=y # CONFIG_CPU_26 is not set CONFIG_CPU_32v4=y CONFIG_CPU_SA110=y +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set +# CONFIG_DISCONTIGMEM is not set # CONFIG_PCI is not set # CONFIG_ISA is not set # CONFIG_ISA_DMA is not set -# CONFIG_SBUS is not set -# CONFIG_PCMCIA is not set # # Loadable module support @@ -38,6 +43,8 @@ # # General setup # +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set CONFIG_NET=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set @@ -49,6 +56,9 @@ CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set # CONFIG_ARTHUR is not set +CONFIG_CMDLINE="root=/dev/nfs rw mem=16M console=ttyS1,38400n8" +CONFIG_LEDS=y +CONFIG_LEDS_TIMER=y # # Parallel port support @@ -64,17 +74,6 @@ # CONFIG_PARPORT_SUNBPP is not set # CONFIG_PARPORT_OTHER is not set CONFIG_PARPORT_1284=y -CONFIG_CMDLINE="root=/dev/nfs rw mem=16M console=ttyS1,38400n8" -CONFIG_LEDS=y - -# -# I2O device support -# -# CONFIG_I2O is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_LAN is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set # # Plug and Play configuration @@ -90,12 +89,8 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_DEV_DAC960 is not set - -# -# Additional Block Devices -# # CONFIG_BLK_DEV_LOOP is not set -CONFIG_BLK_DEV_NBD=m +# CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_LVM is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set @@ -105,74 +100,6 @@ # CONFIG_BLK_DEV_INITRD is not set # -# Character devices -# -# CONFIG_VT is not set -CONFIG_SERIAL=y -CONFIG_SERIAL_CONSOLE=y -CONFIG_SERIAL_EXTENDED=y -# CONFIG_SERIAL_MANY_PORTS is not set -# CONFIG_SERIAL_SHARE_IRQ is not set -# CONFIG_SERIAL_DETECT_IRQ is not set -# CONFIG_SERIAL_MULTIPORT is not set -# CONFIG_HUB6 is not set -# CONFIG_SERIAL_NONSTANDARD is not set -# CONFIG_UNIX98_PTYS is not set -CONFIG_PRINTER=m -# CONFIG_LP_CONSOLE is not set -# CONFIG_PPDEV is not set - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set -# CONFIG_PSMOUSE is not set -# CONFIG_82C710_MOUSE is not set -# CONFIG_PC110_PAD is not set - -# -# Joysticks -# -# CONFIG_JOYSTICK is not set -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -CONFIG_WATCHDOG=y -# CONFIG_WATCHDOG_NOWAYOUT is not set -# CONFIG_WDT is not set -# CONFIG_WDTPCI is not set -CONFIG_SOFT_WATCHDOG=y -# CONFIG_PCWATCHDOG is not set -# CONFIG_ACQUIRE_WDT is not set -# CONFIG_MIXCOMWD is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV 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_DRM is not set -# CONFIG_DRM_TDFX is not set -# CONFIG_AGP is not set - -# # Networking options # CONFIG_PACKET=m @@ -194,7 +121,7 @@ CONFIG_IP_ROUTE_NAT=y # CONFIG_IP_ROUTE_MULTIPATH is not set # CONFIG_IP_ROUTE_TOS is not set -# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_ROUTE_VERBOSE=y # CONFIG_IP_ROUTE_LARGE_TABLES is not set CONFIG_IP_PNP=y CONFIG_IP_PNP_BOOTP=y @@ -206,51 +133,46 @@ CONFIG_IP_ALIAS=y # CONFIG_ARPD is not set CONFIG_SYN_COOKIES=y - -# -# (it is safe to leave these untouched) -# # CONFIG_SKB_LARGE is not set # # IP: Netfilter Configuration # -CONFIG_IP_NF_CONNTRACK=y -CONFIG_IP_NF_FTP=y +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m # CONFIG_IP_NF_QUEUE is not set -CONFIG_IP_NF_IPTABLES=y -CONFIG_IP_NF_MATCH_LIMIT=y +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m # CONFIG_IP_NF_MATCH_MAC is not set -CONFIG_IP_NF_MATCH_MARK=y -CONFIG_IP_NF_MATCH_MULTIPORT=y -CONFIG_IP_NF_MATCH_TOS=y -CONFIG_IP_NF_MATCH_STATE=y -# CONFIG_IP_NF_MATCH_UNCLEAN is not set +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_UNCLEAN=m # CONFIG_IP_NF_MATCH_OWNER is not set -CONFIG_IP_NF_FILTER=y -CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m # CONFIG_IP_NF_TARGET_MIRROR is not set -CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_COMPAT_IPCHAINS=m CONFIG_IP_NF_NAT_NEEDED=y -CONFIG_IP_NF_TARGET_MASQUERADE=y -CONFIG_IP_NF_TARGET_REDIRECT=y -CONFIG_IP_NF_MANGLE=y -CONFIG_IP_NF_TARGET_TOS=y -CONFIG_IP_NF_TARGET_MARK=y -CONFIG_IP_NF_TARGET_LOG=y +# CONFIG_IP_NF_COMPAT_IPFWADM is not set # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set - -# -# -# # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set # CONFIG_LLC is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set @@ -263,16 +185,6 @@ # CONFIG_NET_SCHED is not set # -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# IrDA (infrared) support -# -# CONFIG_IRDA is not set - -# # Network device support # CONFIG_NETDEVICES=y @@ -281,7 +193,7 @@ # ARCnet devices # # CONFIG_ARCNET is not set -CONFIG_DUMMY=m +# CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_ETHERTAP is not set @@ -317,7 +229,7 @@ # CONFIG_PPP_SYNC_TTY is not set CONFIG_PPP_DEFLATE=m CONFIG_PPP_BSDCOMP=m -CONFIG_PPPOE=m +# CONFIG_PPPOE is not set # CONFIG_SLIP is not set # @@ -339,6 +251,16 @@ # CONFIG_WAN is not set # +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# # ATA/IDE/MFM/RLL support # # CONFIG_IDE is not set @@ -351,6 +273,85 @@ # CONFIG_SCSI is not set # +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +CONFIG_SERIAL_EXTENDED=y +# CONFIG_SERIAL_MANY_PORTS is not set +# CONFIG_SERIAL_SHARE_IRQ is not set +# CONFIG_SERIAL_DETECT_IRQ is not set +# CONFIG_SERIAL_MULTIPORT is not set +# CONFIG_HUB6 is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set +CONFIG_PRINTER=m +# CONFIG_LP_CONSOLE is not set +# CONFIG_PPDEV is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +# CONFIG_WDT is not set +# CONFIG_WDTPCI is not set +CONFIG_SOFT_WATCHDOG=y +# CONFIG_PCWATCHDOG is not set +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_MIXCOMWD is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV 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_DRM is not set +# CONFIG_DRM_TDFX is not set +# CONFIG_AGP is not set + +# # File systems # # CONFIG_QUOTA is not set @@ -370,7 +371,7 @@ # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set -# CONFIG_MINIX_FS is not set +CONFIG_MINIX_FS=m # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -399,6 +400,7 @@ CONFIG_ROOT_NFS=y # CONFIG_NFSD is not set # CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_TCP is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/def-configs/footbridge linux/arch/arm/def-configs/footbridge --- v2.4.0-test1/linux/arch/arm/def-configs/footbridge Tue May 23 15:31:33 2000 +++ linux/arch/arm/def-configs/footbridge Mon Jun 19 17:59:33 2000 @@ -138,10 +138,6 @@ CONFIG_PARIDE_ON26=m # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_DEV_DAC960 is not set - -# -# Additional Block Devices -# CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_NBD=m # CONFIG_BLK_DEV_LVM is not set diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/def-configs/graphicsclient linux/arch/arm/def-configs/graphicsclient --- v2.4.0-test1/linux/arch/arm/def-configs/graphicsclient Fri May 12 14:18:55 2000 +++ linux/arch/arm/def-configs/graphicsclient Mon Jun 19 17:59:33 2000 @@ -84,10 +84,6 @@ # Please see Documentation/ide.txt for help/info on IDE drives # # CONFIG_BLK_DEV_HD_ONLY is not set - -# -# Additional Block Devices -# # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/def-configs/lart linux/arch/arm/def-configs/lart --- v2.4.0-test1/linux/arch/arm/def-configs/lart Fri May 12 14:18:55 2000 +++ linux/arch/arm/def-configs/lart Mon Jun 19 17:59:33 2000 @@ -1,5 +1,5 @@ # -# Automatically generated make config: don't edit +# Automatically generated by make menuconfig: don't edit # CONFIG_ARM=y CONFIG_UID16=y @@ -10,25 +10,24 @@ CONFIG_EXPERIMENTAL=y # -# System and processor type +# System and Processor Type # # CONFIG_ARCH_ARC is not set # CONFIG_ARCH_A5K is not set -# CONFIG_ARCH_RPC is not set # CONFIG_ARCH_EBSA110 is not set # CONFIG_FOOTBRIDGE is not set +# CONFIG_ARCH_RPC is not set CONFIG_ARCH_SA1100=y # CONFIG_SA1100_ASSABET is not set -# CONFIG_SA1100_BRUTUS is not set -# CONFIG_SA1100_EMPEG is not set -# CONFIG_SA1100_ITSY is not set # CONFIG_SA1100_BITSY is not set +# CONFIG_SA1100_BRUTUS is not set CONFIG_SA1100_LART=y -# CONFIG_SA1100_PLEB is not set # CONFIG_SA1100_THINCLIENT is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set # CONFIG_SA1100_VICTOR is not set -# CONFIG_SA1100_TIFON is not set CONFIG_DISCONTIGMEM=y +CONFIG_SA1100_FREQUENCY_SCALE=m +CONFIG_SA1100_VOLTAGE_SCALE=y # CONFIG_ARCH_ACORN is not set CONFIG_CPU_32=y # CONFIG_CPU_26 is not set @@ -37,6 +36,7 @@ # CONFIG_PCI is not set # CONFIG_ISA is not set # CONFIG_ISA_DMA is not set +# CONFIG_SBUS is not set CONFIG_ALIGNMENT_TRAP=y # @@ -69,29 +69,38 @@ CONFIG_LEDS=y # CONFIG_LEDS_TIMER is not set CONFIG_LEDS_CPU=y +# CONFIG_HOTPLUG is not set # # I2O device support # # CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set # # Plug and Play configuration # # CONFIG_PNP is not set +# CONFIG_ISAPNP is not set # # Block devices # # CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_DEV_XD is not set - -# -# Additional Block Devices -# +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_LVM is not set # CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_RAID15_DANGEROUS is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_INITRD=y # CONFIG_BLK_DEV_FLASH is not set @@ -144,6 +153,7 @@ # # CONFIG_FTAPE is not set # CONFIG_DRM is not set +# CONFIG_DRM_TDFX is not set # CONFIG_AGP is not set # @@ -163,18 +173,10 @@ # CONFIG_NET_IPGRE is not set # CONFIG_IP_ALIAS is not set # CONFIG_SYN_COOKIES is not set - -# -# (it is safe to leave these untouched) -# # CONFIG_SKB_LARGE is not set # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set - -# -# -# # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_DECNET is not set @@ -230,10 +232,12 @@ # CONFIG_FDDI is not set # CONFIG_HIPPI is not set CONFIG_PPP=y +# CONFIG_PPP_MULTILINK is not set CONFIG_PPP_ASYNC=y # CONFIG_PPP_SYNC_TTY is not set -CONFIG_PPP_DEFLATE=y +CONFIG_PPP_DEFLATE=m CONFIG_PPP_BSDCOMP=m +# CONFIG_PPPOE is not set CONFIG_SLIP=y CONFIG_SLIP_COMPRESSED=y # CONFIG_SLIP_SMART is not set @@ -270,42 +274,118 @@ # CONFIG_SCSI is not set # +# Sound +# +CONFIG_SOUND=m +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +CONFIG_SOUND_OSS=m +CONFIG_SOUND_TRACEINIT=y +# CONFIG_SOUND_DMAP is not set +# CONFIG_SOUND_AD1816 is not set +# CONFIG_SOUND_SGALAXY is not set +# CONFIG_SOUND_ADLIB is not set +# CONFIG_SOUND_ACI_MIXER is not set +# CONFIG_SOUND_CS4232 is not set +# CONFIG_SOUND_SSCAPE is not set +# CONFIG_SOUND_GUS is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_VMIDI is not set +# CONFIG_SOUND_TRIX is not set +# CONFIG_SOUND_MSS is not set +# CONFIG_SOUND_MPU401 is not set +# CONFIG_SOUND_NM256 is not set +# CONFIG_SOUND_MAD16 is not set +# CONFIG_SOUND_PAS is not set +# CONFIG_PAS_JOYSTICK is not set +# CONFIG_SOUND_PSS is not set +# CONFIG_SOUND_SOFTOSS is not set +# CONFIG_SOUND_SB is not set +# CONFIG_SOUND_AWE32_SYNTH is not set +# CONFIG_SOUND_WAVEFRONT is not set +# CONFIG_SOUND_MAUI is not set +# CONFIG_SOUND_YM3812 is not set +# CONFIG_SOUND_OPL3SA1 is not set +# CONFIG_SOUND_OPL3SA2 is not set +# CONFIG_SOUND_YMPCI is not set +# CONFIG_SOUND_UART6850 is not set +# CONFIG_SOUND_AEDSP16 is not set +# CONFIG_SOUND_VIDC is not set +# CONFIG_SOUND_WAVEARTIST is not set +CONFIG_SOUND_SA1100_SSP=m + +# # File systems # # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS 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_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_CRAMFS is not set +# CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set # CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set # # Network File Systems # # CONFIG_CODA_FS is not set -CONFIG_NFS_FS=y +# CONFIG_NFS_FS is not set +# CONFIG_NFS_V3 is not set +# CONFIG_ROOT_NFS is not set # CONFIG_NFSD is not set -CONFIG_SUNRPC=y -CONFIG_LOCKD=y +# CONFIG_NFSD_V3 is not set +# CONFIG_SUNRPC is not set +# CONFIG_LOCKD is not set # CONFIG_SMB_FS is not set # CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set # # Partition Types @@ -325,6 +405,6 @@ CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y -CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO is not set # CONFIG_MAGIC_SYSRQ is not set CONFIG_DEBUG_LL=y diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/def-configs/lusl7200 linux/arch/arm/def-configs/lusl7200 --- v2.4.0-test1/linux/arch/arm/def-configs/lusl7200 Fri May 12 14:18:55 2000 +++ linux/arch/arm/def-configs/lusl7200 Mon Jun 19 17:59:33 2000 @@ -79,10 +79,6 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_DEV_DAC960 is not set - -# -# Additional Block Devices -# # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_LVM is not set diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/def-configs/rpc linux/arch/arm/def-configs/rpc --- v2.4.0-test1/linux/arch/arm/def-configs/rpc Tue May 23 15:31:33 2000 +++ linux/arch/arm/def-configs/rpc Mon Jun 19 17:59:33 2000 @@ -91,10 +91,6 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_DEV_DAC960 is not set - -# -# Additional Block Devices -# CONFIG_BLK_DEV_LOOP=m # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_LVM is not set diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/def-configs/thinclient linux/arch/arm/def-configs/thinclient --- v2.4.0-test1/linux/arch/arm/def-configs/thinclient Fri May 12 14:18:55 2000 +++ linux/arch/arm/def-configs/thinclient Mon Jun 19 17:59:33 2000 @@ -94,10 +94,6 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_DEV_DAC960 is not set - -# -# Additional Block Devices -# # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_LVM is not set @@ -336,10 +332,12 @@ # CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set # CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set @@ -347,23 +345,39 @@ # CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set # # Network File Systems # # CONFIG_CODA_FS is not set CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set CONFIG_ROOT_NFS=y # CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set # CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set # # Partition Types diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/def-configs/victor linux/arch/arm/def-configs/victor --- v2.4.0-test1/linux/arch/arm/def-configs/victor Fri Oct 22 13:21:43 1999 +++ linux/arch/arm/def-configs/victor Mon Jun 19 17:59:33 2000 @@ -80,10 +80,6 @@ # CONFIG_BLK_DEV_IDESCSI is not set # CONFIG_BLK_DEV_CMD640 is not set # CONFIG_IDE_CHIPSETS is not set - -# -# Additional Block Devices -# # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_BLK_DEV_RAM is not set diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/defconfig linux/arch/arm/defconfig --- v2.4.0-test1/linux/arch/arm/defconfig Thu May 11 15:30:05 2000 +++ linux/arch/arm/defconfig Mon Jun 19 17:59:33 2000 @@ -134,10 +134,6 @@ CONFIG_PARIDE_ON26=m # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_DEV_DAC960 is not set - -# -# Additional Block Devices -# CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_MD=y diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/kernel/Makefile linux/arch/arm/kernel/Makefile --- v2.4.0-test1/linux/arch/arm/kernel/Makefile Tue May 23 15:31:33 2000 +++ linux/arch/arm/kernel/Makefile Mon Jun 19 17:59:34 2000 @@ -17,22 +17,23 @@ O_OBJS_rpc = dma-rpc.o O_OBJS_ebsa110 = dma-dummy.o O_OBJS_footbridge = dma.o dma-footbridge.o $(ISA_DMA_OBJS) hw-footbridge.o isa.o +O_OBJS_clps7500 = dma-dummy.o O_OBJS_nexuspci = dma-dummy.o -O_OBJS_sa1100 = dma-dummy.o fiq.o +O_OBJS_sa1100 = dma-dummy.o hw-sa1100.o O_OBJS_l7200 = dma-dummy.o fiq.o O_TARGET := kernel.o # Object file lists. -obj-y := arch.o $(ENTRY_OBJ) ioport.o irq.o process.o ptrace.o \ - semaphore.o setup.o signal.o sys_arm.o time.o traps.o \ - $(O_OBJS_$(MACHINE)) +obj-y := arch.o $(ENTRY_OBJ) irq.o process.o ptrace.o \ + semaphore.o setup.o signal.o sys_arm.o time.o \ + traps.o $(O_OBJS_$(MACHINE)) obj-m := obj-n := obj- := -export-objs := armksyms.o dma.o ecard.o hw-footbridge.o leds-$(MACHINE).o +export-objs := armksyms.o dma.o ecard.o hw-footbridge.o hw-sa1100.o leds-$(MACHINE).o obj-$(CONFIG_ARCH_ACORN) += dma.o ecard.o fiq.o time-acorn.o obj-$(CONFIG_DEBUG_LL) += debug-$(PROCESSOR).o diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/kernel/arch.c linux/arch/arm/kernel/arch.c --- v2.4.0-test1/linux/arch/arm/kernel/arch.c Wed Apr 26 16:34:06 2000 +++ linux/arch/arm/kernel/arch.c Mon Jun 19 17:59:34 2000 @@ -55,6 +55,7 @@ for (i = 0; i < 4; i++) { mi->bank[i].start = PHYS_OFFSET + (i << 26); + mi->bank[i].node = 0; mi->bank[i].size = params->u1.s.pages_in_bank[i] * params->u1.s.page_size; @@ -122,6 +123,17 @@ fixup_netwinder(struct machine_desc *desc, struct param_struct *params, char **cmdline, struct meminfo *mi) { +#ifdef CONFIG_ISAPNP + extern int isapnp_disable; + + /* + * We must not use the kernels ISAPnP code + * on the NetWinder - it will reset the settings + * for the WaveArtist chip and render it inoperable. + */ + isapnp_disable = 1; +#endif + if (params->u1.s.nr_pages != 0x2000 && params->u1.s.nr_pages != 0x4000) { printk(KERN_WARNING "Warning: bad NeTTrom parameters " @@ -181,6 +193,7 @@ mi->nr_banks = 1; mi->bank[0].start = PHYS_OFFSET; mi->bank[0].size = boot_memory_end; + mi->bank[0].node = 0; *cmdline = boot_command_line; } @@ -197,7 +210,8 @@ extern void select_sa1100_io_desc(void); #define SET_BANK(__nr,__start,__size) \ mi->bank[__nr].start = (__start), \ - mi->bank[__nr].size = (__size) + mi->bank[__nr].size = (__size), \ + mi->bank[__nr].node = (((unsigned)(__start) - PHYS_OFFSET) >> 27) static void __init fixup_sa1100(struct machine_desc *desc, struct param_struct *params, char **cmdline, struct meminfo *mi) @@ -252,7 +266,7 @@ setup_initrd(0xc0400000, 4*1024*1024); } - else if (machine_is_thinclient()) { + else if (machine_is_thinclient() || machine_is_graphicsclient()) { SET_BANK( 0, 0xc0000000, 16*1024*1024 ); mi->nr_banks = 1; @@ -312,6 +326,12 @@ FIXUP(fixup_sa1100) MACHINE_END #endif +#ifdef CONFIG_SA1100_GRAPHICSCLIENT +MACHINE_START(GRAPHICSCLIENT, "ADS GraphicsClient") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) +MACHINE_END +#endif #ifdef CONFIG_SA1100_ITSY MACHINE_START(ITSY, "Compaq Itsy") BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) @@ -349,6 +369,35 @@ FIXUP(fixup_sa1100) MACHINE_END #endif +#ifdef CONFIG_SA1100_XP860 +MACHINE_START(XP860, "XP860") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) +MACHINE_END +#endif +#endif + +#ifdef CONFIG_ARCH_L7200 + +static void __init +fixup_l7200(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) +{ + mi->nr_banks = 1; + mi->bank[0].start = PHYS_OFFSET; + mi->bank[0].size = (32*1024*1024); + mi->bank[0].node = 0; + + ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + setup_ramdisk( 1, 0, 0, 8192 ); + setup_initrd( __phys_to_virt(0xf1000000), 0x00162b0d); +} + +MACHINE_START(L7200, "LinkUp Systems L7200SDB") + MAINTAINER("Steve Hill") + BOOT_MEM(0xf0000000, 0x80040000, 0xd0000000) + FIXUP(fixup_l7200) +MACHINE_END #endif #ifdef CONFIG_ARCH_EBSA110 diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/kernel/bios32.c linux/arch/arm/kernel/bios32.c --- v2.4.0-test1/linux/arch/arm/kernel/bios32.c Fri May 12 14:18:55 2000 +++ linux/arch/arm/kernel/bios32.c Mon Jun 19 17:59:34 2000 @@ -21,65 +21,94 @@ extern void hw_init(void); -void pcibios_report_device_errors(int warn) +void pcibios_report_status(u_int status_mask, int warn) { struct pci_dev *dev; pci_for_each_dev(dev) { u16 status; + /* + * ignore host bridge - we handle + * that separately + */ + if (dev->bus->number == 0 && dev->devfn == 0) + continue; + pci_read_config_word(dev, PCI_STATUS, &status); - if ((status & 0xf900) == 0) + status &= status_mask; + if (status == 0) continue; - pci_write_config_word(dev, PCI_STATUS, status & 0xf900); + /* clear the status errors */ + pci_write_config_word(dev, PCI_STATUS, status); if (warn) - printk(KERN_DEBUG "PCI: %02X:%02X: status %04X " - "on %s\n", dev->bus->number, dev->devfn, - status, dev->name); + printk("(%02x:%02x.%d: %04X) ", dev->bus->number, + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), + status); } } /* * We don't use this to fix the device, but initialisation of it. - * It's not the correct use for this, but it works. The actions we - * take are: - * - enable only IO - * - set memory region to start at zero - * - (0x48) enable all memory requests from ISA to be channeled to PCI - * - (0x42) disable ping-pong (as per errata) - * - (0x40) enable PCI packet retry + * It's not the correct use for this, but it works. + * Note that the arbiter/ISA bridge appears to be buggy, specifically in + * the following area: + * 1. park on CPU + * 2. ISA bridge ping-pong + * 3. ISA bridge master handling of target RETRY + * + * Bug 3 is responsible for the sound DMA grinding to a halt. We now + * live with bug 2. */ static void __init pci_fixup_83c553(struct pci_dev *dev) { + /* + * Set memory region to start at address 0, and enable IO + */ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_SPACE_MEMORY); pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_IO); dev->resource[0].end -= dev->resource[0].start; dev->resource[0].start = 0; + /* + * All memory requests from ISA to be channelled to PCI + */ pci_write_config_byte(dev, 0x48, 0xff); - pci_write_config_byte(dev, 0x42, 0x00); + + /* + * Enable ping-pong on bus master to ISA bridge transactions. + * This improves the sound DMA substantially. The fixed + * priority arbiter also helps (see below). + */ + pci_write_config_byte(dev, 0x42, 0x01); + + /* + * Enable PCI retry + */ pci_write_config_byte(dev, 0x40, 0x22); /* - * We used to set the arbiter to "park on last master" - * (bit 1 set), but unfortunately the CyberPro does not - * park the bus. We must therefore park on CPU. + * We used to set the arbiter to "park on last master" (bit + * 1 set), but unfortunately the CyberPro does not park the + * bus. We must therefore park on CPU. Unfortunately, this + * may trigger yet another bug in the 553. */ - pci_write_config_byte(dev, 0x83, 0x00); + pci_write_config_byte(dev, 0x83, 0x02); /* - * Rotate priorities of each PCI request + * Make the ISA DMA request lowest priority, and disable + * rotating priorities completely. */ - pci_write_config_byte(dev, 0x80, 0xe0); - pci_write_config_byte(dev, 0x81, 0x01); + pci_write_config_byte(dev, 0x80, 0x11); + pci_write_config_byte(dev, 0x81, 0x00); /* - * Route INTA input to IRQ 11, and set - * IRQ11 to be level sensitive. + * Route INTA input to IRQ 11, and set IRQ11 to be level + * sensitive. */ pci_write_config_word(dev, 0x44, 0xb000); outb(0x08, 0x4d1); @@ -193,8 +222,8 @@ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); } -/* - * Called after each bus is probed, but before its children +/** + * pcibios_fixup_bus - Called after each bus is probed, but before its children * are examined. */ void __init pcibios_fixup_bus(struct pci_bus *bus) @@ -209,6 +238,8 @@ else BUG(); + busdata->max_lat = 255; + /* * Walk the devices on this bus, working out what we can * and can't support. @@ -216,6 +247,7 @@ for (walk = walk->next; walk != &bus->devices; walk = walk->next) { struct pci_dev *dev = pci_dev_b(walk); u16 status; + u8 max_lat, min_gnt; pci_read_config_word(dev, PCI_STATUS, &status); @@ -227,6 +259,17 @@ busdata->features &= ~PCI_COMMAND_FAST_BACK; /* + * If we encounter a CyberPro 2000, then we disable + * SERR and PERR reporting - this chip doesn't drive the + * parity line correctly. + */ +#if 1 /* !testing */ + if (dev->vendor == PCI_VENDOR_ID_INTERG && + dev->device == PCI_DEVICE_ID_INTERG_2000) + busdata->features &= ~(PCI_COMMAND_SERR | + PCI_COMMAND_PARITY); +#endif + /* * Calculate the maximum devsel latency. */ if (busdata->maxdevsel < (status & PCI_STATUS_DEVSEL_MASK)) @@ -240,6 +283,16 @@ if (dev->class >> 8 == PCI_CLASS_BRIDGE_ISA || dev->class >> 8 == PCI_CLASS_BRIDGE_EISA) have_isa_bridge = !0; + + /* + * Calculate the maximum latency on this bus. Note + * that we ignore any device which reports its max + * latency is the same as its use. + */ + pci_read_config_byte(dev, PCI_MAX_LAT, &max_lat); + pci_read_config_byte(dev, PCI_MIN_GNT, &min_gnt); + if (max_lat && max_lat != min_gnt && max_lat < busdata->max_lat) + busdata->max_lat = max_lat; } /* @@ -249,6 +302,7 @@ for (walk = walk->next; walk != &bus->devices; walk = walk->next) { struct pci_dev *dev = pci_dev_b(walk); u16 cmd; + u8 min_gnt, latency; /* * architecture specific hacks. I don't really want @@ -263,11 +317,27 @@ pci_write_config_dword(dev, 0x40, 0x80000000); /* - * Set latency timer to 32, and a cache line size to 32 bytes. + * Calculate this masters latency timer value. + * This is rather primitive - it does not take + * account of the number of masters in a system + * wanting to use the bus. + */ + pci_read_config_byte(dev, PCI_MIN_GNT, &min_gnt); + if (min_gnt) { + if (min_gnt > busdata->max_lat) + min_gnt = busdata->max_lat; + + latency = (int)min_gnt * 25 / 3; + } else + latency = 32; /* 1us */ + + pci_write_config_byte(dev, PCI_LATENCY_TIMER, latency); + + /* + * Set the cache line size to 32 bytes. * Also, set system error enable, parity error enable. * Disable ROM. */ - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 32); pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 8); pci_read_config_word(dev, PCI_COMMAND, &cmd); @@ -520,15 +590,6 @@ pci_assign_unassigned_resources(); pci_fixup_irqs(hw_pci->swizzle, hw_pci->map_irq); pci_set_bus_ranges(); - -#ifdef CONFIG_FOOTBRIDGE - /* - * Initialise any other hardware after we've got the PCI bus - * initialised. We may need the PCI bus to talk to this other - * hardware. - */ - hw_init(); -#endif } char * __init pcibios_setup(char *str) @@ -544,10 +605,18 @@ { } +/** + * pcibios_set_master - Setup device for bus mastering. + * @dev: PCI device to be setup + */ void pcibios_set_master(struct pci_dev *dev) { } +/** + * pcibios_enable_device - Enable I/O and memory. + * @dev: PCI device to be enabled + */ int pcibios_enable_device(struct pci_dev *dev) { u16 cmd, old_cmd; diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/kernel/bios32.h linux/arch/arm/kernel/bios32.h --- v2.4.0-test1/linux/arch/arm/kernel/bios32.h Sun Mar 19 18:35:30 2000 +++ linux/arch/arm/kernel/bios32.h Mon Jun 19 17:59:34 2000 @@ -10,6 +10,11 @@ * Maximum devsel for this bus. */ u16 maxdevsel; + /* + * The maximum latency that devices on this + * bus can withstand. + */ + u8 max_lat; }; struct arm_pci_sysdata { diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/kernel/calls.S linux/arch/arm/kernel/calls.S --- v2.4.0-test1/linux/arch/arm/kernel/calls.S Fri May 12 14:18:55 2000 +++ linux/arch/arm/kernel/calls.S Mon Jun 19 17:59:34 2000 @@ -119,7 +119,7 @@ .long SYMBOL_NAME(sys_newlstat) .long SYMBOL_NAME(sys_newfstat) .long SYMBOL_NAME(sys_ni_syscall) /* was sys_uname */ -/* 110 */ .long SYMBOL_NAME(sys_iopl) +/* 110 */ .long SYMBOL_NAME(sys_ni_syscall) /* was sys_iopl */ .long SYMBOL_NAME(sys_vhangup) .long SYMBOL_NAME(sys_ni_syscall) .long SYMBOL_NAME(sys_syscall) /* call a syscall */ diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/kernel/debug-armv.S linux/arch/arm/kernel/debug-armv.S --- v2.4.0-test1/linux/arch/arm/kernel/debug-armv.S Fri May 12 14:18:55 2000 +++ linux/arch/arm/kernel/debug-armv.S Mon Jun 19 17:59:34 2000 @@ -64,7 +64,7 @@ beq 1001b .endm -#elif defined(CONFIG_HOST_FOOTBRIDGE) || defined(CONFIG_ADDIN_FOOTBRIDGE) +#elif defined(CONFIG_FOOTBRIDGE) #ifndef CONFIG_DEBUG_DC21285_PORT /* For NetWinder debugging */ .macro addruart,rx diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/kernel/dec21285.c linux/arch/arm/kernel/dec21285.c --- v2.4.0-test1/linux/arch/arm/kernel/dec21285.c Wed Apr 26 16:34:06 2000 +++ linux/arch/arm/kernel/dec21285.c Mon Jun 19 17:59:34 2000 @@ -1,9 +1,8 @@ /* * arch/arm/kernel/dec21285.c: PCI functions for DC21285 * - * Copyright (C) 1998-1999 Russell King, Phil Blundell + * Copyright (C) 1998-2000 Russell King, Phil Blundell */ -#include #include #include #include @@ -23,7 +22,8 @@ #define MAX_SLOTS 21 extern int setup_arm_irq(int, struct irqaction *); -extern void pcibios_report_device_errors(int warn); +extern void pcibios_report_status(u_int status_mask, int warn); +extern void register_isa_ports(unsigned int, unsigned int, unsigned int); static unsigned long dc21285_base_address(struct pci_dev *dev) @@ -145,86 +145,125 @@ dc21285_write_config_dword, }; +static struct timer_list serr_timer; +static struct timer_list perr_timer; + +static void dc21285_enable_error(unsigned long __data) +{ + switch (__data) { + case IRQ_PCI_SERR: + del_timer(&serr_timer); + break; + + case IRQ_PCI_PERR: + del_timer(&perr_timer); + break; + } + + enable_irq(__data); +} + /* * Warn on PCI errors. */ -static void -dc21285_error(int irq, void *dev_id, struct pt_regs *regs) +static void dc21285_abort_irq(int irq, void *dev_id, struct pt_regs *regs) { - static unsigned long next_warn; - unsigned long cmd = *CSR_PCICMD & 0x0000ffff; - unsigned long ctrl = (*CSR_SA110_CNTL) & 0xffffde07; - unsigned long irqstatus = *CSR_IRQ_RAWSTATUS; - int warn = time_after_eq(jiffies, next_warn); - - if (machine_is_netwinder()) - warn = 0; - - ctrl |= SA110_CNTL_DISCARDTIMER; - - if (warn) { - next_warn = jiffies + HZ; - printk(KERN_DEBUG "PCI: "); - } + unsigned int cmd; + unsigned int status; - if (irqstatus & (1 << 31)) { - if (warn) - printk("parity error "); - cmd |= 1 << 31; - } + cmd = *CSR_PCICMD; + status = cmd >> 16; + cmd = cmd & 0xffff; + + if (status & PCI_STATUS_REC_MASTER_ABORT) { + printk(KERN_DEBUG "PCI: master abort: "); + pcibios_report_status(PCI_STATUS_REC_MASTER_ABORT, 1); + printk("\n"); - if (irqstatus & (1 << 30)) { - if (warn) - printk("target abort "); - cmd |= 1 << 28; + cmd |= PCI_STATUS_REC_MASTER_ABORT << 16; } - if (irqstatus & (1 << 29)) { - if (warn) - printk("master abort "); - cmd |= 1 << 29; - } + if (status & PCI_STATUS_REC_TARGET_ABORT) { + printk(KERN_DEBUG "PCI: target abort: "); + pcibios_report_status(PCI_STATUS_SIG_TARGET_ABORT, 1); + printk("\n"); - if (irqstatus & (1 << 28)) { - if (warn) - printk("data parity error "); - cmd |= 1 << 24; + cmd |= PCI_STATUS_REC_TARGET_ABORT << 16; } - if (irqstatus & (1 << 27)) { - if (warn) - printk("discard timer expired "); - ctrl &= ~SA110_CNTL_DISCARDTIMER; - } + *CSR_PCICMD = cmd; +} - if (irqstatus & (1 << 23)) { - if (warn) - printk("system error "); - ctrl |= SA110_CNTL_RXSERR; - } +static void dc21285_serr_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct timer_list *timer = dev_id; + unsigned int cntl; - if (warn) - printk("pc=[<%08lX>]\n", instruction_pointer(regs)); + printk(KERN_DEBUG "PCI: system error received: "); + pcibios_report_status(PCI_STATUS_SIG_SYSTEM_ERROR, 1); + printk("\n"); - pcibios_report_device_errors(warn); + cntl = *CSR_SA110_CNTL & 0xffffdf07; + *CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR; - *CSR_PCICMD = cmd; - *CSR_SA110_CNTL = ctrl; + /* + * back off this interrupt + */ + disable_irq(irq); + timer->expires = jiffies + HZ; + add_timer(timer); } -static struct irqaction dc21285_error_action = { - dc21285_error, SA_INTERRUPT, 0, "PCI error", NULL, NULL -}; +static void dc21285_discard_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + printk(KERN_DEBUG "PCI: discard timer expired\n"); + *CSR_SA110_CNTL &= 0xffffde07; +} + +static void dc21285_dparity_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int cmd; + + printk(KERN_DEBUG "PCI: data parity error detected: "); + pcibios_report_status(PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY, 1); + printk("\n"); + + cmd = *CSR_PCICMD & 0xffff; + *CSR_PCICMD = cmd | 1 << 24; +} + +static void dc21285_parity_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct timer_list *timer = dev_id; + unsigned int cmd; + + printk(KERN_DEBUG "PCI: parity error detected: "); + pcibios_report_status(PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY, 1); + printk("\n"); + + cmd = *CSR_PCICMD & 0xffff; + *CSR_PCICMD = cmd | 1 << 31; + + /* + * back off this interrupt + */ + disable_irq(irq); + timer->expires = jiffies + HZ; + add_timer(timer); +} void __init dc21285_init(void) { - static struct resource csrmem, csrio; - struct arm_pci_sysdata sysdata; unsigned long cntl; - unsigned int mem_size, pci_cmd = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + unsigned int mem_size; + unsigned int pci_cmd = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE; - int i; + int cfn_mode; + /* + * These registers need to be set up whether we're the + * central function or not. + */ mem_size = (unsigned int)high_memory - PAGE_OFFSET; *CSR_SDRAMBASEMASK = (mem_size - 1) & 0x0ffc0000; *CSR_SDRAMBASEOFFSET = 0; @@ -233,60 +272,93 @@ *CSR_CSRBASEOFFSET = 0; *CSR_PCIADDR_EXTN = 0; -#ifdef CONFIG_HOST_FOOTBRIDGE + cfn_mode = __footbridge_cfn_mode(); - csrio.flags = IORESOURCE_IO; - csrio.name = "DC21285"; - csrmem.flags = IORESOURCE_MEM; - csrmem.name = "DC21285"; - - allocate_resource(&ioport_resource, &csrio, 128, - 0xff00, 0xffff, 128, NULL, NULL); - allocate_resource(&iomem_resource, &csrmem, 128, - 0xf4000000, 0xf8000000, 128, NULL, NULL); - - /* - * Map our SDRAM at a known address in PCI space, just in case - * the firmware had other ideas. Using a nonzero base is - * necessary, since some VGA cards forcefully use PCI addresses - * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards). - */ - *CSR_PCICACHELINESIZE = 0x00002008; - *CSR_PCICSRBASE = csrmem.start; - *CSR_PCICSRIOBASE = csrio.start; - *CSR_PCISDRAMBASE = virt_to_bus((void *)PAGE_OFFSET); - *CSR_PCIROMBASE = 0; - *CSR_PCICMD = pci_cmd | + printk(KERN_INFO "PCI: DC21285 footbridge, revision %02lX in " + "%s mode\n", *CSR_CLASSREV & 0xff, cfn_mode ? + "central function" : "addin"); + + if (cfn_mode) { + static struct resource csrmem, csrio; + struct arm_pci_sysdata sysdata; + int i; + + csrio.flags = IORESOURCE_IO; + csrio.name = "DC21285"; + csrmem.flags = IORESOURCE_MEM; + csrmem.name = "DC21285"; + + allocate_resource(&ioport_resource, &csrio, 128, + 0xff00, 0xffff, 128, NULL, NULL); + allocate_resource(&iomem_resource, &csrmem, 128, + 0xf4000000, 0xf8000000, 128, NULL, NULL); + + /* + * Map our SDRAM at a known address in PCI space, just in case + * the firmware had other ideas. Using a nonzero base is + * necessary, since some VGA cards forcefully use PCI addresses + * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards). + */ + *CSR_PCICACHELINESIZE = 0x00002008; + *CSR_PCICSRBASE = csrmem.start; + *CSR_PCICSRIOBASE = csrio.start; + *CSR_PCISDRAMBASE = virt_to_bus((void *)PAGE_OFFSET); + *CSR_PCIROMBASE = 0; + *CSR_PCICMD = pci_cmd | (1 << 31) | (1 << 29) | (1 << 28) | (1 << 24); -#endif - - printk(KERN_DEBUG "PCI: DC21285 footbridge, revision %02lX\n", - *CSR_CLASSREV & 0xff); - - for (i = 0; i < MAX_NR_BUS; i++) { - sysdata.bus[i].features = PCI_COMMAND_FAST_BACK | - PCI_COMMAND_SERR | - PCI_COMMAND_PARITY; - sysdata.bus[i].maxdevsel = PCI_STATUS_DEVSEL_FAST; - } - pci_scan_bus(0, &dc21285_ops, &sysdata); + for (i = 0; i < MAX_NR_BUS; i++) { + sysdata.bus[i].features = PCI_COMMAND_FAST_BACK | + PCI_COMMAND_SERR | + PCI_COMMAND_PARITY; + sysdata.bus[i].maxdevsel = PCI_STATUS_DEVSEL_FAST; + } - pci_cmd |= sysdata.bus[0].features; + pci_scan_bus(0, &dc21285_ops, &sysdata); - printk("Fast back to back PCI transfers %sabled\n", - (sysdata.bus[0].features & PCI_COMMAND_FAST_BACK) ? "en" : "dis"); + pci_cmd |= sysdata.bus[0].features; - /* - * Clear any existing errors - we aren't - * interested in historical data... - */ - cntl = *CSR_SA110_CNTL & 0xffffde07; - *CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR; - *CSR_PCICMD = pci_cmd | 1 << 31 | 1 << 29 | 1 << 28 | 1 << 24; + printk("PCI: Fast back to back transfers %sabled\n", + (sysdata.bus[0].features & PCI_COMMAND_FAST_BACK) ? + "en" : "dis"); + + /* + * Clear any existing errors - we aren't + * interested in historical data... + */ + cntl = *CSR_SA110_CNTL & 0xffffde07; + *CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR; + *CSR_PCICMD = pci_cmd | 1 << 31 | 1 << 29 | 1 << 28 | 1 << 24; + } else { + /* + * If we are not compiled to accept "add-in" mode, then + * we are using a constant virt_to_bus translation which + * can not hope to cater for the way the host BIOS has + * set up the machine. + */ + panic("PCI: this kernel is compiled for central " + "function mode only"); + } /* * Initialise PCI error IRQ after we've finished probing */ - setup_arm_irq(IRQ_PCI_ERR, &dc21285_error_action); + request_irq(IRQ_PCI_ABORT, dc21285_abort_irq, SA_INTERRUPT, "PCI abort", NULL); + request_irq(IRQ_DISCARD_TIMER, dc21285_discard_irq, SA_INTERRUPT, "Discard timer", NULL); + request_irq(IRQ_PCI_DPERR, dc21285_dparity_irq, SA_INTERRUPT, "PCI data parity", NULL); + + init_timer(&serr_timer); + init_timer(&perr_timer); + + serr_timer.data = IRQ_PCI_SERR; + serr_timer.function = dc21285_enable_error; + perr_timer.data = IRQ_PCI_PERR; + perr_timer.function = dc21285_enable_error; + + request_irq(IRQ_PCI_SERR, dc21285_serr_irq, SA_INTERRUPT, + "PCI system error", &serr_timer); + request_irq(IRQ_PCI_PERR, dc21285_parity_irq, SA_INTERRUPT, + "PCI parity error", &perr_timer); + + register_isa_ports(DC21285_PCI_MEM, DC21285_PCI_IO, 0); } diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/kernel/dma-a5k.c linux/arch/arm/kernel/dma-a5k.c --- v2.4.0-test1/linux/arch/arm/kernel/dma-a5k.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/kernel/dma-a5k.c Mon Jun 19 17:59:34 2000 @@ -15,7 +15,9 @@ #include "dma.h" -static struct fiq_handler fh = { NULL, "floppydma", NULL, NULL }; +static struct fiq_handler fh = { + name: "floppydma" +}; int arch_request_dma(dmach_t channel, dma_t *dma, const char *dev_id) { diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/kernel/dma-rpc.c linux/arch/arm/kernel/dma-rpc.c --- v2.4.0-test1/linux/arch/arm/kernel/dma-rpc.c Fri Oct 22 13:21:44 1999 +++ linux/arch/arm/kernel/dma-rpc.c Mon Jun 19 17:59:34 2000 @@ -20,7 +20,9 @@ #include "dma.h" -static struct fiq_handler fh = { NULL, "floppydma", NULL, NULL }; +static struct fiq_handler fh = { + name: "floppydma" +}; #if 0 typedef enum { diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/kernel/ecard.c linux/arch/arm/kernel/ecard.c --- v2.4.0-test1/linux/arch/arm/kernel/ecard.c Tue Dec 7 09:32:40 1999 +++ linux/arch/arm/kernel/ecard.c Mon Jun 19 17:59:34 2000 @@ -52,6 +52,10 @@ #define oldlatch_init() #endif +#ifndef CONFIG_ARCH_RPC +#define HAVE_EXPMASK +#endif + enum req { req_readbytes, req_reset diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/kernel/entry-armv.S linux/arch/arm/kernel/entry-armv.S --- v2.4.0-test1/linux/arch/arm/kernel/entry-armv.S Fri May 12 14:18:55 2000 +++ linux/arch/arm/kernel/entry-armv.S Mon Jun 19 17:59:34 2000 @@ -32,7 +32,7 @@ .text -#define PF_TRACESYS 0x20 +#define PT_TRACESYS 0x00000002 @ Bad Abort numbers @ ----------------- @@ -233,14 +233,12 @@ .macro irq_prio_table .endm -#elif defined(CONFIG_HOST_FOOTBRIDGE) || defined(CONFIG_ADDIN_FOOTBRIDGE) +#elif defined(CONFIG_FOOTBRIDGE) #include .macro disable_fiq .endm - .equ irq_mask_pci_err_high, IRQ_MASK_PCI_ERR & 0xff000000 - .equ irq_mask_pci_err_low, IRQ_MASK_PCI_ERR & 0x00ffffff .equ dc21285_high, ARMCSR_BASE & 0xff000000 .equ dc21285_low, ARMCSR_BASE & 0x00ffffff @@ -311,10 +309,24 @@ movne \irqnr, #IRQ_CONTX bne 1001f - tst \irqstat, #irq_mask_pci_err_high - tsteq \irqstat, #irq_mask_pci_err_low - movne \irqnr, #IRQ_PCI_ERR + tst \irqstat, #IRQ_MASK_PCI_ABORT + movne \irqnr, #IRQ_PCI_ABORT bne 1001f + + tst \irqstat, #IRQ_MASK_PCI_SERR + movne \irqnr, #IRQ_PCI_SERR + bne 1001f + + tst \irqstat, #IRQ_MASK_DISCARD_TIMER + movne \irqnr, #IRQ_DISCARD_TIMER + bne 1001f + + tst \irqstat, #IRQ_MASK_PCI_DPERR + movne \irqnr, #IRQ_PCI_DPERR + bne 1001f + + tst \irqstat, #IRQ_MASK_PCI_PERR + movne \irqnr, #IRQ_PCI_PERR 1001: .endm @@ -389,12 +401,25 @@ ldr \irqnr, [r4, #4] @ ICMR = 0xfa050004 ands \irqstat, \irqstat, \irqnr mov \irqnr, #0 - beq 1002f -1001: tst \irqstat, #1 - addeq \irqnr, \irqnr, #1 - moveq \irqstat, \irqstat, lsr #1 - beq 1001b -1002: + beq 1001f + tst \irqstat, #0xff + moveq \irqstat, \irqstat, lsr #8 + addeq \irqnr, \irqnr, #8 + tsteq \irqstat, #0xff + moveq \irqstat, \irqstat, lsr #8 + addeq \irqnr, \irqnr, #8 + tsteq \irqstat, #0xff + moveq \irqstat, \irqstat, lsr #8 + addeq \irqnr, \irqnr, #8 + tst \irqstat, #0x0f + moveq \irqstat, \irqstat, lsr #4 + addeq \irqnr, \irqnr, #4 + tst \irqstat, #0x03 + moveq \irqstat, \irqstat, lsr #2 + addeq \irqnr, \irqnr, #2 + tst \irqstat, #0x01 + addeqs \irqnr, \irqnr, #1 +1001: .endm .macro irq_prio_table @@ -441,7 +466,8 @@ .macro restore_user_regs ldr r0, [sp, #S_PSR] @ Get calling cpsr - msr cpsr_c, #I_BIT | MODE_SVC @ disable IRQs + mov ip, #I_BIT | MODE_SVC + msr cpsr_c, ip @ disable IRQs msr spsr, r0 @ save in spsr_svc ldmia sp, {r0 - lr}^ @ Get calling r0 - lr mov r0, r0 @@ -592,9 +618,10 @@ bl cpu_data_abort #endif msr cpsr_c, r9 - mov r3, sp + mov r2, sp bl SYMBOL_NAME(do_DataAbort) - msr cpsr_c, #I_BIT | MODE_SVC + mov r0, #I_BIT | MODE_SVC + msr cpsr_c, r0 ldr r0, [sp, #S_PSR] msr spsr, r0 ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr @@ -636,7 +663,8 @@ mov r1, sp @ struct pt_regs *regs bl SYMBOL_NAME(do_undefinstr) -1: msr cpsr_c, #I_BIT | MODE_SVC +1: mov r0, #I_BIT | MODE_SVC + msr cpsr_c, r0 ldr lr, [sp, #S_PSR] @ Get SVC cpsr msr spsr, lr ldmia sp, {r0 - pc}^ @ Restore SVC registers @@ -675,8 +703,9 @@ #else bl cpu_data_abort #endif - msr cpsr_c, #MODE_SVC @ Enable interrupts - mov r3, sp + mov r2, #MODE_SVC + msr cpsr_c, r2 @ Enable interrupts + mov r2, sp adrsvc al, lr, ret_from_sys_call b SYMBOL_NAME(do_DataAbort) @@ -720,9 +749,10 @@ add r10, r10, #TSS_FPESAVE @ r10 = workspace ldr pc, [r4] @ Call FP module USR entry point -fpundefinstr: mov r0, lr +fpundefinstr: mov r0, #MODE_SVC + msr cpsr_c, r0 @ Enable interrupts + mov r0, lr mov r1, sp - msr cpsr_c, #MODE_SVC @ Enable interrupts adrsvc al, lr, ret_from_sys_call b SYMBOL_NAME(do_undefinstr) @@ -736,7 +766,8 @@ stmdb r8, {sp, lr}^ @ Save sp_usr lr_usr alignment_trap r4, r7, __temp_abt zero_fp - msr cpsr_c, #MODE_SVC @ Enable interrupts + mov r0, #MODE_SVC + msr cpsr_c, r0 @ Enable interrupts mov r0, r5 @ address (pc) mov r1, sp @ regs bl SYMBOL_NAME(do_PrefetchAbort) @ call abort handler @@ -816,7 +847,8 @@ @ @ now branch to the relevent MODE handling routine @ - msr spsr_c, #I_BIT | MODE_SVC @ switch to SVC_32 mode + mov r13, #I_BIT | MODE_SVC + msr spsr_c, r13 @ switch to SVC_32 mode and lr, lr, #15 ldr lr, [pc, lr, lsl #2] @@ -856,7 +888,8 @@ @ @ now branch to the relevent MODE handling routine @ - msr spsr_c, #I_BIT | MODE_SVC @ switch to SVC_32 mode + mov r13, #I_BIT | MODE_SVC + msr spsr_c, r13 @ switch to SVC_32 mode and lr, lr, #15 ldr lr, [pc, lr, lsl #2] @@ -897,7 +930,8 @@ @ @ now branch to the relevent MODE handling routine @ - msr spsr_c, #I_BIT | MODE_SVC @ switch to SVC_32 mode + mov r13, #I_BIT | MODE_SVC + msr spsr_c, r13 @ switch to SVC_32 mode ands lr, lr, #15 ldreq lr, .LCtab_pabt @@ -924,7 +958,8 @@ @ @ now branch to the relevent MODE handling routine @ - msr spsr_c, #I_BIT | MODE_SVC @ switch to SVC_32 mode + mov r13, #I_BIT | MODE_SVC + msr spsr_c, r13 @ switch to SVC_32 mode and lr, lr, #15 ldr lr, [pc, lr, lsl #2] diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/kernel/entry-common.S linux/arch/arm/kernel/entry-common.S --- v2.4.0-test1/linux/arch/arm/kernel/entry-common.S Wed Apr 26 16:34:06 2000 +++ linux/arch/arm/kernel/entry-common.S Mon Jun 19 17:59:34 2000 @@ -94,9 +94,9 @@ bcs 2f get_current_task ip - ldr ip, [ip, #TSK_FLAGS] @ check for syscall tracing + ldr ip, [ip, #TSK_PTRACE] @ check for syscall tracing adr tbl, SYMBOL_NAME(sys_call_table) - tst ip, #PF_TRACESYS + tst ip, #PT_TRACESYS ldreq pc, [tbl, scno, lsl #2] @ call sys routine ldr tip, [sp, #S_IP + S_OFF] @ save old IP diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/kernel/hw-footbridge.c linux/arch/arm/kernel/hw-footbridge.c --- v2.4.0-test1/linux/arch/arm/kernel/hw-footbridge.c Sun Mar 19 18:35:30 2000 +++ linux/arch/arm/kernel/hw-footbridge.c Mon Jun 19 17:59:34 2000 @@ -662,12 +662,13 @@ #endif -void __init hw_init(void) +/* + * Initialise any other hardware after we've got the PCI bus + * initialised. We may need the PCI bus to talk to this other + * hardware. + */ +static int __init hw_init(void) { - extern void register_isa_ports(unsigned int, unsigned int, - unsigned int); - register_isa_ports(DC21285_PCI_MEM, DC21285_PCI_IO, 0); - #ifdef CONFIG_ARCH_NETWINDER /* * this ought to have a better home... @@ -678,7 +679,6 @@ */ if (machine_is_netwinder()) { unsigned long flags; - extern int isapnp_disable; wb977_init(); cpld_init(); @@ -687,21 +687,13 @@ spin_lock_irqsave(&gpio_lock, flags); gpio_modify_op(GPIO_RED_LED|GPIO_GREEN_LED, DEFAULT_LEDS); spin_unlock_irqrestore(&gpio_lock, flags); - -#ifdef CONFIG_ISAPNP - /* - * We must not use the kernels ISAPnP code - * on the NetWinder - it will reset the settings - * for the WaveArtist chip and render it inoperable. - */ - isapnp_disable = 1; -#endif } #endif #ifdef CONFIG_ARCH_CATS if (machine_is_cats()) cats_hw_init(); #endif - - leds_event(led_start); + return 0; } + +__initcall(hw_init); diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/kernel/hw-sa1100.c linux/arch/arm/kernel/hw-sa1100.c --- v2.4.0-test1/linux/arch/arm/kernel/hw-sa1100.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/kernel/hw-sa1100.c Mon Jun 19 17:59:34 2000 @@ -0,0 +1,135 @@ +/* + * arch/arm/kernel/hw-sa1100.c + * + * SA1100-dependent machine specifics + * + * Copyright (C) 2000 Nicolas Pitre + * + * This will certainly contain more stuff with time... like power management, + * special hardware autodetection, etc. + * + */ +#include +#include +#include +#include +#include + +#include +#include + + +/* + * SA1100 GPIO edge detection for IRQs: + * IRQs are generated on Falling-Edge, Rising-Edge, or both. + * This must be called *before* the appropriate IRQ is registered. + * Use this instead of directly setting GRER/GFER. + */ + +int GPIO_IRQ_rising_edge; +int GPIO_IRQ_falling_edge; + +void set_GPIO_IRQ_edge( int gpio_mask, int edge ) +{ + if( edge & GPIO_FALLING_EDGE ) + GPIO_IRQ_falling_edge |= gpio_mask; + else + GPIO_IRQ_falling_edge &= ~gpio_mask; + if( edge & GPIO_RISING_EDGE ) + GPIO_IRQ_rising_edge |= gpio_mask; + else + GPIO_IRQ_rising_edge &= ~gpio_mask; +} + +EXPORT_SYMBOL(set_GPIO_IRQ_edge); + + +#ifdef CONFIG_SA1100_ASSABET + +unsigned long BCR_value = BCR_DB1110; +unsigned long SCR_value = SCR_INIT; +EXPORT_SYMBOL(BCR_value); +EXPORT_SYMBOL(SCR_value); + +/* + * Read System Configuration "Register" + * (taken from "Intel StrongARM SA-1110 Microprocessor Development Board + * User's Guide", section 4.4.1) + * + * This same scan is performed in arch/arm/boot/compressed/head-sa1100.S + * to set up the serial port for decompression status messages. We + * repeat it here because the kernel may not be loaded as a zImage, and + * also because it's a hassle to communicate the SCR value to the kernel + * from the decompressor. + */ + +void __init get_assabet_scr(void) +{ + unsigned long flags, scr, i; + + save_flags_cli(flags); + GPDR |= 0x3fc; /* Configure GPIO 9:2 as outputs */ + GPSR = 0x3fc; /* Write 0xFF to GPIO 9:2 */ + GPDR &= ~(0x3fc); /* Configure GPIO 9:2 as inputs */ + for(i = 100; i--; scr = GPLR); /* Read GPIO 9:2 */ + GPDR |= 0x3fc; /* restore correct pin direction */ + restore_flags(flags); + scr &= 0x3fc; /* save as system configuration byte. */ + + SCR_value = scr; +} + +#endif /* CONFIG_SA1100_ASSABET */ + + +#ifdef CONFIG_SA1111 + +void __init sa1111_init(void){ + unsigned long id=SKID; + + if((id & SKID_ID_MASK) == SKID_SA1111_ID) + printk(KERN_INFO "SA-1111 Microprocessor Companion Chip: " + "silicon revision %x, metal revision %x\n", + (id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK)); + else { + printk(KERN_ERR "Could not detect SA-1111!\n"); + return; + } + + /* First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111: + * (SA-1110 Developer's Manual, section 9.1.2.1) + */ + GAFR |= GPIO_GPIO27; + GPDR |= GPIO_GPIO27; + TUCR = TUCR_3_6864MHz; + + /* Now, set up the PLL and RCLK in the SA-1111: */ + SKCR = SKCR_PLL_BYPASS | SKCR_RDYEN | SKCR_OE_EN; + udelay(100); + SKCR = SKCR_PLL_BYPASS | SKCR_RCLKEN | SKCR_RDYEN | SKCR_OE_EN; + + /* SA-1111 Register Access Bus should now be available. Clocks for + * any other SA-1111 functional blocks must be enabled separately + * using the SKPCR. + */ +} + +#endif + + +static void __init hw_sa1100_init(void) +{ + if( machine_is_assabet() ){ + if(machine_has_neponset()){ +#ifdef CONFIG_ASSABET_NEPONSET + LEDS = WHOAMI; + sa1111_init(); +#else + printk( "Warning: Neponset detected but full support " + "hasn't been configured in the kernel\n" ); +#endif + } + } +} + +module_init(hw_sa1100_init); diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/kernel/ioport.c linux/arch/arm/kernel/ioport.c --- v2.4.0-test1/linux/arch/arm/kernel/ioport.c Tue Dec 14 01:27:23 1999 +++ linux/arch/arm/kernel/ioport.c Wed Dec 31 16:00:00 1969 @@ -1,36 +0,0 @@ -/* - * linux/arch/arm/kernel/ioport.c - * - * IO permission support for ARM. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef CONFIG_CPU_32 -asmlinkage int sys_iopl(unsigned long turn_on) -{ - if (turn_on && !capable(CAP_SYS_RAWIO)) - return -EPERM; - - /* - * We only support an on_off approach - */ - modify_domain(DOMAIN_IO, turn_on ? DOMAIN_MANAGER : DOMAIN_CLIENT); - - return 0; -} -#else -asmlinkage int sys_iopl(unsigned long turn_on) -{ - return -ENOSYS; -} -#endif diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/kernel/irq.c linux/arch/arm/kernel/irq.c --- v2.4.0-test1/linux/arch/arm/kernel/irq.c Wed Apr 26 16:34:06 2000 +++ linux/arch/arm/kernel/irq.c Mon Jun 19 17:59:34 2000 @@ -15,7 +15,7 @@ * 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 /* for CONFIG_DEBUG_ERRORS */ +#include #include #include #include @@ -33,13 +33,6 @@ #include #include -#ifndef SMP -#define irq_enter(cpu, irq) (++local_irq_count[cpu]) -#define irq_exit(cpu, irq) (--local_irq_count[cpu]) -#else -#error SMP not supported -#endif - #ifndef cliIF #define cliIF() #endif @@ -85,6 +78,7 @@ }; static struct irqdesc irq_desc[NR_IRQS]; +static volatile unsigned long irq_err_count; /* * Get architecture specific interrupt handlers @@ -133,8 +127,8 @@ action = irq_desc[i].action; if (!action) continue; - p += sprintf(p, "%3d: %10u %s", - i, kstat_irqs(i), action->name); + p += sprintf(p, "%3d: %10u ", i, kstat_irqs(i)); + p += sprintf(p, " %s", action->name); for (action = action->next; action; action = action->next) { p += sprintf(p, ", %s", action->name); } @@ -144,6 +138,7 @@ #ifdef CONFIG_ARCH_ACORN p += get_fiq_list(p); #endif + p += sprintf(p, "Err: %10lu\n", irq_err_count); return p - buf; } @@ -181,10 +176,17 @@ { struct irqdesc * desc; struct irqaction * action; - int status, cpu; + int cpu; irq = fixup_irq(irq); + /* + * Some hardware gives randomly wrong interrupts. Rather + * than crashing, do something sensible. + */ + if (irq >= NR_IRQS) + goto bad_irq; + desc = irq_desc + irq; spin_lock(&irq_controller_lock); @@ -197,10 +199,11 @@ desc->triggered = 1; /* Return with this interrupt masked if no action */ - status = 0; action = desc->action; if (action) { + int status = 0; + if (desc->nomask) { spin_lock(&irq_controller_lock); desc->unmask(irq); @@ -237,9 +240,15 @@ if (softirq_state[cpu].active & softirq_state[cpu].mask) do_softirq(); + return; + +bad_irq: + irq_err_count += 1; + printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq); + return; } -#if defined(CONFIG_ARCH_ACORN) +#ifdef CONFIG_ARCH_ACORN void do_ecard_IRQ(int irq, struct pt_regs *regs) { struct irqdesc * desc; diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/kernel/leds-ebsa110.c linux/arch/arm/kernel/leds-ebsa110.c --- v2.4.0-test1/linux/arch/arm/kernel/leds-ebsa110.c Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/kernel/leds-ebsa110.c Mon Jun 19 17:59:34 2000 @@ -13,7 +13,7 @@ #include #include -void ebsa110_leds_event(led_event_t ledevt) +static void ebsa110_leds_event(led_event_t ledevt) { unsigned long flags; diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/kernel/leds-footbridge.c linux/arch/arm/kernel/leds-footbridge.c --- v2.4.0-test1/linux/arch/arm/kernel/leds-footbridge.c Thu Mar 2 14:36:22 2000 +++ linux/arch/arm/kernel/leds-footbridge.c Mon Jun 19 17:59:34 2000 @@ -46,7 +46,7 @@ switch (evt) { case led_start: hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN; -#ifndef CONFIG_LEDS_IDLE +#ifndef CONFIG_LEDS_CPU hw_led_state |= XBUS_LED_AMBER; #endif led_state |= LED_STATE_ENABLED; @@ -223,11 +223,12 @@ { } -static void __init -init_leds_event(led_event_t evt) -{ - leds_event = dummy_leds_event; +void (*leds_event)(led_event_t) = dummy_leds_event; + +EXPORT_SYMBOL(leds_event); +static int __init leds_init(void) +{ #ifdef CONFIG_FOOTBRIDGE if (machine_is_ebsa285() || machine_is_co285()) leds_event = ebsa285_leds_event; @@ -237,9 +238,9 @@ leds_event = netwinder_leds_event; #endif - leds_event(evt); -} + leds_event(led_start); -void (*leds_event)(led_event_t) = init_leds_event; + return 0; +} -EXPORT_SYMBOL(leds_event); +__initcall(leds_init); diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/kernel/leds-sa1100.c linux/arch/arm/kernel/leds-sa1100.c --- v2.4.0-test1/linux/arch/arm/kernel/leds-sa1100.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/kernel/leds-sa1100.c Mon Jun 19 17:59:34 2000 @@ -0,0 +1,333 @@ +/* + * linux/arch/arm/kernel/leds-sa1100.c + * + * Copyright (C) 2000 John Dorsey + * + * Original (leds-footbridge.c) by Russell King + * + * Added Brutus LEDs support + * Nicolas Pitre, Mar 19, 2000 + * + * Added LART LED support + * Erik Mouw (J.A.K.Mouw@its.tudelft.nl), April 21, 2000 + * + * + * Assabet uses the LEDs as follows: + * - Green - toggles state every 50 timer interrupts + * - Red - on if system is not idle + * + * Brutus uses the LEDs as follows: + * - D3 (Green, GPIO9) - toggles state every 50 timer interrupts + * - D17 (Red, GPIO20) - on if system is not idle + * - D4 (Green, GPIO8) - misc function + * + * LART uses the LED as follows: + * - GPIO23 is the LED, on if system is not idle + * You can use both CONFIG_LEDS_CPU and CONFIG_LEDS_TIMER at the same + * time, but in that case the timer events will still dictate the + * pace of the LED. + * + */ +#include +#include +#include +#include +#include + +#include +#include +#include + + +#define LED_STATE_ENABLED 1 +#define LED_STATE_CLAIMED 2 + +static unsigned int led_state; +static unsigned int hw_led_state; + + +#ifdef CONFIG_SA1100_ASSABET + +#define BCR_LED_MASK (BCR_LED_GREEN | BCR_LED_RED) + +static void assabet_leds_event(led_event_t evt) +{ + unsigned long flags; + + save_flags_cli(flags); + + switch (evt) { + case led_start: + hw_led_state = BCR_LED_RED | BCR_LED_GREEN; + led_state = LED_STATE_ENABLED; + break; + + case led_stop: + led_state &= ~LED_STATE_ENABLED; + break; + + case led_claim: + led_state |= LED_STATE_CLAIMED; + hw_led_state = BCR_LED_RED | BCR_LED_GREEN; + break; + + case led_release: + led_state &= ~LED_STATE_CLAIMED; + hw_led_state = BCR_LED_RED | BCR_LED_GREEN; + break; + +#ifdef CONFIG_LEDS_TIMER + case led_timer: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state ^= BCR_LED_GREEN; + break; +#endif + +#ifdef CONFIG_LEDS_CPU + case led_idle_start: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state |= BCR_LED_RED; + break; + + case led_idle_end: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state &= ~BCR_LED_RED; + break; +#endif + + case led_green_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~BCR_LED_GREEN; + break; + + case led_green_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= BCR_LED_GREEN; + break; + + case led_amber_on: + break; + + case led_amber_off: + break; + + case led_red_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~BCR_LED_RED; + break; + + case led_red_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= BCR_LED_RED; + break; + + default: + break; + } + + if (led_state & LED_STATE_ENABLED) + BCR = BCR_value = (BCR_value & ~BCR_LED_MASK) | hw_led_state; + + restore_flags(flags); +} + +#endif /* CONFIG_SA1100_ASSABET */ + +#ifdef CONFIG_SA1100_BRUTUS + +#define LED_D3 GPIO_GPIO(9) +#define LED_D4 GPIO_GPIO(8) +#define LED_D17 GPIO_GPIO(20) +#define LED_MASK (LED_D3|LED_D4|LED_D17) + +static void brutus_leds_event(led_event_t evt) +{ + unsigned long flags; + + save_flags_cli(flags); + + switch (evt) { + case led_start: + hw_led_state = LED_MASK; + led_state = LED_STATE_ENABLED; + break; + + case led_stop: + led_state &= ~LED_STATE_ENABLED; + break; + + case led_claim: + led_state |= LED_STATE_CLAIMED; + hw_led_state = LED_MASK; + break; + + case led_release: + led_state &= ~LED_STATE_CLAIMED; + hw_led_state = LED_MASK; + break; + +#ifdef CONFIG_LEDS_TIMER + case led_timer: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state ^= LED_D3; + break; +#endif + +#ifdef CONFIG_LEDS_CPU + case led_idle_start: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state |= LED_D17; + break; + + case led_idle_end: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state &= ~LED_D17; + break; +#endif + + case led_green_on: + hw_led_state &= ~LED_D4; + break; + + case led_green_off: + hw_led_state |= LED_D4; + break; + + case led_amber_on: + break; + + case led_amber_off: + break; + + case led_red_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~LED_D17; + break; + + case led_red_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= LED_D17; + break; + + default: + break; + } + + if (led_state & LED_STATE_ENABLED) { + GPSR = hw_led_state; + GPCR = hw_led_state ^ LED_MASK; + } + + restore_flags(flags); +} + +#endif /* CONFIG_SA1100_BRUTUS */ + +#ifdef CONFIG_SA1100_LART + +#define LED_23 GPIO_GPIO23 +#define LED_MASK (LED_23) + + +static void lart_leds_event(led_event_t evt) +{ + unsigned long flags; + + save_flags_cli(flags); + + switch(evt) { + case led_start: + hw_led_state = LED_MASK; + led_state = LED_STATE_ENABLED; + break; + + case led_stop: + led_state &= ~LED_STATE_ENABLED; + break; + + case led_claim: + led_state |= LED_STATE_CLAIMED; + hw_led_state = LED_MASK; + break; + + case led_release: + led_state &= ~LED_STATE_CLAIMED; + hw_led_state = LED_MASK; + break; + +#ifdef CONFIG_LEDS_TIMER + case led_timer: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state ^= LED_23; + break; +#endif + +#ifdef CONFIG_LEDS_CPU + case led_idle_start: + /* The LART people like the LED to be off when the + system is idle... */ + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state &= ~LED_23; + break; + + case led_idle_end: + /* ... and on if the system is not idle */ + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state |= LED_23; + break; +#endif + + case led_red_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~LED_23; + break; + + case led_red_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= LED_23; + break; + + default: + break; + } + + /* Now set the GPIO state, or nothing will happen at all */ + if (led_state & LED_STATE_ENABLED) { + GPSR = hw_led_state; + GPCR = hw_led_state ^ LED_MASK; + } + + restore_flags(flags); +} + +#endif /* CONFIG_SA1100_LART */ + +static void dummy_leds_event(led_event_t evt) +{ +} + +void (*leds_event)(led_event_t) = dummy_leds_event; + +EXPORT_SYMBOL(leds_event); + +static int __init +sa1100_leds_init(void) +{ +#ifdef CONFIG_SA1100_ASSABET + if (machine_is_assabet()) + leds_event = assabet_leds_event; +#endif +#ifdef CONFIG_SA1100_BRUTUS + if (machine_is_brutus()) + leds_event = brutus_leds_event; +#endif +#ifdef CONFIG_SA1100_LART + if (machine_is_lart()) + leds_event = lart_leds_event; +#endif + + leds_event(led_start); + return 0; +} + +__initcall(sa1100_leds_init); diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c --- v2.4.0-test1/linux/arch/arm/kernel/process.c Tue Apr 11 15:09:12 2000 +++ linux/arch/arm/kernel/process.c Mon Jun 19 17:59:34 2000 @@ -353,10 +353,12 @@ pid_t __ret; __asm__ __volatile__( - "mov r0, %1 @ kernel_thread sys_clone\n" -" mov r1, #0\n" - __syscall(clone)"\n" -" mov %0, r0" + "mov r0, %1 @ kernel_thread sys_clone + mov r1, #0 + "__syscall(clone)" + teq r0, #0 @ if we are the child + moveq fp, #0 @ ensure that fp is zero + mov %0, r0" : "=r" (__ret) : "Ir" (flags | CLONE_VM) : "r0", "r1"); if (__ret == 0) diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/kernel/ptrace.c linux/arch/arm/kernel/ptrace.c --- v2.4.0-test1/linux/arch/arm/kernel/ptrace.c Tue Mar 14 19:10:39 2000 +++ linux/arch/arm/kernel/ptrace.c Mon Jun 19 17:59:34 2000 @@ -393,10 +393,10 @@ ret = -EPERM; if (request == PTRACE_TRACEME) { /* are we already being traced? */ - if (current->flags & PF_PTRACED) + if (current->ptrace & PT_PTRACED) goto out; /* set the ptrace bit in the process flags. */ - current->flags |= PF_PTRACED; + current->ptrace |= PT_PTRACED; ret = 0; goto out; } @@ -419,9 +419,9 @@ (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) goto out; /* the same process cannot be attached many times */ - if (child->flags & PF_PTRACED) + if (child->ptrace & PT_PTRACED) goto out; - child->flags |= PF_PTRACED; + child->ptrace |= PT_PTRACED; if (child->p_pptr != current) { REMOVE_LINKS(child); child->p_pptr = current; @@ -432,7 +432,7 @@ goto out; } ret = -ESRCH; - if (!(child->flags & PF_PTRACED)) + if (!(child->ptrace & PT_PTRACED)) goto out; if (child->state != TASK_STOPPED) { if (request != PTRACE_KILL) @@ -486,9 +486,9 @@ if ((unsigned long) data > _NSIG) goto out; if (request == PTRACE_SYSCALL) - child->flags |= PF_TRACESYS; + child->ptrace |= PT_TRACESYS; else - child->flags &= ~PF_TRACESYS; + child->ptrace &= ~PT_TRACESYS; child->exit_code = data; wake_up_process (child); /* make sure single-step breakpoint is gone. */ @@ -515,7 +515,7 @@ if ((unsigned long) data > _NSIG) goto out; child->thread.debug.nsaved = -1; - child->flags &= ~PF_TRACESYS; + child->ptrace &= ~PT_TRACESYS; wake_up_process(child); child->exit_code = data; /* give it a chance to run. */ @@ -568,7 +568,7 @@ ret = -EIO; if ((unsigned long) data > _NSIG) goto out; - child->flags &= ~(PF_PTRACED|PF_TRACESYS); + child->ptrace &= ~(PT_PTRACED|PT_TRACESYS); wake_up_process (child); child->exit_code = data; REMOVE_LINKS(child); @@ -590,8 +590,8 @@ asmlinkage void syscall_trace(void) { - if ((current->flags & (PF_PTRACED|PF_TRACESYS)) - != (PF_PTRACED|PF_TRACESYS)) + if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) + != (PT_PTRACED|PT_TRACESYS)) return; current->exit_code = SIGTRAP; current->state = TASK_STOPPED; diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/kernel/semaphore.c linux/arch/arm/kernel/semaphore.c --- v2.4.0-test1/linux/arch/arm/kernel/semaphore.c Sun Feb 13 19:29:03 2000 +++ linux/arch/arm/kernel/semaphore.c Mon Jun 19 17:59:34 2000 @@ -290,68 +290,95 @@ * need to convert that sequence back into the C sequence when * there is contention on the semaphore. * - * r0 contains the semaphore pointer on entry. Save the C-clobbered - * registers (r0 to r3, ip and lr) except r0 in the cases where it - * is used as a return value.. + * 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(" .section .text.lock, \"ax\" .align 5 .globl __down_failed __down_failed: - stmfd sp!, {r0 - r3, ip, lr} + stmfd sp!, {r0 - r3, lr} + mov r0, ip bl __down - ldmfd sp!, {r0 - r3, ip, pc} + ldmfd sp!, {r0 - r3, pc} .align 5 .globl __down_interruptible_failed __down_interruptible_failed: - stmfd sp!, {r1 - r3, ip, lr} + stmfd sp!, {r0 - r3, lr} + mov r0, ip bl __down_interruptible - ldmfd sp!, {r1 - r3, ip, pc} + mov ip, r0 + ldmfd sp!, {r0 - r3, pc} .align 5 .globl __down_trylock_failed __down_trylock_failed: - stmfd sp!, {r1 - r3, ip, lr} + stmfd sp!, {r0 - r3, lr} + mov r0, ip bl __down_trylock - ldmfd sp!, {r1 - r3, ip, pc} + mov ip, r0 + ldmfd sp!, {r0 - r3, pc} .align 5 .globl __up_wakeup __up_wakeup: - stmfd sp!, {r0 - r3, ip, lr} + stmfd sp!, {r0 - r3, lr} + mov r0, ip bl __up - ldmfd sp!, {r0 - r3, ip, pc} + ldmfd sp!, {r0 - r3, pc} .align 5 .globl __down_read_failed __down_read_failed: - stmfd sp!, {r0 - r3, ip, lr} + stmfd sp!, {r0 - r3, lr} + mov r0, ip bcc 1f - bl down_read_failed_biased - ldmfd sp!, {r0 - r3, ip, pc} -1: bl down_read_failed - /***/ +1: bl down_read_failed_biased + ldmfd sp!, {r0 - r3, pc} +2: bl down_read_failed + mrs r1, cpsr + orr r2, r1, #128 + msr cpsr_c, r2 + ldr r3, [r0] + subs r3, r3, #1 + str r3, [r0] + msr cpsr_c, r1 + ldmplfd sp!, {r0 - r3, pc} + bcc 2b + b 1b .align 5 .globl __down_write_failed __down_write_failed: - stmfd sp!, {r0 - r3, ip, lr} + stmfd sp!, {r0 - r3, lr} + mov r0, ip bcc 1f - bl down_write_failed_biased - ldmfd sp!, {r0 - r3, ip, pc} -1: bl down_write_failed - /***/ +1: bl down_write_failed_biased + ldmfd sp!, {r0 - r3, pc} +2: bl down_write_failed + mrs r1, cpsr + orr r2, r1, #128 + msr cpsr_c, r2 + ldr r3, [r0] + subs r3, r3, #"RW_LOCK_BIAS_STR" + str r3, [r0] + msr cpsr_c, r1 + ldmeqfd sp!, {r0 - r3, pc} + bcc 2b + b 1b .align 5 .globl __rwsem_wake __rwsem_wake: - stmfd sp!, {r0 - r3, ip, lr} + stmfd sp!, {r0 - r3, lr} + mov r0, ip beq 1f bl rwsem_wake_readers - ldmfd sp!, {r0 - r3, ip, pc} + ldmfd sp!, {r0 - r3, pc} 1: bl rwsem_wake_writer - ldmfd sp!, {r0 - r3, ip, pc} + ldmfd sp!, {r0 - r3, pc} .previous "); diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/kernel/setup.c linux/arch/arm/kernel/setup.c --- v2.4.0-test1/linux/arch/arm/kernel/setup.c Wed Apr 26 16:34:06 2000 +++ linux/arch/arm/kernel/setup.c Mon Jun 19 17:59:34 2000 @@ -124,11 +124,11 @@ #ifdef MULTI_CPU processor = *list->proc; +#endif printk("Processor: %s %s revision %d\n", proc_info.manufacturer, proc_info.cpu_name, (int)processor_id & 15); -#endif sprintf(system_utsname.machine, "%s%c", list->arch_name, ENDIANNESS); sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS); @@ -164,24 +164,6 @@ return list; } -static unsigned long __init memparse(char *ptr, char **retptr) -{ - unsigned long ret = simple_strtoul(ptr, retptr, 0); - - switch (**retptr) { - case 'M': - case 'm': - ret <<= 10; - case 'K': - case 'k': - ret <<= 10; - (*retptr)++; - default: - break; - } - return ret; -} - /* * Initial parsing of the command line. We need to pick out the * memory size. We look for mem=size@start, where start and size @@ -217,6 +199,7 @@ mi->bank[mi->nr_banks].start = start; mi->bank[mi->nr_banks].size = size; + mi->bank[mi->nr_banks].node = 0; mi->nr_banks += 1; } c = *from++; @@ -378,6 +361,7 @@ if (meminfo.nr_banks == 0) { meminfo.nr_banks = 1; meminfo.bank[0].start = PHYS_OFFSET; + meminfo.bank[0].node = 0; if (params) meminfo.bank[0].size = params->u1.s.nr_pages << PAGE_SHIFT; else @@ -393,8 +377,8 @@ saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; parse_cmdline(&meminfo, cmdline_p, from); bootmem_init(&meminfo); - request_standard_resources(&meminfo, mdesc); paging_init(&meminfo); + request_standard_resources(&meminfo, mdesc); #ifdef CONFIG_VT #if defined(CONFIG_VGA_CONSOLE) diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/kernel/signal.c linux/arch/arm/kernel/signal.c --- v2.4.0-test1/linux/arch/arm/kernel/signal.c Mon Jun 19 16:31:56 2000 +++ linux/arch/arm/kernel/signal.c Mon Jun 19 17:59:34 2000 @@ -512,7 +512,7 @@ if (!signr) break; - if ((current->flags & PF_PTRACED) && signr != SIGKILL) { + if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { /* Let the debugger run. */ current->exit_code = signr; current->state = TASK_STOPPED; diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/kernel/time.c linux/arch/arm/kernel/time.c --- v2.4.0-test1/linux/arch/arm/kernel/time.c Wed Apr 26 16:34:06 2000 +++ linux/arch/arm/kernel/time.c Mon Jun 19 17:59:34 2000 @@ -154,21 +154,29 @@ static void do_leds(void) { - static unsigned int count = 50; - static int last_pid; +#ifdef CONFIG_LEDS_CPU + { + static int last_pid; - if (current->pid != last_pid) { - last_pid = current->pid; - if (last_pid) - leds_event(led_idle_end); - else - leds_event(led_idle_start); + if (current->pid != last_pid) { + last_pid = current->pid; + if (last_pid) + leds_event(led_idle_end); + else + leds_event(led_idle_start); + } } - - if (--count == 0) { - count = 50; - leds_event(led_timer); +#endif +#ifdef CONFIG_LEDS_TIMER + { + static unsigned int count = 50; + + if (--count == 0) { + count = 50; + leds_event(led_timer); + } } +#endif } #else #define do_leds() diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/lib/changebit.S linux/arch/arm/lib/changebit.S --- v2.4.0-test1/linux/arch/arm/lib/changebit.S Fri Jan 21 18:19:15 2000 +++ linux/arch/arm/lib/changebit.S Mon Jun 19 17:59:34 2000 @@ -9,18 +9,15 @@ .text /* Purpose : Function to change a bit - * Prototype: int change_bit(int bit,int *addr) + * Prototype: int change_bit(int bit, void *addr) */ ENTRY(change_bit) - and r2, r0, #7 - mov r3, #1 - mov r3, r3, lsl r2 - SAVEIRQS(ip) - DISABLEIRQS(ip) + 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] - RESTOREIRQS(ip) + restore_irqs ip RETINSTR(mov,pc,lr) - - diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/lib/clearbit.S linux/arch/arm/lib/clearbit.S --- v2.4.0-test1/linux/arch/arm/lib/clearbit.S Fri Jan 21 18:19:16 2000 +++ linux/arch/arm/lib/clearbit.S Mon Jun 19 17:59:34 2000 @@ -8,19 +8,20 @@ #include .text -@ Purpose : Function to clear a bit -@ Prototype: int clear_bit(int bit,int *addr) +/* + * Purpose : Function to clear a bit + * Prototype: int clear_bit(int bit, void *addr) + */ ENTRY(clear_bit) and r2, r0, #7 mov r3, #1 mov r3, r3, lsl r2 - SAVEIRQS(ip) - DISABLEIRQS(ip) + save_and_disable_irqs ip, r2 ldrb r2, [r1, r0, lsr #3] bic r2, r2, r3 strb r2, [r1, r0, lsr #3] - RESTOREIRQS(ip) + restore_irqs ip RETINSTR(mov,pc,lr) diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/lib/findbit.S linux/arch/arm/lib/findbit.S --- v2.4.0-test1/linux/arch/arm/lib/findbit.S Thu Mar 2 14:36:22 2000 +++ linux/arch/arm/lib/findbit.S Mon Jun 19 17:59:34 2000 @@ -1,65 +1,53 @@ /* - * linux/arch/arm/lib/bitops.S + * linux/arch/arm/lib/findbit.S * - * Copyright (C) 1995-1996 Russell King + * Copyright (C) 1995-2000 Russell King */ #include #include .text -@ Purpose : Find a 'zero' bit -@ Prototype: int find_first_zero_bit(char *addr,int maxbit); - +/* + * Purpose : Find a 'zero' bit + * Prototype: int find_first_zero_bit(void *addr, int maxbit); + */ ENTRY(find_first_zero_bit) - mov r2, #0 @ Initialise bit position -Lfindzbit1lp: ldrb r3, [r0, r2, lsr #3] @ Check byte, if 0xFF, then all bits set - teq r3, #0xFF - bne Lfoundzbit - add r2, r2, #8 - cmp r2, r1 @ Check to see if we have come to the end - bcc Lfindzbit1lp - add r0, r1, #1 @ Make sure that we flag an error - RETINSTR(mov,pc,lr) -Lfoundzbit: tst r3, #1 @ Check individual bits - moveq r0, r2 - RETINSTR(moveq,pc,lr) - tst r3, #2 - addeq r0, r2, #1 - RETINSTR(moveq,pc,lr) - tst r3, #4 - addeq r0, r2, #2 - RETINSTR(moveq,pc,lr) - tst r3, #8 - addeq r0, r2, #3 - RETINSTR(moveq,pc,lr) - tst r3, #16 - addeq r0, r2, #4 - RETINSTR(moveq,pc,lr) - tst r3, #32 - addeq r0, r2, #5 - RETINSTR(moveq,pc,lr) - tst r3, #64 - addeq r0, r2, #6 - RETINSTR(moveq,pc,lr) - add r0, r2, #7 + mov r2, #0 +.bytelp: 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 + cmp r2, r1 @ any more? + bcc .bytelp + add r0, r1, #1 @ no free bits RETINSTR(mov,pc,lr) -@ Purpose : Find next 'zero' bit -@ Prototype: int find_next_zero_bit(char *addr,int maxbit,int offset) - +/* + * Purpose : Find next 'zero' bit + * Prototype: int find_next_zero_bit(void *addr, int maxbit, int offset) + */ ENTRY(find_next_zero_bit) - tst r2, #7 - beq Lfindzbit1lp @ If new byte, goto old routine + ands ip, r2, #7 + beq .bytelp @ If new byte, goto old routine ldrb r3, [r0, r2, lsr#3] - orr r3, r3, #0xFF00 @ Set top bits so we wont get confused - str r4, [sp, #-4]! - and r4, r2, #7 - mov r3, r3, lsr r4 @ Shift right by no. of bits - ldr r4, [sp], #4 - and r3, r3, #0xFF - teq r3, #0xFF - orreq r2, r2, #7 + eor r3, r3, #0xff @ now looking for a 1 bit + movs r3, r3, lsr ip @ shift off unused bits + orreq r2, r2, #7 @ if zero, then no bits here + addeq r2, r2, #1 @ align bit pointer + beq .bytelp @ 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 - beq Lfindzbit1lp @ If all bits are set, goto old routine - b Lfoundzbit + mov r0, r2 + RETINSTR(mov,pc,lr) + diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/lib/getconsdata.c linux/arch/arm/lib/getconsdata.c --- v2.4.0-test1/linux/arch/arm/lib/getconsdata.c Thu Mar 2 14:36:22 2000 +++ linux/arch/arm/lib/getconsdata.c Mon Jun 19 17:59:34 2000 @@ -1,7 +1,7 @@ /* * linux/arch/arm/lib/getconsdata.c * - * Copyright (C) 1995-1998 Russell King + * Copyright (C) 1995-2000 Russell King */ #include #include @@ -25,15 +25,11 @@ #define OFF_TSK(n) (unsigned long)&(((struct task_struct *)0)->n) #define OFF_MM(n) (unsigned long)&(((struct mm_struct *)0)->n) -unsigned long TSK_STATE = OFF_TSK(state); -unsigned long TSK_FLAGS = OFF_TSK(flags); -unsigned long TSK_NEED_RESCHED = OFF_TSK(need_resched); unsigned long TSK_SIGPENDING = OFF_TSK(sigpending); unsigned long TSK_ADDR_LIMIT = OFF_TSK(addr_limit); +unsigned long TSK_NEED_RESCHED = OFF_TSK(need_resched); +unsigned long TSK_PTRACE = OFF_TSK(ptrace); unsigned long TSK_USED_MATH = OFF_TSK(used_math); - -unsigned long MM = OFF_TSK(mm); -unsigned long PGD = OFF_MM(pgd); unsigned long TSS_SAVE = OFF_TSK(thread.save); unsigned long TSS_FPESAVE = OFF_TSK(thread.fpstate.soft.save); diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/lib/setbit.S linux/arch/arm/lib/setbit.S --- v2.4.0-test1/linux/arch/arm/lib/setbit.S Fri Jan 21 18:19:16 2000 +++ linux/arch/arm/lib/setbit.S Mon Jun 19 17:59:34 2000 @@ -8,19 +8,20 @@ #include .text -@ Purpose : Function to set a bit -@ Prototype: int set_bit(int bit,int *addr) +/* + * Purpose : Function to set a bit + * Prototype: int set_bit(int bit, void *addr) + */ ENTRY(set_bit) and r2, r0, #7 mov r3, #1 mov r3, r3, lsl r2 - SAVEIRQS(ip) - DISABLEIRQS(ip) + save_and_disable_irqs ip, r2 ldrb r2, [r1, r0, lsr #3] orr r2, r2, r3 strb r2, [r1, r0, lsr #3] - RESTOREIRQS(ip) + restore_irqs ip RETINSTR(mov,pc,lr) diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/lib/testchangebit.S linux/arch/arm/lib/testchangebit.S --- v2.4.0-test1/linux/arch/arm/lib/testchangebit.S Fri Jan 21 18:19:16 2000 +++ linux/arch/arm/lib/testchangebit.S Mon Jun 19 17:59:34 2000 @@ -12,14 +12,13 @@ add r1, r1, r0, lsr #3 and r3, r0, #7 mov r0, #1 - SAVEIRQS(ip) - DISABLEIRQS(ip) + save_and_disable_irqs ip, r2 ldrb r2, [r1] tst r2, r0, lsl r3 eor r2, r2, r0, lsl r3 - moveq r0, #0 strb r2, [r1] - RESTOREIRQS(ip) + restore_irqs ip + moveq r0, #0 RETINSTR(mov,pc,lr) diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/lib/testclearbit.S linux/arch/arm/lib/testclearbit.S --- v2.4.0-test1/linux/arch/arm/lib/testclearbit.S Fri Jan 21 18:19:16 2000 +++ linux/arch/arm/lib/testclearbit.S Mon Jun 19 17:59:34 2000 @@ -10,16 +10,15 @@ ENTRY(test_and_clear_bit) add r1, r1, r0, lsr #3 @ Get byte offset - and r3, r0, #7 @ Get bit offset + and r3, r0, #7 @ Get bit offset mov r0, #1 - SAVEIRQS(ip) - DISABLEIRQS(ip) + save_and_disable_irqs ip, r2 ldrb r2, [r1] tst r2, r0, lsl r3 bic r2, r2, r0, lsl r3 - moveq r0, #0 strb r2, [r1] - RESTOREIRQS(ip) + restore_irqs ip + moveq r0, #0 RETINSTR(mov,pc,lr) diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/lib/testsetbit.S linux/arch/arm/lib/testsetbit.S --- v2.4.0-test1/linux/arch/arm/lib/testsetbit.S Fri Jan 21 18:19:16 2000 +++ linux/arch/arm/lib/testsetbit.S Mon Jun 19 17:59:34 2000 @@ -12,14 +12,13 @@ add r1, r1, r0, lsr #3 @ Get byte offset and r3, r0, #7 @ Get bit offset mov r0, #1 - SAVEIRQS(ip) - DISABLEIRQS(ip) + save_and_disable_irqs ip, r2 ldrb r2, [r1] tst r2, r0, lsl r3 orr r2, r2, r0, lsl r3 - moveq r0, #0 strb r2, [r1] - RESTOREIRQS(ip) + restore_irqs ip + moveq r0, #0 RETINSTR(mov,pc,lr) diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/lib/uaccess.S linux/arch/arm/lib/uaccess.S --- v2.4.0-test1/linux/arch/arm/lib/uaccess.S Fri Jan 21 18:19:16 2000 +++ linux/arch/arm/lib/uaccess.S Mon Jun 19 17:59:34 2000 @@ -538,13 +538,18 @@ .section .fixup,"ax" .align 0 - /* We took an exception. Zero out the buffer and pretend no - data was copied. */ -9001: ldr r0, [sp], #4 - ldr r1, [sp] - teq r1, #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 SYMBOL_NAME(__memzero) - LOADREGS(fd,sp!, {r0, r4 - r7, pc}) + mov r0, r4 + LOADREGS(fd,sp!, {r4 - r7, pc}) .previous /* Prototype: int __arch_clear_user(void *addr, size_t sz) diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/mm/Makefile linux/arch/arm/mm/Makefile --- v2.4.0-test1/linux/arch/arm/mm/Makefile Tue Apr 11 15:09:12 2000 +++ linux/arch/arm/mm/Makefile Mon Jun 19 17:59:34 2000 @@ -22,6 +22,9 @@ ifeq ($(CONFIG_CPU_ARM7),y) P_OBJS += proc-arm6,7.o endif + ifeq ($(CONFIG_CPU_ARM720),y) + P_OBJS += proc-arm720.o + endif ifeq ($(CONFIG_CPU_SA110),y) P_OBJS += proc-sa110.o endif @@ -41,5 +44,6 @@ fault-armo.o: fault-common.c proc-arm2,3.o: ../lib/constants.h proc-arm6,7.o: ../lib/constants.h +proc-arm720.o: ../lib/constants.h proc-sa110.o: ../lib/constants.h diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/mm/consistent.c linux/arch/arm/mm/consistent.c --- v2.4.0-test1/linux/arch/arm/mm/consistent.c Wed Apr 26 16:34:06 2000 +++ linux/arch/arm/mm/consistent.c Mon Jun 19 17:59:34 2000 @@ -9,8 +9,10 @@ #include #include #include +#include #include +#include #include /* @@ -19,6 +21,8 @@ * whether this could be called from an interrupt context or not. For * now, we expressly forbid it, especially as some of the stuff we do * here is not interrupt context safe. + * + * Note that this does *not* zero the allocated area! */ void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle) { @@ -36,15 +40,21 @@ if (!page) goto no_page; - memset((void *)page, 0, size); - clean_cache_area(page, size); - - *dma_handle = virt_to_bus((void *)page); - ret = __ioremap(virt_to_phys((void *)page), size, 0); if (ret) { /* free wasted pages */ unsigned long end = page + (PAGE_SIZE << order); + + /* + * we need to ensure that there are no + * cachelines in use, or worse dirty in + * this area. + */ + dma_cache_inv(page, size); + dma_cache_inv(ret, size); + + *dma_handle = virt_to_bus((void *)page); + page += size; while (page < end) { free_page(page); diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/mm/fault-armv.c linux/arch/arm/mm/fault-armv.c --- v2.4.0-test1/linux/arch/arm/mm/fault-armv.c Sun Mar 19 18:35:30 2000 +++ linux/arch/arm/mm/fault-armv.c Mon Jun 19 17:59:34 2000 @@ -250,6 +250,8 @@ } } +if (addr != eaddr) +printk("PC = %08lx, instr = %08x, addr = %08lx, eaddr = %08lx\n", instruction_pointer(regs), instr, addr, eaddr); if (LDST_L_BIT(instr)) { regs->uregs[rd] = get_unaligned((unsigned long *)eaddr); if (rd == 15) @@ -383,29 +385,38 @@ "more information\n" asmlinkage void -do_DataAbort(unsigned long addr, int fsr, int error_code, struct pt_regs *regs) +do_DataAbort(unsigned long addr, int error_code, struct pt_regs *regs, int fsr) { - const struct fsr_info *inf; + const struct fsr_info *inf = fsr_info + (fsr & 15); - if (user_mode(regs) && addr == regs->ARM_pc) { + if (addr == regs->ARM_pc) + goto weirdness; + + if (!inf->fn) + goto bad; + + if (!inf->fn(addr, error_code, regs)) + return; +bad: + force_sig(inf->sig, current); + die_if_kernel(inf->name, regs, fsr); + return; + +weirdness: + if (user_mode(regs)) { static int first = 1; - if (first) { + if (first) /* * I want statistical information on this problem, * but we don't want to hastle the users too much. */ printk(BUG_PROC_MSG, fsr); - first = 0; - } + first = 0; return; } - inf = fsr_info + (fsr & 15); - - if (!inf->fn || inf->fn(addr, error_code, regs)) { - force_sig(inf->sig, current); - die_if_kernel(inf->name, regs, fsr); - } + if (!inf->fn || inf->fn(addr, error_code, regs)) + goto bad; } asmlinkage int diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/mm/fault-common.c linux/arch/arm/mm/fault-common.c --- v2.4.0-test1/linux/arch/arm/mm/fault-common.c Wed Apr 26 16:34:06 2000 +++ linux/arch/arm/mm/fault-common.c Mon Jun 19 17:59:34 2000 @@ -16,6 +16,10 @@ { pgd_t *pgd; + if (!mm) + mm = &init_mm; + + printk(KERN_ALERT "pgd = %p\n", mm->pgd); pgd = pgd_offset(mm, addr); printk(KERN_ALERT "*pgd = %08lx", pgd_val(*pgd)); @@ -52,39 +56,78 @@ printk("\n"); } -/* - * Oops. The kernel tried to access some bad page. We'll have to - * terminate things with extreme prejudice. - */ -static void -kernel_page_fault(unsigned long addr, int write_access, struct pt_regs *regs, - struct task_struct *tsk, struct mm_struct *mm) +static int __do_page_fault(struct mm_struct *mm, unsigned long addr, int mode, struct task_struct *tsk) { - char *reason; + 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; - if (addr < PAGE_SIZE) - reason = "NULL pointer dereference"; + /* + * Ok, we have a good vm_area for this + * memory access, so we can handle it. + */ +good_area: + if (READ_FAULT(mode)) /* read? */ + mask = VM_READ|VM_EXEC; else - reason = "paging request"; + mask = VM_WRITE; - printk(KERN_ALERT "Unable to handle kernel %s at virtual address %08lx\n", - reason, addr); - if (!mm) - mm = &init_mm; + fault = -1; /* bad access type */ + if (!(vma->vm_flags & mask)) + goto out; - printk(KERN_ALERT "pgd = %p\n", mm->pgd); - show_pte(mm, addr); - die("Oops", regs, write_access); + /* + * 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(mode)); - do_exit(SIGKILL); + /* + * 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 + */ + tsk->policy |= SCHED_YIELD; + schedule(); + goto survive; + +check_stack: + if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr)) + goto good_area; +out: + return fault; } static int do_page_fault(unsigned long addr, int mode, struct pt_regs *regs) { struct task_struct *tsk; struct mm_struct *mm; - struct vm_area_struct *vma; unsigned long fixup; + int fault; tsk = current; mm = tsk->mm; @@ -97,57 +140,77 @@ goto no_context; down(&mm->mmap_sem); - vma = find_vma(mm, addr); - if (!vma) - goto bad_area; - if (vma->vm_start <= addr) - goto good_area; - if (!(vma->vm_flags & VM_GROWSDOWN) || expand_stack(vma, addr)) - goto bad_area; + fault = __do_page_fault(mm, addr, mode, tsk); + up(&mm->mmap_sem); /* - * Ok, we have a good vm_area for this memory access, so - * we can handle it.. + * Handle the "normal" case first */ -good_area: - if (READ_FAULT(mode)) { /* read? */ - if (!(vma->vm_flags & (VM_READ|VM_EXEC))) - goto bad_area; - } else { - if (!(vma->vm_flags & VM_WRITE)) - goto bad_area; - } + if (fault > 0) + return 0; /* - * If for any reason at all we couldn't handle the fault, - * make sure we exit gracefully rather than endlessly redo - * the fault. + * We had some memory, but were unable to + * successfully fix up this page fault. */ - if (!handle_mm_fault(mm, vma, addr & PAGE_MASK, DO_COW(mode))) + if (fault == 0) goto do_sigbus; - up(&mm->mmap_sem); - return 0; - /* - * Something tried to access memory that isn't in our memory map.. - * Fix it, but check if it's kernel or user first.. + * If we are in kernel mode at this point, we + * have no context to handle this fault with. */ -bad_area: - up(&mm->mmap_sem); + 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 { + /* + * Something tried to access memory that isn't in our memory map.. + * User mode accesses just cause a SIGSEGV + */ + struct siginfo si; + +#ifdef CONFIG_DEBUG_USER + printk(KERN_DEBUG "%s: unhandled page fault at pc=0x%08lx, " + "lr=0x%08lx (bad address=0x%08lx, code %d)\n", + tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode); +#endif - /* User mode accesses just cause a SIGSEGV */ - if (user_mode(regs)) { tsk->thread.address = addr; tsk->thread.error_code = mode; tsk->thread.trap_no = 14; -#ifdef CONFIG_DEBUG_USER - printk("%s: memory violation at pc=0x%08lx, lr=0x%08lx (bad address=0x%08lx, code %d)\n", - tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode); -#endif - force_sig(SIGSEGV, tsk); - return 0; + si.si_signo = SIGSEGV; + si.si_code = fault == -1 ? SEGV_ACCERR : SEGV_MAPERR; + si.si_addr = (void *)addr; + force_sig_info(SIGSEGV, &si, tsk); } + 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; + tsk->thread.error_code = mode; + tsk->thread.trap_no = 14; + force_sig(SIGBUS, tsk); + + /* Kernel mode? Handle exceptions or die */ + if (user_mode(regs)) + return 0; no_context: /* Are we prepared to handle this kernel fault? */ @@ -160,29 +223,16 @@ return 0; } - kernel_page_fault(addr, mode, regs, tsk, mm); - return 0; - -do_sigbus: /* - * We ran out of memory, or some other thing happened to us that made - * us unable to handle the page fault gracefully. + * Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. */ - up(&mm->mmap_sem); + printk(KERN_ALERT "Unable to handle kernel %s at virtual address %08lx\n", + (addr < PAGE_SIZE) ? "NULL pointer dereference" : "paging request", addr); - /* - * Send a sigbus, regardless of whether we were in kernel - * or user mode. - */ - tsk->thread.address = addr; - tsk->thread.error_code = mode; - tsk->thread.trap_no = 14; - force_sig(SIGBUS, tsk); + show_pte(mm, addr); + die("Oops", regs, mode); + do_exit(SIGKILL); - /* Kernel mode? Handle exceptions or die */ - if (!user_mode(regs)) - goto no_context; return 0; } - - diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/mm/init.c linux/arch/arm/mm/init.c --- v2.4.0-test1/linux/arch/arm/mm/init.c Wed Apr 26 16:34:06 2000 +++ linux/arch/arm/mm/init.c Mon Jun 19 17:59:34 2000 @@ -31,16 +31,23 @@ #include "map.h" +#ifndef CONFIG_DISCONTIGMEM +#define NR_NODES 1 +#else +#define NR_NODES 4 +#endif + #ifdef CONFIG_CPU_32 #define TABLE_OFFSET (PTRS_PER_PTE) #else #define TABLE_OFFSET 0 #endif + #define TABLE_SIZE ((TABLE_OFFSET + PTRS_PER_PTE) * sizeof(void *)) static unsigned long totalram_pages; pgd_t swapper_pg_dir[PTRS_PER_PGD]; -extern int _stext, _text, _etext, _edata, _end; +extern char _stext, _text, _etext, _end, __init_begin, __init_end; /* * The sole use of this is to pass memory configuration @@ -173,6 +180,12 @@ show_buffers(); } +struct node_info { + unsigned int start; + unsigned int end; + int bootmap_pages; +}; + #define O_PFN_DOWN(x) ((x) >> PAGE_SHIFT) #define V_PFN_DOWN(x) O_PFN_DOWN(__pa(x)) @@ -183,34 +196,24 @@ #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) +find_bootmap_pfn(int node, struct meminfo *mi, unsigned int bootmap_pages) { unsigned int start_pfn, bank, bootmap_pfn; start_pfn = V_PFN_UP(&_end); bootmap_pfn = 0; - /* - * FIXME: We really want to avoid allocating the bootmap - * over the top of the initrd. - */ -#ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start) { - if (__pa(initrd_end) > mi->end) { - printk ("initrd extends beyond end of memory " - "(0x%08lx > 0x%08lx) - disabling initrd\n", - __pa(initrd_end), mi->end); - initrd_start = 0; - initrd_end = 0; - } - } -#endif - for (bank = 0; bank < mi->nr_banks; bank ++) { unsigned int start, end; - if (mi->bank[bank].size == 0) + if (mi->bank[bank].node != node) continue; start = O_PFN_UP(mi->bank[bank].start); @@ -239,99 +242,224 @@ } /* - * Initialise one node of the bootmem allocator. For now, we - * only initialise node 0. Notice that we have a bootmem - * bitmap per node. + * 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 setup_bootmem_node(int node, struct meminfo *mi) +static unsigned int __init +find_memend_and_nodes(struct meminfo *mi, struct node_info *np) { - unsigned int end_pfn, start_pfn, bootmap_pages, bootmap_pfn; - unsigned int i; + unsigned int i, bootmem_pages = 0, memend_pfn = 0; + + for (i = 0; i < NR_NODES; i++) { + np[i].start = -1U; + np[i].end = 0; + np[i].bootmap_pages = 0; + } + + for (i = 0; i < mi->nr_banks; i++) { + unsigned long start, end; + int node; + + if (mi->bank[i].size == 0) { + /* + * Mark this bank with an invalid node number + */ + mi->bank[i].node = -1; + continue; + } + + node = mi->bank[i].node; + + if (node >= numnodes) { + numnodes = node + 1; - if (node != 0) /* only initialise node 0 for now */ - return; + /* + * Make sure we haven't exceeded the maximum number + * of nodes that we have in this configuration. If + * we have, we're in trouble. (maybe we ought to + * limit, instead of bugging?) + */ + if (numnodes > NR_NODES) + BUG(); + } + + /* + * Get the start and end pfns for this bank + */ + start = O_PFN_UP(mi->bank[i].start); + end = O_PFN_DOWN(mi->bank[i].start + mi->bank[i].size); - start_pfn = O_PFN_UP(PHYS_OFFSET); - end_pfn = O_PFN_DOWN(mi->end); - bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn); - bootmap_pfn = find_bootmap_pfn(mi, bootmap_pages); + if (np[node].start > start) + np[node].start = start; + + if (np[node].end < end) + np[node].end = end; + + if (memend_pfn < end) + memend_pfn = end; + } /* - * Initialise the boot-time allocator + * Calculate the number of pages we require to + * store the bootmem bitmaps. */ - init_bootmem_node(node, bootmap_pfn, start_pfn, end_pfn); + for (i = 0; i < numnodes; i++) { + if (np[i].end == 0) + continue; + + np[i].bootmap_pages = bootmem_bootmap_pages(np[i].end - + np[i].start); + bootmem_pages += np[i].bootmap_pages; + } /* - * Register all available RAM with the bootmem allocator. + * 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. */ - for (i = 0; i < mi->nr_banks; i++) - if (mi->bank[i].size) - free_bootmem_node(node, mi->bank[i].start, - PFN_SIZE(mi->bank[i].size) << PAGE_SHIFT); + max_low_pfn = memend_pfn - O_PFN_DOWN(PHYS_OFFSET); + mi->end = memend_pfn << PAGE_SHIFT; - reserve_bootmem_node(node, bootmap_pfn << PAGE_SHIFT, - bootmap_pages << PAGE_SHIFT); + return bootmem_pages; } -/* - * Initialise the bootmem allocator. - */ -void __init bootmem_init(struct meminfo *mi) +static int __init check_initrd(struct meminfo *mi) { - unsigned int i, node; + int initrd_node = -2; +#ifdef CONFIG_BLK_DEV_INITRD /* - * Calculate the physical address of the top of memory. - * Note that there are no guarantees assumed about the - * ordering of the bank information. + * Make sure that the initrd is within a valid area of + * memory. */ - mi->end = 0; - for (i = 0; i < mi->nr_banks; i++) { - unsigned long end; + if (initrd_start) { + unsigned long phys_initrd_start, phys_initrd_end; + unsigned int i; + + phys_initrd_start = __pa(initrd_start); + phys_initrd_end = __pa(initrd_end); + + for (i = 0; i < mi->nr_banks; i++) { + unsigned long bank_end; - if (mi->bank[i].size != 0) { - end = mi->bank[i].start + mi->bank[i].size; - if (mi->end < end) - mi->end = end; + bank_end = mi->bank[i].start + mi->bank[i].size; + + if (mi->bank[i].start <= phys_initrd_start && + phys_initrd_end <= bank_end) + initrd_node = mi->bank[i].node; } } - max_low_pfn = O_PFN_DOWN(mi->end - PHYS_OFFSET); + if (initrd_node == -1) { + printk(KERN_ERR "initrd (0x%08lx - 0x%08lx) extends beyond " + "physical memory - disabling initrd\n", + initrd_start, initrd_end); + initrd_start = initrd_end = 0; + } +#endif - /* - * Setup each node - */ - for (node = 0; node < numnodes; node++) - setup_bootmem_node(node, mi); + return initrd_node; +} +/* + * Reserve the various regions of node 0 + */ +static inline void reserve_node_zero(unsigned int bootmap_pfn, unsigned int bootmap_pages) +{ /* * Register the kernel text and data with bootmem. * Note that this can only be in node 0. */ - reserve_bootmem_node(0, V_PFN_DOWN(&_stext) << PAGE_SHIFT, - PFN_RANGE(&_stext, &_end) << PAGE_SHIFT); + reserve_bootmem_node(0, __pa(&_stext), &_end - &_stext); #ifdef CONFIG_CPU_32 /* * Reserve the page tables. These are already in use, * and can only be in node 0. */ - reserve_bootmem_node(0, V_PFN_DOWN(swapper_pg_dir) << PAGE_SHIFT, - PFN_SIZE(PTRS_PER_PGD * sizeof(void *)) << PAGE_SHIFT); + reserve_bootmem_node(0, __pa(swapper_pg_dir), + PTRS_PER_PGD * sizeof(void *)); #endif -#ifdef CONFIG_BLK_DEV_INITRD /* - * This may be in any bank. Currently, we assume that - * it is in bank 0. + * And don't forget to reserve the allocator bitmap, + * which will be freed later. */ - if (initrd_start) - reserve_bootmem_node(0, V_PFN_DOWN(initrd_start) << PAGE_SHIFT, - PFN_RANGE(initrd_start, initrd_end) << PAGE_SHIFT); + reserve_bootmem_node(0, bootmap_pfn << PAGE_SHIFT, + bootmap_pages << PAGE_SHIFT); +} + +/* + * Register all available RAM in this node with the bootmem allocator. + */ +static inline void free_bootmem_node_bank(int node, struct meminfo *mi) +{ + int bank; + + for (bank = 0; bank < mi->nr_banks; bank++) + if (mi->bank[bank].node == node) + free_bootmem_node(node, mi->bank[bank].start, + mi->bank[bank].size); +} + +/* + * 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[NR_NODES], *np = node_info; + unsigned int bootmap_pages, bootmap_pfn, map_pg; + int node, initrd_node; + + bootmap_pages = find_memend_and_nodes(mi, np); + bootmap_pfn = find_bootmap_pfn(0, mi, bootmap_pages); + initrd_node = check_initrd(mi); + + map_pg = bootmap_pfn; + + for (node = 0; node < numnodes; node++, np++) { + /* + * If there are no pages in this node, ignore it. + * Note that node 0 must always have some pages. + */ + if (np->end == 0) { + if (node == 0) + BUG(); + continue; + } + + /* + * Initialise the bootmem allocator. + */ + init_bootmem_node(node, map_pg, np->start, np->end); + free_bootmem_node_bank(node, mi); + map_pg += np->bootmap_pages; + + /* + * If this is node 0, we need to reserve some areas ASAP - + * we may use bootmem on node 0 to setup the other nodes. + */ + if (node == 0) + reserve_node_zero(bootmap_pfn, bootmap_pages); + } + + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_node >= 0) + reserve_bootmem_node(initrd_node, __pa(initrd_start), + initrd_end - initrd_start); #endif + + if (map_pg != bootmap_pfn + bootmap_pages) + BUG(); } /* - * paging_init() sets up the page tables... + * 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) { @@ -378,11 +506,23 @@ * The size of this node has already been determined. * If we need to do anything fancy with the allocation * of this memory to the zones, now is the time to do - * it. For now, we don't touch zhole_size. + * it. */ zone_size[0] = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT); + /* + * For each bank in this node, calculate the size of the + * holes. holes = node_size - sum(bank_sizes_in_node) + */ + zhole_size[0] = zone_size[0]; + for (i = 0; i < mi->nr_banks; i++) { + if (mi->bank[i].node != node) + continue; + + zhole_size[0] -= mi->bank[i].size >> PAGE_SHIFT; + } + free_area_init_node(node, pgdat, zone_size, bdata->node_boot_start, zhole_size); } @@ -399,31 +539,6 @@ empty_bad_pte_table = ((pte_t *)bad_table) + TABLE_OFFSET; } -static inline void free_unused_mem_map(void) -{ - struct page *page, *end; - - end = mem_map + max_mapnr; - - for (page = mem_map; page < end; page++) { - unsigned long low, high; - - if (!PageSkip(page)) - continue; - - low = PAGE_ALIGN((unsigned long)(page + 1)); - if (page->next_hash < page) - high = ((unsigned long)end) & PAGE_MASK; - else - high = ((unsigned long)page->next_hash) & PAGE_MASK; - - while (low < high) { - ClearPageReserved(mem_map + MAP_NR(low)); - low += PAGE_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 @@ -431,7 +546,6 @@ */ void __init mem_init(void) { - extern char __init_begin, __init_end; unsigned int codepages, datapages, initpages; int i, node; @@ -443,8 +557,7 @@ max_mapnr = MAP_NR(high_memory); /* - * We may have non-contiguous memory. Setup the PageSkip stuff, - * and mark the areas of mem_map which can be freed + * We may have non-contiguous memory. */ if (meminfo.nr_banks != 1) create_memmap_holes(&meminfo); @@ -500,8 +613,6 @@ void free_initmem(void) { - extern char __init_begin, __init_end; - printk("Freeing unused kernel memory:"); free_area((unsigned long)(&__init_begin), diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/mm/mm-armv.c linux/arch/arm/mm/mm-armv.c --- v2.4.0-test1/linux/arch/arm/mm/mm-armv.c Wed Apr 26 16:34:06 2000 +++ linux/arch/arm/mm/mm-armv.c Mon Jun 19 17:59:34 2000 @@ -411,50 +411,41 @@ } /* - * The mem_map array can get very big. Mark the end of the valid mem_map - * banks with PG_skip, and setup the address validity bitmap. + * The mem_map array can get very big. Free the unused area of the memory map. */ -void __init create_memmap_holes(struct meminfo *mi) +static inline void free_unused_memmap_node(int node, struct meminfo *mi) { - unsigned int start_pfn, end_pfn = -1; - struct page *pg = NULL; + unsigned long bank_start, prev_bank_end = 0; unsigned int i; -#define PFN(x) (((x) - PHYS_OFFSET) >> PAGE_SHIFT) -#define free_bootmem(s,sz) free_bootmem(((s)<nr_banks; i++) { - if (mi->bank[i].size == 0) + if (mi->bank[i].size == 0 || mi->bank[i].node != node) continue; - start_pfn = PFN(mi->bank[i].start); + bank_start = mi->bank[i].start & PAGE_MASK; /* - * subtle here - if we have a full bank, then - * start_pfn == end_pfn, and we don't want to - * set PG_skip, or next_hash + * If we had a previous bank, and there is a space + * between the current bank and the previous, free it. */ - if (pg && start_pfn != end_pfn) { - set_bit(PG_skip, &pg->flags); - pg->next_hash = mem_map + start_pfn; - - start_pfn = PFN(PAGE_ALIGN(__pa(pg + 1))); - end_pfn = PFN(__pa(pg->next_hash) & PAGE_MASK); - - if (end_pfn != start_pfn) - free_bootmem(start_pfn, end_pfn - start_pfn); - - pg = NULL; - } + if (prev_bank_end && prev_bank_end != bank_start) + free_bootmem_node(node, prev_bank_end, + bank_start - prev_bank_end); - end_pfn = PFN(mi->bank[i].start + mi->bank[i].size); - - if (end_pfn != PFN(mi->end)) - pg = mem_map + end_pfn; + prev_bank_end = PAGE_ALIGN(mi->bank[i].start + + mi->bank[i].size); } +} - if (pg) { - set_bit(PG_skip, &pg->flags); - pg->next_hash = NULL; - } +void __init create_memmap_holes(struct meminfo *mi) +{ + int node; + + for (node = 0; node < numnodes; node++) + free_unused_memmap_node(node, mi); } diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/mm/mm-footbridge.c linux/arch/arm/mm/mm-footbridge.c --- v2.4.0-test1/linux/arch/arm/mm/mm-footbridge.c Mon Nov 1 13:56:26 1999 +++ linux/arch/arm/mm/mm-footbridge.c Mon Jun 19 17:59:34 2000 @@ -29,7 +29,7 @@ * You can then access the PCI bus at 0xe0000000 and 0xffe00000. */ -#ifdef CONFIG_HOST_FOOTBRIDGE +#ifdef CONFIG_FOOTBRIDGE_HOST /* * The mapping when the footbridge is in host mode. diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/mm/mm-l7200.c linux/arch/arm/mm/mm-l7200.c --- v2.4.0-test1/linux/arch/arm/mm/mm-l7200.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mm/mm-l7200.c Mon Jun 19 17:59:34 2000 @@ -0,0 +1,25 @@ +/* + * arch/arm/mm/mm-lusl7200.c + * + * Extra MM routines for LUSL7200 architecture + * + * Copyright (C) 2000 Steven J. Hill + */ + +#include + +#include +#include +#include +#include + +#include "map.h" + +#define SIZE(x) (sizeof(x) / sizeof(x[0])) + +struct map_desc io_desc[] __initdata = { + { IO_BASE, IO_START, IO_SIZE, DOMAIN_IO, 0, 1 ,0 ,0}, + { IO_BASE_2, IO_START_2, IO_SIZE_2, DOMAIN_IO, 0, 1 ,0 ,0}, +}; + +unsigned int __initdata io_desc_size = SIZE(io_desc); diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/mm/mm-sa1100.c linux/arch/arm/mm/mm-sa1100.c --- v2.4.0-test1/linux/arch/arm/mm/mm-sa1100.c Fri May 12 14:18:55 2000 +++ linux/arch/arm/mm/mm-sa1100.c Mon Jun 19 17:59:34 2000 @@ -11,13 +11,14 @@ * Memory is listed physically now. * * 2000/04/07 Nicolas Pitre - * Reworked for real-time selection of memory definitions + * Reworked for run-time selection of memory definitions * */ #include #include #include +#include #include #include @@ -44,7 +45,9 @@ static struct map_desc assabet_io_desc[] __initdata = { #ifdef CONFIG_SA1100_ASSABET { 0xd0000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ + { 0xd4000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* System Registers */ { 0xdc000000, 0x12000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Board Control Register */ + { 0xd8000000, 0x40000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */ SA1100_STD_IO_MAPPING #endif }; @@ -140,4 +143,21 @@ io_desc_size = SIZE(default_io_desc); } } + +#ifdef CONFIG_DISCONTIGMEM + +/* + * Our node_data structure for discontigous memory. + * There is 4 possible nodes i.e. the 4 SA1100 RAM banks. + */ + +static bootmem_data_t node_bootmem_data[4]; + +pg_data_t sa1100_node_data[4] = +{ { bdata: &node_bootmem_data[0] }, + { bdata: &node_bootmem_data[1] }, + { bdata: &node_bootmem_data[2] }, + { bdata: &node_bootmem_data[3] } }; + +#endif diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/mm/proc-arm6,7.S linux/arch/arm/mm/proc-arm6,7.S --- v2.4.0-test1/linux/arch/arm/mm/proc-arm6,7.S Fri May 12 14:18:55 2000 +++ linux/arch/arm/mm/proc-arm6,7.S Mon Jun 19 17:59:34 2000 @@ -93,37 +93,30 @@ * Purpose : obtain information about current aborted instruction * * Returns : r0 = address of abort - * : r1 = FSR - * : r2 != 0 if writing + * : r1 != 0 if writing + * : r3 = FSR * : sp = pointer to registers */ -Lukabttxt: .ascii "Unknown data abort code %d [pc=%p, *pc=%p] LR=%p\0" - .align - -msg: .ascii "DA*%p=%p\n\0" - .align - ENTRY(cpu_arm6_data_abort) ldr r4, [r0] @ read instruction causing problem - mov r2, r4, lsr #19 @ r2 b1 = L - and r1, r4, #14 << 24 - and r2, r2, #2 @ check read/write bit - teq r1, #4 << 23 + mov r1, r4, lsr #19 @ r1 b1 = L + and r2, r4, #14 << 24 + and r1, r1, #2 @ check read/write bit + teq r2, #8 << 24 @ was it ldm/stm bne Ldata_simple - Ldata_ldmstm: tst r4, #1 << 21 @ check writeback bit beq Ldata_simple 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 + and r2, r4, r7, lsl #1 + add r0, r0, r2, lsr #1 + and r2, r4, r7, lsl #2 + add r0, r0, r2, lsr #2 + and r2, r4, r7, lsl #3 + add r0, r0, r2, lsr #3 add r0, r0, r0, lsr #8 add r0, r0, r0, lsr #4 and r7, r0, #15 @ r7 = no. of registers to transfer. @@ -134,16 +127,16 @@ addeq r7, r0, r7, lsl #2 @ Do correction (signed) Ldata_saver7: str r7, [sp, r5, lsr #14] @ Put register Ldata_simple: mrc p15, 0, r0, c6, c0, 0 @ get FAR - mrc p15, 0, r1, c5, c0, 0 @ get FSR - and r1, r1, #255 + mrc p15, 0, r3, c5, c0, 0 @ get FSR + and r3, r3, #255 mov pc, lr ENTRY(cpu_arm7_data_abort) ldr r4, [r0] @ read instruction causing problem - mov r2, r4, lsr #19 @ r2 b1 = L - and r1, r4, #15 << 24 - and r2, r2, #2 @ check read/write bit - add pc, pc, r1, lsr #22 @ Now branch to the relevent processing routine + mov r1, r4, lsr #19 @ r1 b1 = L + and r2, r4, #15 << 24 + and r1, r1, #2 @ check read/write bit + add pc, pc, r2, lsr #22 @ Now branch to the relevent processing routine movs pc, lr b Ldata_unknown @@ -162,7 +155,7 @@ b Ldata_simple @ ldc rd, [rn, #m] b Ldata_unknown Ldata_unknown: @ Part of jumptable - mov r0, r1 + mov r0, r2 mov r1, r4 mov r2, r3 b baddataabort @@ -172,13 +165,13 @@ tst r4, #1 << 21 @ check writeback bit beq Ldata_simple Ldata_lateldrpostconst: - movs r1, r4, lsl #20 @ Get offset + movs r2, r4, lsl #20 @ Get offset beq Ldata_simple and r5, r4, #15 << 16 @ Get Rn ldr r0, [sp, r5, lsr #14] tst r4, #1 << 23 @ U bit - subne r7, r0, r1, lsr #20 - addeq r7, r0, r1, lsr #20 + subne r7, r0, r2, lsr #20 + addeq r7, r0, r2, lsr #20 b Ldata_saver7 Ldata_lateldrprereg: @@ -186,7 +179,7 @@ beq Ldata_simple Ldata_lateldrpostreg: and r5, r4, #15 - ldr r1, [sp, r5, lsl #2] @ Get Rm + ldr r2, [sp, r5, lsl #2] @ Get Rm mov r3, r4, lsr #7 ands r3, r3, #31 and r6, r4, #0x70 @@ -194,7 +187,7 @@ add pc, pc, r6 mov r0, r0 - mov r1, r1, lsl r3 @ 0: LSL #!0 + mov r2, r2, lsl r3 @ 0: LSL #!0 b 1f b 1f @ 1: LSL #0 mov r0, r0 @@ -202,25 +195,25 @@ mov r0, r0 b 1f @ 3: MUL? mov r0, r0 - mov r1, r1, lsr r3 @ 4: LSR #!0 + mov r2, r2, lsr r3 @ 4: LSR #!0 b 1f - mov r1, r1, lsr #32 @ 5: LSR #32 + mov r2, r2, lsr #32 @ 5: LSR #32 b 1f b 1f @ 6: MUL? mov r0, r0 b 1f @ 7: MUL? mov r0, r0 - mov r1, r1, asr r3 @ 8: ASR #!0 + mov r2, r2, asr r3 @ 8: ASR #!0 b 1f - mov r1, r1, asr #32 @ 9: ASR #32 + mov r2, r2, asr #32 @ 9: ASR #32 b 1f b 1f @ A: MUL? mov r0, r0 b 1f @ B: MUL? mov r0, r0 - mov r1, r1, ror r3 @ C: ROR #!0 + mov r2, r2, ror r3 @ C: ROR #!0 b 1f - mov r1, r1, rrx @ D: RRX + mov r2, r2, rrx @ D: RRX b 1f mov r0, r0 @ E: MUL? mov r0, r0 @@ -230,8 +223,8 @@ 1: and r5, r4, #15 << 16 @ Get Rn ldr r0, [sp, r5, lsr #14] tst r4, #1 << 23 @ U bit - subne r7, r0, r1 - addeq r7, r0, r1 + subne r7, r0, r2 + addeq r7, r0, r2 b Ldata_saver7 /* @@ -254,7 +247,8 @@ ENTRY(cpu_arm6_proc_fin) ENTRY(cpu_arm7_proc_fin) - msr cpsr_c, #F_BIT | I_BIT | SVC_MODE + mov r0, #F_BIT | I_BIT | SVC_MODE + msr cpsr_c, r0 mov r0, #0x31 @ ....S..DP...M mcr p15, 0, r0, c1, c0, 0 @ disable caches mov pc, lr @@ -364,7 +358,8 @@ .section ".text.init", #alloc, #execinstr -__arm6_setup: msr cpsr_c, #F_BIT | I_BIT | SVC_MODE +__arm6_setup: mov r0, #F_BIT | I_BIT | SVC_MODE + msr cpsr_c, r0 mov r0, #0 mcr p15, 0, r0, c7, c0 @ flush caches on v3 mcr p15, 0, r0, c5, c0 @ flush TLBs on v3 @@ -375,7 +370,8 @@ orr r0, r0, #0x100 mov pc, lr -__arm7_setup: msr cpsr_c, #F_BIT | I_BIT | SVC_MODE +__arm7_setup: mov r0, #F_BIT | I_BIT | SVC_MODE + msr cpsr_c, r0 mov r0, #0 mcr p15, 0, r0, c7, c0 @ flush caches on v3 mcr p15, 0, r0, c5, c0 @ flush TLBs on v3 diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/mm/proc-arm720.S linux/arch/arm/mm/proc-arm720.S --- v2.4.0-test1/linux/arch/arm/mm/proc-arm720.S Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mm/proc-arm720.S Mon Jun 19 17:59:34 2000 @@ -0,0 +1,398 @@ +/* + * linux/arch/arm/mm/proc-arm720.S: MMU functions for ARM720 + * + * Copyright (C) 2000 Steve Hill (sjhill@cotw.com) + * Rob Scott (rscott@mtrob.fdns.net) + * + * These are the low level assembler for performing cache and TLB + * functions on the ARM720T. + * + * Changelog: + * 05-09-2000 SJH Created by moving 720 specific functions + * out of 'proc-arm6,7.S' per RSK discussion + */ +#include +#include +#include +#include +#include "../lib/constants.h" + +/* + * Function: arm720_flush_cache_all (void) + * : arm720_flush_cache_page (unsigned long address, int size, + * int flags) + * + * Params : address Area start address + * : size size of area + * : flags b0 = I cache as well + * + * Purpose : Flush all cache lines + */ +ENTRY(cpu_arm720_flush_cache_all) +ENTRY(cpu_arm720_flush_cache_area) +ENTRY(cpu_arm720_flush_cache_entry) +ENTRY(cpu_arm720_flush_icache_area) +ENTRY(cpu_arm720_flush_icache_page) +ENTRY(cpu_arm720_cache_wback_area) +ENTRY(cpu_arm720_cache_purge_area) + mov r0, #0 + mcr p15, 0, r0, c7, c7, 0 @ flush cache + mov pc, lr + +ENTRY(cpu_arm720_clean_cache_area) +ENTRY(cpu_arm720_flush_ram_page) + mov pc, lr + +/* + * Function: arm720_flush_tlb_all (void) + * + * Purpose : flush all TLB entries in all caches + */ +ENTRY(cpu_arm720_flush_tlb_all) + mov r0, #0 + mcr p15, 0, r0, c8, c7, 0 @ flush TLB (v4) + mov pc, lr + +/* + * Function: arm720_flush_tlb_page (unsigned long address, int end, int flags) + * + * Params : address Area start address + * : end Area end address + * : flags b0 = I cache as well + * + * Purpose : flush a TLB entry + */ +ENTRY(cpu_arm720_flush_tlb_area) +1: mcr p15, 0, r0, c8, c7, 1 @ flush TLB (v4) + add r0, r0, #4096 + cmp r0, r1 + blt 1b + mov pc, lr + +/* + * Function: arm720_flush_tlb_page (unsigned long address, int flags) + * + * Params : address Address + * : flags b0 = I-TLB as well + * + * Purpose : flush a TLB entry + */ +ENTRY(cpu_arm720_flush_tlb_page) + mcr p15, 0, r0, c8, c7, 1 @ flush TLB (v4) + mov pc, lr + +/* + * Function: arm720_data_abort () + * + * Params : r0 = address of aborted instruction + * + * Purpose : obtain information about current aborted instruction + * + * Returns : r0 = address of abort + * : r1 != 0 if writing + * : r3 = FSR + * : sp = pointer to registers + */ + +Ldata_ldmstm: tst r4, #1 << 21 @ check writeback bit + beq Ldata_simple + mov r7, #0x11 + orr r7, r7, r7, lsl #8 + and r0, r4, r7 + and r2, r4, r7, lsl #1 + add r0, r0, r2, lsr #1 + and r2, r4, r7, lsl #2 + add r0, r0, r2, lsr #2 + and r2, r4, r7, lsl #3 + add r0, r0, r2, lsr #3 + add r0, r0, r0, lsr #8 + add r0, r0, r0, lsr #4 + and r7, r0, #15 @ r7 = no. of registers to transfer. + and r5, r4, #15 << 16 @ Get Rn + ldr r0, [sp, r5, lsr #14] @ Get register + tst r4, #1 << 23 @ U bit + subne r7, r0, r7, lsl #2 + addeq r7, r0, r7, lsl #2 @ Do correction (signed) +Ldata_saver7: str r7, [sp, r5, lsr #14] @ Put register +Ldata_simple: mrc p15, 0, r0, c6, c0, 0 @ get FAR + mrc p15, 0, r3, c5, c0, 0 @ get FSR + and r3, r3, #15 + mov pc, lr + +ENTRY(cpu_arm720_data_abort) + ldr r4, [r0] @ read instruction causing problem + mov r1, r4, lsr #19 @ r1 b1 = L + and r2, r4, #15 << 24 + and r1, r1, #2 @ check read/write bit + add pc, pc, r2, lsr #22 @ Now branch to the relevent processing routine + movs pc, lr + + b Ldata_unknown + b Ldata_unknown + b Ldata_unknown + b Ldata_unknown + b Ldata_lateldrpostconst @ ldr rd, [rn], #m + b Ldata_lateldrpreconst @ ldr rd, [rn, #m] @ RegVal + b Ldata_lateldrpostreg @ ldr rd, [rn], rm + b Ldata_lateldrprereg @ ldr rd, [rn, rm] + b Ldata_ldmstm @ ldm*a rn, + b Ldata_ldmstm @ ldm*b rn, + b Ldata_unknown + b Ldata_unknown + b Ldata_simple @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m + b Ldata_simple @ ldc rd, [rn, #m] + b Ldata_unknown +Ldata_unknown: @ Part of jumptable + mov r0, r2 + mov r1, r4 + mov r2, r3 + b baddataabort + + +Ldata_lateldrpreconst: + tst r4, #1 << 21 @ check writeback bit + beq Ldata_simple +Ldata_lateldrpostconst: + movs r2, r4, lsl #20 @ Get offset + beq Ldata_simple + and r5, r4, #15 << 16 @ Get Rn + ldr r0, [sp, r5, lsr #14] + tst r4, #1 << 23 @ U bit + subne r7, r0, r2, lsr #20 + addeq r7, r0, r2, lsr #20 + b Ldata_saver7 + +Ldata_lateldrprereg: + tst r4, #1 << 21 @ check writeback bit + beq Ldata_simple +Ldata_lateldrpostreg: + and r5, r4, #15 + ldr r2, [sp, r5, lsl #2] @ Get Rm + mov r3, r4, lsr #7 + ands r3, r3, #31 + and r6, r4, #0x70 + orreq r6, r6, #8 + add pc, pc, r6 + mov r0, r0 + + mov r2, r2, lsl r3 @ 0: LSL #!0 + b 1f + b 1f @ 1: LSL #0 + mov r0, r0 + b 1f @ 2: MUL? + mov r0, r0 + b 1f @ 3: MUL? + mov r0, r0 + mov r2, r2, lsr r3 @ 4: LSR #!0 + b 1f + mov r2, r2, lsr #32 @ 5: LSR #32 + b 1f + b 1f @ 6: MUL? + mov r0, r0 + b 1f @ 7: MUL? + mov r0, r0 + mov r2, r2, asr r3 @ 8: ASR #!0 + b 1f + mov r2, r2, asr #32 @ 9: ASR #32 + b 1f + b 1f @ A: MUL? + mov r0, r0 + b 1f @ B: MUL? + mov r0, r0 + mov r2, r2, ror r3 @ C: ROR #!0 + b 1f + mov r2, r2, rrx @ D: RRX + b 1f + mov r0, r0 @ E: MUL? + mov r0, r0 + mov r0, r0 @ F: MUL? + + +1: and r5, r4, #15 << 16 @ Get Rn + ldr r0, [sp, r5, lsr #14] + tst r4, #1 << 23 @ U bit + subne r7, r0, r2 + addeq r7, r0, r2 + b Ldata_saver7 + +/* + * Function: arm720_check_bugs (void) + * : arm720_proc_init (void) + * : arm720_proc_fin (void) + * : arm720_proc_do_idle (void) + * + * Notes : This processor does not require these + */ +ENTRY(cpu_arm720_check_bugs) + mrs ip, cpsr + bic ip, ip, #F_BIT + msr cpsr, ip + mov pc, lr + +ENTRY(cpu_arm720_proc_init) + mov pc, lr + +ENTRY(cpu_arm720_proc_fin) + mrs r0, cpsr + orr r0, r0, #F_BIT | I_BIT + msr cpsr, r0 + mov r0, #0x31 @ ....S..DP...M + mcr p15, 0, r0, c1, c0, 0 @ disable caches + mov pc, lr + +ENTRY(cpu_arm720_do_idle) + mov r0, #-EINVAL + mov pc, lr + +/* + * Function: arm720_set_pgd(unsigned long pgd_phys) + * Params : pgd_phys Physical address of page table + * Purpose : Perform a task switch, saving the old process' state and restoring + * the new. + */ +ENTRY(cpu_arm720_set_pgd) + mov r1, #0 + mcr p15, 0, r1, c7, c7, 0 @ flush cache + mcr p15, 0, r0, c2, c0, 0 @ update page table ptr + mcr p15, 0, r1, c8, c7, 0 @ flush TLB (v4) + mov pc, lr + +/* + * Function: arm720_set_pmd () + * + * Params : r0 = Address to set + * : r1 = value to set + * + * Purpose : Set a PMD and flush it out of any WB cache + */ +ENTRY(cpu_arm720_set_pmd) + tst r1, #3 + orrne r1, r1, #16 @ Updatable bit is + str r1, [r0] @ always set on ARM720 + mov pc, lr + +/* + * Function: arm720_set_pte(pte_t *ptep, pte_t pte) + * Params : r0 = Address to set + * : r1 = value to set + * Purpose : Set a PTE and flush it out of any WB cache + */ + .align 5 +ENTRY(cpu_arm720_set_pte) + str r1, [r0], #-1024 @ linux version + + eor r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY + + bic r2, r1, #0xff0 + bic r2, r2, #3 + orr r2, r2, #HPTE_TYPE_SMALL + + tst r1, #LPTE_USER | LPTE_EXEC @ User or Exec? + orrne r2, r2, #HPTE_AP_READ + + tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty? + orreq r2, r2, #HPTE_AP_WRITE + + tst r1, #LPTE_PRESENT | LPTE_YOUNG @ Present and Young + movne r2, #0 + + str r2, [r0] @ hardware version + + mcr p15, 0, r0, c7, c7, 0 @ flush cache + mcr p15, 0, r0, c8, c7, 0 @ flush TLB (v4) + mov pc, lr + +/* + * Function: arm720_reset + * Params : r0 = address to jump to + * Notes : This sets up everything for a reset + */ +ENTRY(cpu_arm720_reset) + mov r0, #0 + mcr p15, 0, r0, c7, c7, 0 @ flush cache + mcr p15, 0, r0, c8, c7, 0 @ flush TLB (v4) + mov pc, lr + + +cpu_armvlsi_name: + .asciz "ARM/VLSI" +cpu_arm720_name: + .asciz "ARM 720" + .align + + .section ".text.init", #alloc, #execinstr + +__arm720_setup: mov r0, #0 + mcr p15, 0, r0, c7, c7, 0 @ flush caches on v4 + mcr p15, 0, r0, c8, c7, 0 @ flush TLB (v4) + mcr p15, 0, r4, c2, c0 @ load page table pointer + mov r0, #0x1f @ Domains 0, 1 = client + mcr p15, 0, r0, c3, c0 @ load domain access register + + /* Set CP15 Control reg bits (RSBLDPWCAM) */ + mov r0, #0x7d @ ...LDPWC.M + orr r0, r0, #0x100 @ .S.LDPWC.M + mov pc, lr @ __ret (head-armv.S) + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm720_processor_functions, #object +ENTRY(arm720_processor_functions) + .word cpu_arm720_data_abort + .word cpu_arm720_check_bugs + .word cpu_arm720_proc_init + .word cpu_arm720_proc_fin + .word cpu_arm720_flush_cache_all + .word cpu_arm720_flush_cache_area + .word cpu_arm720_flush_cache_entry + .word cpu_arm720_clean_cache_area + .word cpu_arm720_flush_ram_page + .word cpu_arm720_flush_tlb_all + .word cpu_arm720_flush_tlb_area + .word cpu_arm720_set_pgd + .word cpu_arm720_set_pmd + .word cpu_arm720_set_pte + .word cpu_arm720_reset + .word cpu_arm720_flush_icache_area + .word cpu_arm720_cache_wback_area + .word cpu_arm720_cache_purge_area + .word cpu_arm720_flush_tlb_page + .word cpu_arm720_do_idle + .word cpu_arm720_flush_icache_page + .size arm720_processor_functions, . - arm720_processor_functions + + .type cpu_arm720_info, #object +cpu_arm720_info: + .long cpu_armvlsi_name + .long cpu_arm720_name + .size cpu_arm720_info, . - cpu_arm720_info + + .type cpu_arch_name, #object +cpu_arch_name: .asciz "armv4" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: .asciz "v4" + .size cpu_elf_name, . - cpu_elf_name + .align + +/* + * See /include/asm-arm for a definition of this structure. + */ + + .section ".proc.info", #alloc, #execinstr + + .type __arm720_proc_info, #object +__arm720_proc_info: + .long 0x41807200 @ cpu_val + .long 0xffffff00 @ cpu_mask + .long 0x00000c12 @ __cpu_mmu_flags + b __arm720_setup @ --cpu_flush + .long cpu_arch_name @ arch_name + .long cpu_elf_name @ elf_name + .long HWCAP_SWP | HWCAP_26BIT @ elf_hwcap + .long cpu_arm720_info @ info + .long arm720_processor_functions + .size __arm720_proc_info, . - __arm720_proc_info diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/mm/proc-sa110.S linux/arch/arm/mm/proc-sa110.S --- v2.4.0-test1/linux/arch/arm/mm/proc-sa110.S Fri May 12 14:18:55 2000 +++ linux/arch/arm/mm/proc-sa110.S Mon Jun 19 17:59:34 2000 @@ -7,6 +7,9 @@ * functions on the StrongARM-110, StrongARM-1100 and StrongARM-1110. * * Note that SA1100 and SA1110 share everything but their name and CPU ID. + * + * 12-jun-2000, Erik Mouw (J.A.K.Mouw@its.tudelft.nl): + * Flush the read buffer at context switches */ #include #include @@ -82,6 +85,7 @@ mov ip, #0 teq r2, #0 mcrne p15, 0, ip, c7, c5, 0 @ flush I cache + mcr p15, 0, r1, c9, c0, 0 @ flush RB mcr p15, 0, ip, c7, c10, 4 @ drain WB mov pc, lr @@ -300,19 +304,18 @@ * Params : r0 = address of aborted instruction * Purpose : obtain information about current aborted instruction * Returns : r0 = address of abort - * : r1 = FSR - * : r2 != 0 if writing + * : r1 != 0 if writing + * : r3 = FSR */ .align 5 ENTRY(cpu_sa110_data_abort) ENTRY(cpu_sa1100_data_abort) - ldr r2, [r0] @ read instruction causing problem + ldr r1, [r0] @ read instruction causing problem mrc p15, 0, r0, c6, c0, 0 @ get FAR - mov r2, r2, lsr #19 @ b1 = L - and r3, r2, #0x69 << 2 - and r2, r2, #2 - mrc p15, 0, r1, c5, c0, 0 @ get FSR - and r1, r1, #255 + mov r1, r1, lsr #19 @ b1 = L + and r1, r1, #2 + mrc p15, 0, r3, c5, c0, 0 @ get FSR + and r3, r3, #255 mov pc, lr .align 5 @@ -351,6 +354,7 @@ flush_1100_dcache r3, ip, r1 mov r1, #0 mcr p15, 0, r1, c7, c5, 0 @ flush I cache + mcr p15, 0, r1, c9, c0, 0 @ flush RB mcr p15, 0, r1, c7, c10, 4 @ drain WB mcr p15, 0, r0, c2, c0, 0 @ load page table pointer mcr p15, 0, r1, c8, c7, 0 @ flush TLBs @@ -423,7 +427,8 @@ ENTRY(cpu_sa110_proc_fin) stmfd sp!, {r1, lr} - msr cpsr_c, #F_BIT | I_BIT | SVC_MODE + mov ip, #F_BIT | I_BIT | SVC_MODE + msr cpsr_c, ip bl cpu_sa110_flush_cache_all @ clean caches 1: mov r0, #0 mcr p15, 0, r0, c15, c2, 2 @ Disable clock switching @@ -435,7 +440,8 @@ ENTRY(cpu_sa1100_proc_fin) stmfd sp!, {r1, lr} - msr cpsr_c, #F_BIT | I_BIT | SVC_MODE + mov ip, #F_BIT | I_BIT | SVC_MODE + msr cpsr_c, ip bl cpu_sa1100_flush_cache_all @ clean caches b 1b @@ -501,7 +507,11 @@ .section ".text.init", #alloc, #execinstr -__sa110_setup: msr cpsr_c, #F_BIT | I_BIT | SVC_MODE +__sa1100_setup: @ Allow read-buffer operations from userland + mcr p15, 0, r0, c9, c0, 5 + +__sa110_setup: mov r0, #F_BIT | I_BIT | SVC_MODE + msr cpsr_c, r0 mov r0, #0 mcr p15, 0, r0, c7, c7 @ flush I,D caches on v4 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 @@ -623,7 +633,7 @@ .long 0x4401a110 .long 0xfffffff0 .long 0x00000c02 - b __sa110_setup + b __sa1100_setup .long cpu_arch_name .long cpu_elf_name .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT @@ -636,7 +646,7 @@ .long 0x6901b110 .long 0xfffffff0 .long 0x00000c02 - b __sa110_setup + b __sa1100_setup .long cpu_arch_name .long cpu_elf_name .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/Makefile linux/arch/i386/Makefile --- v2.4.0-test1/linux/arch/i386/Makefile Mon Jun 19 16:31:57 2000 +++ linux/arch/i386/Makefile Mon Jun 19 12:56:08 2000 @@ -49,7 +49,7 @@ CFLAGS += $(shell if $(CC) -march=i686 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i686"; fi) endif -ifdef CONFIG_M686FX +ifdef CONFIG_M686FXSR CFLAGS += $(shell if $(CC) -march=i686 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i686"; fi) endif @@ -59,6 +59,22 @@ ifdef CONFIG_MK7 CFLAGS += $(shell if $(CC) -march=i686 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i686"; fi) -malign-functions=4 -fschedule-insns2 -mwide-multiply -fexpensive-optimizations +endif + +ifdef CONFIG_MCRUSOE +CFLAGS += $(shell if $(CC) -march=i586 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i586"; fi) +endif + +ifdef CONFIG_MWINCHIPC6 +CFLAGS += $(shell if $(CC) -march=i686 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i686"; fi) +endif + +ifdef CONFIG_MWINCHIP2 +CFLAGS += $(shell if $(CC) -march=i686 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i686"; fi) +endif + +ifdef CONFIG_MWINCHIP3D +CFLAGS += $(shell if $(CC) -march=i686 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i686"; fi) endif HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.4.0-test1/linux/arch/i386/config.in Mon Jun 19 16:31:57 2000 +++ linux/arch/i386/config.in Mon Jun 19 12:56:08 2000 @@ -1,6 +1,6 @@ # # For a description of the syntax of this configuration file, -# see the Configure script. +# see Documentation/kbuild/config-language.txt. # mainmenu_name "Linux Kernel Configuration" @@ -19,14 +19,17 @@ comment 'Processor type and features' choice 'Processor family' \ "386 CONFIG_M386 \ - 486/Cx486 CONFIG_M486 \ + 486 CONFIG_M486 \ 586/K5/5x86/6x86/6x86MX CONFIG_M586 \ - Pentium/TSC CONFIG_M586TSC \ - PPro/Pentium-II CONFIG_M686 \ - Pentium-III CONFIG_M686FX \ + Pentium/Pentium-MMX CONFIG_M586TSC \ + Pentium-Pro/Celeron/Pentium-II CONFIG_M686 \ + Pentium-III CONFIG_M686FXSR \ K6/K6-II/K6-III CONFIG_MK6 \ - Athlon CONFIG_MK7 \ - Crusoe CONFIG_MCRUSOE" PPro + Athlon/K7 CONFIG_MK7 \ + Crusoe CONFIG_MCRUSOE \ + Winchip-C6 CONFIG_MWINCHIPC6 \ + Winchip-2 CONFIG_MWINCHIP2 \ + Winchip-2A/3 CONFIG_MWINCHIP3D" Pentium-Pro # # Define implied options from the CPU selection here # @@ -62,13 +65,16 @@ define_bool CONFIG_X86_PGE y define_bool CONFIG_X86_USE_PPRO_CHECKSUM y fi -if [ "$CONFIG_M686FX" = "y" ]; then +if [ "$CONFIG_M686FXSR" = "y" ]; then define_int CONFIG_X86_L1_CACHE_BYTES 32 define_bool CONFIG_X86_TSC y define_bool CONFIG_X86_GOOD_APIC y define_bool CONFIG_X86_PGE y define_bool CONFIG_X86_USE_PPRO_CHECKSUM y - define_bool CONFIG_X86_FX y + define_bool CONFIG_X86_FXSR y + define_bool CONFIG_X86_XMM y +else + define_bool CONFIG_X86_FXSR n fi if [ "$CONFIG_MK6" = "y" ]; then define_int CONFIG_X86_L1_CACHE_BYTES 32 @@ -88,6 +94,24 @@ define_int CONFIG_X86_L1_CACHE_BYTES 32 define_bool CONFIG_X86_TSC y fi +if [ "$CONFIG_MWINCHIPC6" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_BYTES 32 + define_bool CONFIG_X86_ALIGNMENT_16 y + define_bool CONFIG_X86_USE_PPRO_CHECKSUM y +fi +if [ "$CONFIG_MWINCHIP2" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_BYTES 32 + define_bool CONFIG_X86_ALIGNMENT_16 y + define_bool CONFIG_X86_TSC y + define_bool CONFIG_X86_USE_PPRO_CHECKSUM y +fi +if [ "$CONFIG_MWINCHIP3D" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_BYTES 32 + define_bool CONFIG_X86_ALIGNMENT_16 y + define_bool CONFIG_X86_TSC y + define_bool CONFIG_X86_USE_PPRO_CHECKSUM y + define_bool CONFIG_X86_USE_3DNOW y +fi tristate '/dev/cpu/microcode - Intel P6 CPU microcode support' CONFIG_MICROCODE tristate '/dev/cpu/*/msr - Model-specific register support' CONFIG_X86_MSR @@ -105,7 +129,7 @@ define_bool CONFIG_X86_PAE y fi -if [ "$CONFIG_X86_FX" != "y" ]; then +if [ "$CONFIG_X86_FXSR" != "y" ]; then bool 'Math emulation' CONFIG_MATH_EMULATION fi bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.4.0-test1/linux/arch/i386/defconfig Mon Jun 19 16:31:57 2000 +++ linux/arch/i386/defconfig Wed Jun 21 16:46:25 2000 @@ -19,10 +19,13 @@ # CONFIG_M586 is not set # CONFIG_M586TSC is not set CONFIG_M686=y -# CONFIG_M686FX is not set +# CONFIG_M686FXSR is not set # CONFIG_MK6 is not set # CONFIG_MK7 is not set # CONFIG_MCRUSOE is not set +# CONFIG_MWINCHIPC6 is not set +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set CONFIG_X86_WP_WORKS_OK=y CONFIG_X86_INVLPG=y CONFIG_X86_CMPXCHG=y @@ -33,6 +36,7 @@ CONFIG_X86_GOOD_APIC=y CONFIG_X86_PGE=y CONFIG_X86_USE_PPRO_CHECKSUM=y +# CONFIG_X86_FXSR is not set # CONFIG_MICROCODE is not set # CONFIG_X86_MSR is not set # CONFIG_X86_CPUID is not set @@ -105,16 +109,14 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_DEV_DAC960 is not set - -# -# Additional Block Devices -# # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_LVM 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_BLK_DEV_RAM is not set # CONFIG_BLK_DEV_INITRD is not set @@ -148,6 +150,7 @@ # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set # # Telephony Support @@ -179,6 +182,8 @@ # CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set # CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set # CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set # CONFIG_BLK_DEV_IDECS is not set CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set @@ -207,27 +212,24 @@ # CONFIG_BLK_DEV_AMD7409 is not set # CONFIG_AMD7409_OVERRIDE is not set # CONFIG_BLK_DEV_CMD64X is not set -# CONFIG_CMD64X_RAID is not set # CONFIG_BLK_DEV_CY82C693 is not set # CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_HPT34X is not set # CONFIG_HPT34X_AUTODMA is not set # CONFIG_BLK_DEV_HPT366 is not set -# CONFIG_HPT366_FIP is not set -# CONFIG_HPT366_MODE3 is not set # CONFIG_BLK_DEV_PIIX is not set # CONFIG_PIIX_TUNING is not set # CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_OPTI621 is not set # CONFIG_BLK_DEV_PDC202XX is not set # CONFIG_PDC202XX_BURST is not set -# CONFIG_PDC202XX_MASTER is not set # CONFIG_BLK_DEV_SIS5513 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set # CONFIG_VIA82CXXX_TUNING is not set # CONFIG_IDE_CHIPSETS is not set # CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set CONFIG_BLK_DEV_IDE_MODES=y # @@ -461,6 +463,7 @@ # Watchdog Cards # # CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile --- v2.4.0-test1/linux/arch/i386/kernel/Makefile Mon Jun 19 16:31:57 2000 +++ linux/arch/i386/kernel/Makefile Wed Jun 21 20:59:38 2000 @@ -13,87 +13,38 @@ all: kernel.o head.o init_task.o O_TARGET := kernel.o -O_OBJS := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ - ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \ - pci-dma.o -OX_OBJS := i386_ksyms.o -MX_OBJS := -ifdef CONFIG_PCI -O_OBJS += pci-i386.o -ifdef CONFIG_VISWS -O_OBJS += pci-visws.o -else -O_OBJS += pci-pc.o pci-irq.o -endif -endif - -ifdef CONFIG_MCA -OX_OBJS += mca.o -endif - -ifeq ($(CONFIG_MTRR),y) -OX_OBJS += mtrr.o -else - ifeq ($(CONFIG_MTRR),m) - MX_OBJS += mtrr.o - endif -endif - -ifeq ($(CONFIG_X86_MSR),y) -OX_OBJS += msr.o -else - ifeq ($(CONFIG_X86_MSR),m) - MX_OBJS += msr.o - endif -endif - -ifeq ($(CONFIG_X86_CPUID),y) -OX_OBJS += cpuid.o -else - ifeq ($(CONFIG_X86_CPUID),m) - MX_OBJS += cpuid.o - endif -endif +export-objs := mca.o mtrr.o msr.o cpuid.o microcode.o i386_ksyms.o -ifeq ($(CONFIG_MICROCODE),y) -OX_OBJS += microcode.o -else - ifeq ($(CONFIG_MICROCODE),m) - MX_OBJS += microcode.o - endif -endif +obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ + ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \ + pci-dma.o i386_ksyms.o i387.o -ifeq ($(CONFIG_ACPI),y) -O_OBJS += acpi.o -else - ifeq ($(CONFIG_ACPI),m) - M_OBJS += acpi.o - endif -endif -ifeq ($(CONFIG_APM),y) -O_OBJS += apm.o +ifdef CONFIG_PCI +obj-y += pci-i386.o +ifdef CONFIG_VISWS +obj-y += pci-visws.o else - ifeq ($(CONFIG_APM),m) - M_OBJS += apm.o - endif -endif - -ifdef CONFIG_SMP -O_OBJS += smp.o smpboot.o trampoline.o +obj-y += pci-pc.o pci-irq.o endif - -ifdef CONFIG_X86_LOCAL_APIC -O_OBJS += apic.o endif -ifdef CONFIG_X86_IO_APIC -O_OBJS += io_apic.o mpparse.o -endif - -ifdef CONFIG_X86_VISWS_APIC -O_OBJS += visws_apic.o -endif +obj-$(CONFIG_MCA) += mca.o +obj-$(CONFIG_MTRR) += mtrr.o +obj-$(CONFIG_X86_MSR) += msr.o +obj-$(CONFIG_X86_CPUID) += cpuid.o +obj-$(CONFIG_MICROCODE) += microcode.o +obj-$(CONFIG_ACPI) += acpi.o +obj-$(CONFIG_APM) += apm.o +obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o +obj-$(CONFIG_X86_LOCAL_APIC) += apic.o +obj-$(CONFIG_X86_IO_APIC) += io_apic.o mpparse.o +obj-$(CONFIG_X86_VISWS_APIC) += visws_apic.o + +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/acpi.c linux/arch/i386/kernel/acpi.c --- v2.4.0-test1/linux/arch/i386/kernel/acpi.c Tue May 23 15:31:33 2000 +++ linux/arch/i386/kernel/acpi.c Mon Jun 19 12:56:08 2000 @@ -700,7 +700,7 @@ if (!(pmregmisc & ACPI_PIIX4_PMIOSE)) return -ENODEV; - base = dev->resource[PCI_BRIDGE_RESOURCES].start & PCI_BASE_ADDRESS_IO_MASK; + base = pci_resource_start (dev, PCI_BRIDGE_RESOURCES); if (!base) return -ENODEV; @@ -759,7 +759,6 @@ if (!base) return -ENODEV; } - base &= PCI_BASE_ADDRESS_IO_MASK; pci_read_config_byte(dev, 0x42, &irq); @@ -824,7 +823,7 @@ {acpi_init_via}, }; -const static struct pci_device_id acpi_pci_tbl[] = +static struct pci_device_id acpi_pci_tbl[] __initdata = { {0x8086, 0x7113, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_INTEL_PIIX4}, {0x1106, 0x3040, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VIA_586}, @@ -1169,6 +1168,8 @@ acpi_sleep_start = get_cmos_time(); acpi_enter_dx(ACPI_D3); + // disable interrupts globally while suspended + cli(); acpi_sleep_state = state; facp = (struct acpi_facp*) acpi_facp.table; @@ -1191,6 +1192,8 @@ // finished sleeping, update system time acpi_update_clock(); acpi_enter_dx(ACPI_D0); + // reenable interrupts globally after resume + sti(); acpi_sleep_state = ACPI_S0; return 0; diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/apic.c linux/arch/i386/kernel/apic.c --- v2.4.0-test1/linux/arch/i386/kernel/apic.c Mon Jun 19 16:31:57 2000 +++ linux/arch/i386/kernel/apic.c Mon Jun 19 18:39:17 2000 @@ -325,18 +325,18 @@ */ static unsigned int __init get_8254_timer_count(void) { - extern rwlock_t xtime_lock; + extern spinlock_t i8253_lock; unsigned long flags; unsigned int count; - write_lock_irqsave(&xtime_lock, flags); + spin_lock_irqsave(&i8253_lock, flags); outb_p(0x00, 0x43); count = inb_p(0x40); count |= inb_p(0x40) << 8; - write_unlock_irqrestore(&xtime_lock, flags); + spin_unlock_irqrestore(&i8253_lock, flags); return count; } @@ -423,21 +423,21 @@ __setup_APIC_LVTT(clocks); - t0 = apic_read(APIC_TMCCT)*APIC_DIVISOR; + t0 = apic_read(APIC_TMICT)*APIC_DIVISOR; + /* Wait till TMCCT gets reloaded from TMICT... */ + do { + t1 = apic_read(APIC_TMCCT)*APIC_DIVISOR; + delta = (int)(t0 - t1 - slice*(smp_processor_id()+1)); + } while (delta >= 0); + /* Now wait for our slice for real. */ do { - /* - * It looks like the 82489DX cannot handle - * consecutive reads of the TMCCT register well; - * this dummy read prevents it from a lockup. - */ - apic_read(APIC_SPIV); t1 = apic_read(APIC_TMCCT)*APIC_DIVISOR; delta = (int)(t0 - t1 - slice*(smp_processor_id()+1)); } while (delta < 0); __setup_APIC_LVTT(clocks); - printk("CPU%d\n", + printk("CPU%d\n", smp_processor_id(), t0, t1, delta, slice, clocks); __restore_flags(flags); @@ -464,7 +464,7 @@ int i; const int LOOPS = HZ/10; - printk("calibrating APIC timer ... "); + printk("calibrating APIC timer ...\n"); /* * Put whatever arbitrary (but long enough) timeout @@ -509,7 +509,7 @@ result = (tt1-tt2)*APIC_DIVISOR/LOOPS; if (cpu_has_tsc) - printk("\n..... CPU clock speed is %ld.%04ld MHz.\n", + printk("..... CPU clock speed is %ld.%04ld MHz.\n", ((long)(t2-t1)/LOOPS)/(1000000/HZ), ((long)(t2-t1)/LOOPS)%(1000000/HZ)); @@ -701,7 +701,7 @@ ack_APIC_irq(); /* see sw-dev-man vol 3, chapter 7.4.13.5 */ - printk("spurious APIC interrupt on CPU#%d, should never happen.\n", + printk(KERN_INFO "spurious APIC interrupt on CPU#%d, should never happen.\n", smp_processor_id()); } @@ -718,32 +718,32 @@ spin_lock(&err_lock); v = apic_read(APIC_ESR); - printk("APIC error interrupt on CPU#%d, should never happen.\n", + printk(KERN_INFO "APIC error interrupt on CPU#%d, should never happen.\n", smp_processor_id()); - printk("... APIC ESR0: %08lx\n", v); + printk(KERN_INFO "... APIC ESR0: %08lx\n", v); apic_write(APIC_ESR, 0); v |= apic_read(APIC_ESR); - printk("... APIC ESR1: %08lx\n", v); + printk(KERN_INFO "... APIC ESR1: %08lx\n", v); /* * Be a bit more verbose. (multiple bits can be set) */ if (v & 0x01) - printk("... bit 0: APIC Send CS Error (hw problem).\n"); + printk(KERN_INFO "... bit 0: APIC Send CS Error (hw problem).\n"); if (v & 0x02) - printk("... bit 1: APIC Receive CS Error (hw problem).\n"); + printk(KERN_INFO "... bit 1: APIC Receive CS Error (hw problem).\n"); if (v & 0x04) - printk("... bit 2: APIC Send Accept Error.\n"); + printk(KERN_INFO "... bit 2: APIC Send Accept Error.\n"); if (v & 0x08) - printk("... bit 3: APIC Receive Accept Error.\n"); + printk(KERN_INFO "... bit 3: APIC Receive Accept Error.\n"); if (v & 0x10) - printk("... bit 4: Reserved!.\n"); + printk(KERN_INFO "... bit 4: Reserved!.\n"); if (v & 0x20) - printk("... bit 5: Send Illegal Vector (kernel bug).\n"); + printk(KERN_INFO "... bit 5: Send Illegal Vector (kernel bug).\n"); if (v & 0x40) - printk("... bit 6: Received Illegal Vector.\n"); + printk(KERN_INFO "... bit 6: Received Illegal Vector.\n"); if (v & 0x80) - printk("... bit 7: Illegal Register Address.\n"); + printk(KERN_INFO "... bit 7: Illegal Register Address.\n"); ack_APIC_irq(); diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c --- v2.4.0-test1/linux/arch/i386/kernel/apm.c Mon Jun 19 16:31:57 2000 +++ linux/arch/i386/kernel/apm.c Thu Jun 22 07:17:52 2000 @@ -135,6 +135,13 @@ * Fix the Thinkpad (again) :-( (CONFIG_APM_IGNORE_MULTIPLE_SUSPENDS * is now the way life works). * Fix thinko in suspend() (wrong return). + * Notify drivers on critical suspend. + * Make kapmd absorb more idle time (Pavel Machek + * modified by sfr). + * Disable interrupts while we are suspended (Andy Henroid + * fixed by sfr). + * Make power off work on SMP again (Tony Hoyle + * and ) modified by sfr. * * APM 1.1 Reference: * @@ -864,19 +871,51 @@ #endif } +static int send_event(apm_event_t event) +{ + switch (event) { + case APM_SYS_SUSPEND: + case APM_CRITICAL_SUSPEND: + case APM_USER_SUSPEND: + /* map all suspends to ACPI D3 */ + if (pm_send_all(PM_SUSPEND, (void *)3)) { + if (event == APM_CRITICAL_SUSPEND) { + printk(KERN_CRIT "apm: Critical suspend was vetoed, expect armageddon\n" ); + return 0; + } + if (apm_bios_info.version > 0x100) + apm_set_power_state(APM_STATE_REJECT); + return 0; + } + break; + case APM_NORMAL_RESUME: + case APM_CRITICAL_RESUME: + /* map all resumes to ACPI D0 */ + (void) pm_send_all(PM_RESUME, (void *)0); + break; + } + + return 1; +} + static int suspend(void) { int err; struct apm_user *as; get_time_diff(); + cli(); err = apm_set_power_state(APM_STATE_SUSPEND); reinit_timer(); set_time(); if (err == APM_NO_ERROR) err = APM_SUCCESS; - if (err != APM_SUCCESS) + if (err != APM_SUCCESS) { apm_error("suspend", err); + send_event(APM_NORMAL_RESUME); + sti(); + queue_event(APM_NORMAL_RESUME, NULL); + } for (as = user_list; as != NULL; as = as->next) { as->suspend_wait = 0; as->suspend_result = ((err == APM_SUCCESS) ? 0 : -EIO); @@ -914,33 +953,6 @@ return 0; } -static int send_event(apm_event_t event, struct apm_user *sender) -{ - switch (event) { - case APM_SYS_SUSPEND: - case APM_CRITICAL_SUSPEND: - case APM_USER_SUSPEND: - /* map all suspends to ACPI D3 */ - if (pm_send_all(PM_SUSPEND, (void *)3)) { - if (event == APM_CRITICAL_SUSPEND) { - printk(KERN_CRIT "apm: Critical suspend was vetoed, expect armagedon\n" ); - return 0; - } - if (apm_bios_info.version > 0x100) - apm_set_power_state(APM_STATE_REJECT); - return 0; - } - break; - case APM_NORMAL_RESUME: - case APM_CRITICAL_RESUME: - /* map all resumes to ACPI D0 */ - (void) pm_send_all(PM_RESUME, (void *)0); - break; - } - - return 1; -} - static void check_events(void) { apm_event_t event; @@ -966,7 +978,7 @@ switch (event) { case APM_SYS_STANDBY: case APM_USER_STANDBY: - if (send_event(event, NULL)) { + if (send_event(event)) { queue_event(event, NULL); if (standbys_pending <= 0) standby(); @@ -984,17 +996,17 @@ if (ignore_bounce) break; #endif - /* - * If we are already processing a SUSPEND, - * then further SUSPEND events from the BIOS - * will be ignored. We also return here to - * cope with the fact that the Thinkpads keep - * sending a SUSPEND event until something else - * happens! - */ + /* + * If we are already processing a SUSPEND, + * then further SUSPEND events from the BIOS + * will be ignored. We also return here to + * cope with the fact that the Thinkpads keep + * sending a SUSPEND event until something else + * happens! + */ if (waiting_for_resume) - return; - if (send_event(event, NULL)) { + return; + if (send_event(event)) { queue_event(event, NULL); waiting_for_resume = 1; if (suspends_pending <= 0) @@ -1011,14 +1023,16 @@ ignore_bounce = 1; #endif set_time(); - send_event(event, NULL); + send_event(event); + sti(); queue_event(event, NULL); break; case APM_CAPABILITY_CHANGE: case APM_LOW_BATTERY: case APM_POWER_STATUS_CHANGE: - send_event(event, NULL); + send_event(event); + queue_event(event, NULL); break; case APM_UPDATE_TIME: @@ -1026,7 +1040,11 @@ break; case APM_CRITICAL_SUSPEND: - send_event(event, NULL); /* We can only hope it worked; critical suspend may not fail */ + send_event(event); + /* + * We can only hope it worked - we are not allowed + * to reject a critical suspend. + */ (void) suspend(); break; } @@ -1066,11 +1084,8 @@ int timeout = HZ; DECLARE_WAITQUEUE(wait, current); - if (smp_num_cpus > 1) - return; - add_wait_queue(&apm_waitqueue, &wait); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); for (;;) { /* Nothing to do, just sleep for the timeout */ timeout = 2*timeout; @@ -1084,7 +1099,7 @@ * Ok, check all events, check for idle (and mark us sleeping * so as not to count towards the load average).. */ - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); apm_event_handler(); #ifdef CONFIG_APM_CPU_IDLE if (!system_idle()) @@ -1093,7 +1108,7 @@ unsigned long start = jiffies; while ((!exit_kapmd) && system_idle()) { apm_do_idle(); - if (jiffies - start > (5*APM_CHECK_TIMEOUT)) { + if ((jiffies - start) > APM_CHECK_TIMEOUT) { apm_event_handler(); start = jiffies; } @@ -1137,7 +1152,7 @@ schedule(); goto repeat; } - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); remove_wait_queue(&apm_waitqueue, &wait); } i = count; @@ -1199,8 +1214,10 @@ as->standbys_read--; as->standbys_pending--; standbys_pending--; - } else if (!send_event(APM_USER_STANDBY, as)) + } else if (!send_event(APM_USER_STANDBY)) return -EAGAIN; + else + queue_event(APM_USER_STANDBY, as); if (standbys_pending <= 0) standby(); break; @@ -1209,8 +1226,10 @@ as->suspends_read--; as->suspends_pending--; suspends_pending--; - } else if (!send_event(APM_USER_SUSPEND, as)) + } else if (!send_event(APM_USER_SUSPEND)) return -EAGAIN; + else + queue_event(APM_USER_SUSPEND, as); if (suspends_pending <= 0) { if (suspend() != APM_SUCCESS) return -EIO; @@ -1224,7 +1243,7 @@ break; schedule(); } - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); remove_wait_queue(&apm_suspend_waitqueue, &wait); return as->suspend_result; } @@ -1268,7 +1287,6 @@ as1->next = as->next; } kfree_s(as, sizeof(*as)); - MOD_DEC_USE_COUNT; return 0; } @@ -1276,13 +1294,10 @@ { struct apm_user * as; - MOD_INC_USE_COUNT; - as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL); if (as == NULL) { printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n", sizeof(*as)); - MOD_DEC_USE_COUNT; return -ENOMEM; } as->magic = APM_BIOS_MAGIC; @@ -1403,6 +1418,7 @@ strcpy(current->comm, "kapmd"); sigfillset(¤t->blocked); + current->tty = NULL; /* get rid of controlling tty */ if (apm_bios_info.version > 0x100) { /* @@ -1487,27 +1503,15 @@ #ifdef CONFIG_MAGIC_SYSRQ sysrq_power_off = apm_power_off; #endif + if (smp_num_cpus == 1) { #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) - if (smp_num_cpus == 1) console_blank_hook = apm_console_blank; #endif - - pm_active = 1; - - apm_mainloop(); - - pm_active = 0; - + apm_mainloop(); #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) - if (smp_num_cpus == 1) console_blank_hook = NULL; #endif -#ifdef CONFIG_MAGIC_SYSRQ - sysrq_power_off = NULL; -#endif - if (power_off) - pm_power_off = NULL; - + } kapmd_running = 0; return 0; @@ -1540,6 +1544,7 @@ __setup("apm=", apm_setup); static struct file_operations apm_bios_fops = { + owner: THIS_MODULE, read: do_read, poll: do_poll, ioctl: do_ioctl, @@ -1618,6 +1623,7 @@ printk(KERN_NOTICE "apm: overridden by ACPI.\n"); APM_INIT_ERROR_RETURN; } + pm_active = 1; /* * Set up a segment that references the real mode segment 0x40 @@ -1676,9 +1682,15 @@ { misc_deregister(&apm_device); remove_proc_entry("apm", NULL); +#ifdef CONFIG_MAGIC_SYSRQ + sysrq_power_off = NULL; +#endif + if (power_off) + pm_power_off = NULL; exit_kapmd = 1; while (kapmd_running) schedule(); + pm_active = 0; } module_init(apm_init); diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/cpuid.c linux/arch/i386/kernel/cpuid.c --- v2.4.0-test1/linux/arch/i386/kernel/cpuid.c Mon Jun 19 16:31:57 2000 +++ linux/arch/i386/kernel/cpuid.c Tue Jun 20 13:58:42 2000 @@ -64,11 +64,11 @@ if ( cpu == smp_processor_id() ) { cpuid(reg, &data[0], &data[1], &data[2], &data[3]); } else { - cmd->cpu = cpu; - cmd->reg = reg; - cmd->data = data; + cmd.cpu = cpu; + cmd.reg = reg; + cmd.data = data; - smp_call_function(cpuid_smp_cpuid, (void *)cmd, 1, 1); + smp_call_function(cpuid_smp_cpuid, &cmd, 1, 1); } } #else /* ! CONFIG_SMP */ @@ -120,17 +120,13 @@ static int cpuid_open(struct inode *inode, struct file *file) { int cpu = MINOR(file->f_dentry->d_inode->i_rdev); - + struct cpuinfo_x86 *c = &(cpu_data)[cpu]; + if ( !(cpu_online_map & (1UL << cpu)) ) - return -ENXIO; /* No such CPU */ + return -ENXIO; /* No such CPU */ + if ( c->cpuid_level < 0 ) + return -EIO; /* CPUID not supported */ - MOD_INC_USE_COUNT; - return 0; -} - -static int cpuid_release(struct inode *inode, struct file *file) -{ - MOD_DEC_USE_COUNT; return 0; } @@ -138,10 +134,10 @@ * File operations we support */ static struct file_operations cpuid_fops = { + owner: THIS_MODULE, llseek: cpuid_seek, read: cpuid_read, open: cpuid_open, - release: cpuid_release, }; int __init cpuid_init(void) diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S --- v2.4.0-test1/linux/arch/i386/kernel/entry.S Mon Jun 19 16:31:57 2000 +++ linux/arch/i386/kernel/entry.S Wed Jun 21 20:59:38 2000 @@ -78,6 +78,7 @@ exec_domain = 16 need_resched = 20 processor = 56 +tsk_ptrace = 60 ENOSYS = 38 @@ -180,7 +181,7 @@ call SYMBOL_NAME(schedule_tail) addl $4, %esp GET_CURRENT(%ebx) - testb $0x20,flags(%ebx) # PF_TRACESYS + testb $0x02,tsk_ptrace(%ebx) # PT_TRACESYS jne tracesys_exit jmp ret_from_sys_call @@ -197,7 +198,7 @@ GET_CURRENT(%ebx) cmpl $(NR_syscalls),%eax jae badsys - testb $0x20,flags(%ebx) # PF_TRACESYS + testb $0x02,tsk_ptrace(%ebx) # PT_TRACESYS jne tracesys call *SYMBOL_NAME(sys_call_table)(,%eax,4) movl %eax,EAX(%esp) # save the return value @@ -322,6 +323,11 @@ pushl $ SYMBOL_NAME(do_coprocessor_error) jmp error_code +ENTRY(simd_coprocessor_error) + pushl $0 + pushl $ SYMBOL_NAME(do_simd_coprocessor_error) + jmp error_code + ENTRY(device_not_available) pushl $-1 # mark this as an int SAVE_ALL @@ -411,11 +417,6 @@ ENTRY(spurious_interrupt_bug) pushl $0 pushl $ SYMBOL_NAME(do_spurious_interrupt_bug) - jmp error_code - -ENTRY(xmm_fault) - pushl $0 - pushl $ SYMBOL_NAME(do_xmm_fault) jmp error_code .data diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c --- v2.4.0-test1/linux/arch/i386/kernel/i386_ksyms.c Wed Apr 26 16:34:06 2000 +++ linux/arch/i386/kernel/i386_ksyms.c Thu Jun 22 07:17:16 2000 @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -24,7 +25,6 @@ #include extern void dump_thread(struct pt_regs *, struct user *); -extern int dump_fpu(elf_fpregset_t *); extern spinlock_t rtc_lock; #if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) @@ -51,6 +51,7 @@ EXPORT_SYMBOL(__verify_write); EXPORT_SYMBOL(dump_thread); EXPORT_SYMBOL(dump_fpu); +EXPORT_SYMBOL(dump_extended_fpu); EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(iounmap); EXPORT_SYMBOL(__io_virt_debug); @@ -99,6 +100,10 @@ EXPORT_SYMBOL(pci_alloc_consistent); EXPORT_SYMBOL(pci_free_consistent); + +#ifdef CONFIG_PCI +EXPORT_SYMBOL(pcibios_penalize_isa_irq); +#endif #ifdef CONFIG_X86_USE_3DNOW EXPORT_SYMBOL(_mmx_memcpy); diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/i387.c linux/arch/i386/kernel/i387.c --- v2.4.0-test1/linux/arch/i386/kernel/i387.c Wed Dec 31 16:00:00 1969 +++ linux/arch/i386/kernel/i387.c Wed Jun 21 20:59:38 2000 @@ -0,0 +1,507 @@ +/* + * linux/arch/i386/kernel/i387.c + * + * Copyright (C) 1994 Linus Torvalds + * + * Pentium III FXSR, SSE support + * General FPU state handling cleanups + * Gareth Hughes , May 2000 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_X86_FXSR) +#define HAVE_FXSR 1 +#elif defined(CONFIG_X86_RUNTIME_FXSR) +#define HAVE_FXSR (cpu_has_fxsr) +#else +#define HAVE_FXSR 0 +#endif + +#ifdef CONFIG_MATH_EMULATION +#define HAVE_HWFP (boot_cpu_data.hard_math) +#else +#define HAVE_HWFP 1 +#endif + +/* + * FPU lazy state save handling. + */ + +void save_fpu( struct task_struct *tsk ) +{ + if ( HAVE_FXSR ) { + asm volatile( "fxsave %0 ; fwait" + : "=m" (tsk->thread.i387.fxsave) ); + } else { + asm volatile( "fnsave %0 ; fwait" + : "=m" (tsk->thread.i387.fsave) ); + } + tsk->flags &= ~PF_USEDFPU; + stts(); +} + +void save_init_fpu( struct task_struct *tsk ) +{ + if ( HAVE_FXSR ) { + asm volatile( "fxsave %0 ; fnclex" + : "=m" (tsk->thread.i387.fxsave) ); + } else { + asm volatile( "fnsave %0 ; fwait" + : "=m" (tsk->thread.i387.fsave) ); + } + tsk->flags &= ~PF_USEDFPU; + stts(); +} + +void restore_fpu( struct task_struct *tsk ) +{ + if ( HAVE_FXSR ) { + asm volatile( "fxrstor %0" + : : "m" (tsk->thread.i387.fxsave) ); + } else { + asm volatile( "frstor %0" + : : "m" (tsk->thread.i387.fsave) ); + } +} + +/* + * FPU tag word conversions. + */ + +static inline unsigned short twd_i387_to_fxsr( unsigned short twd ) +{ + unsigned short ret = 0; + int i; + + for ( i = 0 ; i < 8 ; i++ ) { + if ( (twd & 0x3) != 0x3 ) { + ret |= (1 << i); + } + twd = twd >> 2; + } + return ret; +} + +static inline unsigned long twd_fxsr_to_i387( struct i387_fxsave_struct *fxsave ) +{ + struct _fpxreg *st = NULL; + unsigned long twd = (unsigned long) fxsave->twd; + unsigned long tag; + unsigned long ret = 0xffff0000; + int i; + +#define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16); + + for ( i = 0 ; i < 8 ; i++ ) { + if ( twd & 0x1 ) { + st = (struct _fpxreg *) FPREG_ADDR( fxsave, i ); + + switch ( st->exponent ) { + case 0xffff: + tag = 2; /* Special */ + break; + case 0x0000: + if ( !st->significand[0] && + !st->significand[1] && + !st->significand[2] && + !st->significand[3] ) { + tag = 1; /* Zero */ + } else { + tag = 2; /* Special */ + } + break; + default: + if ( st->significand[3] & 0x8000 ) { + tag = 0; /* Valid */ + } else { + tag = 2; /* Special */ + } + break; + } + } else { + tag = 3; /* Empty */ + } + ret |= (tag << (2 * i)); + twd = twd >> 1; + } + return ret; +} + +/* + * FPU state interaction. + */ + +unsigned short get_fpu_cwd( struct task_struct *tsk ) +{ + if ( HAVE_FXSR ) { + return tsk->thread.i387.fxsave.cwd; + } else { + return (unsigned short)tsk->thread.i387.fsave.cwd; + } +} + +unsigned short get_fpu_swd( struct task_struct *tsk ) +{ + if ( HAVE_FXSR ) { + return tsk->thread.i387.fxsave.swd; + } else { + return (unsigned short)tsk->thread.i387.fsave.swd; + } +} + +unsigned short get_fpu_twd( struct task_struct *tsk ) +{ + if ( HAVE_FXSR ) { + return tsk->thread.i387.fxsave.twd; + } else { + return (unsigned short)tsk->thread.i387.fsave.twd; + } +} + +unsigned short get_fpu_mxcsr( struct task_struct *tsk ) +{ + if ( HAVE_FXSR ) { + return tsk->thread.i387.fxsave.mxcsr; + } else { + return 0x1f80; + } +} + +void set_fpu_cwd( struct task_struct *tsk, unsigned short cwd ) +{ + if ( HAVE_FXSR ) { + tsk->thread.i387.fxsave.cwd = cwd; + } else { + tsk->thread.i387.fsave.cwd = ((long)cwd | 0xffff0000); + } +} + +void set_fpu_swd( struct task_struct *tsk, unsigned short swd ) +{ + if ( HAVE_FXSR ) { + tsk->thread.i387.fxsave.swd = swd; + } else { + tsk->thread.i387.fsave.swd = ((long)swd | 0xffff0000); + } +} + +void set_fpu_twd( struct task_struct *tsk, unsigned short twd ) +{ + if ( HAVE_FXSR ) { + tsk->thread.i387.fxsave.twd = twd_i387_to_fxsr(twd); + } else { + tsk->thread.i387.fsave.twd = ((long)twd | 0xffff0000); + } +} + +void set_fpu_mxcsr( struct task_struct *tsk, unsigned short mxcsr ) +{ + if ( HAVE_FXSR ) { + tsk->thread.i387.fxsave.mxcsr = mxcsr; + } +} + +/* + * FXSR floating point environment conversions. + */ + +static inline int convert_fxsr_to_user( struct _fpstate *buf, + struct i387_fxsave_struct *fxsave ) +{ + unsigned long env[7]; + struct _fpreg *to; + struct _fpxreg *from; + int i; + + env[0] = (unsigned long)fxsave->cwd | 0xffff0000; + env[1] = (unsigned long)fxsave->swd | 0xffff0000; + env[2] = twd_fxsr_to_i387(fxsave); + env[3] = fxsave->fip; + env[4] = fxsave->fcs | ((unsigned long)fxsave->fop << 16); + env[5] = fxsave->foo; + env[6] = fxsave->fos; + + if ( __copy_to_user( buf, env, 7 * sizeof(unsigned long) ) ) + return 1; + + to = &buf->_st[0]; + from = (struct _fpxreg *) &fxsave->st_space[0]; + for ( i = 0 ; i < 8 ; i++, to++, from++ ) { + if ( __copy_to_user( to, from, sizeof(*to) ) ) + return 1; + } + return 0; +} + +static inline int convert_fxsr_from_user( struct i387_fxsave_struct *fxsave, + struct _fpstate *buf ) +{ + unsigned long env[7]; + struct _fpxreg *to; + struct _fpreg *from; + int i; + + if ( __copy_from_user( env, buf, 7 * sizeof(long) ) ) + return 1; + + fxsave->cwd = (unsigned short)(env[0] & 0xffff); + fxsave->swd = (unsigned short)(env[1] & 0xffff); + fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff)); + fxsave->fip = env[3]; + fxsave->fop = (unsigned short)((env[4] & 0xffff0000) >> 16); + fxsave->fcs = (env[4] & 0xffff); + fxsave->foo = env[5]; + fxsave->fos = env[6]; + + to = (struct _fpxreg *) &fxsave->st_space[0]; + from = &buf->_st[0]; + for ( i = 0 ; i < 8 ; i++, to++, from++ ) { + if ( __copy_from_user( to, from, sizeof(*from) ) ) + return 1; + } + return 0; +} + +/* + * Signal frame handlers. + */ + +static inline int save_i387_fsave( struct _fpstate *buf ) +{ + struct task_struct *tsk = current; + + unlazy_fpu( tsk ); + tsk->thread.i387.fsave.status = tsk->thread.i387.fsave.swd; + if ( __copy_to_user( buf, &tsk->thread.i387.fsave, + sizeof(struct i387_fsave_struct) ) ) + return -1; + return 1; +} + +static inline int save_i387_fxsave( struct _fpstate *buf ) +{ + struct task_struct *tsk = current; + int err = 0; + + unlazy_fpu( tsk ); + + if ( convert_fxsr_to_user( buf, &tsk->thread.i387.fxsave ) ) + return -1; + + err |= __put_user( tsk->thread.i387.fxsave.swd, &buf->status ); + err |= __put_user( X86_FXSR_MAGIC, &buf->magic ); + if ( err ) + return -1; + + if ( __copy_to_user( &buf->_fxsr_env[0], &tsk->thread.i387.fxsave, + sizeof(struct i387_fxsave_struct) ) ) + return -1; + return 1; +} + +int save_i387( struct _fpstate *buf ) +{ + if ( !current->used_math ) + return 0; + + /* This will cause a "finit" to be triggered by the next + * attempted FPU operation by the 'current' process. + */ + current->used_math = 0; + + if ( HAVE_HWFP ) { + if ( HAVE_FXSR ) { + return save_i387_fxsave( buf ); + } else { + return save_i387_fsave( buf ); + } + } else { + return save_i387_soft( ¤t->thread.i387.soft, buf ); + } +} + +static inline int restore_i387_fsave( struct _fpstate *buf ) +{ + struct task_struct *tsk = current; + clear_fpu( tsk ); + return __copy_from_user( &tsk->thread.i387.fsave, buf, + sizeof(struct i387_fsave_struct) ); +} + +static inline int restore_i387_fxsave( struct _fpstate *buf ) +{ + struct task_struct *tsk = current; + clear_fpu( tsk ); + if ( __copy_from_user( &tsk->thread.i387.fxsave, &buf->_fxsr_env[0], + sizeof(struct i387_fxsave_struct) ) ) + return 1; + return convert_fxsr_from_user( &tsk->thread.i387.fxsave, buf ); +} + +int restore_i387( struct _fpstate *buf ) +{ + int err; + + if ( HAVE_HWFP ) { + if ( HAVE_FXSR ) { + err = restore_i387_fxsave( buf ); + } else { + err = restore_i387_fsave( buf ); + } + } else { + err = restore_i387_soft( ¤t->thread.i387.soft, buf ); + } + current->used_math = 1; + return err; +} + +/* + * ptrace request handlers. + */ + +static inline int get_fpregs_fsave( struct user_i387_struct *buf, + struct task_struct *tsk ) +{ + return __copy_to_user( buf, &tsk->thread.i387.fsave, + sizeof(struct user_i387_struct) ); +} + +static inline int get_fpregs_fxsave( struct user_i387_struct *buf, + struct task_struct *tsk ) +{ + return convert_fxsr_to_user( (struct _fpstate *)buf, + &tsk->thread.i387.fxsave ); +} + +int get_fpregs( struct user_i387_struct *buf, struct task_struct *tsk ) +{ + if ( HAVE_HWFP ) { + if ( HAVE_FXSR ) { + return get_fpregs_fxsave( buf, tsk ); + } else { + return get_fpregs_fsave( buf, tsk ); + } + } else { + return save_i387_soft( &tsk->thread.i387.soft, + (struct _fpstate *)buf ); + } +} + +static inline int set_fpregs_fsave( struct task_struct *tsk, + struct user_i387_struct *buf ) +{ + return __copy_from_user( &tsk->thread.i387.fsave, buf, + sizeof(struct user_i387_struct) ); +} + +static inline int set_fpregs_fxsave( struct task_struct *tsk, + struct user_i387_struct *buf ) +{ + return convert_fxsr_from_user( &tsk->thread.i387.fxsave, + (struct _fpstate *)buf ); +} + +int set_fpregs( struct task_struct *tsk, struct user_i387_struct *buf ) +{ + if ( HAVE_HWFP ) { + if ( HAVE_FXSR ) { + return set_fpregs_fxsave( tsk, buf ); + } else { + return set_fpregs_fsave( tsk, buf ); + } + } else { + return restore_i387_soft( &tsk->thread.i387.soft, + (struct _fpstate *)buf ); + } +} + +int get_fpxregs( struct user_fxsr_struct *buf, struct task_struct *tsk ) +{ + if ( HAVE_FXSR ) { + __copy_to_user( (void *)buf, &tsk->thread.i387.fxsave, + sizeof(struct user_fxsr_struct) ); + return 0; + } else { + return -EIO; + } +} + +int set_fpxregs( struct task_struct *tsk, struct user_fxsr_struct *buf ) +{ + if ( HAVE_FXSR ) { + __copy_from_user( &tsk->thread.i387.fxsave, (void *)buf, + sizeof(struct user_fxsr_struct) ); + return 0; + } else { + return -EIO; + } +} + +/* + * FPU state for core dumps. + */ + +static inline void copy_fpu_fsave( struct task_struct *tsk, + struct user_i387_struct *fpu ) +{ + memcpy( fpu, &tsk->thread.i387.fsave, + sizeof(struct user_i387_struct) ); +} + +static inline void copy_fpu_fxsave( struct task_struct *tsk, + struct user_i387_struct *fpu ) +{ + unsigned short *to; + unsigned short *from; + int i; + + memcpy( fpu, &tsk->thread.i387.fxsave, 7 * sizeof(long) ); + + to = (unsigned short *)&fpu->st_space[0]; + from = (unsigned short *)&tsk->thread.i387.fxsave.st_space[0]; + for ( i = 0 ; i < 8 ; i++, to += 5, from += 8 ) { + memcpy( to, from, 5 * sizeof(unsigned short) ); + } +} + +int dump_fpu( struct pt_regs *regs, struct user_i387_struct *fpu ) +{ + int fpvalid; + struct task_struct *tsk = current; + + fpvalid = tsk->used_math; + if ( fpvalid ) { + unlazy_fpu( tsk ); + if ( HAVE_FXSR ) { + copy_fpu_fxsave( tsk, fpu ); + } else { + copy_fpu_fsave( tsk, fpu ); + } + } + + return fpvalid; +} + +int dump_extended_fpu( struct pt_regs *regs, struct user_fxsr_struct *fpu ) +{ + int fpvalid; + struct task_struct *tsk = current; + + fpvalid = tsk->used_math && HAVE_FXSR; + if ( fpvalid ) { + unlazy_fpu( tsk ); + memcpy( fpu, &tsk->thread.i387.fxsave, + sizeof(struct user_fxsr_struct) ); + } + + return fpvalid; +} diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/i8259.c linux/arch/i386/kernel/i8259.c --- v2.4.0-test1/linux/arch/i386/kernel/i8259.c Mon Jun 19 16:31:57 2000 +++ linux/arch/i386/kernel/i8259.c Tue Jun 20 14:25:08 2000 @@ -127,7 +127,7 @@ * moves to arch independent land */ -static spinlock_t i8259A_lock = SPIN_LOCK_UNLOCKED; +spinlock_t i8259A_lock = SPIN_LOCK_UNLOCKED; static void end_8259A_irq (unsigned int irq) { @@ -180,10 +180,6 @@ */ unsigned long io_apic_irqs = 0; -/* - * These have to be protected by the irq controller spinlock - * before being called. - */ void disable_8259A_irq(unsigned int irq) { unsigned int mask = 1 << irq; @@ -239,6 +235,8 @@ /* * This function assumes to be called rarely. Switching between * 8259A registers is slow. + * This has to be protected by the irq controller spinlock + * before being called. */ static inline int i8259A_irq_real(unsigned int irq) { @@ -337,8 +335,7 @@ { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&i8259A_lock, flags); outb(0xff, 0x21); /* mask all of 8259A-1 */ outb(0xff, 0xA1); /* mask all of 8259A-2 */ @@ -372,7 +369,7 @@ outb(cached_21, 0x21); /* restore master IRQ mask */ outb(cached_A1, 0xA1); /* restore slave IRQ mask */ - restore_flags(flags); + spin_unlock_irqrestore(&i8259A_lock, flags); } #ifndef CONFIG_VISWS @@ -397,7 +394,11 @@ math_error((void *)regs->eip); } -static struct irqaction irq13 = { math_error_irq, 0, 0, "fpu", NULL, NULL }; +/* + * New motherboards sometimes make IRQ 13 be a PCI interrupt, + * so allow interrupt sharing. + */ +static struct irqaction irq13 = { math_error_irq, SA_SHIRQ, 0, "fpu", NULL, NULL }; /* * IRQ2 is cascade interrupt to second interrupt controller diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c --- v2.4.0-test1/linux/arch/i386/kernel/io_apic.c Tue May 23 15:31:33 2000 +++ linux/arch/i386/kernel/io_apic.c Mon Jun 19 18:39:17 2000 @@ -175,8 +175,6 @@ static int __init ioapic_setup(char *str) { - extern int skip_ioapic_setup; /* defined in arch/i386/kernel/smp.c */ - skip_ioapic_setup = 1; return 1; } @@ -658,8 +656,6 @@ /* mask LVT0 */ apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT); - init_8259A(1); - /* * We use logical delivery to get the timer IRQ * to the first CPU. @@ -907,24 +903,27 @@ void /*__init*/ print_PIC(void) { + extern spinlock_t i8259A_lock; unsigned int v, flags; printk(KERN_DEBUG "\nprinting PIC contents\n"); + spin_lock_irqsave(&i8259A_lock, flags); + v = inb(0xa1) << 8 | inb(0x21); printk(KERN_DEBUG "... PIC IMR: %04x\n", v); v = inb(0xa0) << 8 | inb(0x20); printk(KERN_DEBUG "... PIC IRR: %04x\n", v); - __save_flags(flags); - __cli(); outb(0x0b,0xa0); outb(0x0b,0x20); v = inb(0xa0) << 8 | inb(0x20); outb(0x0a,0xa0); outb(0x0a,0x20); - __restore_flags(flags); + + spin_unlock_irqrestore(&i8259A_lock, flags); + printk(KERN_DEBUG "... PIC ISR: %04x\n", v); v = inb(0x4d1) << 8 | inb(0x4d0); @@ -991,6 +990,14 @@ /* Read the register 0 value */ *(int *)®_00 = io_apic_read(apic, 0); + if (mp_ioapics[apic].mpc_apicid >= 0xf) { + printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n", + apic, mp_ioapics[apic].mpc_apicid); + printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n", + reg_00.ID); + mp_ioapics[apic].mpc_apicid = reg_00.ID; + } + /* * Read the right value from the MPC table and * write it into the ID register. @@ -1295,6 +1302,7 @@ */ static inline void check_timer(void) { + extern int timer_ack; int pin1, pin2; int vector; @@ -1305,6 +1313,18 @@ vector = assign_irq_vector(0); set_intr_gate(vector, interrupt[0]); + /* + * Subtle, code in do_timer_interrupt() expects an AEOI + * mode for the 8259A whenever interrupts are routed + * through I/O APICs. Also IRQ0 has to be enabled in + * the 8259A which implies the virtual wire has to be + * disabled in the local APIC. + */ + apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT); + init_8259A(1); + timer_ack = 1; + enable_8259A_irq(0); + pin1 = find_timer_pin(mp_INT); pin2 = find_timer_pin(mp_ExtINT); @@ -1318,7 +1338,6 @@ if (timer_irq_works()) { if (nmi_watchdog) { disable_8259A_irq(0); - init_8259A(1); setup_nmi(); enable_8259A_irq(0); nmi_irq_works(); @@ -1360,7 +1379,6 @@ disable_8259A_irq(0); irq_desc[0].handler = &lapic_irq_type; - init_8259A(1); /* AEOI mode */ apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector); /* Fixed mode */ enable_8259A_irq(0); diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/microcode.c linux/arch/i386/kernel/microcode.c --- v2.4.0-test1/linux/arch/i386/kernel/microcode.c Thu Mar 2 14:36:22 2000 +++ linux/arch/i386/kernel/microcode.c Wed Jun 21 22:30:59 2000 @@ -25,6 +25,11 @@ * and frees the saved copy of applied microcode. * 1.03 29 February 2000, Tigran Aivazian * Made to use devfs (/dev/cpu/microcode) + cleanups. + * 1.04 06 June 2000, Simon Trimmer + * Added misc device support (now uses both devfs and misc). + * Added MICROCODE_IOCFREE ioctl to clear memory. + * 1.05 09 June 2000, Simon Trimmer + * Messages for error cases (non intel & no suitable microcode). */ #include @@ -33,16 +38,17 @@ #include #include #include +#include #include #include #include #include -#define MICROCODE_VERSION "1.03" +#define MICROCODE_VERSION "1.05" -MODULE_DESCRIPTION("CPU (P6) microcode update driver"); -MODULE_AUTHOR("Tigran Aivazian "); +MODULE_DESCRIPTION("Intel CPU (P6) microcode update driver"); +MODULE_AUTHOR("Tigran Aivazian "); EXPORT_NO_SYMBOLS; /* VFS interface */ @@ -50,6 +56,7 @@ static int microcode_release(struct inode *, struct file *); static ssize_t microcode_read(struct file *, char *, size_t, loff_t *); static ssize_t microcode_write(struct file *, const char *, size_t, loff_t *); +static int microcode_ioctl(struct inode *, struct file *, unsigned int, unsigned long); /* internal helpers to do the work */ @@ -60,43 +67,62 @@ * Bits in microcode_status. (31 bits of room for future expansion) */ #define MICROCODE_IS_OPEN 0 /* set if device is in use */ -static unsigned long microcode_status = 0; + +static unsigned long microcode_status; /* the actual array of microcode blocks, each 2048 bytes */ -static struct microcode *microcode = NULL; -static unsigned int microcode_num = 0; -static char *mc_applied = NULL; /* holds an array of applied microcode blocks */ -static unsigned int mc_fsize; /* used often, so compute once at microcode_init() */ +static struct microcode *microcode; +static unsigned int microcode_num; +static char *mc_applied; /* holds an array of applied microcode blocks */ +static unsigned int mc_fsize; static struct file_operations microcode_fops = { + owner: THIS_MODULE, read: microcode_read, write: microcode_write, + ioctl: microcode_ioctl, open: microcode_open, release: microcode_release, }; +static struct miscdevice microcode_dev = { + minor: MICROCODE_MINOR, + name: "microcode", + fops: µcode_fops, +}; + static devfs_handle_t devfs_handle; static int __init microcode_init(void) { - devfs_handle = devfs_register(NULL, "cpu/microcode", 0, DEVFS_FL_DEFAULT, 0, 0, - S_IFREG | S_IRUSR | S_IWUSR, 0, 0, µcode_fops, NULL); - if (!devfs_handle) { - printk(KERN_ERR "microcode: can't create /dev/cpu/microcode\n"); - return -ENOMEM; - } - /* XXX assume no hotplug CPUs so smp_num_cpus does not change */ - mc_fsize = smp_num_cpus * sizeof(struct microcode); - printk(KERN_INFO "P6 Microcode Update Driver v%s registered\n", MICROCODE_VERSION); + int error = 0; + + if (misc_register(µcode_dev) < 0) { + printk(KERN_WARNING + "microcode: can't misc_register on minor=%d\n", + MICROCODE_MINOR); + error = 1; + } + devfs_handle = devfs_register(NULL, "cpu/microcode", + DEVFS_FL_DEFAULT, 0, 0, S_IFREG | S_IRUSR | S_IWUSR, + µcode_fops, NULL); + if (devfs_handle == NULL && error) { + printk(KERN_ERR "microcode: failed to devfs_register()\n"); + return -EINVAL; + } + printk(KERN_INFO "P6 Microcode Update Driver v%s registered\n", + MICROCODE_VERSION); return 0; } static void __exit microcode_exit(void) { + misc_deregister(µcode_dev); devfs_unregister(devfs_handle); if (mc_applied) kfree(mc_applied); - printk(KERN_INFO "P6 Microcode Update Driver v%s unregistered\n", MICROCODE_VERSION); + printk(KERN_INFO "P6 Microcode Update Driver v%s unregistered\n", + MICROCODE_VERSION); } module_init(microcode_init); @@ -114,25 +140,16 @@ if (test_and_set_bit(MICROCODE_IS_OPEN, µcode_status)) return -EBUSY; - if ((file->f_flags & O_ACCMODE) == O_WRONLY && mc_applied) { - devfs_set_file_size(devfs_handle, 0); - memset(mc_applied, 0, mc_fsize); - kfree(mc_applied); - mc_applied = NULL; - } - - MOD_INC_USE_COUNT; return 0; } static int microcode_release(struct inode *inode, struct file *file) { clear_bit(MICROCODE_IS_OPEN, µcode_status); - MOD_DEC_USE_COUNT; return 0; } -/* a pointer to 'struct update_req' is passed to the IPI hanlder = do_update_one() +/* a pointer to 'struct update_req' is passed to the IPI handler = do_update_one() * update_req[cpu].err is set to 1 if update failed on 'cpu', 0 otherwise * if err==0, microcode[update_req[cpu].slot] points to applied block of microcode */ @@ -167,12 +184,14 @@ struct cpuinfo_x86 *c = cpu_data + cpu_num; struct update_req *req = (struct update_req *)arg + cpu_num; unsigned int pf = 0, val[2], rev, sig; - int i; + int i,found=0; req->err = 1; /* be pessimistic */ - if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6) + if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6){ + printk(KERN_ERR "microcode: CPU%d not an Intel P6\n", cpu_num ); return; + } sig = c->x86_mask + (c->x86_model<<4) + (c->x86<<8); @@ -186,6 +205,8 @@ if (microcode[i].sig == sig && microcode[i].pf == pf && microcode[i].ldrver == 1 && microcode[i].hdrver == 1) { + found=1; + rdmsr(0x8B, val[0], rev); if (microcode[i].rev <= rev) { printk(KERN_ERR @@ -205,7 +226,7 @@ } wrmsr(0x79, (unsigned int)(m->bits), 0); - __asm__ __volatile__ ("cpuid"); + __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx", "cc"); rdmsr(0x8B, val[0], val[1]); req->err = 0; @@ -216,6 +237,9 @@ } break; } + + if(!found) + printk(KERN_ERR "microcode: found no data for CPU%d (sig=%x, pflags=%d)\n", cpu_num, sig, pf); } static ssize_t microcode_read(struct file *file, char *buf, size_t len, loff_t *ppos) @@ -240,7 +264,8 @@ return -EINVAL; } if (!mc_applied) { - mc_applied = kmalloc(mc_fsize, GFP_KERNEL); + mc_applied = kmalloc(smp_num_cpus*sizeof(struct microcode), + GFP_KERNEL); if (!mc_applied) { printk(KERN_ERR "microcode: out of memory for saved microcode\n"); return -ENOMEM; @@ -257,17 +282,45 @@ } if (copy_from_user(microcode, buf, len)) { ret = -EFAULT; - goto out_vfree; + goto out_fsize; } if(do_microcode_update()) { ret = -EIO; - goto out_vfree; + goto out_fsize; + } else { + mc_fsize = smp_num_cpus * sizeof(struct microcode); + ret = (ssize_t)len; } +out_fsize: devfs_set_file_size(devfs_handle, mc_fsize); - ret = (ssize_t)len; -out_vfree: vfree(microcode); out_unlock: unlock_kernel(); return ret; +} + +static int microcode_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + switch(cmd) { + case MICROCODE_IOCFREE: + if (mc_applied) { + devfs_set_file_size(devfs_handle, 0); + memset(mc_applied, 0, mc_fsize); + kfree(mc_applied); + mc_applied = NULL; + printk(KERN_WARNING + "microcode: freed %d bytes\n", mc_fsize); + mc_fsize = 0; + return 0; + } + return -ENODATA; + + default: + printk(KERN_ERR "microcode: unknown ioctl cmd=%d\n", + cmd); + return -EINVAL; + } + /* NOT REACHED */ + return -EINVAL; } diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/msr.c linux/arch/i386/kernel/msr.c --- v2.4.0-test1/linux/arch/i386/kernel/msr.c Mon Jun 19 16:31:57 2000 +++ linux/arch/i386/kernel/msr.c Tue Jun 20 13:58:42 2000 @@ -40,44 +40,47 @@ #include #include +/* Note: "err" is handled in a funny way below. Otherwise one version + of gcc or another breaks. */ + extern inline int wrmsr_eio(u32 reg, u32 eax, u32 edx) { - int err = 0; + int err; asm volatile( "1: wrmsr\n" "2:\n" ".section .fixup,\"ax\"\n" "3: movl %4,%0\n" - " jmp 1b\n" + " jmp 2b\n" ".previous\n" ".section __ex_table,\"a\"\n" " .align 4\n" " .long 1b,3b\n" ".previous" - : "+r" (err) - : "a" (eax), "d" (edx), "c" (reg), "i" (-EIO)); + : "=&bDS" (err) + : "a" (eax), "d" (edx), "c" (reg), "i" (-EIO), "0" (0)); return err; } extern inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx) { - int err = 0; + int err; asm volatile( "1: rdmsr\n" "2:\n" ".section .fixup,\"ax\"\n" "3: movl %4,%0\n" - " jmp 1b\n" + " jmp 2b\n" ".previous\n" ".section __ex_table,\"a\"\n" " .align 4\n" " .long 1b,3b\n" ".previous" - : "+r" (err), "=a" (*eax), "=d" (*eax) - : "c" (reg), "i" (-EIO)); + : "=&bDS" (err), "=a" (*eax), "=d" (*edx) + : "c" (reg), "i" (-EIO), "0" (0)); return err; } @@ -96,7 +99,7 @@ struct msr_command *cmd = (struct msr_command *) cmd_block; if ( cmd->cpu == smp_processor_id() ) - cmd->err = wrmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]); + cmd->err = wrmsr_eio(cmd->reg, cmd->data[0], cmd->data[1]); } static void msr_smp_rdmsr(void *cmd_block) @@ -119,7 +122,7 @@ cmd.data[0] = eax; cmd.data[1] = edx; - smp_call_function(msr_smp_wrmsr, (void *)cmd, 1, 1); + smp_call_function(msr_smp_wrmsr, &cmd, 1, 1); return cmd.err; } } @@ -134,7 +137,7 @@ cmd.cpu = cpu; cmd.reg = reg; - smp_call_function(msr_smp_rdmsr, (void *)cmd, 1, 1); + smp_call_function(msr_smp_rdmsr, &cmd, 1, 1); *eax = cmd.data[0]; *edx = cmd.data[1]; @@ -224,18 +227,13 @@ static int msr_open(struct inode *inode, struct file *file) { int cpu = MINOR(file->f_dentry->d_inode->i_rdev); + struct cpuinfo_x86 *c = &(cpu_data)[cpu]; - if ( !(cpu_online_map & (1UL << cpu)) || - !((cpu_data)[cpu].x86_capability & X86_FEATURE_MSR) ) - return -ENXIO; /* No such CPU */ + if ( !(cpu_online_map & (1UL << cpu)) ) + return -ENXIO; /* No such CPU */ + if ( !(c->x86_capability & X86_FEATURE_MSR) ) + return -EIO; /* MSR not supported */ - MOD_INC_USE_COUNT; - return 0; -} - -static int msr_release(struct inode *inode, struct file *file) -{ - MOD_DEC_USE_COUNT; return 0; } @@ -243,11 +241,11 @@ * File operations we support */ static struct file_operations msr_fops = { + owner: THIS_MODULE, llseek: msr_seek, read: msr_read, write: msr_write, open: msr_open, - release: msr_release, }; int __init msr_init(void) diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c --- v2.4.0-test1/linux/arch/i386/kernel/mtrr.c Wed Apr 26 16:34:06 2000 +++ linux/arch/i386/kernel/mtrr.c Wed Jun 21 22:30:59 2000 @@ -1531,7 +1531,6 @@ int i, max; unsigned int *fcount = file->private_data; - MOD_DEC_USE_COUNT; if (fcount == NULL) return 0; max = get_num_var_ranges (); for (i = 0; i < max; ++i) @@ -1549,6 +1548,7 @@ static struct file_operations mtrr_fops = { + owner: THIS_MODULE, read: mtrr_read, write: mtrr_write, ioctl: mtrr_ioctl, @@ -1881,11 +1881,12 @@ #ifdef CONFIG_PROC_FS proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root); + proc_root_mtrr->owner = THIS_MODULE; proc_root_mtrr->proc_fops = &mtrr_fops; #endif #ifdef CONFIG_DEVFS_FS - devfs_handle = devfs_register (NULL, "cpu/mtrr", 0, DEVFS_FL_DEFAULT, 0, 0, - S_IFREG | S_IRUGO | S_IWUSR, 0, 0, + devfs_handle = devfs_register (NULL, "cpu/mtrr", DEVFS_FL_DEFAULT, 0, 0, + S_IFREG | S_IRUGO | S_IWUSR, &mtrr_fops, NULL); #endif init_table (); diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/pci-i386.c linux/arch/i386/kernel/pci-i386.c --- v2.4.0-test1/linux/arch/i386/kernel/pci-i386.c Tue May 23 15:31:33 2000 +++ linux/arch/i386/kernel/pci-i386.c Mon Jun 19 12:56:08 2000 @@ -106,6 +106,7 @@ reg = PCI_BASE_ADDRESS_0 + 4*resource; } else if (resource == PCI_ROM_RESOURCE) { res->flags |= PCI_ROM_ADDRESS_ENABLE; + new |= PCI_ROM_ADDRESS_ENABLE; reg = dev->rom_base_reg; } else { /* Somebody might have asked allocation of a non-standard resource */ diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/pci-i386.h linux/arch/i386/kernel/pci-i386.h --- v2.4.0-test1/linux/arch/i386/kernel/pci-i386.h Thu May 11 15:30:06 2000 +++ linux/arch/i386/kernel/pci-i386.h Thu Jun 22 07:17:16 2000 @@ -68,4 +68,4 @@ void pcibios_irq_init(void); void pcibios_fixup_irqs(void); -int pcibios_lookup_irq(struct pci_dev *dev, int assign); +void pcibios_enable_irq(struct pci_dev *dev); diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/pci-irq.c linux/arch/i386/kernel/pci-irq.c --- v2.4.0-test1/linux/arch/i386/kernel/pci-irq.c Tue May 23 15:31:33 2000 +++ linux/arch/i386/kernel/pci-irq.c Fri Jun 23 19:50:50 2000 @@ -14,11 +14,11 @@ #include #include +#include +#include #include "pci-i386.h" -extern int skip_ioapic_setup; - #define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24)) #define PIRQ_VERSION 0x0100 @@ -27,13 +27,13 @@ /* * Never use: 0, 1, 2 (timer, keyboard, and cascade) * Avoid using: 13, 14 and 15 (FP error and IDE). - * Penalize: 3, 4, 7, 12 (known ISA uses: serial, parallel and mouse) + * Penalize: 3, 4, 6, 7, 12 (known ISA uses: serial, floppy, parallel and mouse) */ unsigned int pcibios_irq_mask = 0xfff8; -static unsigned pirq_penalty[16] = { - 10000, 10000, 10000, 100, 100, 0, 0, 100, - 0, 0, 0, 0, 100, 1000, 1000, 1000 +static int pirq_penalty[16] = { + 1000000, 1000000, 1000000, 1000, 1000, 0, 1000, 1000, + 0, 0, 0, 0, 1000, 100000, 100000, 100000 }; struct irq_router { @@ -128,14 +128,13 @@ static int pirq_ali_get(struct pci_dev *router, struct pci_dev *dev, int pirq) { static unsigned char irqmap[16] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 }; + u8 x; + unsigned reg; + pirq--; - if (pirq < 8) { - u8 x; - unsigned reg = 0x48 + (pirq >> 1); - pci_read_config_byte(router, reg, &x); - return irqmap[(pirq & 1) ? (x >> 4) : (x & 0x0f)]; - } - return 0; + reg = 0x48 + (pirq >> 1); + pci_read_config_byte(router, reg, &x); + return irqmap[(pirq & 1) ? (x >> 4) : (x & 0x0f)]; } static int pirq_ali_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) @@ -143,7 +142,7 @@ static unsigned char irqmap[16] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 }; unsigned int val = irqmap[irq]; pirq--; - if (val && pirq < 8) { + if (val) { u8 x; unsigned reg = 0x48 + (pirq >> 1); pci_read_config_byte(router, reg, &x); @@ -222,7 +221,7 @@ { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0, pirq_piix_get, pirq_piix_set }, { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, pirq_piix_get, pirq_piix_set }, { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, pirq_piix_get, pirq_piix_set }, - { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82440MX_1, pirq_piix_get, pirq_piix_set }, + { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_0, pirq_piix_get, pirq_piix_set }, { "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set }, { "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, pirq_via_get, pirq_via_set }, { "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, pirq_via_get, pirq_via_set }, @@ -287,7 +286,11 @@ return NULL; } -int pcibios_lookup_irq(struct pci_dev *dev, int assign) +static void pcibios_test_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +{ +} + +static int pcibios_lookup_irq(struct pci_dev *dev, int assign) { struct irq_info *info; int i, pirq, pin, newirq; @@ -323,19 +326,24 @@ /* Find the best IRQ to assign */ newirq = 0; - for (i = 0; i < 16; i++) { - if (!(mask & (1 << i))) - continue; - if (pirq_penalty[i] < pirq_penalty[newirq]) - newirq = i; + if (assign) { + for (i = 0; i < 16; i++) { + if (!(mask & (1 << i))) + continue; + if (pirq_penalty[i] < pirq_penalty[newirq] && + !request_irq(i, pcibios_test_irq_handler, SA_SHIRQ, "pci-test", dev)) { + free_irq(i, dev); + newirq = i; + } + } + DBG(" -> newirq=%d", newirq); } - DBG(" -> newirq=%d", newirq); /* Try to get current IRQ */ if (r->get && (irq = r->get(pirq_router_dev, d, pirq))) { DBG(" -> got IRQ %d\n", irq); msg = "Found"; - } else if (assign && newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) { + } else if (newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) { DBG(" -> assigning IRQ %d", newirq); if (r->set(pirq_router_dev, d, pirq, newirq)) { DBG(" ... OK\n"); @@ -346,7 +354,7 @@ if (!irq) { DBG(" ... failed\n"); - if (assign && newirq && mask == (1 << newirq)) { + if (newirq && mask == (1 << newirq)) { msg = "Guessed"; irq = newirq; } else @@ -379,6 +387,15 @@ if (pirq_table) { pirq_peer_trick(); pirq_find_router(); + if (pirq_table->exclusive_irqs) { + int i; + for (i=0; i<16; i++) + if (!(pirq_table->exclusive_irqs & (1 << i))) + pirq_penalty[i] += 100; + } + /* If we're using the I/O APIC, avoid using the PCI IRQ routing table */ + if (io_apic_assign_pci_irqs) + pirq_table = NULL; } } @@ -397,16 +414,19 @@ DBG("%s: ignoring bogus IRQ %d\n", dev->slot_name, dev->irq); dev->irq = 0; } + /* If the IRQ is already assigned to a PCI device, ignore its ISA use penalty */ + if (pirq_penalty[dev->irq] >= 100 && pirq_penalty[dev->irq] < 100000) + pirq_penalty[dev->irq] = 0; pirq_penalty[dev->irq]++; } pci_for_each_dev(dev) { pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); -#if defined(CONFIG_X86_IO_APIC) +#ifdef CONFIG_X86_IO_APIC /* * Recalculate IRQ numbers if we use the I/O APIC. */ - if (!skip_ioapic_setup) + if (io_apic_assign_pci_irqs) { int irq; @@ -441,5 +461,33 @@ */ if (pin && !dev->irq) pcibios_lookup_irq(dev, 0); + } +} + +void __init pcibios_penalize_isa_irq(int irq) +{ + /* + * If any ISAPnP device reports an IRQ in its list of possible + * IRQ's, we try to avoid assigning it to PCI devices. + */ + pirq_penalty[irq] += 100; +} + +void pcibios_enable_irq(struct pci_dev *dev) +{ + if (!dev->irq) { + u8 pin; + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + if (pin && !pcibios_lookup_irq(dev, 1)) { + char *msg; + if (io_apic_assign_pci_irqs) + msg = " Probably buggy MP table."; + else if (pci_probe & PCI_BIOS_IRQ_SCAN) + msg = ""; + else + msg = " Please try using pci=biosirq."; + printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n", + 'A' + pin - 1, dev->slot_name, msg); + } } } diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/pci-pc.c linux/arch/i386/kernel/pci-pc.c --- v2.4.0-test1/linux/arch/i386/kernel/pci-pc.c Tue May 23 15:31:33 2000 +++ linux/arch/i386/kernel/pci-pc.c Thu Jun 22 07:17:16 2000 @@ -14,7 +14,6 @@ #include #include -#include #include "pci-i386.h" @@ -1046,13 +1045,6 @@ if ((err = pcibios_enable_resources(dev)) < 0) return err; - if (!dev->irq) { - u8 pin; - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); - if (pin && !pcibios_lookup_irq(dev, 1)) - printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n", - 'A' + pin - 1, dev->slot_name, - (pci_probe & PCI_BIOS_IRQ_SCAN) ? "" : " Please try using pci=biosirq."); - } + pcibios_enable_irq(dev); return 0; } diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/pci-visws.c linux/arch/i386/kernel/pci-visws.c --- v2.4.0-test1/linux/arch/i386/kernel/pci-visws.c Thu Jan 6 12:57:47 2000 +++ linux/arch/i386/kernel/pci-visws.c Thu Jun 22 07:17:16 2000 @@ -135,3 +135,7 @@ { return pcibios_enable_resources(dev); } + +void __init pcibios_penalize_isa_irq(irq) +{ +} diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- v2.4.0-test1/linux/arch/i386/kernel/process.c Mon Jun 19 16:31:57 2000 +++ linux/arch/i386/kernel/process.c Wed Jun 21 20:59:38 2000 @@ -2,8 +2,9 @@ * linux/arch/i386/kernel/process.c * * Copyright (C) 1995 Linus Torvalds - * Pentium III code by Ingo Molnar with changes and support for - * OS exception support by Goutham Rao + * + * Pentium III FXSR, SSE support + * Gareth Hughes , May 2000 */ /* @@ -38,6 +39,7 @@ #include #include #include +#include #include #include #ifdef CONFIG_MATH_EMULATION @@ -471,94 +473,6 @@ return; } -#ifdef CONFIG_X86_FX - -int i387_hard_to_user ( struct _fpstate * user, - struct i387_hard_struct * hard) -{ - int i, err = 0; - short *tmp, *tmp2; - long *ltmp1, *ltmp2; - - err |= put_user(hard->cwd, &user->cw); - err |= put_user(hard->swd, &user->sw); - err |= put_user(fputag_KNIto387(hard->twd), &user->tag); - err |= put_user(hard->fip, &user->ipoff); - err |= put_user(hard->fcs, &user->cssel); - err |= put_user(hard->fdp, &user->dataoff); - err |= put_user(hard->fds, &user->datasel); - err |= put_user(hard->mxcsr, &user->mxcsr); - - tmp = (short *)&user->_st; - tmp2 = (short *)&hard->st_space; - - /* - * Transform the two layouts: - * (we do not mix 32-bit access with 16-bit access because - * thats suboptimal on PPros) - */ - for (i = 0; i < 8; i++) - { - err |= put_user(*tmp2, tmp); tmp++; tmp2++; - err |= put_user(*tmp2, tmp); tmp++; tmp2++; - err |= put_user(*tmp2, tmp); tmp++; tmp2++; - err |= put_user(*tmp2, tmp); tmp++; tmp2++; - err |= put_user(*tmp2, tmp); tmp++; tmp2 += 3; - } - - ltmp1 = (unsigned long *)&(user->_xmm[0]); - ltmp2 = (unsigned long *)&(hard->xmm_space[0]); - for(i = 0; i < 88; i++) - { - err |= put_user(*ltmp2, ltmp1); - ltmp1++; ltmp2++; - } - - return err; -} - -int i387_user_to_hard (struct i387_hard_struct * hard, - struct _fpstate * user) -{ - int i, err = 0; - short *tmp, *tmp2; - long *ltmp1, *ltmp2; - - err |= get_user(hard->cwd, &user->cw); - err |= get_user(hard->swd, &user->sw); - err |= get_user(hard->twd, &user->tag); - hard->twd = fputag_387toKNI(hard->twd); - err |= get_user(hard->fip, &user->ipoff); - err |= get_user(hard->fcs, &user->cssel); - err |= get_user(hard->fdp, &user->dataoff); - err |= get_user(hard->fds, &user->datasel); - err |= get_user(hard->mxcsr, &user->mxcsr); - - tmp2 = (short *)&hard->st_space; - tmp = (short *)&user->_st; - - for (i = 0; i < 8; i++) - { - err |= get_user(*tmp2, tmp); tmp++; tmp2++; - err |= get_user(*tmp2, tmp); tmp++; tmp2++; - err |= get_user(*tmp2, tmp); tmp++; tmp2++; - err |= get_user(*tmp2, tmp); tmp++; tmp2++; - err |= get_user(*tmp2, tmp); tmp++; tmp2 += 3; - } - - ltmp1 = (unsigned long *)(&user->_xmm[0]); - ltmp2 = (unsigned long *)(&hard->xmm_space[0]); - for(i = 0; i < (88); i++) - { - err |= get_user(*ltmp2, ltmp1); - ltmp2++; ltmp1++; - } - - return err; -} - -#endif - /* * Save a segment. */ @@ -590,23 +504,6 @@ } /* - * fill in the FPU structure for a core dump. - */ -int dump_fpu (struct pt_regs * regs, struct user_i387_struct* fpu) -{ - int fpvalid; - struct task_struct *tsk = current; - - fpvalid = tsk->used_math; - if (fpvalid) { - unlazy_fpu(tsk); - memcpy(fpu,&tsk->thread.i387.hard,sizeof(*fpu)); - } - - return fpvalid; -} - -/* * fill in the user structure for a core dump.. */ void dump_thread(struct pt_regs * regs, struct user * dump) @@ -788,7 +685,7 @@ goto out; error = do_execve(filename, (char **) regs.ecx, (char **) regs.edx, ®s); if (error == 0) - current->flags &= ~PF_DTRACE; + current->ptrace &= ~PT_DTRACE; putname(filename); out: return error; diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c --- v2.4.0-test1/linux/arch/i386/kernel/ptrace.c Mon Jun 19 16:31:57 2000 +++ linux/arch/i386/kernel/ptrace.c Thu Jun 22 06:59:53 2000 @@ -1,9 +1,10 @@ /* ptrace.c */ /* By Ross Biro 1/23/92 */ -/* FXSAVE/FXRSTOR support by Ingo Molnar and modifications by Goutham Rao */ -/* edited by Linus Torvalds */ +/* + * Pentium III FXSR, SSE support + * Gareth Hughes , May 2000 + */ -#include /* for CONFIG_MATH_EMULATION */ #include #include #include @@ -17,6 +18,7 @@ #include #include #include +#include #include /* @@ -141,10 +143,10 @@ ret = -EPERM; if (request == PTRACE_TRACEME) { /* are we already being traced? */ - if (current->flags & PF_PTRACED) + if (current->ptrace & PT_PTRACED) goto out; /* set the ptrace bit in the process flags. */ - current->flags |= PF_PTRACED; + current->ptrace |= PT_PTRACED; ret = 0; goto out; } @@ -174,9 +176,9 @@ (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) goto out_tsk; /* the same process cannot be attached many times */ - if (child->flags & PF_PTRACED) + if (child->ptrace & PT_PTRACED) goto out_tsk; - child->flags |= PF_PTRACED; + child->ptrace |= PT_PTRACED; write_lock_irq(&tasklist_lock); if (child->p_pptr != current) { @@ -191,7 +193,7 @@ goto out_tsk; } ret = -ESRCH; - if (!(child->flags & PF_PTRACED)) + if (!(child->ptrace & PT_PTRACED)) goto out_tsk; if (child->state != TASK_STOPPED) { if (request != PTRACE_KILL) @@ -291,9 +293,9 @@ if ((unsigned long) data > _NSIG) break; if (request == PTRACE_SYSCALL) - child->flags |= PF_TRACESYS; + child->ptrace |= PT_TRACESYS; else - child->flags &= ~PF_TRACESYS; + child->ptrace &= ~PT_TRACESYS; child->exit_code = data; /* make sure the single step bit is not set. */ tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; @@ -328,10 +330,10 @@ ret = -EIO; if ((unsigned long) data > _NSIG) break; - child->flags &= ~PF_TRACESYS; - if ((child->flags & PF_DTRACE) == 0) { + child->ptrace &= ~PT_TRACESYS; + if ((child->ptrace & PT_DTRACE) == 0) { /* Spurious delayed TF traps may occur */ - child->flags |= PF_DTRACE; + child->ptrace |= PT_DTRACE; } tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG; put_stack_long(child, EFL_OFFSET, tmp); @@ -348,7 +350,7 @@ ret = -EIO; if ((unsigned long) data > _NSIG) break; - child->flags &= ~(PF_PTRACED|PF_TRACESYS); + child->ptrace &= ~(PT_PTRACED|PT_TRACESYS); child->exit_code = data; write_lock_irq(&tasklist_lock); REMOVE_LINKS(child); @@ -392,48 +394,62 @@ } case PTRACE_GETFPREGS: { /* Get the child FPU state. */ - if (!access_ok(VERIFY_WRITE, (unsigned *)data, sizeof(struct user_i387_struct))) { + if (!access_ok(VERIFY_WRITE, (unsigned *)data, + sizeof(struct user_i387_struct))) { ret = -EIO; break; } ret = 0; if ( !child->used_math ) { /* Simulate an empty FPU. */ - i387_set_cwd(child->thread.i387.hard, 0x037f); - i387_set_swd(child->thread.i387.hard, 0x0000); - i387_set_twd(child->thread.i387.hard, 0xffff); - } -#ifdef CONFIG_MATH_EMULATION - if ( boot_cpu_data.hard_math ) { -#endif - i387_hard_to_user((struct _fpstate *)data, &child->thread.i387.hard); -#ifdef CONFIG_MATH_EMULATION - } else { - save_i387_soft(&child->thread.i387.soft, (struct _fpstate *)data); + set_fpu_cwd(child, 0x037f); + set_fpu_swd(child, 0x0000); + set_fpu_twd(child, 0xffff); } -#endif + get_fpregs((struct user_i387_struct *)data, child); break; } case PTRACE_SETFPREGS: { /* Set the child FPU state. */ - if (!access_ok(VERIFY_READ, (unsigned *)data, sizeof(struct user_i387_struct))) { + if (!access_ok(VERIFY_READ, (unsigned *)data, + sizeof(struct user_i387_struct))) { ret = -EIO; break; } child->used_math = 1; -#ifdef CONFIG_MATH_EMULATION - if ( boot_cpu_data.hard_math ) { -#endif - i387_user_to_hard(&child->thread.i387.hard,(struct _fpstate *)data); -#ifdef CONFIG_MATH_EMULATION - } else { - restore_i387_soft(&child->thread.i387.soft, (struct _fpstate *)data); - } -#endif + set_fpregs(child, (struct user_i387_struct *)data); ret = 0; break; } + case PTRACE_GETFPXREGS: { /* Get the child extended FPU state. */ + if (!access_ok(VERIFY_WRITE, (unsigned *)data, + sizeof(struct user_fxsr_struct))) { + ret = -EIO; + break; + } + if ( !child->used_math ) { + /* Simulate an empty FPU. */ + set_fpu_cwd(child, 0x037f); + set_fpu_swd(child, 0x0000); + set_fpu_twd(child, 0xffff); + set_fpu_mxcsr(child, 0x1f80); + } + ret = get_fpxregs((struct user_fxsr_struct *)data, child); + break; + } + + case PTRACE_SETFPXREGS: { /* Set the child extended FPU state. */ + if (!access_ok(VERIFY_READ, (unsigned *)data, + sizeof(struct user_fxsr_struct))) { + ret = -EIO; + break; + } + child->used_math = 1; + ret = set_fpxregs(child, (struct user_fxsr_struct *)data); + break; + } + default: ret = -EIO; break; @@ -447,8 +463,8 @@ asmlinkage void syscall_trace(void) { - if ((current->flags & (PF_PTRACED|PF_TRACESYS)) - != (PF_PTRACED|PF_TRACESYS)) + if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) != + (PT_PTRACED|PT_TRACESYS)) return; current->exit_code = SIGTRAP; current->state = TASK_STOPPED; diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.4.0-test1/linux/arch/i386/kernel/setup.c Mon Jun 19 16:31:57 2000 +++ linux/arch/i386/kernel/setup.c Wed Jun 21 20:59:38 2000 @@ -39,8 +39,10 @@ * Detection for Celeron coppermine, identify_cpu() overhauled, * and a few other clean ups. * Dave Jones , April 2000 - * Pentium-III code by Ingo Molnar and modifications by Goutham Rao * + * Pentium III FXSR, SSE support + * General FPU state handling cleanups + * Gareth Hughes , May 2000 */ /* @@ -373,24 +375,6 @@ } } -unsigned long __init memparse(char *ptr, char **retptr) -{ - unsigned long ret; - - ret = simple_strtoul(ptr, retptr, 0); - - if (**retptr == 'K' || **retptr == 'k') { - ret <<= 10; - (*retptr)++; - } - else if (**retptr == 'M' || **retptr == 'm') { - ret <<= 20; - (*retptr)++; - } - return ret; -} /* memparse */ - - void __init add_memory_region(unsigned long start, unsigned long size, int type) { @@ -528,6 +512,7 @@ else { start_at = HIGH_MEMORY; mem_size -= HIGH_MEMORY; + usermem=0; } add_memory_region(start_at, mem_size, E820_RAM); } @@ -801,20 +786,6 @@ conswitchp = &dummy_con; #endif #endif -#ifdef CONFIG_X86_FX - if (boot_cpu_data.x86_capability & X86_FEATURE_FXSR) - { - printk("Enabling extended fast FPU save and restore ... "); - set_in_cr4(X86_CR4_OSFXSR); - printk("done.\n"); - } - if (boot_cpu_data.x86_capability & X86_FEATURE_XMM) - { - printk("Enabling KNI unmasked exception support ... "); - set_in_cr4(X86_CR4_OSXMMEXCPT); - printk("done.\n"); - } -#endif } static int __init get_model_name(struct cpuinfo_x86 *c) @@ -921,8 +892,8 @@ cpuid(0x80000000, &n, &dummy, &dummy, &dummy); if (n >= 0x80000005) { cpuid(0x80000005, &dummy, &dummy, &ecx, &edx); - printk("CPU: L1 I Cache: %dK L1 D Cache: %dK\n", - ecx>>24, edx>>24); + printk("CPU: L1 I Cache: %dK L1 D Cache: %dK (%d bytes/line)\n", + edx>>24, ecx>>24, edx&0xFF); c->x86_cache_size=(ecx>>24)+(edx>>24); } if (n >= 0x80000006) { @@ -1155,6 +1126,8 @@ name="C6"; fcr_set=ECX8|DSMC|EDCTLB|EMMX|ERETSTK; fcr_clr=DPDC; + printk("Disabling bugged TSC.\n"); + c->x86_capability &= ~X86_FEATURE_TSC; break; case 8: switch(c->x86_mask) { @@ -1337,8 +1310,8 @@ { X86_VENDOR_INTEL, 6, { "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)", NULL, "Pentium II (Deschutes)", "Mobile Pentium II", - "Pentium III (Katmai)", "Pentium III (Coppermine)", NULL, NULL, - NULL, NULL, NULL, NULL }}, + "Pentium III (Katmai)", "Pentium III (Coppermine)", NULL, + "Pentium III (Cascades)", NULL, NULL, NULL, NULL }}, { X86_VENDOR_AMD, 4, { NULL, NULL, NULL, "486 DX/2", NULL, NULL, NULL, "486 DX/2-WB", "486 DX/4", "486 DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT", @@ -1350,7 +1323,7 @@ "K6-3", NULL, NULL, NULL, NULL, NULL, NULL }}, { X86_VENDOR_AMD, 6, { "Athlon", "Athlon", - NULL, NULL, NULL, NULL, + "Athlon", NULL, "Athlon", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, { X86_VENDOR_UMC, 4, @@ -1367,17 +1340,30 @@ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, }; -void __init identify_cpu(struct cpuinfo_x86 *c) +/* + * Detect a NexGen CPU running without BIOS hypercode new enough + * to have CPUID. (Thanks to Herbert Oppmann) + */ + +static int deep_magic_nexgen_probe(void) { - int i=0; - char *p = NULL; - - c->loops_per_sec = loops_per_sec; - c->x86_cache_size = -1; - - get_cpu_vendor(c); + int ret; + + __asm__ __volatile__ ( + " movw $0x5555, %%ax\n" + " xorw %%dx,%%dx\n" + " movw $2, %%cx\n" + " divw %%cx\n" + " movl $0, %%eax\n" + " jnz 1f\n" + " movl $1, %%eax\n" + "1:\n" + : "=a" (ret) : : "cx", "dx" ); + return ret; +} - /* It should be possible for the user to override this. */ +static void squash_the_stupid_serial_number(struct cpuinfo_x86 *c) +{ if(c->x86_capability&(1<<18)) { /* Disable processor serial number */ unsigned long lo,hi; @@ -1386,12 +1372,32 @@ wrmsr(0x119,lo,hi); printk(KERN_INFO "CPU serial number disabled.\n"); } +} + +void __init identify_cpu(struct cpuinfo_x86 *c) +{ + int i=0; + char *p = NULL; + + c->loops_per_sec = loops_per_sec; + c->x86_cache_size = -1; + + get_cpu_vendor(c); + switch (c->x86_vendor) { case X86_VENDOR_UNKNOWN: if (c->cpuid_level < 0) + { + /* It may be a nexgen with cpuid disabled.. */ + if(deep_magic_nexgen_probe()) + { + strcpy(c->x86_model_id, "Nx586"); + c->x86_vendor = X86_VENDOR_NEXGEN; + } return; + } break; case X86_VENDOR_CYRIX: @@ -1408,6 +1414,9 @@ return; case X86_VENDOR_INTEL: + + squash_the_stupid_serial_number(c); + if (c->cpuid_level > 1) { /* supports eax=2 call */ int edx, dummy; @@ -1422,24 +1431,26 @@ c->x86_cache_size = 0; break; - case 0x41: + case 0x41: /* 4-way 128 */ c->x86_cache_size = 128; break; - case 0x42: - case 0x82: /*Detect 256-Kbyte cache on Coppermine*/ + case 0x42: /* 4-way 256 */ + case 0x82: /* 8-way 256 */ c->x86_cache_size = 256; break; - case 0x43: + case 0x43: /* 4-way 512 */ c->x86_cache_size = 512; break; - case 0x44: + case 0x44: /* 4-way 1024 */ + case 0x84: /* 8-way 1024 */ c->x86_cache_size = 1024; break; - case 0x45: + case 0x45: /* 4-way 2048 */ + case 0x85: /* 8-way 2048 */ c->x86_cache_size = 2048; break; @@ -1479,9 +1490,14 @@ case X86_VENDOR_TRANSMETA: transmeta_model(c); + squash_the_stupid_serial_number(c); return; } + /* may be changed in the switch so needs to be after */ + + if(c->x86_vendor == X86_VENDOR_NEXGEN) + c->x86_cache_size = 256; /* A few had 1Mb.. */ for (i = 0; i < sizeof(cpu_models)/sizeof(struct cpu_model_info); i++) { if (cpu_models[i].vendor == c->x86_vendor && @@ -1614,7 +1630,9 @@ x86_cap_flags[10] = "sep"; if (c->x86 < 6) x86_cap_flags[16] = "fcmov"; + x86_cap_flags[16] = "pat"; x86_cap_flags[22] = "mmxext"; + x86_cap_flags[24] = "fxsr"; x86_cap_flags[30] = "3dnowext"; x86_cap_flags[31] = "3dnow"; break; @@ -1674,6 +1692,18 @@ return p - buffer; } +#ifndef CONFIG_X86_TSC +static int tsc_disable __initdata = 0; + +static int __init tsc_setup(char *str) +{ + tsc_disable = 1; + return 1; +} + +__setup("notsc", tsc_setup); +#endif + static unsigned long cpu_initialized __initdata = 0; /* @@ -1695,6 +1725,13 @@ if (cpu_has_vme || cpu_has_tsc || cpu_has_de) clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE); +#ifndef CONFIG_X86_TSC + if (tsc_disable && cpu_has_tsc) { + printk("Disabling TSC...\n"); + boot_cpu_data.x86_capability &= ~X86_FEATURE_TSC; + set_in_cr4(X86_CR4_TSD); + } +#endif __asm__ __volatile__("lgdt %0": "=m" (gdt_descr)); __asm__ __volatile__("lidt %0": "=m" (idt_descr)); diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c --- v2.4.0-test1/linux/arch/i386/kernel/signal.c Mon Jun 19 16:31:57 2000 +++ linux/arch/i386/kernel/signal.c Thu Jun 22 06:59:53 2000 @@ -4,12 +4,9 @@ * Copyright (C) 1991, 1992 Linus Torvalds * * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson - * Pentium III support by Ingo Molnar, modifications and OS Exception support - * by Goutham Rao + * 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes */ -#include - #include #include #include @@ -23,6 +20,7 @@ #include #include #include +#include #define DEBUG_SIG 0 @@ -187,29 +185,6 @@ char retcode[8]; }; - -static inline int restore_i387_hard(struct _fpstate *buf) -{ - struct task_struct *tsk = current; - clear_fpu(tsk); - return i387_user_to_hard(&tsk->thread.i387.hard, buf); -} - -static inline int restore_i387(struct _fpstate *buf) -{ - int err; -#ifndef CONFIG_MATH_EMULATION - err = restore_i387_hard(buf); -#else - if (boot_cpu_data.hard_math) - err = restore_i387_hard(buf); - else - err = restore_i387_soft(¤t->thread.i387.soft, buf); -#endif - current->used_math = 1; - return err; -} - static int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *peax) { @@ -340,35 +315,6 @@ * Set up a signal frame. */ -static inline int save_i387_hard(struct _fpstate * buf) -{ - struct task_struct *tsk = current; - - unlazy_fpu(tsk); - tsk->thread.i387.hard.status = tsk->thread.i387.hard.swd; - if (i387_hard_to_user(buf, &tsk->thread.i387.hard)) - return -1; - return 1; -} - -static int save_i387(struct _fpstate *buf) -{ - if (!current->used_math) - return 0; - - /* This will cause a "finit" to be triggered by the next - attempted FPU operation by the 'current' process. - */ - current->used_math = 0; - -#ifndef CONFIG_MATH_EMULATION - return save_i387_hard(buf); -#else - return boot_cpu_data.hard_math ? save_i387_hard(buf) - : save_i387_soft(¤t->thread.i387.soft, buf); -#endif -} - static int setup_sigcontext(struct sigcontext *sc, struct _fpstate *fpstate, struct pt_regs *regs, unsigned long mask) @@ -662,7 +608,7 @@ if (!signr) break; - if ((current->flags & PF_PTRACED) && signr != SIGKILL) { + if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { /* Let the debugger run. */ current->exit_code = signr; current->state = TASK_STOPPED; diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/smpboot.c linux/arch/i386/kernel/smpboot.c --- v2.4.0-test1/linux/arch/i386/kernel/smpboot.c Mon Jun 19 16:31:57 2000 +++ linux/arch/i386/kernel/smpboot.c Mon Jun 19 18:39:17 2000 @@ -344,12 +344,22 @@ extern void calibrate_delay(void); +static atomic_t init_deasserted; + void __init smp_callin(void) { int cpuid, phys_id; unsigned long timeout; /* + * If waken up by an INIT in an 82489DX configuration + * we may get here before an INIT-deassert IPI reaches + * our local APIC. We have to wait for the IPI or we'll + * lock up on an APIC access. + */ + while (!atomic_read(&init_deasserted)); + + /* * (This works even if the APIC is not enabled.) */ phys_id = GET_APIC_ID(apic_read(APIC_ID)); @@ -573,6 +583,8 @@ * the targeted processor. */ + atomic_set(&init_deasserted, 0); + Dprintk("Setting warm reset code and vector.\n"); CMOS_WRITE(0xa, 0xf); @@ -642,6 +654,8 @@ send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; } while (send_status && (timeout++ < 1000)); + atomic_set(&init_deasserted, 1); + /* * Should we send STARTUP IPIs ? * @@ -869,14 +883,6 @@ phys_cpu_present_map |= (1 << hard_smp_processor_id()); } - /* - * If SMP should be disabled, then really disable it! - */ - if (!max_cpus) { - smp_found_config = 0; - printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n"); - } - { int reg; @@ -912,6 +918,20 @@ Dprintk("Getting LVT1: %x\n", reg); } + /* + * If SMP should be disabled, then really disable it! + */ + if (!max_cpus) { + smp_found_config = 0; + printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n"); +#ifndef CONFIG_VISWS + io_apic_irqs = 0; +#endif + cpu_online_map = phys_cpu_present_map = 1; + smp_num_cpus = 1; + goto smp_done; + } + connect_bsp_APIC(); setup_local_APIC(); @@ -998,7 +1018,6 @@ setup_IO_APIC(); #endif -smp_done: /* * Set up all local APIC timers in the system: */ @@ -1010,6 +1029,7 @@ if (cpu_has_tsc && cpucount) synchronize_tsc_bp(); +smp_done: zap_low_mappings(); } diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c --- v2.4.0-test1/linux/arch/i386/kernel/time.c Sun Mar 19 18:35:30 2000 +++ linux/arch/i386/kernel/time.c Mon Jun 19 18:39:17 2000 @@ -114,10 +114,12 @@ #define TICK_SIZE tick -#ifndef CONFIG_X86_TSC - spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED; +extern spinlock_t i8259A_lock; + +#ifndef CONFIG_X86_TSC + /* This function must be called with interrupts disabled * It was inspired by Steve McCanne's microtime-i386 for BSD. -- jrs * @@ -176,6 +178,7 @@ jiffies_t = jiffies; count |= inb_p(0x40) << 8; + spin_unlock(&i8253_lock); /* * avoiding timer inconsistencies (they are rare, but they happen)... @@ -194,10 +197,18 @@ if( count > count_p ) { /* the nutcase */ - outb_p(0x0A, 0x20); + int i; - /* assumption about timer being IRQ1 */ - if( inb(0x20) & 0x01 ) { + spin_lock(&i8259A_lock); + /* + * This is tricky when I/O APICs are used; + * see do_timer_interrupt(). + */ + i = inb(0x20); + spin_unlock(&i8259A_lock); + + /* assumption about timer being IRQ0 */ + if (i & 0x01) { /* * We cannot detect lost timer interrupts ... * well, that's why we call them lost, don't we? :) @@ -222,7 +233,6 @@ } } else jiffies_p = jiffies_t; - spin_unlock(&i8253_lock); count_p = count; @@ -365,12 +375,30 @@ /* last time the cmos clock got updated */ static long last_rtc_update = 0; +int timer_ack = 0; + /* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick */ static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { +#ifdef CONFIG_X86_IO_APIC + if (timer_ack) { + /* + * Subtle, when I/O APICs are used we have to ack timer IRQ + * manually to reset the IRR bit for do_slow_gettimeoffset(). + * This will also deassert NMI lines for the watchdog if run + * on an 82489DX-based system. + */ + spin_lock(&i8259A_lock); + outb(0x0c, 0x20); + /* Ack the IRQ; AEOI will end it automatically. */ + inb(0x20); + spin_unlock(&i8259A_lock); + } +#endif + #ifdef CONFIG_VISWS /* Clear the interrupt */ co_cpu_write(CO_CPU_STAT,co_cpu_read(CO_CPU_STAT) & ~CO_STAT_TIMEINTR); @@ -459,19 +487,12 @@ rdtscl(last_tsc_low); -#if 0 /* - * SUBTLE: this is not necessary from here because it's implicit in the - * write xtime_lock. - */ spin_lock(&i8253_lock); -#endif outb_p(0x00, 0x43); /* latch the count ASAP */ count = inb_p(0x40); /* read the latched count */ count |= inb(0x40) << 8; -#if 0 spin_unlock(&i8253_lock); -#endif count = ((LATCH-1) - count) * TICK_SIZE; delay_at_last_interrupt = (count + LATCH/2) / LATCH; @@ -667,7 +688,7 @@ dodgy_tsc(); - if (boot_cpu_data.x86_capability & X86_FEATURE_TSC) { + if (cpu_has_tsc) { unsigned long tsc_quotient = calibrate_tsc(); if (tsc_quotient) { fast_gettimeoffset_quotient = tsc_quotient; diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c --- v2.4.0-test1/linux/arch/i386/kernel/traps.c Mon Jun 19 16:31:57 2000 +++ linux/arch/i386/kernel/traps.c Wed Jun 21 20:59:38 2000 @@ -2,7 +2,9 @@ * linux/arch/i386/traps.c * * Copyright (C) 1991, 1992 Linus Torvalds - * FXSAVE/FXRSTOR support by Ingo Molnar, OS exception support by Goutham Rao + * + * Pentium III FXSR, SSE support + * Gareth Hughes , May 2000 */ /* @@ -35,6 +37,7 @@ #include #include #include +#include #include #include @@ -136,8 +139,6 @@ unlock_kernel(); \ } -void page_exception(void); - asmlinkage void divide_error(void); asmlinkage void debug(void); asmlinkage void nmi(void); @@ -154,10 +155,10 @@ asmlinkage void general_protection(void); asmlinkage void page_fault(void); asmlinkage void coprocessor_error(void); +asmlinkage void simd_coprocessor_error(void); asmlinkage void reserved(void); asmlinkage void alignment_check(void); asmlinkage void spurious_interrupt_bug(void); -asmlinkage void xmm_fault(void); int kstack_depth_to_print = 24; @@ -320,7 +321,6 @@ DO_ERROR(12, SIGBUS, "stack segment", stack_segment, current) DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, current, BUS_ADRALN, get_cr2()) DO_ERROR(18, SIGSEGV, "reserved", reserved, current) -DO_VM86_ERROR(19, SIGFPE, "XMM fault", xmm_fault, current) asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) { @@ -537,12 +537,12 @@ * The TF error should be masked out only if the current * process is not traced and if the TRAP flag has been set * previously by a tracing process (condition detected by - * the PF_DTRACE flag); remember that the i386 TRAP flag + * the PT_DTRACE flag); remember that the i386 TRAP flag * can be modified by the process itself in user mode, * allowing programs to debug themselves without the ptrace() * interface. */ - if ((tsk->flags & (PF_DTRACE|PF_PTRACED)) == PF_DTRACE) + if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE) goto clear_TF; } @@ -586,13 +586,13 @@ { struct task_struct * task; siginfo_t info; + unsigned short cwd, swd; /* - * Save the info for the exception handler - * (this will also clear the error) + * Save the info for the exception handler and clear the error. */ task = current; - save_fpu(task); + save_init_fpu(task); task->thread.trap_no = 16; task->thread.error_code = 0; info.si_signo = SIGFPE; @@ -609,9 +609,9 @@ * and it will suffer the consequences since we won't be able to * fully reproduce the context of the exception */ - switch(((~task->thread.i387.hard.cwd) & - task->thread.i387.hard.swd & 0x3f) | - (task->thread.i387.hard.swd & 0x240)) { + cwd = get_fpu_cwd(task); + swd = get_fpu_swd(task); + switch (((~cwd) & swd & 0x3f) | (swd & 0x240)) { case 0x000: default: break; @@ -643,6 +643,79 @@ math_error((void *)regs->eip); } +void simd_math_error(void *eip) +{ + struct task_struct * task; + siginfo_t info; + unsigned short mxcsr; + + /* + * Save the info for the exception handler and clear the error. + */ + task = current; + save_init_fpu(task); + load_mxcsr(0x1f80); + task->thread.trap_no = 19; + task->thread.error_code = 0; + info.si_signo = SIGFPE; + info.si_errno = 0; + info.si_code = __SI_FAULT; + info.si_addr = eip; + /* + * The SIMD FPU exceptions are handled a little differently, as there + * is only a single status/control register. Thus, to determine which + * unmasked exception was caught we must mask the exception mask bits + * at 0x1f80, and then use these to mask the exception bits at 0x3f. + */ + mxcsr = get_fpu_mxcsr(task); + switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) { + case 0x000: + default: + break; + case 0x001: /* Invalid Op */ + info.si_code = FPE_FLTINV; + break; + case 0x002: /* Denormalize */ + case 0x010: /* Underflow */ + info.si_code = FPE_FLTUND; + break; + case 0x004: /* Zero Divide */ + info.si_code = FPE_FLTDIV; + break; + case 0x008: /* Overflow */ + info.si_code = FPE_FLTOVF; + break; + case 0x020: /* Precision */ + info.si_code = FPE_FLTRES; + break; + } + force_sig_info(SIGFPE, &info, task); +} + +asmlinkage void do_simd_coprocessor_error(struct pt_regs * regs, + long error_code) +{ + if (cpu_has_xmm) { + /* Handle SIMD FPU exceptions on PIII+ processors. */ + ignore_irq13 = 1; + simd_math_error((void *)regs->eip); + } else { + /* + * Handle strange cache flush from user space exception + * in all other cases. This is undocumented behaviour. + */ + if (regs->eflags & VM_MASK) { + handle_vm86_fault((struct kernel_vm86_regs *)regs, + error_code); + return; + } + die_if_kernel("cache flush denied", regs, error_code); + current->thread.trap_no = 19; + current->thread.error_code = error_code; + force_sig(SIGSEGV, current); + } +} + asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs, long error_code) { @@ -663,17 +736,16 @@ { __asm__ __volatile__("clts"); /* Allow maths ops (or we recurse) */ - if(current->used_math) - i387_restore_hard(current->thread.i387); - else - { + if (current->used_math) { + restore_fpu(current); + } else { /* * Our first FPU usage, clean the chip. */ __asm__("fninit"); current->used_math = 1; } - current->flags|=PF_USEDFPU; /* So we fnsave on switch_to() */ + current->flags |= PF_USEDFPU; /* So we fnsave on switch_to() */ } #ifndef CONFIG_MATH_EMULATION @@ -907,7 +979,7 @@ set_trap_gate(15,&spurious_interrupt_bug); set_trap_gate(16,&coprocessor_error); set_trap_gate(17,&alignment_check); - set_trap_gate(19,&xmm_fault); + set_trap_gate(19,&simd_coprocessor_error); set_system_gate(SYSCALL_VECTOR,&system_call); diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/vm86.c linux/arch/i386/kernel/vm86.c --- v2.4.0-test1/linux/arch/i386/kernel/vm86.c Mon Dec 20 18:48:21 1999 +++ linux/arch/i386/kernel/vm86.c Mon Jun 19 18:10:44 2000 @@ -443,7 +443,7 @@ } if (trapno !=1) return 1; /* we let this handle by the calling routine */ - if (current->flags & PF_PTRACED) { + if (current->ptrace & PT_PTRACED) { unsigned long flags; spin_lock_irqsave(¤t->sigmask_lock, flags); sigdelset(¤t->blocked, SIGTRAP); diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/math-emu/fpu_entry.c linux/arch/i386/math-emu/fpu_entry.c --- v2.4.0-test1/linux/arch/i386/math-emu/fpu_entry.c Fri Jul 23 13:19:02 1999 +++ linux/arch/i386/math-emu/fpu_entry.c Mon Jun 19 18:10:44 2000 @@ -210,7 +210,7 @@ } FPU_lookahead = 1; - if (current->flags & PF_PTRACED) + if (current->ptrace & PT_PTRACED) FPU_lookahead = 0; if ( !valid_prefix(&byte1, (u_char **)&FPU_EIP, diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/math-emu/get_address.c linux/arch/i386/math-emu/get_address.c --- v2.4.0-test1/linux/arch/i386/math-emu/get_address.c Sun Sep 13 12:18:03 1998 +++ linux/arch/i386/math-emu/get_address.c Mon Jun 19 12:56:08 2000 @@ -155,6 +155,7 @@ { struct desc_struct descriptor; unsigned long base_address, limit, address, seg_top; + unsigned short selector; segment--; @@ -174,12 +175,15 @@ case PREFIX_FS_-1: /* The cast is needed here to get gcc 2.8.0 to use a 16 bit register in the assembler statement. */ - __asm__("mov %%fs,%0":"=r" ((unsigned short)addr->selector)); + + __asm__("mov %%fs,%0":"=r" (selector)); + addr->selector = selector; break; case PREFIX_GS_-1: /* The cast is needed here to get gcc 2.8.0 to use a 16 bit register in the assembler statement. */ - __asm__("mov %%gs,%0":"=r" ((unsigned short)addr->selector)); + __asm__("mov %%gs,%0":"=r" (selector)); + addr->selector = selector; break; default: addr->selector = PM_REG_(segment); diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/Makefile linux/arch/ia64/Makefile --- v2.4.0-test1/linux/arch/ia64/Makefile Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/Makefile Thu Jun 22 07:09:44 2000 @@ -12,15 +12,11 @@ AWK := awk LINKFLAGS = -static -T arch/$(ARCH)/vmlinux.lds -# next line is for HP compiler backend: -#AFLAGS += -DGCC_RETVAL_POINTER_IN_R8 -# The next line is needed when compiling with the July snapshot of the Cygnus compiler: -#EXTRA = -D__GCC_DOESNT_KNOW_IN_REGS__ -# next two lines are for the September snapshot of the Cygnus compiler: -AFLAGS += -D__GCC_MULTIREG_RETVALS__ -Wa,-x -EXTRA = -D__GCC_MULTIREG_RETVALS__ +AFLAGS += -Wa,-x +EXTRA = -CFLAGS := $(CFLAGS) -pipe $(EXTRA) -Wa,-x -ffixed-r13 -mfixed-range=f10-f15,f32-f127 +CFLAGS := $(CFLAGS) -pipe $(EXTRA) -Wa,-x -ffixed-r13 -mfixed-range=f10-f15,f32-f127 \ + -mconstant-gp -funwind-tables ifdef CONFIG_IA64_GENERIC CORE_FILES := arch/$(ARCH)/hp/hp.a \ diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/boot/Makefile linux/arch/ia64/boot/Makefile --- v2.4.0-test1/linux/arch/ia64/boot/Makefile Tue Apr 11 15:09:12 2000 +++ linux/arch/ia64/boot/Makefile Thu Jun 22 07:09:44 2000 @@ -25,7 +25,8 @@ all: $(TARGETS) bootloader: $(OBJECTS) - $(LD) $(LINKFLAGS) $(OBJECTS) $(LIBS) -o bootloader + $(LD) $(LINKFLAGS) $(OBJECTS) $(TOPDIR)/lib/lib.a $(TOPDIR)/arch/$(ARCH)/lib/lib.a \ + -o bootloader clean: rm -f $(TARGETS) diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/config.in linux/arch/ia64/config.in --- v2.4.0-test1/linux/arch/ia64/config.in Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/config.in Thu Jun 22 07:09:44 2000 @@ -1,10 +1,12 @@ +# For a description of the syntax of this configuration file, +# see Documentation/kbuild/config-language.txt. +# mainmenu_name "Kernel configuration of Linux for IA-64 machines" mainmenu_option next_comment comment 'General setup' define_bool CONFIG_IA64 y -define_bool CONFIG_ITANIUM y # easy choice for now... ;-) define_bool CONFIG_ISA n define_bool CONFIG_SBUS n @@ -22,10 +24,13 @@ 64KB CONFIG_IA64_PAGE_SIZE_64KB" 16KB if [ "$CONFIG_IA64_DIG" = "y" ]; then + define_bool CONFIG_ITANIUM y + define_bool CONFIG_IA64_BRL_EMU y bool ' Enable Itanium A-step specific code' CONFIG_ITANIUM_ASTEP_SPECIFIC + bool ' Enable Itanium A1-step specific code' CONFIG_ITANIUM_A1_SPECIFIC + bool ' Enable use of global TLB purge instruction (ptc.g)' CONFIG_ITANIUM_PTCG bool ' Enable SoftSDV hacks' CONFIG_IA64_SOFTSDV_HACKS - bool ' Enable BigSur hacks' CONFIG_IA64_BIGSUR_HACKS - bool ' Enable Lion hacks' CONFIG_IA64_LION_HACKS + bool ' Enable AzusA hacks' CONFIG_IA64_AZUSA_HACKS bool ' Emulate PAL/SAL/EFI firmware' CONFIG_IA64_FW_EMU bool ' Enable IA64 Machine Check Abort' CONFIG_IA64_MCA fi @@ -43,6 +48,7 @@ bool 'SMP support' CONFIG_SMP bool 'Performance monitor support' CONFIG_PERFMON +bool '/proc/palinfo support' CONFIG_IA64_PALINFO bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC @@ -187,5 +193,6 @@ bool 'Turn on compare-and-exchange bug checking (slow!)' CONFIG_IA64_DEBUG_CMPXCHG bool 'Turn on irq debug checks (slow!)' CONFIG_IA64_DEBUG_IRQ bool 'Print possible IA64 hazards to console' CONFIG_IA64_PRINT_HAZARDS +bool 'Enable new unwind support' CONFIG_IA64_NEW_UNWIND endmenu diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/defconfig linux/arch/ia64/defconfig --- v2.4.0-test1/linux/arch/ia64/defconfig Thu May 11 15:30:06 2000 +++ linux/arch/ia64/defconfig Thu Jun 22 07:09:44 2000 @@ -115,8 +115,8 @@ CONFIG_IDEDMA_PCI_EXPERIMENTAL=y # CONFIG_IDEDMA_PCI_WIP is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set -# CONFIG_BLK_DEV_AEC62XX is not set -# CONFIG_AEC62XX_TUNING is not set +# CONFIG_BLK_DEV_AEC6210 is not set +# CONFIG_AEC6210_TUNING is not set # CONFIG_BLK_DEV_ALI15X3 is not set # CONFIG_WDC_ALI15X3 is not set # CONFIG_BLK_DEV_AMD7409 is not set diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/dig/iosapic.c linux/arch/ia64/dig/iosapic.c --- v2.4.0-test1/linux/arch/ia64/dig/iosapic.c Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/dig/iosapic.c Thu Jun 22 07:09:44 2000 @@ -67,6 +67,12 @@ (delivery << IO_SAPIC_DELIVERY_SHIFT) | vector); +#ifdef CONFIG_IA64_AZUSA_HACKS + /* set Flush Disable bit */ + if (iosapic_addr != 0xc0000000fec00000) + low32 |= (1 << 17); +#endif + /* dest contains both id and eid */ high32 = (dest << IO_SAPIC_DEST_SHIFT); @@ -216,30 +222,33 @@ } void -iosapic_init (unsigned long address) +iosapic_init (unsigned long address, int irqbase) { struct hw_interrupt_type *irq_type; struct pci_vector_struct *vectors; int i, irq; - /* - * Map the legacy ISA devices into the IOSAPIC data. Some of - * these may get reprogrammed later on with data from the ACPI - * Interrupt Source Override table. - */ - for (i = 0; i < 16; i++) { - irq = isa_irq_to_vector(i); - iosapic_pin(irq) = i; - iosapic_bus(irq) = BUS_ISA; - iosapic_busdata(irq) = 0; - iosapic_dmode(irq) = IO_SAPIC_LOWEST_PRIORITY; - iosapic_trigger(irq) = IO_SAPIC_EDGE; - iosapic_polarity(irq) = IO_SAPIC_POL_HIGH; + if (irqbase == 0) + /* + * Map the legacy ISA devices into the IOSAPIC data. + * Some of these may get reprogrammed later on with + * data from the ACPI Interrupt Source Override table. + */ + for (i = 0; i < 16; i++) { + irq = isa_irq_to_vector(i); + iosapic_pin(irq) = i; + iosapic_bus(irq) = BUS_ISA; + iosapic_busdata(irq) = 0; + iosapic_dmode(irq) = IO_SAPIC_LOWEST_PRIORITY; + iosapic_trigger(irq) = IO_SAPIC_EDGE; + iosapic_polarity(irq) = IO_SAPIC_POL_HIGH; #ifdef DEBUG_IRQ_ROUTING - printk("ISA: IRQ %02x -> Vector %02x IOSAPIC Pin %d\n", i, irq, iosapic_pin(irq)); + printk("ISA: IRQ %02x -> Vector %02x IOSAPIC Pin %d\n", + i, irq, iosapic_pin(irq)); #endif - } + } +#ifndef CONFIG_IA64_SOFTSDV_HACKS /* * Map the PCI Interrupt data into the ACPI IOSAPIC data using * the info that the bootstrap loader passed to us. @@ -250,6 +259,8 @@ irq = vectors[i].irq; if (irq < 16) irq = isa_irq_to_vector(irq); + if (iosapic_baseirq(irq) != irqbase) + continue; iosapic_bustype(irq) = BUS_PCI; iosapic_pin(irq) = irq - iosapic_baseirq(irq); @@ -270,8 +281,12 @@ irq, iosapic_pin(irq)); #endif } +#endif /* CONFIG_IA64_SOFTSDV_HACKS */ for (i = 0; i < NR_IRQS; ++i) { + if (iosapic_baseirq(i) != irqbase) + continue; + if (iosapic_pin(i) != -1) { if (iosapic_trigger(i) == IO_SAPIC_LEVEL) irq_type = &irq_type_iosapic_level; diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/dig/setup.c linux/arch/ia64/dig/setup.c --- v2.4.0-test1/linux/arch/ia64/dig/setup.c Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/dig/setup.c Thu Jun 22 07:09:44 2000 @@ -53,6 +53,10 @@ */ ROOT_DEV = to_kdev_t(0x0802); /* default to second partition on first drive */ +#ifdef CONFIG_IA64_SOFTSDV_HACKS + ROOT_DEV = to_kdev_t(0x0302); /* 2nd partion on 1st IDE */ +#endif /* CONFIG_IA64_SOFTSDV_HACKS */ + #ifdef CONFIG_SMP init_smp_config(); #endif diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/hp/hpsim_irq.c linux/arch/ia64/hp/hpsim_irq.c --- v2.4.0-test1/linux/arch/ia64/hp/hpsim_irq.c Fri Mar 10 16:40:39 2000 +++ linux/arch/ia64/hp/hpsim_irq.c Thu Jun 22 07:09:44 2000 @@ -6,6 +6,8 @@ */ #include +#include +#include #include static unsigned int diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/ia32/binfmt_elf32.c linux/arch/ia64/ia32/binfmt_elf32.c --- v2.4.0-test1/linux/arch/ia64/ia32/binfmt_elf32.c Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/ia32/binfmt_elf32.c Thu Jun 22 07:09:44 2000 @@ -2,6 +2,8 @@ * IA-32 ELF support. * * Copyright (C) 1999 Arun Sharma + * + * 06/16/00 A. Mallick initialize csd/ssd/tssd/cflg for ia32_load_state */ #include #include @@ -84,6 +86,15 @@ current->thread.map_base = 0x40000000; + + /* setup ia32 state for ia32_load_state */ + + current->thread.eflag = IA32_EFLAG; + current->thread.csd = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0xBL, 1L, 3L, 1L, 1L, 1L); + current->thread.ssd = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, 3L, 1L, 1L, 1L); + current->thread.tssd = IA64_SEG_DESCRIPTOR(IA32_PAGE_OFFSET + PAGE_SIZE, 0x1FFFL, 0xBL, + 1L, 3L, 1L, 1L, 1L); + /* CS descriptor */ __asm__("mov ar.csd = %0" : /* no outputs */ : "r" IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0xBL, 1L, @@ -96,9 +107,6 @@ __asm__("mov ar.eflag = %0" : /* no outputs */ : "r" (IA32_EFLAG)); /* Control registers */ - __asm__("mov ar.cflg = %0" - : /* no outputs */ - : "r" (((ulong) IA32_CR4 << 32) | IA32_CR0)); __asm__("mov ar.fsr = %0" : /* no outputs */ : "r" ((ulong)IA32_FSR_DEFAULT)); diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/ia32/ia32_entry.S linux/arch/ia64/ia32/ia32_entry.S --- v2.4.0-test1/linux/arch/ia64/ia32/ia32_entry.S Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/ia32/ia32_entry.S Thu Jun 22 07:09:44 2000 @@ -1,14 +1,15 @@ +#include #include #include +#include "../kernel/entry.h" + // // Get possibly unaligned sigmask argument into an aligned // kernel buffer .text - .proc ia32_rt_sigsuspend - .global ia32_rt_sigsuspend -ia32_rt_sigsuspend: +GLOBAL_ENTRY(ia32_rt_sigsuspend) // We'll cheat and not do an alloc here since we are ultimately // going to do a simple branch to the IA64 sys_rt_sigsuspend. // r32 is still the first argument which is the signal mask. @@ -32,24 +33,22 @@ st4 [r32]=r2 st4 [r10]=r3 br.cond.sptk.many sys_rt_sigsuspend +END(ia32_rt_sigsuspend) .section __ex_table,"a" data4 @gprel(1b) data4 (2b-1b)|1 .previous +GLOBAL_ENTRY(ia32_ret_from_syscall) + PT_REGS_UNWIND_INFO(0) - .endp ia32_rt_sigsuspend - - .global ia32_ret_from_syscall - .proc ia32_ret_from_syscall -ia32_ret_from_syscall: cmp.ge p6,p7=r8,r0 // syscall executed successfully? adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8 ;; st8 [r2]=r8 // store return value in slot for r8 br.cond.sptk.few ia64_leave_kernel - .endp ia32_ret_from_syscall +END(ia32_ret_from_syscall) // // Invoke a system call, but do some tracing before and after the call. @@ -61,9 +60,8 @@ // r15 = syscall number // b6 = syscall entry point // - .global ia32_trace_syscall - .proc ia32_trace_syscall -ia32_trace_syscall: +GLOBAL_ENTRY(ia32_trace_syscall) + PT_REGS_UNWIND_INFO(0) br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch syscall args .Lret4: br.call.sptk.few rp=b6 // do the syscall .Lret5: cmp.lt p6,p0=r8,r0 // syscall failed? @@ -72,42 +70,38 @@ st8.spill [r2]=r8 // store return value in slot for r8 br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch return value .Lret6: br.cond.sptk.many ia64_leave_kernel // rp MUST be != ia64_leave_kernel! +END(ia32_trace_syscall) - .endp ia32_trace_syscall - - .align 16 - .global sys32_vfork - .proc sys32_vfork -sys32_vfork: +GLOBAL_ENTRY(sys32_vfork) alloc r16=ar.pfs,2,2,3,0;; mov out0=IA64_CLONE_VFORK|IA64_CLONE_VM|SIGCHLD // out0 = clone_flags br.cond.sptk.few .fork1 // do the work - .endp sys32_vfork +END(sys32_vfork) - .align 16 - .global sys32_fork - .proc sys32_fork -sys32_fork: - alloc r16=ar.pfs,2,2,3,0;; +GLOBAL_ENTRY(sys32_fork) + UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)) + alloc r16=ar.pfs,2,2,3,0 mov out0=SIGCHLD // out0 = clone_flags + ;; .fork1: - movl r28=1f - mov loc1=rp - br.cond.sptk.many save_switch_stack -1: - mov loc0=r16 // save ar.pfs across do_fork + mov loc0=rp + mov loc1=r16 // save ar.pfs across do_fork + DO_SAVE_SWITCH_STACK + + UNW(.body) + adds out2=IA64_SWITCH_STACK_SIZE+16,sp adds r2=IA64_SWITCH_STACK_SIZE+IA64_PT_REGS_R12_OFFSET+16,sp ;; ld8 out1=[r2] // fetch usp from pt_regs.r12 br.call.sptk.few rp=do_fork .ret1: - mov ar.pfs=loc0 + mov ar.pfs=loc1 + UNW(.restore sp) adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack - mov rp=loc1 - ;; + mov rp=loc0 br.ret.sptk.many rp - .endp sys32_fork +END(sys32_fork) .rodata .align 8 @@ -304,3 +298,8 @@ data8 sys_ni_syscall /* streams1 */ data8 sys_ni_syscall /* streams2 */ data8 sys32_vfork /* 190 */ + /* + * CAUTION: If any system calls are added beyond this point + * then the check in `arch/ia64/kernel/ivt.S' will have + * to be modified also. You've been warned. + */ diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/ia32/ia32_signal.c linux/arch/ia64/ia32/ia32_signal.c --- v2.4.0-test1/linux/arch/ia64/ia32/ia32_signal.c Mon Jun 19 16:31:57 2000 +++ linux/arch/ia64/ia32/ia32_signal.c Thu Jun 22 07:09:44 2000 @@ -55,7 +55,7 @@ }; static int -copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from) +copy_siginfo_to_user32 (siginfo_t32 *to, siginfo_t *from) { int err; @@ -104,6 +104,7 @@ struct pt_regs *regs, unsigned long mask) { int err = 0; + unsigned long flag; err |= __put_user((regs->r16 >> 32) & 0xffff , (unsigned int *)&sc->fs); err |= __put_user((regs->r16 >> 48) & 0xffff , (unsigned int *)&sc->gs); @@ -124,9 +125,11 @@ #endif err |= __put_user(regs->cr_iip, &sc->eip); err |= __put_user(regs->r17 & 0xffff, (unsigned int *)&sc->cs); -#if 0 - err |= __put_user(regs->eflags, &sc->eflags); -#endif + /* + * `eflags' is in an ar register for this context + */ + asm volatile ("mov %0=ar.eflag ;;" : "=r"(flag)); + err |= __put_user((unsigned int)flag, &sc->eflags); err |= __put_user(regs->r12, &sc->esp_at_signal); err |= __put_user((regs->r17 >> 16) & 0xffff, (unsigned int *)&sc->ss); @@ -190,15 +193,26 @@ COPY(cr_iip, eip); COPY_SEG_STRICT(cs); COPY_SEG_STRICT(ss); -#if 0 { - unsigned int tmpflags; - err |= __get_user(tmpflags, &sc->eflags); - /* XXX: Change this to ar.eflags */ - regs->eflags = (regs->eflags & ~0x40DD5) | (tmpflags & 0x40DD5); - regs->orig_eax = -1; /* disable syscall checks */ + unsigned int tmpflags; + unsigned long flag; + + /* + * IA32 `eflags' is not part of `pt_regs', it's + * in an ar register which is part of the thread + * context. Fortunately, we are executing in the + * IA32 process's context. + */ + err |= __get_user(tmpflags, &sc->eflags); + asm volatile ("mov %0=ar.eflag ;;" : "=r"(flag)); + flag &= ~0x40DD5; + flag |= (tmpflags & 0x40DD5); + asm volatile ("mov ar.eflag=%0 ;;" :: "r"(flag)); + + regs->r1 = -1; /* disable syscall checks, r1 is orig_eax */ } +#if 0 { struct _fpstate * buf; err |= __get_user(buf, &sc->fpstate); @@ -271,7 +285,7 @@ /* Set up to return from userspace. If provided, use a stub already in userspace. */ - err |= __put_user(frame->retcode, &frame->pretcode); + err |= __put_user((long)frame->retcode, &frame->pretcode); /* This is popl %eax ; movl $,%eax ; int $0x80 */ err |= __put_user(0xb858, (short *)(frame->retcode+0)); #define __IA32_NR_sigreturn 119 @@ -326,8 +340,8 @@ ? current->exec_domain->signal_invmap[sig] : sig), &frame->sig); - err |= __put_user(&frame->info, &frame->pinfo); - err |= __put_user(&frame->uc, &frame->puc); + err |= __put_user((long)&frame->info, &frame->pinfo); + err |= __put_user((long)&frame->uc, &frame->puc); err |= copy_siginfo_to_user32(&frame->info, info); /* Create the ucontext. */ @@ -341,7 +355,7 @@ regs, set->sig[0]); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); - err |= __put_user(frame->retcode, &frame->pretcode); + err |= __put_user((long)frame->retcode, &frame->pretcode); /* This is movl $,%eax ; int $0x80 */ err |= __put_user(0xb8, (char *)(frame->retcode+0)); #define __IA32_NR_rt_sigreturn 173 diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/ia32/ia32_support.c linux/arch/ia64/ia32/ia32_support.c --- v2.4.0-test1/linux/arch/ia64/ia32/ia32_support.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/ia32/ia32_support.c Thu Jun 22 07:09:44 2000 @@ -1,6 +1,9 @@ /* * IA32 helper functions + * + * 06/16/00 A. Mallick added csd/ssd/tssd for ia32 thread context */ + #include #include #include @@ -15,6 +18,57 @@ extern unsigned long *ia32_gdt_table, *ia32_tss; extern void die_if_kernel (char *str, struct pt_regs *regs, long err); + +void +ia32_save_state (struct thread_struct *thread) +{ + unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd, tssd; + + asm ("mov %0=ar.eflag;" + "mov %1=ar.fsr;" + "mov %2=ar.fcr;" + "mov %3=ar.fir;" + "mov %4=ar.fdr;" + "mov %5=ar.csd;" + "mov %6=ar.ssd;" + "mov %7=ar.k1" + : "=r"(eflag), "=r"(fsr), "=r"(fcr), "=r"(fir), "=r"(fdr), + "=r"(csd), "=r"(ssd), "=r"(tssd)); + thread->eflag = eflag; + thread->fsr = fsr; + thread->fcr = fcr; + thread->fir = fir; + thread->fdr = fdr; + thread->csd = csd; + thread->ssd = ssd; + thread->tssd = tssd; +} + +void +ia32_load_state (struct thread_struct *thread) +{ + unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd, tssd; + + eflag = thread->eflag; + fsr = thread->fsr; + fcr = thread->fcr; + fir = thread->fir; + fdr = thread->fdr; + csd = thread->csd; + ssd = thread->ssd; + tssd = thread->tssd; + + asm volatile ("mov ar.eflag=%0;" + "mov ar.fsr=%1;" + "mov ar.fcr=%2;" + "mov ar.fir=%3;" + "mov ar.fdr=%4;" + "mov ar.csd=%5;" + "mov ar.ssd=%6;" + "mov ar.k1=%7" + :: "r"(eflag), "r"(fsr), "r"(fcr), "r"(fir), "r"(fdr), + "r"(csd), "r"(ssd), "r"(tssd)); +} /* * Setup IA32 GDT and TSS diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/ia32/ia32_traps.c linux/arch/ia64/ia32/ia32_traps.c --- v2.4.0-test1/linux/arch/ia64/ia32/ia32_traps.c Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/ia32/ia32_traps.c Thu Jun 22 07:09:44 2000 @@ -1,3 +1,9 @@ +/* + * IA32 exceptions handler + * + * 06/16/00 A. Mallick added siginfo for most cases (close to IA32) + */ + #include #include @@ -9,9 +15,11 @@ { struct siginfo siginfo; + siginfo.si_errno = 0; switch ((isr >> 16) & 0xff) { case 1: case 2: + siginfo.si_signo = SIGTRAP; if (isr == 0) siginfo.si_code = TRAP_TRACE; else if (isr & 0x4) @@ -21,27 +29,96 @@ break; case 3: + siginfo.si_signo = SIGTRAP; siginfo.si_code = TRAP_BRKPT; break; case 0: /* Divide fault */ + siginfo.si_signo = SIGFPE; + siginfo.si_code = FPE_INTDIV; + break; + case 4: /* Overflow */ case 5: /* Bounds fault */ + siginfo.si_signo = SIGFPE; + siginfo.si_code = 0; + break; + case 6: /* Invalid Op-code */ + siginfo.si_signo = SIGILL; + siginfo.si_code = ILL_ILLOPN; + break; + case 7: /* FP DNA */ case 8: /* Double Fault */ case 9: /* Invalid TSS */ case 11: /* Segment not present */ case 12: /* Stack fault */ case 13: /* General Protection Fault */ + siginfo.si_signo = SIGSEGV; + siginfo.si_code = 0; + break; + case 16: /* Pending FP error */ + { + unsigned long fsr, fcr; + + asm ("mov %0=ar.fsr;" + "mov %1=ar.fcr;" + : "=r"(fsr), "=r"(fcr)); + + siginfo.si_signo = SIGFPE; + /* + * (~cwd & swd) will mask out exceptions that are not set to unmasked + * status. 0x3f is the exception bits in these regs, 0x200 is the + * C1 reg you need in case of a stack fault, 0x040 is the stack + * fault bit. We should only be taking one exception at a time, + * so if this combination doesn't produce any single exception, + * then we have a bad program that isn't syncronizing its FPU usage + * and it will suffer the consequences since we won't be able to + * fully reproduce the context of the exception + */ + switch(((~fcr) & (fsr & 0x3f)) | (fsr & 0x240)) { + case 0x000: + default: + siginfo.si_code = 0; + break; + case 0x001: /* Invalid Op */ + case 0x040: /* Stack Fault */ + case 0x240: /* Stack Fault | Direction */ + siginfo.si_code = FPE_FLTINV; + break; + case 0x002: /* Denormalize */ + case 0x010: /* Underflow */ + siginfo.si_code = FPE_FLTUND; + break; + case 0x004: /* Zero Divide */ + siginfo.si_code = FPE_FLTDIV; + break; + case 0x008: /* Overflow */ + siginfo.si_code = FPE_FLTOVF; + break; + case 0x020: /* Precision */ + siginfo.si_code = FPE_FLTRES; + break; + } + + break; + } + case 17: /* Alignment check */ + siginfo.si_signo = SIGSEGV; + siginfo.si_code = BUS_ADRALN; + break; + case 19: /* SSE Numeric error */ + siginfo.si_signo = SIGFPE; + siginfo.si_code = 0; + break; + default: return -1; } - siginfo.si_signo = SIGTRAP; - siginfo.si_errno = 0; - send_sig_info(SIGTRAP, &siginfo, current); + force_sig_info(SIGTRAP, &siginfo, current); return 0; } diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/ia32/sys_ia32.c linux/arch/ia64/ia32/sys_ia32.c --- v2.4.0-test1/linux/arch/ia64/ia32/sys_ia32.c Tue May 23 15:31:33 2000 +++ linux/arch/ia64/ia32/sys_ia32.c Thu Jun 22 07:09:44 2000 @@ -7,6 +7,8 @@ * Copyright (C) 1999 Arun Sharma * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 2000 Hewlett-Packard Co. + * Copyright (C) 2000 David Mosberger-Tang * * These routines maintain argument size conversion between 32bit and 64bit * environment. @@ -55,24 +57,29 @@ #include #include -#define A(__x) ((unsigned long)(__x)) -#define AA(__x) ((unsigned long)(__x)) +#define A(__x) ((unsigned long)(__x)) +#define AA(__x) ((unsigned long)(__x)) +#define ROUND_UP(x,a) ((__typeof__(x))(((unsigned long)(x) + ((a) - 1)) & ~((a) - 1))) +#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) + +extern asmlinkage long sys_execve (char *, char **, char **, struct pt_regs *); +extern asmlinkage long sys_munmap (unsigned long, size_t len); +extern asmlinkage long sys_mprotect (unsigned long, size_t, unsigned long); static int nargs(unsigned int arg, char **ap) { - char *ptr; - int n, err; + int n, err, addr; n = 0; do { - if (err = get_user(ptr, (int *)arg)) + if ((err = get_user(addr, (int *)A(arg))) != 0) return(err); if (ap) - *ap++ = ptr; + *ap++ = (char *)A(addr); arg += sizeof(unsigned int); n++; - } while (ptr); + } while (addr); return(n - 1); } @@ -106,14 +113,14 @@ down(¤t->mm->mmap_sem); lock_kernel(); - av = do_mmap_pgoff(0, NULL, len, - PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0); + av = (char **) do_mmap_pgoff(0, 0UL, len, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, 0); unlock_kernel(); up(¤t->mm->mmap_sem); if (IS_ERR(av)) - return(av); + return (long)av; ae = av + na + 1; av[na] = (char *)0; ae[ne] = (char *)0; @@ -121,7 +128,7 @@ (void)nargs(envp, ae); r = sys_execve(filename, av, ae, regs); if (IS_ERR(r)) - sys_munmap(av, len); + sys_munmap((unsigned long) av, len); return(r); } @@ -146,9 +153,9 @@ return err; } -extern asmlinkage int sys_newstat(char * filename, struct stat * statbuf); +extern asmlinkage long sys_newstat(char * filename, struct stat * statbuf); -asmlinkage int +asmlinkage long sys32_newstat(char * filename, struct stat32 *statbuf) { int ret; @@ -163,9 +170,9 @@ return ret; } -extern asmlinkage int sys_newlstat(char * filename, struct stat * statbuf); +extern asmlinkage long sys_newlstat(char * filename, struct stat * statbuf); -asmlinkage int +asmlinkage long sys32_newlstat(char * filename, struct stat32 *statbuf) { int ret; @@ -180,9 +187,9 @@ return ret; } -extern asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf); +extern asmlinkage long sys_newfstat(unsigned int fd, struct stat * statbuf); -asmlinkage int +asmlinkage long sys32_newfstat(unsigned int fd, struct stat32 *statbuf) { int ret; @@ -214,31 +221,26 @@ return -EINVAL; if (prot & PROT_WRITE) prot |= PROT_EXEC; -#ifdef DDD -#else // DDD prot |= PROT_WRITE; -#endif // DDD front = NULL; back = NULL; if ((baddr = (addr & PAGE_MASK)) != addr && get_user(c, (char *)baddr) == 0) { front = kmalloc(addr - baddr, GFP_KERNEL); memcpy(front, (void *)baddr, addr - baddr); } -#ifndef DDD - if (addr) -#endif - if (((addr + len) & ~PAGE_MASK) && get_user(c, (char *)(addr + len)) == 0) { + if (addr && ((addr + len) & ~PAGE_MASK) && get_user(c, (char *)(addr + len)) == 0) { back = kmalloc(PAGE_SIZE - ((addr + len) & ~PAGE_MASK), GFP_KERNEL); - memcpy(back, addr + len, PAGE_SIZE - ((addr + len) & ~PAGE_MASK)); + memcpy(back, (char *)addr + len, PAGE_SIZE - ((addr + len) & ~PAGE_MASK)); } - if ((r = do_mmap(0, baddr, len + (addr - baddr), prot, flags | MAP_ANONYMOUS, 0)) < 0) + down(¤t->mm->mmap_sem); + r = do_mmap(0, baddr, len + (addr - baddr), prot, flags | MAP_ANONYMOUS, 0); + up(¤t->mm->mmap_sem); + if (r < 0) return(r); -#ifndef DDD if (addr == 0) addr = r; -#endif // DDD if (back) { - memcpy(addr + len, back, PAGE_SIZE - ((addr + len) & ~PAGE_MASK)); + memcpy((char *)addr + len, back, PAGE_SIZE - ((addr + len) & ~PAGE_MASK)); kfree(back); } if (front) { @@ -246,7 +248,7 @@ kfree(front); } if (flags & MAP_ANONYMOUS) { - memset(addr, 0, len); + memset((char *)addr, 0, len); return(addr); } if (!file) @@ -280,7 +282,7 @@ unsigned int offset; }; -asmlinkage int +asmlinkage long sys32_mmap(struct mmap_arg_struct *arg) { int error = -EFAULT; @@ -290,7 +292,6 @@ if (copy_from_user(&a, arg, sizeof(a))) return -EFAULT; - down(¤t->mm->mmap_sem); lock_kernel(); if (!(a.flags & MAP_ANONYMOUS)) { error = -EBADF; @@ -300,23 +301,19 @@ } a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -#ifdef DDD if ((a.flags & MAP_FIXED) && ((a.addr & ~PAGE_MASK) || (a.offset & ~PAGE_MASK))) { -#else // DDD - if (1) { -#endif // DDD unlock_kernel(); - up(¤t->mm->mmap_sem); error = do_mmap_fake(file, a.addr, a.len, a.prot, a.flags, a.offset); - down(¤t->mm->mmap_sem); lock_kernel(); - } else + } else { + down(¤t->mm->mmap_sem); error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset); + up(¤t->mm->mmap_sem); + } if (file) fput(file); out: unlock_kernel(); - up(¤t->mm->mmap_sem); return error; } @@ -349,7 +346,7 @@ return(sys_mprotect(start & PAGE_MASK, len & PAGE_MASK, prot)); } -asmlinkage int +asmlinkage long sys32_rt_sigaction(int sig, struct sigaction32 *act, struct sigaction32 *oact, unsigned int sigsetsize) { @@ -408,10 +405,10 @@ } -extern asmlinkage int sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset, - size_t sigsetsize); +extern asmlinkage long sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset, + size_t sigsetsize); -asmlinkage int +asmlinkage long sys32_rt_sigprocmask(int how, sigset32_t *set, sigset32_t *oset, unsigned int sigsetsize) { @@ -466,9 +463,9 @@ return err; } -extern asmlinkage int sys_statfs(const char * path, struct statfs * buf); +extern asmlinkage long sys_statfs(const char * path, struct statfs * buf); -asmlinkage int +asmlinkage long sys32_statfs(const char * path, struct statfs32 *buf) { int ret; @@ -483,9 +480,9 @@ return ret; } -extern asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf); +extern asmlinkage long sys_fstatfs(unsigned int fd, struct statfs * buf); -asmlinkage int +asmlinkage long sys32_fstatfs(unsigned int fd, struct statfs32 *buf) { int ret; @@ -552,7 +549,7 @@ extern int do_getitimer(int which, struct itimerval *value); -asmlinkage int +asmlinkage long sys32_getitimer(int which, struct itimerval32 *it) { struct itimerval kit; @@ -567,7 +564,7 @@ extern int do_setitimer(int which, struct itimerval *, struct itimerval *); -asmlinkage int +asmlinkage long sys32_setitimer(int which, struct itimerval32 *in, struct itimerval32 *out) { struct itimerval kin, kout; @@ -612,7 +609,7 @@ extern struct timezone sys_tz; extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz); -asmlinkage int +asmlinkage long sys32_gettimeofday(struct timeval32 *tv, struct timezone *tz) { if (tv) { @@ -628,7 +625,7 @@ return 0; } -asmlinkage int +asmlinkage long sys32_settimeofday(struct timeval32 *tv, struct timezone *tz) { struct timeval ktv; @@ -646,56 +643,135 @@ return do_sys_settimeofday(tv ? &ktv : NULL, tz ? &ktz : NULL); } -struct dirent32 { - unsigned int d_ino; - unsigned int d_off; - unsigned short d_reclen; - char d_name[NAME_MAX + 1]; +struct linux32_dirent { + u32 d_ino; + u32 d_off; + u16 d_reclen; + char d_name[1]; }; -static void -xlate_dirent(void *dirent64, void *dirent32, long n) +struct old_linux32_dirent { + u32 d_ino; + u32 d_offset; + u16 d_namlen; + char d_name[1]; +}; + +struct getdents32_callback { + struct linux32_dirent * current_dir; + struct linux32_dirent * previous; + int count; + int error; +}; + +struct readdir32_callback { + struct old_linux32_dirent * dirent; + int count; +}; + +static int +filldir32 (void *__buf, const char *name, int namlen, off_t offset, ino_t ino) { - long off; - struct dirent *dirp; - struct dirent32 *dirp32; - - off = 0; - while (off < n) { - dirp = (struct dirent *)(dirent64 + off); - dirp32 = (struct dirent32 *)(dirent32 + off); - off += dirp->d_reclen; - dirp32->d_ino = dirp->d_ino; - dirp32->d_off = (unsigned int)dirp->d_off; - dirp32->d_reclen = dirp->d_reclen; - strncpy(dirp32->d_name, dirp->d_name, dirp->d_reclen - ((3 * 4) + 2)); - } - return; + struct linux32_dirent * dirent; + struct getdents32_callback * buf = (struct getdents32_callback *) __buf; + int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1, 4); + + buf->error = -EINVAL; /* only used if we fail.. */ + if (reclen > buf->count) + return -EINVAL; + dirent = buf->previous; + if (dirent) + put_user(offset, &dirent->d_off); + dirent = buf->current_dir; + buf->previous = dirent; + put_user(ino, &dirent->d_ino); + put_user(reclen, &dirent->d_reclen); + copy_to_user(dirent->d_name, name, namlen); + put_user(0, dirent->d_name + namlen); + ((char *) dirent) += reclen; + buf->current_dir = dirent; + buf->count -= reclen; + return 0; } asmlinkage long -sys32_getdents(unsigned int fd, void * dirent32, unsigned int count) +sys32_getdents (unsigned int fd, void * dirent, unsigned int count) +{ + struct file * file; + struct linux32_dirent * lastdirent; + struct getdents32_callback buf; + int error; + + error = -EBADF; + file = fget(fd); + if (!file) + goto out; + + buf.current_dir = (struct linux32_dirent *) dirent; + buf.previous = NULL; + buf.count = count; + buf.error = 0; + + lock_kernel(); + error = vfs_readdir(file, filldir32, &buf); + if (error < 0) + goto out_putf; + error = buf.error; + lastdirent = buf.previous; + if (lastdirent) { + put_user(file->f_pos, &lastdirent->d_off); + error = count - buf.count; + } + +out_putf: + unlock_kernel(); + fput(file); +out: + return error; +} + +static int +fillonedir32 (void * __buf, const char * name, int namlen, off_t offset, ino_t ino) { - long n; - void *dirent64; + struct readdir32_callback * buf = (struct readdir32_callback *) __buf; + struct old_linux32_dirent * dirent; - dirent64 = (unsigned long)(dirent32 + (sizeof(long) - 1)) & ~(sizeof(long) - 1); - if ((n = sys_getdents(fd, dirent64, count - (dirent64 - dirent32))) < 0) - return(n); - xlate_dirent(dirent64, dirent32, n); - return(n); + if (buf->count) + return -EINVAL; + buf->count++; + dirent = buf->dirent; + put_user(ino, &dirent->d_ino); + put_user(offset, &dirent->d_offset); + put_user(namlen, &dirent->d_namlen); + copy_to_user(dirent->d_name, name, namlen); + put_user(0, dirent->d_name + namlen); + return 0; } -asmlinkage int -sys32_readdir(unsigned int fd, void * dirent32, unsigned int count) +asmlinkage long +sys32_readdir (unsigned int fd, void * dirent, unsigned int count) { - int n; - struct dirent dirent64; + int error; + struct file * file; + struct readdir32_callback buf; - if ((n = old_readdir(fd, &dirent64, count)) < 0) - return(n); - xlate_dirent(&dirent64, dirent32, dirent64.d_reclen); - return(n); + error = -EBADF; + file = fget(fd); + if (!file) + goto out; + + buf.count = 0; + buf.dirent = dirent; + + lock_kernel(); + error = vfs_readdir(file, fillonedir32, &buf); + if (error >= 0) + error = buf.count; + unlock_kernel(); + + fput(file); +out: + return error; } /* @@ -708,9 +784,9 @@ */ #define MAX_SELECT_SECONDS \ ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1) -#define ROUND_UP(x,y) (((x)+(y)-1)/(y)) +#define ROUND_UP_TIME(x,y) (((x)+(y)-1)/(y)) -asmlinkage int +asmlinkage long sys32_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval32 *tvp32) { fd_set_bits fds; @@ -730,7 +806,7 @@ goto out_nofds; if ((unsigned long) sec < MAX_SELECT_SECONDS) { - timeout = ROUND_UP(usec, 1000000/HZ); + timeout = ROUND_UP_TIME(usec, 1000000/HZ); timeout += sec * (unsigned long) HZ; } } @@ -807,13 +883,15 @@ unsigned int tvp; }; -asmlinkage int old_select(struct sel_arg_struct *arg) +asmlinkage long +old_select(struct sel_arg_struct *arg) { struct sel_arg_struct a; if (copy_from_user(&a, arg, sizeof(a))) return -EFAULT; - return sys32_select(a.n, a.inp, a.outp, a.exp, a.tvp); + return sys32_select(a.n, (fd_set *)A(a.inp), (fd_set *)A(a.outp), (fd_set *)A(a.exp), + (struct timeval32 *)A(a.tvp)); } struct timespec32 { @@ -821,10 +899,9 @@ int tv_nsec; }; -extern asmlinkage int sys_nanosleep(struct timespec *rqtp, - struct timespec *rmtp); +extern asmlinkage long sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp); -asmlinkage int +asmlinkage long sys32_nanosleep(struct timespec32 *rqtp, struct timespec32 *rmtp) { struct timespec t; @@ -1005,9 +1082,9 @@ int rlim_max; }; -extern asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim); +extern asmlinkage long sys_getrlimit(unsigned int resource, struct rlimit *rlim); -asmlinkage int +asmlinkage long sys32_getrlimit(unsigned int resource, struct rlimit32 *rlim) { struct rlimit r; @@ -1024,9 +1101,9 @@ return ret; } -extern asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim); +extern asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit *rlim); -asmlinkage int +asmlinkage long sys32_setrlimit(unsigned int resource, struct rlimit32 *rlim) { struct rlimit r; @@ -1047,118 +1124,6 @@ return ret; } -/* Argument list sizes for sys_socketcall */ -#define AL(x) ((x) * sizeof(u32)) -static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), - AL(3),AL(3),AL(4),AL(4),AL(4),AL(6), - AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)}; -#undef AL - -extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen); -extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, - int addrlen); -extern asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, - int *upeer_addrlen); -extern asmlinkage int sys_getsockname(int fd, struct sockaddr *usockaddr, - int *usockaddr_len); -extern asmlinkage int sys_getpeername(int fd, struct sockaddr *usockaddr, - int *usockaddr_len); -extern asmlinkage int sys_send(int fd, void *buff, size_t len, unsigned flags); -extern asmlinkage int sys_sendto(int fd, u32 buff, __kernel_size_t32 len, - unsigned flags, u32 addr, int addr_len); -extern asmlinkage int sys_recv(int fd, void *ubuf, size_t size, unsigned flags); -extern asmlinkage int sys_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size, - unsigned flags, u32 addr, u32 addr_len); -extern asmlinkage int sys_setsockopt(int fd, int level, int optname, - char *optval, int optlen); -extern asmlinkage int sys_getsockopt(int fd, int level, int optname, - u32 optval, u32 optlen); - -extern asmlinkage int sys_socket(int family, int type, int protocol); -extern asmlinkage int sys_socketpair(int family, int type, int protocol, - int usockvec[2]); -extern asmlinkage int sys_shutdown(int fd, int how); -extern asmlinkage int sys_listen(int fd, int backlog); - -asmlinkage int sys32_socketcall(int call, u32 *args) -{ - int i, ret; - u32 a[6]; - u32 a0,a1; - - if (callSYS_RECVMSG) - return -EINVAL; - if (copy_from_user(a, args, nas[call])) - return -EFAULT; - a0=a[0]; - a1=a[1]; - - switch(call) - { - case SYS_SOCKET: - ret = sys_socket(a0, a1, a[2]); - break; - case SYS_BIND: - ret = sys_bind(a0, (struct sockaddr *)A(a1), a[2]); - break; - case SYS_CONNECT: - ret = sys_connect(a0, (struct sockaddr *)A(a1), a[2]); - break; - case SYS_LISTEN: - ret = sys_listen(a0, a1); - break; - case SYS_ACCEPT: - ret = sys_accept(a0, (struct sockaddr *)A(a1), - (int *)A(a[2])); - break; - case SYS_GETSOCKNAME: - ret = sys_getsockname(a0, (struct sockaddr *)A(a1), - (int *)A(a[2])); - break; - case SYS_GETPEERNAME: - ret = sys_getpeername(a0, (struct sockaddr *)A(a1), - (int *)A(a[2])); - break; - case SYS_SOCKETPAIR: - ret = sys_socketpair(a0, a1, a[2], (int *)A(a[3])); - break; - case SYS_SEND: - ret = sys_send(a0, (void *)A(a1), a[2], a[3]); - break; - case SYS_SENDTO: - ret = sys_sendto(a0, a1, a[2], a[3], a[4], a[5]); - break; - case SYS_RECV: - ret = sys_recv(a0, (void *)A(a1), a[2], a[3]); - break; - case SYS_RECVFROM: - ret = sys_recvfrom(a0, a1, a[2], a[3], a[4], a[5]); - break; - case SYS_SHUTDOWN: - ret = sys_shutdown(a0,a1); - break; - case SYS_SETSOCKOPT: - ret = sys_setsockopt(a0, a1, a[2], (char *)A(a[3]), - a[4]); - break; - case SYS_GETSOCKOPT: - ret = sys_getsockopt(a0, a1, a[2], a[3], a[4]); - break; - case SYS_SENDMSG: - ret = sys32_sendmsg(a0, (struct msghdr32 *)A(a1), - a[2]); - break; - case SYS_RECVMSG: - ret = sys32_recvmsg(a0, (struct msghdr32 *)A(a1), - a[2]); - break; - default: - ret = EINVAL; - break; - } - return ret; -} - /* * Declare the IA32 version of the msghdr */ @@ -1181,13 +1146,13 @@ if (!access_ok(VERIFY_READ, mp32, sizeof(*mp32))) return(-EFAULT); __get_user(i, &mp32->msg_name); - mp->msg_name = (void *)i; + mp->msg_name = (void *)A(i); __get_user(mp->msg_namelen, &mp32->msg_namelen); __get_user(i, &mp32->msg_iov); - mp->msg_iov = (struct iov *)i; + mp->msg_iov = (struct iovec *)A(i); __get_user(mp->msg_iovlen, &mp32->msg_iovlen); __get_user(i, &mp32->msg_control); - mp->msg_control = (void *)i; + mp->msg_control = (void *)A(i); __get_user(mp->msg_controllen, &mp32->msg_controllen); __get_user(mp->msg_flags, &mp32->msg_flags); return(0); @@ -1233,7 +1198,7 @@ iov32 = (struct iovec32 *)iov; for (ct = m->msg_iovlen; ct-- > 0; ) { iov[ct].iov_len = (__kernel_size_t)iov32[ct].iov_len; - iov[ct].iov_base = (void *)iov32[ct].iov_base; + iov[ct].iov_base = (void *) A(iov32[ct].iov_base); err += iov[ct].iov_len; } out: @@ -1258,7 +1223,7 @@ * BSD sendmsg interface */ -asmlinkage int sys32_sendmsg(int fd, struct msghdr32 *msg, unsigned flags) +int sys32_sendmsg(int fd, struct msghdr32 *msg, unsigned flags) { struct socket *sock; char address[MAX_SOCK_ADDR]; @@ -1337,7 +1302,8 @@ * BSD recvmsg interface */ -asmlinkage int sys32_recvmsg(int fd, struct msghdr32 *msg, unsigned int flags) +int +sys32_recvmsg (int fd, struct msghdr32 *msg, unsigned int flags) { struct socket *sock; struct iovec iovstack[UIO_FASTIOV]; @@ -1419,6 +1385,118 @@ return err; } +/* Argument list sizes for sys_socketcall */ +#define AL(x) ((x) * sizeof(u32)) +static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), + AL(3),AL(3),AL(4),AL(4),AL(4),AL(6), + AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)}; +#undef AL + +extern asmlinkage long sys_bind(int fd, struct sockaddr *umyaddr, int addrlen); +extern asmlinkage long sys_connect(int fd, struct sockaddr *uservaddr, + int addrlen); +extern asmlinkage long sys_accept(int fd, struct sockaddr *upeer_sockaddr, + int *upeer_addrlen); +extern asmlinkage long sys_getsockname(int fd, struct sockaddr *usockaddr, + int *usockaddr_len); +extern asmlinkage long sys_getpeername(int fd, struct sockaddr *usockaddr, + int *usockaddr_len); +extern asmlinkage long sys_send(int fd, void *buff, size_t len, unsigned flags); +extern asmlinkage long sys_sendto(int fd, u32 buff, __kernel_size_t32 len, + unsigned flags, u32 addr, int addr_len); +extern asmlinkage long sys_recv(int fd, void *ubuf, size_t size, unsigned flags); +extern asmlinkage long sys_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size, + unsigned flags, u32 addr, u32 addr_len); +extern asmlinkage long sys_setsockopt(int fd, int level, int optname, + char *optval, int optlen); +extern asmlinkage long sys_getsockopt(int fd, int level, int optname, + u32 optval, u32 optlen); + +extern asmlinkage long sys_socket(int family, int type, int protocol); +extern asmlinkage long sys_socketpair(int family, int type, int protocol, + int usockvec[2]); +extern asmlinkage long sys_shutdown(int fd, int how); +extern asmlinkage long sys_listen(int fd, int backlog); + +asmlinkage long sys32_socketcall(int call, u32 *args) +{ + int ret; + u32 a[6]; + u32 a0,a1; + + if (callSYS_RECVMSG) + return -EINVAL; + if (copy_from_user(a, args, nas[call])) + return -EFAULT; + a0=a[0]; + a1=a[1]; + + switch(call) + { + case SYS_SOCKET: + ret = sys_socket(a0, a1, a[2]); + break; + case SYS_BIND: + ret = sys_bind(a0, (struct sockaddr *)A(a1), a[2]); + break; + case SYS_CONNECT: + ret = sys_connect(a0, (struct sockaddr *)A(a1), a[2]); + break; + case SYS_LISTEN: + ret = sys_listen(a0, a1); + break; + case SYS_ACCEPT: + ret = sys_accept(a0, (struct sockaddr *)A(a1), + (int *)A(a[2])); + break; + case SYS_GETSOCKNAME: + ret = sys_getsockname(a0, (struct sockaddr *)A(a1), + (int *)A(a[2])); + break; + case SYS_GETPEERNAME: + ret = sys_getpeername(a0, (struct sockaddr *)A(a1), + (int *)A(a[2])); + break; + case SYS_SOCKETPAIR: + ret = sys_socketpair(a0, a1, a[2], (int *)A(a[3])); + break; + case SYS_SEND: + ret = sys_send(a0, (void *)A(a1), a[2], a[3]); + break; + case SYS_SENDTO: + ret = sys_sendto(a0, a1, a[2], a[3], a[4], a[5]); + break; + case SYS_RECV: + ret = sys_recv(a0, (void *)A(a1), a[2], a[3]); + break; + case SYS_RECVFROM: + ret = sys_recvfrom(a0, a1, a[2], a[3], a[4], a[5]); + break; + case SYS_SHUTDOWN: + ret = sys_shutdown(a0,a1); + break; + case SYS_SETSOCKOPT: + ret = sys_setsockopt(a0, a1, a[2], (char *)A(a[3]), + a[4]); + break; + case SYS_GETSOCKOPT: + ret = sys_getsockopt(a0, a1, a[2], a[3], a[4]); + break; + case SYS_SENDMSG: + ret = sys32_sendmsg(a0, (struct msghdr32 *)A(a1), + a[2]); + break; + case SYS_RECVMSG: + ret = sys32_recvmsg(a0, (struct msghdr32 *)A(a1), + a[2]); + break; + default: + ret = EINVAL; + break; + } + return ret; +} + /* * sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit emulation.. * @@ -1613,7 +1691,7 @@ static int do_sys32_msgctl (int first, int second, void *uptr) { - int err, err2; + int err = -EINVAL, err2; struct msqid_ds m; struct msqid64_ds m64; struct msqid_ds32 *up = (struct msqid_ds32 *)uptr; @@ -1644,7 +1722,7 @@ case MSG_STAT: old_fs = get_fs (); set_fs (KERNEL_DS); - err = sys_msgctl (first, second, &m64); + err = sys_msgctl (first, second, (void *) &m64); set_fs (old_fs); err2 = put_user (m64.msg_perm.key, &up->msg_perm.key); err2 |= __put_user(m64.msg_perm.uid, &up->msg_perm.uid); @@ -1725,7 +1803,7 @@ case SHM_STAT: old_fs = get_fs (); set_fs (KERNEL_DS); - err = sys_shmctl (first, second, &s64); + err = sys_shmctl (first, second, (void *) &s64); set_fs (old_fs); if (err < 0) break; @@ -1753,7 +1831,7 @@ case SHM_INFO: old_fs = get_fs (); set_fs (KERNEL_DS); - err = sys_shmctl (first, second, &si); + err = sys_shmctl (first, second, (void *)&si); set_fs (old_fs); if (err < 0) break; @@ -1773,7 +1851,7 @@ return err; } -asmlinkage int +asmlinkage long sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth) { int version, err; @@ -1898,10 +1976,10 @@ return err; } -extern asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr, +extern asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru); -asmlinkage int +asmlinkage long sys32_wait4(__kernel_pid_t32 pid, unsigned int *stat_addr, int options, struct rusage32 *ru) { @@ -1923,17 +2001,17 @@ } } -asmlinkage int +asmlinkage long sys32_waitpid(__kernel_pid_t32 pid, unsigned int *stat_addr, int options) { return sys32_wait4(pid, stat_addr, options, NULL); } -extern asmlinkage int +extern asmlinkage long sys_getrusage(int who, struct rusage *ru); -asmlinkage int +asmlinkage long sys32_getrusage(int who, struct rusage32 *ru) { struct rusage r; @@ -2429,9 +2507,9 @@ /* 32-bit timeval and related flotsam. */ -extern asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on); +extern asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on); -asmlinkage int +asmlinkage long sys32_ioperm(u32 from, u32 num, int on) { return sys_ioperm((unsigned long)from, (unsigned long)num, on); @@ -2503,10 +2581,10 @@ __kernel_time_t32 dqb_itime; }; -extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, +extern asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr); -asmlinkage int +asmlinkage long sys32_quotactl(int cmd, const char *special, int id, unsigned long addr) { int cmds = cmd >> SUBCMDSHIFT; @@ -2550,13 +2628,13 @@ return err; } -extern asmlinkage int sys_utime(char * filename, struct utimbuf * times); +extern asmlinkage long sys_utime(char * filename, struct utimbuf * times); struct utimbuf32 { __kernel_time_t32 actime, modtime; }; -asmlinkage int +asmlinkage long sys32_utime(char * filename, struct utimbuf32 *times) { struct utimbuf t; @@ -2640,10 +2718,10 @@ __put_user(*fdset, ufdset); } -extern asmlinkage int sys_sysfs(int option, unsigned long arg1, +extern asmlinkage long sys_sysfs(int option, unsigned long arg1, unsigned long arg2); -asmlinkage int +asmlinkage long sys32_sysfs(int option, u32 arg1, u32 arg2) { return sys_sysfs(option, arg1, arg2); @@ -2739,7 +2817,7 @@ #define SMBFS_NAME "smbfs" #define NCPFS_NAME "ncpfs" -asmlinkage int +asmlinkage long sys32_mount(char *dev_name, char *dir_name, char *type, unsigned long new_flags, u32 data) { @@ -2813,9 +2891,9 @@ char _f[22]; }; -extern asmlinkage int sys_sysinfo(struct sysinfo *info); +extern asmlinkage long sys_sysinfo(struct sysinfo *info); -asmlinkage int +asmlinkage long sys32_sysinfo(struct sysinfo32 *info) { struct sysinfo s; @@ -2841,10 +2919,10 @@ return ret; } -extern asmlinkage int sys_sched_rr_get_interval(pid_t pid, +extern asmlinkage long sys_sched_rr_get_interval(pid_t pid, struct timespec *interval); -asmlinkage int +asmlinkage long sys32_sched_rr_get_interval(__kernel_pid_t32 pid, struct timespec32 *interval) { struct timespec t; @@ -2860,10 +2938,10 @@ return ret; } -extern asmlinkage int sys_sigprocmask(int how, old_sigset_t *set, +extern asmlinkage long sys_sigprocmask(int how, old_sigset_t *set, old_sigset_t *oset); -asmlinkage int +asmlinkage long sys32_sigprocmask(int how, old_sigset_t32 *set, old_sigset_t32 *oset) { old_sigset_t s; @@ -2879,9 +2957,9 @@ return 0; } -extern asmlinkage int sys_sigpending(old_sigset_t *set); +extern asmlinkage long sys_sigpending(old_sigset_t *set); -asmlinkage int +asmlinkage long sys32_sigpending(old_sigset_t32 *set) { old_sigset_t s; @@ -2895,9 +2973,9 @@ return ret; } -extern asmlinkage int sys_rt_sigpending(sigset_t *set, size_t sigsetsize); +extern asmlinkage long sys_rt_sigpending(sigset_t *set, size_t sigsetsize); -asmlinkage int +asmlinkage long sys32_rt_sigpending(sigset_t32 *set, __kernel_size_t32 sigsetsize) { sigset_t s; @@ -3000,11 +3078,11 @@ return d; } -extern asmlinkage int +extern asmlinkage long sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo, const struct timespec *uts, size_t sigsetsize); -asmlinkage int +asmlinkage long sys32_rt_sigtimedwait(sigset_t32 *uthese, siginfo_t32 *uinfo, struct timespec32 *uts, __kernel_size_t32 sigsetsize) { @@ -3041,10 +3119,10 @@ return ret; } -extern asmlinkage int +extern asmlinkage long sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo); -asmlinkage int +asmlinkage long sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 *uinfo) { siginfo_t info; @@ -3062,9 +3140,9 @@ return ret; } -extern asmlinkage int sys_setreuid(uid_t ruid, uid_t euid); +extern asmlinkage long sys_setreuid(uid_t ruid, uid_t euid); -asmlinkage int sys32_setreuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid) +asmlinkage long sys32_setreuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid) { uid_t sruid, seuid; @@ -3073,9 +3151,9 @@ return sys_setreuid(sruid, seuid); } -extern asmlinkage int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid); +extern asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid); -asmlinkage int +asmlinkage long sys32_setresuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid, __kernel_uid_t32 suid) { @@ -3087,9 +3165,9 @@ return sys_setresuid(sruid, seuid, ssuid); } -extern asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); +extern asmlinkage long sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); -asmlinkage int +asmlinkage long sys32_getresuid(__kernel_uid_t32 *ruid, __kernel_uid_t32 *euid, __kernel_uid_t32 *suid) { @@ -3105,9 +3183,9 @@ return ret; } -extern asmlinkage int sys_setregid(gid_t rgid, gid_t egid); +extern asmlinkage long sys_setregid(gid_t rgid, gid_t egid); -asmlinkage int +asmlinkage long sys32_setregid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid) { gid_t srgid, segid; @@ -3117,9 +3195,9 @@ return sys_setregid(srgid, segid); } -extern asmlinkage int sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid); +extern asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid); -asmlinkage int +asmlinkage long sys32_setresgid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid, __kernel_gid_t32 sgid) { @@ -3131,9 +3209,9 @@ return sys_setresgid(srgid, segid, ssgid); } -extern asmlinkage int sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); +extern asmlinkage long sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); -asmlinkage int +asmlinkage long sys32_getresgid(__kernel_gid_t32 *rgid, __kernel_gid_t32 *egid, __kernel_gid_t32 *sgid) { @@ -3152,9 +3230,9 @@ return ret; } -extern asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist); +extern asmlinkage long sys_getgroups(int gidsetsize, gid_t *grouplist); -asmlinkage int +asmlinkage long sys32_getgroups(int gidsetsize, __kernel_gid_t32 *grouplist) { gid_t gl[NGROUPS]; @@ -3171,9 +3249,9 @@ return ret; } -extern asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist); +extern asmlinkage long sys_setgroups(int gidsetsize, gid_t *grouplist); -asmlinkage int +asmlinkage long sys32_setgroups(int gidsetsize, __kernel_gid_t32 *grouplist) { gid_t gl[NGROUPS]; @@ -3617,7 +3695,7 @@ kmsg->msg_control = (void *) orig_cmsg_uptr; } -asmlinkage int +asmlinkage long sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags) { struct socket *sock; @@ -3665,7 +3743,7 @@ return err; } -asmlinkage int +asmlinkage long sys32_recvmsg(int fd, struct msghdr32 *user_msg, unsigned int user_flags) { struct iovec iovstack[UIO_FASTIOV]; @@ -3756,7 +3834,7 @@ extern void check_pending(int signum); -asmlinkage int +asmlinkage long sys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact) { @@ -3801,21 +3879,21 @@ return sys_create_module(name_user, (size_t)size); } -extern asmlinkage int sys_init_module(const char *name_user, +extern asmlinkage long sys_init_module(const char *name_user, struct module *mod_user); /* Hey, when you're trying to init module, take time and prepare us a nice 64bit * module structure, even if from 32bit modutils... Why to pollute kernel... :)) */ -asmlinkage int +asmlinkage long sys32_init_module(const char *name_user, struct module *mod_user) { return sys_init_module(name_user, mod_user); } -extern asmlinkage int sys_delete_module(const char *name_user); +extern asmlinkage long sys_delete_module(const char *name_user); -asmlinkage int +asmlinkage long sys32_delete_module(const char *name_user) { return sys_delete_module(name_user); @@ -4090,7 +4168,7 @@ return error; } -asmlinkage int +asmlinkage long sys32_query_module(char *name_user, int which, char *buf, __kernel_size_t32 bufsize, u32 ret) { @@ -4158,9 +4236,9 @@ char name[60]; }; -extern asmlinkage int sys_get_kernel_syms(struct kernel_sym *table); +extern asmlinkage long sys_get_kernel_syms(struct kernel_sym *table); -asmlinkage int +asmlinkage long sys32_get_kernel_syms(struct kernel_sym32 *table) { int len, i; @@ -4192,19 +4270,19 @@ return -ENOSYS; } -asmlinkage int +asmlinkage long sys32_init_module(const char *name_user, struct module *mod_user) { return -ENOSYS; } -asmlinkage int +asmlinkage long sys32_delete_module(const char *name_user) { return -ENOSYS; } -asmlinkage int +asmlinkage long sys32_query_module(const char *name_user, int which, char *buf, size_t bufsize, size_t *ret) { @@ -4216,7 +4294,7 @@ return -ENOSYS; } -asmlinkage int +asmlinkage long sys32_get_kernel_syms(struct kernel_sym *table) { return -ENOSYS; @@ -4432,7 +4510,7 @@ return err; } -extern asmlinkage int sys_nfsservctl(int cmd, void *arg, void *resp); +extern asmlinkage long sys_nfsservctl(int cmd, void *arg, void *resp); int asmlinkage sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32) @@ -4503,9 +4581,9 @@ return err; } -asmlinkage int sys_utimes(char *, struct timeval *); +asmlinkage long sys_utimes(char *, struct timeval *); -asmlinkage int +asmlinkage long sys32_utimes(char *filename, struct timeval32 *tvs) { char *kfilename; @@ -4533,7 +4611,7 @@ } /* These are here just in case some old ia32 binary calls it. */ -asmlinkage int +asmlinkage long sys32_pause(void) { current->state = TASK_INTERRUPTIBLE; @@ -4542,19 +4620,19 @@ } /* PCI config space poking. */ -extern asmlinkage int sys_pciconfig_read(unsigned long bus, +extern asmlinkage long sys_pciconfig_read(unsigned long bus, unsigned long dfn, unsigned long off, unsigned long len, unsigned char *buf); -extern asmlinkage int sys_pciconfig_write(unsigned long bus, +extern asmlinkage long sys_pciconfig_write(unsigned long bus, unsigned long dfn, unsigned long off, unsigned long len, unsigned char *buf); -asmlinkage int +asmlinkage long sys32_pciconfig_read(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf) { return sys_pciconfig_read((unsigned long) bus, @@ -4564,7 +4642,7 @@ (unsigned char *)AA(ubuf)); } -asmlinkage int +asmlinkage long sys32_pciconfig_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf) { return sys_pciconfig_write((unsigned long) bus, @@ -4574,11 +4652,11 @@ (unsigned char *)AA(ubuf)); } -extern asmlinkage int sys_prctl(int option, unsigned long arg2, +extern asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5); -asmlinkage int +asmlinkage long sys32_prctl(int option, u32 arg2, u32 arg3, u32 arg4, u32 arg5) { return sys_prctl(option, @@ -4589,9 +4667,9 @@ } -extern asmlinkage int sys_newuname(struct new_utsname * name); +extern asmlinkage long sys_newuname(struct new_utsname * name); -asmlinkage int +asmlinkage long sys32_newuname(struct new_utsname * name) { int ret = sys_newuname(name); @@ -4627,9 +4705,9 @@ } -extern asmlinkage int sys_personality(unsigned long); +extern asmlinkage long sys_personality(unsigned long); -asmlinkage int +asmlinkage long sys32_personality(unsigned long personality) { int ret; @@ -4646,7 +4724,7 @@ extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count); -asmlinkage int +asmlinkage long sys32_sendfile(int out_fd, int in_fd, __kernel_off_t32 *offset, s32 count) { mm_segment_t old_fs = get_fs(); @@ -4683,7 +4761,7 @@ extern int do_adjtimex(struct timex *); -asmlinkage int +asmlinkage long sys32_adjtimex(struct timex32 *utp) { struct timex txc; diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/Makefile linux/arch/ia64/kernel/Makefile --- v2.4.0-test1/linux/arch/ia64/kernel/Makefile Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/kernel/Makefile Thu Jun 22 07:09:44 2000 @@ -1,11 +1,6 @@ # # Makefile for the linux kernel. # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definitions are now in the main makefile... .S.s: $(CPP) $(AFLAGS) -o $*.s $< @@ -15,16 +10,19 @@ all: kernel.o head.o init_task.o O_TARGET := kernel.o -O_OBJS := acpi.o entry.o gate.o efi.o efi_stub.o irq.o irq_ia64.o irq_sapic.o ivt.o \ - pal.o pci-dma.o process.o perfmon.o ptrace.o sal.o sal_stub.o semaphore.o setup.o \ +O_OBJS := acpi.o entry.o gate.o efi.o efi_stub.o irq.o irq_ia64.o irq_sapic.o ivt.o \ + pal.o pci-dma.o process.o perfmon.o ptrace.o sal.o semaphore.o setup.o \ signal.o sys_ia64.o traps.o time.o unaligned.o unwind.o -#O_OBJS := fpreg.o -#OX_OBJS := ia64_ksyms.o +OX_OBJS := ia64_ksyms.o ifdef CONFIG_IA64_GENERIC O_OBJS += machvec.o endif +ifdef CONFIG_IA64_PALINFO +O_OBJS += palinfo.o +endif + ifdef CONFIG_PCI O_OBJS += pci.o endif @@ -35,6 +33,10 @@ ifdef CONFIG_IA64_MCA O_OBJS += mca.o mca_asm.o +endif + +ifdef CONFIG_IA64_BRL_EMU +O_OBJS += brl_emu.o endif clean:: diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/acpi.c linux/arch/ia64/kernel/acpi.c --- v2.4.0-test1/linux/arch/ia64/kernel/acpi.c Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/kernel/acpi.c Thu Jun 22 07:09:44 2000 @@ -89,16 +89,16 @@ #ifdef CONFIG_IA64_DIG acpi_entry_iosapic_t *iosapic = (acpi_entry_iosapic_t *) p; unsigned int ver, v; - int l, pins; + int l, max_pin; ver = iosapic_version(iosapic->address); - pins = (ver >> 16) & 0xff; + max_pin = (ver >> 16) & 0xff; printk("IOSAPIC Version %x.%x: address 0x%lx IRQs 0x%x - 0x%x\n", (ver & 0xf0) >> 4, (ver & 0x0f), iosapic->address, - iosapic->irq_base, iosapic->irq_base + pins); + iosapic->irq_base, iosapic->irq_base + max_pin); - for (l = 0; l < pins; l++) { + for (l = 0; l <= max_pin; l++) { v = iosapic->irq_base + l; if (v < 16) v = isa_irq_to_vector(v); @@ -110,7 +110,7 @@ iosapic_addr(v) = (unsigned long) ioremap(iosapic->address, 0); iosapic_baseirq(v) = iosapic->irq_base; } - iosapic_init(iosapic->address); + iosapic_init(iosapic->address, iosapic->irq_base); #endif } diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/brl_emu.c linux/arch/ia64/kernel/brl_emu.c --- v2.4.0-test1/linux/arch/ia64/kernel/brl_emu.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/brl_emu.c Thu Jun 22 07:09:44 2000 @@ -0,0 +1,220 @@ +/* + * Emulation of the "brl" instruction for IA64 processors that + * don't support it in hardware. + * Author: Stephan Zeisset, Intel Corp. + */ + +#include +#include +#include +#include + +extern char ia64_set_b1, ia64_set_b2, ia64_set_b3, ia64_set_b4, ia64_set_b5; + +struct illegal_op_return { + unsigned long fkt, arg1, arg2, arg3; +}; + +/* + * The unimplemented bits of a virtual address must be set + * to the value of the most significant implemented bit. + * unimpl_va_mask includes all unimplemented bits and + * the most significant implemented bit, so the result + * of an and operation with the mask must be all 0's + * or all 1's for the address to be valid. + */ +#define unimplemented_virtual_address(va) ( \ + ((va) & my_cpu_data.unimpl_va_mask) != 0 && \ + ((va) & my_cpu_data.unimpl_va_mask) != my_cpu_data.unimpl_va_mask \ +) + +/* + * The unimplemented bits of a physical address must be 0. + * unimpl_pa_mask includes all unimplemented bits, so the result + * of an and operation with the mask must be all 0's for the + * address to be valid. + */ +#define unimplemented_physical_address(pa) ( \ + ((pa) & my_cpu_data.unimpl_pa_mask) != 0 \ +) + +/* + * Handle an illegal operation fault that was caused by an + * unimplemented "brl" instruction. + * If we are not successful (e.g because the illegal operation + * wasn't caused by a "brl" after all), we return -1. + * If we are successful, we return either 0 or the address + * of a "fixup" function for manipulating preserved register + * state. + */ + +struct illegal_op_return +ia64_emulate_brl (struct pt_regs *regs, unsigned long ar_ec) +{ + unsigned long bundle[2]; + unsigned long opcode, btype, qp, offset; + unsigned long next_ip; + struct siginfo siginfo; + struct illegal_op_return rv; + int tmp_taken, unimplemented_address; + + rv.fkt = (unsigned long) -1; + + /* + * Decode the instruction bundle. + */ + + if (copy_from_user(bundle, (void *) (regs->cr_iip), sizeof(bundle))) + return rv; + + next_ip = (unsigned long) regs->cr_iip + 16; + + /* "brl" must be in slot 2. */ + if (ia64_psr(regs)->ri != 1) return rv; + + /* Must be "mlx" template */ + if ((bundle[0] & 0x1e) != 0x4) return rv; + + opcode = (bundle[1] >> 60); + btype = ((bundle[1] >> 29) & 0x7); + qp = ((bundle[1] >> 23) & 0x3f); + offset = ((bundle[1] & 0x0800000000000000L) << 4) + | ((bundle[1] & 0x00fffff000000000L) >> 32) + | ((bundle[1] & 0x00000000007fffffL) << 40) + | ((bundle[0] & 0xffff000000000000L) >> 24); + + tmp_taken = regs->pr & (1L << qp); + + switch(opcode) { + + case 0xC: + /* + * Long Branch. + */ + if (btype != 0) return rv; + rv.fkt = 0; + if (!(tmp_taken)) { + /* + * Qualifying predicate is 0. + * Skip instruction. + */ + regs->cr_iip = next_ip; + ia64_psr(regs)->ri = 0; + return rv; + } + break; + + case 0xD: + /* + * Long Call. + */ + rv.fkt = 0; + if (!(tmp_taken)) { + /* + * Qualifying predicate is 0. + * Skip instruction. + */ + regs->cr_iip = next_ip; + ia64_psr(regs)->ri = 0; + return rv; + } + + /* + * BR[btype] = IP+16 + */ + switch(btype) { + case 0: + regs->b0 = next_ip; + break; + case 1: + rv.fkt = (unsigned long) &ia64_set_b1; + break; + case 2: + rv.fkt = (unsigned long) &ia64_set_b2; + break; + case 3: + rv.fkt = (unsigned long) &ia64_set_b3; + break; + case 4: + rv.fkt = (unsigned long) &ia64_set_b4; + break; + case 5: + rv.fkt = (unsigned long) &ia64_set_b5; + break; + case 6: + regs->b6 = next_ip; + break; + case 7: + regs->b7 = next_ip; + break; + } + rv.arg1 = next_ip; + + /* + * AR[PFS].pfm = CFM + * AR[PFS].pec = AR[EC] + * AR[PFS].ppl = PSR.cpl + */ + regs->ar_pfs = ((regs->cr_ifs & 0x3fffffffff) + | (ar_ec << 52) + | ((unsigned long) ia64_psr(regs)->cpl << 62)); + + /* + * CFM.sof -= CFM.sol + * CFM.sol = 0 + * CFM.sor = 0 + * CFM.rrb.gr = 0 + * CFM.rrb.fr = 0 + * CFM.rrb.pr = 0 + */ + regs->cr_ifs = ((regs->cr_ifs & 0xffffffc00000007f) + - ((regs->cr_ifs >> 7) & 0x7f)); + + break; + + default: + /* + * Unknown opcode. + */ + return rv; + + } + + regs->cr_iip += offset; + ia64_psr(regs)->ri = 0; + + if (ia64_psr(regs)->it == 0) + unimplemented_address = unimplemented_physical_address(regs->cr_iip); + else + unimplemented_address = unimplemented_virtual_address(regs->cr_iip); + + if (unimplemented_address) { + /* + * The target address contains unimplemented bits. + */ + printk("Woah! Unimplemented Instruction Address Trap!\n"); + siginfo.si_signo = SIGILL; + siginfo.si_errno = 0; + siginfo.si_code = ILL_BADIADDR; + force_sig_info(SIGILL, &siginfo, current); + } else if (ia64_psr(regs)->tb) { + /* + * Branch Tracing is enabled. + * Force a taken branch signal. + */ + siginfo.si_signo = SIGTRAP; + siginfo.si_errno = 0; + siginfo.si_code = TRAP_BRANCH; + force_sig_info(SIGTRAP, &siginfo, current); + } else if (ia64_psr(regs)->ss) { + /* + * Single Step is enabled. + * Force a trace signal. + */ + siginfo.si_signo = SIGTRAP; + siginfo.si_errno = 0; + siginfo.si_code = TRAP_TRACE; + force_sig_info(SIGTRAP, &siginfo, current); + } + return rv; +} diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/efi.c linux/arch/ia64/kernel/efi.c --- v2.4.0-test1/linux/arch/ia64/kernel/efi.c Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/kernel/efi.c Thu Jun 22 07:09:44 2000 @@ -5,15 +5,18 @@ * * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond - * Copyright (C) 1999 Hewlett-Packard Co. + * Copyright (C) 1999-2000 Hewlett-Packard Co. * Copyright (C) 1999 David Mosberger-Tang - * Copyright (C) 1999 Stephane Eranian + * Copyright (C) 1999-2000 Stephane Eranian * * All EFI Runtime Services are not implemented yet as EFI only * supports physical mode addressing on SoftSDV. This is to be fixed * in a future version. --drummond 1999-07-20 * * Implemented EFI runtime services and virtual mode calls. --davidm + * + * Goutham Rao: + * Skip non-WB memory and ignore empty memory ranges. */ #include #include @@ -22,6 +25,7 @@ #include #include +#include #include #define EFI_DEBUG 0 @@ -172,6 +176,14 @@ continue; } + if (!(md->attribute & EFI_MEMORY_WB)) + continue; + if (md->num_pages == 0) { + printk("efi_memmap_walk: ignoring empty region at 0x%lx", + md->phys_addr); + continue; + } + curr.start = PAGE_OFFSET + md->phys_addr; curr.end = curr.start + (md->num_pages << 12); @@ -207,6 +219,61 @@ } } +/* + * Look for the PAL_CODE region reported by EFI and maps it using an + * ITR to enable safe PAL calls in virtual mode. See IA-64 Processor + * Abstraction Layer chapter 11 in ADAG + */ +static void +map_pal_code (void) +{ + void *efi_map_start, *efi_map_end, *p; + efi_memory_desc_t *md; + u64 efi_desc_size; + int pal_code_count=0; + u64 mask, flags; + u64 vaddr; + + efi_map_start = __va(ia64_boot_param.efi_memmap); + efi_map_end = efi_map_start + ia64_boot_param.efi_memmap_size; + efi_desc_size = ia64_boot_param.efi_memdesc_size; + + for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { + md = p; + if (md->type != EFI_PAL_CODE) continue; + + if (++pal_code_count > 1) { + printk(KERN_ERR "Too many EFI Pal Code memory ranges, dropped @ %lx\n", + md->phys_addr); + continue; + } + mask = ~((1 << _PAGE_SIZE_4M)-1); /* XXX should be dynamic? */ + vaddr = PAGE_OFFSET + md->phys_addr; + + printk(__FUNCTION__": mapping PAL code [0x%lx-0x%lx) into [0x%lx-0x%lx)\n", + md->phys_addr, md->phys_addr + (md->num_pages << 12), + vaddr & mask, (vaddr & mask) + 4*1024*1024); + + /* + * Cannot write to CRx with PSR.ic=1 + */ + ia64_clear_ic(flags); + + /* + * ITR0/DTR0: used for kernel code/data + * ITR1/DTR1: used by HP simulator + * ITR2/DTR2: map PAL code + * ITR3/DTR3: used to map PAL calls buffer + */ + ia64_itr(0x1, 2, vaddr & mask, + pte_val(mk_pte_phys(md->phys_addr, + __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RX))), + _PAGE_SIZE_4M); + local_irq_restore(flags); + ia64_srlz_i (); + } +} + void __init efi_init (void) { @@ -291,6 +358,8 @@ } } #endif + + map_pal_code(); } void diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/efi_stub.S linux/arch/ia64/kernel/efi_stub.S --- v2.4.0-test1/linux/arch/ia64/kernel/efi_stub.S Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/efi_stub.S Thu Jun 22 07:09:44 2000 @@ -1,7 +1,8 @@ /* * EFI call stub. * - * Copyright (C) 1999 David Mosberger + * Copyright (C) 1999-2000 Hewlett-Packard Co + * Copyright (C) 1999-2000 David Mosberger * * This stub allows us to make EFI calls in physical mode with interrupts * turned off. We need this because we can't call SetVirtualMap() until @@ -30,6 +31,7 @@ (IA64_PSR_BN) #include +#include .text .psr abi64 @@ -39,53 +41,6 @@ .text /* - * Switch execution mode from virtual to physical or vice versa. - * - * Inputs: - * r16 = new psr to establish - */ - .proc switch_mode -switch_mode: - { - alloc r2=ar.pfs,0,0,0,0 - rsm psr.i | psr.ic // disable interrupts and interrupt collection - mov r15=ip - } - ;; - { - flushrs // must be first insn in group - srlz.i - shr.u r19=r15,61 // r19 <- top 3 bits of current IP - } - ;; - mov cr.ipsr=r16 // set new PSR - add r3=1f-switch_mode,r15 - xor r15=0x7,r19 // flip the region bits - - mov r17=ar.bsp - mov r14=rp // get return address into a general register - - // switch RSE backing store: - ;; - dep r17=r15,r17,61,3 // make ar.bsp physical or virtual - mov r18=ar.rnat // save ar.rnat - ;; - mov ar.bspstore=r17 // this steps on ar.rnat - dep r3=r15,r3,61,3 // make rfi return address physical or virtual - ;; - mov cr.iip=r3 - mov cr.ifs=r0 - dep sp=r15,sp,61,3 // make stack pointer physical or virtual - ;; - mov ar.rnat=r18 // restore ar.rnat - dep r14=r15,r14,61,3 // make function return address physical or virtual - rfi // must be last insn in group - ;; -1: mov rp=r14 - br.ret.sptk.few rp - .endp switch_mode - -/* * Inputs: * in0 = address of function descriptor of EFI routine to call * in1..in7 = arguments to routine @@ -94,13 +49,12 @@ * r8 = EFI_STATUS returned by called function */ - .global efi_call_phys - .proc efi_call_phys -efi_call_phys: - - alloc loc0=ar.pfs,8,5,7,0 +GLOBAL_ENTRY(efi_call_phys) + UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)) + alloc loc1=ar.pfs,8,5,7,0 ld8 r2=[in0],8 // load EFI function's entry point - mov loc1=rp + mov loc0=rp + UNW(.body) ;; mov loc2=gp // save global pointer mov loc4=ar.rsc // save RSE configuration @@ -121,7 +75,7 @@ ;; andcm r16=loc3,r16 // get psr with IT, DT, and RT bits cleared mov out3=in4 - br.call.sptk.few rp=switch_mode + br.call.sptk.few rp=ia64_switch_mode .ret0: mov out4=in5 mov out5=in6 @@ -130,12 +84,11 @@ .ret1: mov ar.rsc=r0 // put RSE in enforced lazy, LE mode mov r16=loc3 - br.call.sptk.few rp=switch_mode // return to virtual mode + br.call.sptk.few rp=ia64_switch_mode // return to virtual mode .ret2: mov ar.rsc=loc4 // restore RSE configuration - mov ar.pfs=loc0 - mov rp=loc1 + mov ar.pfs=loc1 + mov rp=loc0 mov gp=loc2 br.ret.sptk.few rp - - .endp efi_call_phys +END(efi_call_phys) diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/entry.S linux/arch/ia64/kernel/entry.S --- v2.4.0-test1/linux/arch/ia64/kernel/entry.S Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/kernel/entry.S Thu Jun 22 07:09:44 2000 @@ -13,8 +13,6 @@ /* * Global (preserved) predicate usage on syscall entry/exit path: * - * - * pEOI: See entry.h. * pKern: See entry.h. * pSys: See entry.h. * pNonSys: !pSys @@ -30,6 +28,7 @@ #include #include #include +#include #include "entry.h" @@ -42,11 +41,11 @@ * execve() is special because in case of success, we need to * setup a null register window frame. */ - .align 16 - .proc ia64_execve -ia64_execve: - alloc loc0=ar.pfs,3,2,4,0 - mov loc1=rp +ENTRY(ia64_execve) + UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(3)) + alloc loc1=ar.pfs,3,2,4,0 + mov loc0=rp + UNW(.body) mov out0=in0 // filename ;; // stop bit between alloc and call mov out1=in1 // argv @@ -54,25 +53,22 @@ add out3=16,sp // regs br.call.sptk.few rp=sys_execve .ret0: cmp4.ge p6,p0=r8,r0 - mov ar.pfs=loc0 // restore ar.pfs + mov ar.pfs=loc1 // restore ar.pfs ;; (p6) mov ar.pfs=r0 // clear ar.pfs in case of success sxt4 r8=r8 // return 64-bit result - mov rp=loc1 + mov rp=loc0 br.ret.sptk.few rp - .endp ia64_execve +END(ia64_execve) - .align 16 - .global sys_clone - .proc sys_clone -sys_clone: +GLOBAL_ENTRY(sys_clone) + UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)) alloc r16=ar.pfs,2,2,3,0;; - movl r28=1f - mov loc1=rp - br.cond.sptk.many save_switch_stack -1: - mov loc0=r16 // save ar.pfs across do_fork + mov loc0=rp + DO_SAVE_SWITCH_STACK + mov loc1=r16 // save ar.pfs across do_fork + UNW(.body) adds out2=IA64_SWITCH_STACK_SIZE+16,sp adds r2=IA64_SWITCH_STACK_SIZE+IA64_PT_REGS_R12_OFFSET+16,sp cmp.eq p8,p9=in1,r0 // usp == 0? @@ -82,24 +78,22 @@ (p9) mov out1=in1 br.call.sptk.few rp=do_fork .ret1: - mov ar.pfs=loc0 + mov ar.pfs=loc1 + UNW(.restore sp) adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack - mov rp=loc1 + mov rp=loc0 ;; br.ret.sptk.many rp - .endp sys_clone +END(sys_clone) /* - * prev_task <- switch_to(struct task_struct *next) + * prev_task <- ia64_switch_to(struct task_struct *next) */ - .align 16 - .global ia64_switch_to - .proc ia64_switch_to -ia64_switch_to: +GLOBAL_ENTRY(ia64_switch_to) + UNW(.prologue) alloc r16=ar.pfs,1,0,0,0 - movl r28=1f - br.cond.sptk.many save_switch_stack -1: + DO_SAVE_SWITCH_STACK + UNW(.body) // disable interrupts to ensure atomicity for next few instructions: mov r17=psr // M-unit ;; @@ -123,66 +117,60 @@ mov psr.l=r17 ;; srlz.d - - movl r28=1f - br.cond.sptk.many load_switch_stack -1: + DO_LOAD_SWITCH_STACK( ) br.ret.sptk.few rp - .endp ia64_switch_to +END(ia64_switch_to) +#ifndef CONFIG_IA64_NEW_UNWIND /* * Like save_switch_stack, but also save the stack frame that is active * at the time this function is called. */ - .align 16 - .proc save_switch_stack_with_current_frame -save_switch_stack_with_current_frame: -1: { - alloc r16=ar.pfs,0,0,0,0 // pass ar.pfs to save_switch_stack - mov r28=ip - } - ;; - adds r28=1f-1b,r28 - br.cond.sptk.many save_switch_stack -1: br.ret.sptk.few rp - .endp save_switch_stack_with_current_frame +ENTRY(save_switch_stack_with_current_frame) + UNW(.prologue) + alloc r16=ar.pfs,0,0,0,0 // pass ar.pfs to save_switch_stack + DO_SAVE_SWITCH_STACK + br.ret.sptk.few rp +END(save_switch_stack_with_current_frame) +#endif /* !CONFIG_IA64_NEW_UNWIND */ + /* * Note that interrupts are enabled during save_switch_stack and * load_switch_stack. This means that we may get an interrupt with * "sp" pointing to the new kernel stack while ar.bspstore is still * pointing to the old kernel backing store area. Since ar.rsc, * ar.rnat, ar.bsp, and ar.bspstore are all preserved by interrupts, - * this is not a problem. + * this is not a problem. Also, we don't need to specify unwind + * information for preserved registers that are not modified in + * save_switch_stack as the right unwind information is already + * specified at the call-site of save_switch_stack. */ /* * save_switch_stack: * - r16 holds ar.pfs - * - r28 holds address to return to + * - b7 holds address to return to * - rp (b0) holds return address to save */ - .align 16 - .global save_switch_stack - .proc save_switch_stack -save_switch_stack: +GLOBAL_ENTRY(save_switch_stack) + UNW(.prologue) + UNW(.altrp b7) flushrs // flush dirty regs to backing store (must be first in insn group) mov r17=ar.unat // preserve caller's - adds r2=-IA64_SWITCH_STACK_SIZE+16,sp // r2 = &sw->caller_unat + adds r2=16,sp // r2 = &sw->caller_unat ;; mov r18=ar.fpsr // preserve fpsr mov ar.rsc=r0 // put RSE in mode: enforced lazy, little endian, pl 0 ;; mov r19=ar.rnat - adds r3=-IA64_SWITCH_STACK_SIZE+24,sp // r3 = &sw->ar_fpsr - - // Note: the instruction ordering is important here: we can't - // store anything to the switch stack before sp is updated - // as otherwise an interrupt might overwrite the memory! - adds sp=-IA64_SWITCH_STACK_SIZE,sp + adds r3=24,sp // r3 = &sw->ar_fpsr ;; + .savesp ar.unat,SW(CALLER_UNAT) st8 [r2]=r17,16 + .savesp ar.fpsr,SW(AR_FPSR) st8 [r3]=r18,24 ;; + UNW(.body) stf.spill [r2]=f2,32 stf.spill [r3]=f3,32 mov r21=b0 @@ -259,16 +247,17 @@ st8 [r3]=r21 // save predicate registers mov ar.rsc=3 // put RSE back into eager mode, pl 0 br.cond.sptk.few b7 - .endp save_switch_stack +END(save_switch_stack) /* * load_switch_stack: - * - r28 holds address to return to + * - b7 holds address to return to */ - .align 16 - .proc load_switch_stack -load_switch_stack: +ENTRY(load_switch_stack) + UNW(.prologue) + UNW(.altrp b7) invala // invalidate ALAT + UNW(.body) adds r2=IA64_SWITCH_STACK_B0_OFFSET+16,sp // get pointer to switch_stack.b0 mov ar.rsc=r0 // put RSE into enforced lazy mode adds r3=IA64_SWITCH_STACK_B0_OFFSET+24,sp // get pointer to switch_stack.b1 @@ -353,21 +342,16 @@ ;; ld8.fill r4=[r2],16 ld8.fill r5=[r3],16 - mov b7=r28 ;; ld8.fill r6=[r2],16 ld8.fill r7=[r3],16 mov ar.unat=r18 // restore caller's unat mov ar.fpsr=r19 // restore fpsr mov ar.rsc=3 // put RSE back into eager mode, pl 0 - adds sp=IA64_SWITCH_STACK_SIZE,sp // pop switch_stack br.cond.sptk.few b7 - .endp load_switch_stack +END(load_switch_stack) - .align 16 - .global __ia64_syscall - .proc __ia64_syscall -__ia64_syscall: +GLOBAL_ENTRY(__ia64_syscall) .regstk 6,0,0,0 mov r15=in5 // put syscall number in place break __BREAK_SYSCALL @@ -377,30 +361,42 @@ (p6) st4 [r2]=r8 (p6) mov r8=-1 br.ret.sptk.few rp - .endp __ia64_syscall +END(__ia64_syscall) // // We invoke syscall_trace through this intermediate function to // ensure that the syscall input arguments are not clobbered. We // also use it to preserve b6, which contains the syscall entry point. // - .align 16 - .global invoke_syscall_trace - .proc invoke_syscall_trace -invoke_syscall_trace: - alloc loc0=ar.pfs,8,3,0,0 +GLOBAL_ENTRY(invoke_syscall_trace) +#ifdef CONFIG_IA64_NEW_UNWIND + UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)) + alloc loc1=ar.pfs,8,3,0,0 + mov loc0=rp + UNW(.body) + mov loc2=b6 + ;; + br.call.sptk.few rp=syscall_trace +.ret3: mov rp=loc0 + mov ar.pfs=loc1 + mov b6=loc2 + br.ret.sptk.few rp +#else /* !CONFIG_IA64_NEW_SYSCALL */ + UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)) + alloc loc1=ar.pfs,8,3,0,0 ;; // WAW on CFM at the br.call - mov loc1=rp + mov loc0=rp br.call.sptk.many rp=save_switch_stack_with_current_frame // must preserve b6!! .ret2: mov loc2=b6 br.call.sptk.few rp=syscall_trace .ret3: adds sp=IA64_SWITCH_STACK_SIZE,sp // drop switch_stack frame - mov rp=loc1 - mov ar.pfs=loc0 + mov rp=loc0 + mov ar.pfs=loc1 mov b6=loc2 ;; br.ret.sptk.few rp - .endp invoke_syscall_trace +#endif /* !CONFIG_IA64_NEW_SYSCALL */ +END(invoke_syscall_trace) // // Invoke a system call, but do some tracing before and after the call. @@ -414,19 +410,19 @@ // .global ia64_trace_syscall .global ia64_strace_leave_kernel - .global ia64_strace_clear_r8 - .proc ia64_strace_clear_r8 -ia64_strace_clear_r8: // this is where we return after cloning when PF_TRACESYS is on +GLOBAL_ENTRY(ia64_strace_clear_r8) + // this is where we return after cloning when PF_TRACESYS is on + PT_REGS_UNWIND_INFO(0) # ifdef CONFIG_SMP br.call.sptk.few rp=invoke_schedule_tail # endif mov r8=0 br strace_check_retval - .endp ia64_strace_clear_r8 +END(ia64_strace_clear_r8) - .proc ia64_trace_syscall -ia64_trace_syscall: +ENTRY(ia64_trace_syscall) + PT_REGS_UNWIND_INFO(0) br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch syscall args .ret4: br.call.sptk.few rp=b6 // do the syscall strace_check_retval: @@ -454,7 +450,7 @@ (p6) mov r10=-1 (p6) mov r8=r9 br.cond.sptk.few strace_save_retval - .endp ia64_trace_syscall +END(ia64_trace_syscall) /* * A couple of convenience macros to help implement/understand the state @@ -472,12 +468,8 @@ #define rKRBS r22 #define rB6 r21 - .align 16 - .global ia64_ret_from_syscall - .global ia64_ret_from_syscall_clear_r8 - .global ia64_leave_kernel - .proc ia64_ret_from_syscall -ia64_ret_from_syscall_clear_r8: +GLOBAL_ENTRY(ia64_ret_from_syscall_clear_r8) + PT_REGS_UNWIND_INFO(0) #ifdef CONFIG_SMP // In SMP mode, we need to call schedule_tail to complete the scheduling process. // Called by ia64_switch_to after do_fork()->copy_thread(). r8 contains the @@ -487,7 +479,10 @@ #endif mov r8=0 ;; // added stop bits to prevent r8 dependency -ia64_ret_from_syscall: +END(ia64_ret_from_syscall_clear_r8) + // fall through +GLOBAL_ENTRY(ia64_ret_from_syscall) + PT_REGS_UNWIND_INFO(0) cmp.ge p6,p7=r8,r0 // syscall executed successfully? adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8 adds r3=IA64_PT_REGS_R8_OFFSET+32,sp // r3 = &pt_regs.r10 @@ -497,19 +492,21 @@ .mem.offset 8,0 (p6) st8.spill [r3]=r0 // clear error indication in slot for r10 and set unat bit (p7) br.cond.spnt.few handle_syscall_error // handle potential syscall failure - -ia64_leave_kernel: +END(ia64_ret_from_syscall) + // fall through +GLOBAL_ENTRY(ia64_leave_kernel) // check & deliver software interrupts: + PT_REGS_UNWIND_INFO(0) #ifdef CONFIG_SMP - adds r2=IA64_TASK_PROCESSOR_OFFSET,r13 - movl r3=softirq_state + adds r2=IA64_TASK_PROCESSOR_OFFSET,r13 + movl r3=softirq_state ;; - ld4 r2=[r2] + ld4 r2=[r2] ;; - shl r2=r2,SMP_LOG_CACHE_BYTES // can't use shladd here... + shl r2=r2,SMP_LOG_CACHE_BYTES // can't use shladd here... ;; - add r3=r2,r3 + add r3=r2,r3 #else movl r3=softirq_state #endif @@ -538,32 +535,28 @@ ld4 r14=[r14] mov rp=r3 // arrange for schedule() to return to back_from_resched ;; - /* - * If pEOI is set, we need to write the cr.eoi now and then - * clear pEOI because both invoke_schedule() and - * handle_signal_delivery() may call the scheduler. Since - * we're returning to user-level, we get at most one nested - * interrupt of the same priority level, which doesn't tax the - * kernel stack too much. - */ -(pEOI) mov cr.eoi=r0 cmp.ne p6,p0=r2,r0 cmp.ne p2,p0=r14,r0 // NOTE: pKern is an alias for p2!! -(pEOI) cmp.ne pEOI,p0=r0,r0 // clear pEOI before calling schedule() srlz.d (p6) br.call.spnt.many b6=invoke_schedule // ignore return value 2: // check & deliver pending signals: (p2) br.call.spnt.few rp=handle_signal_delivery -#if defined(CONFIG_SMP) || defined(CONFIG_IA64_SOFTSDV_HACKS) +#if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_IA64_SOFTSDV_HACKS) // Check for lost ticks + rsm psr.i mov r2 = ar.itc + movl r14 = 1000 // latency tolerance mov r3 = cr.itm ;; sub r2 = r2, r3 ;; + sub r2 = r2, r14 + ;; cmp.ge p6,p7 = r2, r0 (p6) br.call.spnt.few rp=invoke_ia64_reset_itm + ;; + ssm psr.i #endif restore_all: @@ -692,18 +685,6 @@ ;; add r18=r16,r18 // adjust the loadrs value ;; -#ifdef CONFIG_IA64_SOFTSDV_HACKS - // Reset ITM if we've missed a timer tick. Workaround for SoftSDV bug - mov r16 = r2 - mov r2 = ar.itc - mov r17 = cr.itm - ;; - cmp.gt p6,p7 = r2, r17 -(p6) addl r17 = 100, r2 - ;; - mov cr.itm = r17 - mov r2 = r16 -#endif dont_preserve_current_frame: alloc r16=ar.pfs,0,0,0,0 // drop the current call frame (noop for syscalls) ;; @@ -724,14 +705,14 @@ mov ar.rsc=rARRSC mov ar.unat=rARUNAT mov cr.ifs=rCRIFS // restore cr.ifs only if not a (synchronous) syscall -(pEOI) mov cr.eoi=r0 mov pr=rARPR,-1 mov cr.iip=rCRIIP mov cr.ipsr=rCRIPSR ;; rfi;; // must be last instruction in an insn group +END(ia64_leave_kernel) -handle_syscall_error: +ENTRY(handle_syscall_error) /* * Some system calls (e.g., ptrace, mmap) can return arbitrary * values which could lead us to mistake a negative return @@ -740,6 +721,7 @@ * If pt_regs.r8 is zero, we assume that the call completed * successfully. */ + PT_REGS_UNWIND_INFO(0) ld8 r3=[r2] // load pt_regs.r8 sub r9=0,r8 // negate return value to get errno ;; @@ -753,205 +735,283 @@ .mem.offset 0,0; st8.spill [r2]=r9 // store errno in pt_regs.r8 and set unat bit .mem.offset 8,0; st8.spill [r3]=r10 // store error indication in pt_regs.r10 and set unat bit br.cond.sptk.many ia64_leave_kernel - .endp handle_syscall_error +END(handle_syscall_error) #ifdef CONFIG_SMP /* * Invoke schedule_tail(task) while preserving in0-in7, which may be needed * in case a system call gets restarted. */ - .proc invoke_schedule_tail -invoke_schedule_tail: - alloc loc0=ar.pfs,8,2,1,0 - mov loc1=rp +ENTRY(invoke_schedule_tail) + UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)) + alloc loc1=ar.pfs,8,2,1,0 + mov loc0=rp mov out0=r8 // Address of previous task ;; br.call.sptk.few rp=schedule_tail .ret8: - mov ar.pfs=loc0 - mov rp=loc1 + mov ar.pfs=loc1 + mov rp=loc0 br.ret.sptk.many rp - .endp invoke_schedule_tail +END(invoke_schedule_tail) + +#endif /* CONFIG_SMP */ + +#if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_IA64_SOFTSDV_HACKS) - .proc invoke_ia64_reset_itm -invoke_ia64_reset_itm: - alloc loc0=ar.pfs,8,2,0,0 - mov loc1=rp +ENTRY(invoke_ia64_reset_itm) + UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)) + alloc loc1=ar.pfs,8,2,0,0 + mov loc0=rp ;; + UNW(.body) br.call.sptk.many rp=ia64_reset_itm ;; - mov ar.pfs=loc0 - mov rp=loc1 + mov ar.pfs=loc1 + mov rp=loc0 br.ret.sptk.many rp - .endp invoke_ia64_reset_itm +END(invoke_ia64_reset_itm) -#endif /* CONFIG_SMP */ +#endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC || CONFIG_IA64_SOFTSDV_HACKS */ /* * Invoke do_softirq() while preserving in0-in7, which may be needed * in case a system call gets restarted. */ - .proc invoke_do_softirq -invoke_do_softirq: - alloc loc0=ar.pfs,8,2,0,0 - mov loc1=rp -(pEOI) mov cr.eoi=r0 +ENTRY(invoke_do_softirq) + UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)) + alloc loc1=ar.pfs,8,2,0,0 + mov loc0=rp ;; -(pEOI) cmp.ne pEOI,p0=r0,r0 + UNW(.body) br.call.sptk.few rp=do_softirq .ret9: - mov ar.pfs=loc0 - mov rp=loc1 + mov ar.pfs=loc1 + mov rp=loc0 br.ret.sptk.many rp - .endp invoke_do_softirq +END(invoke_do_softirq) /* * Invoke schedule() while preserving in0-in7, which may be needed * in case a system call gets restarted. */ - .proc invoke_schedule -invoke_schedule: - alloc loc0=ar.pfs,8,2,0,0 - mov loc1=rp +ENTRY(invoke_schedule) + UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)) + alloc loc1=ar.pfs,8,2,0,0 + mov loc0=rp ;; + UNW(.body) br.call.sptk.few rp=schedule .ret10: - mov ar.pfs=loc0 - mov rp=loc1 + mov ar.pfs=loc1 + mov rp=loc0 br.ret.sptk.many rp - .endp invoke_schedule +END(invoke_schedule) // // Setup stack and call ia64_do_signal. Note that pSys and pNonSys need to // be set up by the caller. We declare 8 input registers so the system call // args get preserved, in case we need to restart a system call. // - .align 16 - .proc handle_signal_delivery -handle_signal_delivery: - alloc loc0=ar.pfs,8,2,3,0 // preserve all eight input regs in case of syscall restart! +ENTRY(handle_signal_delivery) +#ifdef CONFIG_IA64_NEW_UNWIND + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) + alloc loc1=ar.pfs,8,2,3,0 // preserve all eight input regs in case of syscall restart! mov r9=ar.unat - - // If the process is being ptraced, the signal may not actually be delivered to - // the process. Instead, SIGCHLD will be sent to the parent. We need to - // setup a switch_stack so ptrace can inspect the processes state if necessary. - adds r2=IA64_TASK_FLAGS_OFFSET,r13 - ;; - ld8 r2=[r2] + mov loc0=rp // save return address mov out0=0 // there is no "oldset" - adds out1=16,sp // out1=&pt_regs - ;; + adds out1=0,sp // out1=&sigscratch (pSys) mov out2=1 // out2==1 => we're in a syscall - tbit.nz p16,p17=r2,PF_PTRACED_BIT -(p16) br.cond.spnt.many setup_switch_stack ;; -back_from_setup_switch_stack: (pNonSys) mov out2=0 // out2==0 => not a syscall - adds r3=-IA64_SWITCH_STACK_SIZE+IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp -(p17) adds sp=-IA64_SWITCH_STACK_SIZE,sp // make space for (dummy) switch_stack - ;; -(p17) st8 [r3]=r9 // save ar.unat in sw->caller_unat - mov loc1=rp // save return address + .fframe 16 + .spillpsp ar.unat, 16 // (note that offset is relative to psp+0x10!) + st8 [sp]=r9,-16 // allocate space for ar.unat and save it + .body br.call.sptk.few rp=ia64_do_signal .ret11: - adds r3=IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp + .restore sp + adds sp=16,sp // pop scratch stack space ;; - ld8 r9=[r3] // load new unat from sw->caller_unat - mov rp=loc1 + ld8 r9=[sp] // load new unat from sw->caller_unat + mov rp=loc0 ;; -(p17) adds sp=IA64_SWITCH_STACK_SIZE,sp // drop (dummy) switch_stack -(p17) mov ar.unat=r9 -(p17) mov ar.pfs=loc0 -(p17) br.ret.sptk.many rp - - // restore the switch stack (ptrace may have modified it): - movl r28=1f - br.cond.sptk.many load_switch_stack -1: br.ret.sptk.many rp - // NOT REACHED - -setup_switch_stack: - movl r28=back_from_setup_switch_stack - mov r16=loc0 - br.cond.sptk.many save_switch_stack - // NOT REACHED - - .endp handle_signal_delivery - - .align 16 - .proc sys_rt_sigsuspend - .global sys_rt_sigsuspend -sys_rt_sigsuspend: - alloc loc0=ar.pfs,2,2,3,0 - - // If the process is being ptraced, the signal may not actually be delivered to - // the process. Instead, SIGCHLD will be sent to the parent. We need to - // setup a switch_stack so ptrace can inspect the processes state if necessary. - // Also, the process might not ptraced until stopped in sigsuspend, so this - // isn't something that we can do conditionally based upon the value of - // PF_PTRACED_BIT. + mov ar.unat=r9 + mov ar.pfs=loc1 + br.ret.sptk.many rp +#else /* !CONFIG_IA64_NEW_UNWIND */ + .prologue + alloc r16=ar.pfs,8,0,3,0 // preserve all eight input regs in case of syscall restart! + DO_SAVE_SWITCH_STACK + UNW(.body) + + mov out0=0 // there is no "oldset" + adds out1=16,sp // out1=&sigscratch + .pred.rel.mutex pSys, pNonSys +(pSys) mov out2=1 // out2==1 => we're in a syscall +(pNonSys) mov out2=0 // out2==0 => not a syscall + br.call.sptk.few rp=ia64_do_signal +.ret11: + // restore the switch stack (ptrace may have modified it) + DO_LOAD_SWITCH_STACK( ) + br.ret.sptk.many rp +#endif /* !CONFIG_IA64_NEW_UNWIND */ +END(handle_signal_delivery) + +GLOBAL_ENTRY(sys_rt_sigsuspend) +#ifdef CONFIG_IA64_NEW_UNWIND + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) + alloc loc1=ar.pfs,8,2,3,0 // preserve all eight input regs in case of syscall restart! + mov r9=ar.unat + mov loc0=rp // save return address mov out0=in0 // mask mov out1=in1 // sigsetsize + adds out2=0,sp // out2=&sigscratch ;; - adds out2=16,sp // out1=&pt_regs - movl r28=back_from_sigsuspend_setup_switch_stack - mov r16=loc0 - br.cond.sptk.many save_switch_stack - ;; -back_from_sigsuspend_setup_switch_stack: - mov loc1=rp // save return address - br.call.sptk.many rp=ia64_rt_sigsuspend + .fframe 16 + .spillpsp ar.unat, 16 // (note that offset is relative to psp+0x10!) + st8 [sp]=r9,-16 // allocate space for ar.unat and save it + .body + br.call.sptk.few rp=ia64_rt_sigsuspend .ret12: - adds r3=IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp + .restore sp + adds sp=16,sp // pop scratch stack space ;; - ld8 r9=[r3] // load new unat from sw->caller_unat - mov rp=loc1 + ld8 r9=[sp] // load new unat from sw->caller_unat + mov rp=loc0 ;; + mov ar.unat=r9 + mov ar.pfs=loc1 + br.ret.sptk.many rp +#else /* !CONFIG_IA64_NEW_UNWIND */ + UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)) + alloc r16=ar.pfs,2,0,3,0 + DO_SAVE_SWITCH_STACK + UNW(.body) - // restore the switch stack (ptrace may have modified it): - movl r28=1f - br.cond.sptk.many load_switch_stack -1: br.ret.sptk.many rp - // NOT REACHED - .endp sys_rt_sigsuspend - - .align 16 - .proc sys_rt_sigreturn -sys_rt_sigreturn: + mov out0=in0 // mask + mov out1=in1 // sigsetsize + adds out2=16,sp // out1=&sigscratch + br.call.sptk.many rp=ia64_rt_sigsuspend +.ret12: + // restore the switch stack (ptrace may have modified it) + DO_LOAD_SWITCH_STACK( ) + br.ret.sptk.many rp +#endif /* !CONFIG_IA64_NEW_UNWIND */ +END(sys_rt_sigsuspend) + +ENTRY(sys_rt_sigreturn) +#ifdef CONFIG_IA64_NEW_UNWIND .regstk 0,0,3,0 // inherited from gate.s:invoke_sighandler() - adds out0=16,sp // out0 = &pt_regs - adds sp=-IA64_SWITCH_STACK_SIZE,sp // make space for unat and padding + PT_REGS_UNWIND_INFO(0) + .prologue + PT_REGS_SAVES(16) + adds sp=-16,sp + .body + cmp.eq pNonSys,p0=r0,r0 // sigreturn isn't a normal syscall... + ;; + adds out0=16,sp // out0 = &sigscratch + br.call.sptk.few rp=ia64_rt_sigreturn +.ret13: + adds sp=16,sp // doesn't drop pt_regs, so don't mark it as restoring sp! + PT_REGS_UNWIND_INFO(0) // instead, create a new body section with the smaller frame + ;; + ld8 r9=[sp] // load new ar.unat + mov b7=r8 ;; + mov ar.unat=r9 + br b7 +#else /* !CONFIG_IA64_NEW_UNWIND */ + .regstk 0,0,3,0 // inherited from gate.s:invoke_sighandler() + PT_REGS_UNWIND_INFO(0) + UNW(.prologue) + UNW(.fframe IA64_PT_REGS_SIZE+IA64_SWITCH_STACK_SIZE) + UNW(.spillsp rp, PT(CR_IIP)+IA64_SWITCH_STACK_SIZE) + UNW(.spillsp ar.pfs, PT(CR_IFS)+IA64_SWITCH_STACK_SIZE) + UNW(.spillsp ar.unat, PT(AR_UNAT)+IA64_SWITCH_STACK_SIZE) + UNW(.spillsp pr, PT(PR)+IA64_SWITCH_STACK_SIZE) + adds sp=-IA64_SWITCH_STACK_SIZE,sp cmp.eq pNonSys,p0=r0,r0 // sigreturn isn't a normal syscall... + ;; + UNW(.body) + + adds out0=16,sp // out0 = &sigscratch br.call.sptk.few rp=ia64_rt_sigreturn .ret13: adds r3=IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp ;; ld8 r9=[r3] // load new ar.unat - mov rp=r8 + mov b7=r8 ;; + PT_REGS_UNWIND_INFO(0) adds sp=IA64_SWITCH_STACK_SIZE,sp // drop (dummy) switch-stack frame mov ar.unat=r9 - br rp - .endp sys_rt_sigreturn + br b7 +#endif /* !CONFIG_IA64_NEW_UNWIND */ +END(sys_rt_sigreturn) - .align 16 - .global ia64_prepare_handle_unaligned - .proc ia64_prepare_handle_unaligned -ia64_prepare_handle_unaligned: - movl r28=1f +GLOBAL_ENTRY(ia64_prepare_handle_unaligned) // // r16 = fake ar.pfs, we simply need to make sure // privilege is still 0 // + PT_REGS_UNWIND_INFO(0) mov r16=r0 - br.cond.sptk.few save_switch_stack -1: br.call.sptk.few rp=ia64_handle_unaligned // stack frame setup in ivt + DO_SAVE_SWITCH_STACK + br.call.sptk.few rp=ia64_handle_unaligned // stack frame setup in ivt .ret14: - movl r28=2f - br.cond.sptk.many load_switch_stack -2: br.cond.sptk.many rp // goes to ia64_leave_kernel - .endp ia64_prepare_handle_unaligned + DO_LOAD_SWITCH_STACK(PT_REGS_UNWIND_INFO(0)) + br.cond.sptk.many rp // goes to ia64_leave_kernel +END(ia64_prepare_handle_unaligned) + +#ifdef CONFIG_IA64_NEW_UNWIND + + // + // unw_init_running(void (*callback)(info, arg), void *arg) + // +# define EXTRA_FRAME_SIZE ((UNW_FRAME_INFO_SIZE+15)&~15) + +GLOBAL_ENTRY(unw_init_running) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2) + alloc loc1=ar.pfs,2,3,3,0 + ;; + ld8 loc2=[in0],8 + mov loc0=rp + mov r16=loc1 + DO_SAVE_SWITCH_STACK + .body + + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2) + .fframe IA64_SWITCH_STACK_SIZE+EXTRA_FRAME_SIZE + SWITCH_STACK_SAVES(EXTRA_FRAME_SIZE) + adds sp=-EXTRA_FRAME_SIZE,sp + .body + ;; + adds out0=16,sp // &info + mov out1=r13 // current + adds out2=16+EXTRA_FRAME_SIZE,sp // &switch_stack + br.call.sptk.few rp=unw_init_frame_info +1: adds out0=16,sp // &info + mov b6=loc2 + mov loc2=gp // save gp across indirect function call + ;; + ld8 gp=[in0] + mov out1=in1 // arg + br.call.sptk.few rp=b6 // invoke the callback function +1: mov gp=loc2 // restore gp + + // For now, we don't allow changing registers from within + // unw_init_running; if we ever want to allow that, we'd + // have to do a load_switch_stack here: + .restore sp + adds sp=IA64_SWITCH_STACK_SIZE+EXTRA_FRAME_SIZE,sp + + mov ar.pfs=loc1 + mov rp=loc0 + br.ret.sptk.many rp +END(unw_init_running) + +#endif .rodata .align 8 @@ -1053,9 +1113,9 @@ data8 sys_syslog data8 sys_setitimer data8 sys_getitimer - data8 sys_newstat // 1120 - data8 sys_newlstat - data8 sys_newfstat + data8 ia64_oldstat // 1120 + data8 ia64_oldlstat + data8 ia64_oldfstat data8 sys_vhangup data8 sys_lchown data8 sys_vm86 // 1125 @@ -1065,7 +1125,7 @@ data8 sys_setdomainname data8 sys_newuname // 1130 data8 sys_adjtimex - data8 sys_create_module + data8 ia64_create_module data8 sys_init_module data8 sys_delete_module data8 sys_get_kernel_syms // 1135 @@ -1143,9 +1203,9 @@ data8 sys_pivot_root data8 sys_mincore data8 sys_madvise - data8 ia64_ni_syscall // 1210 - data8 ia64_ni_syscall - data8 ia64_ni_syscall + data8 sys_newstat // 1210 + data8 sys_newlstat + data8 sys_newfstat data8 ia64_ni_syscall data8 ia64_ni_syscall data8 ia64_ni_syscall // 1215 @@ -1212,4 +1272,3 @@ data8 ia64_ni_syscall data8 ia64_ni_syscall data8 ia64_ni_syscall - diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/entry.h linux/arch/ia64/kernel/entry.h --- v2.4.0-test1/linux/arch/ia64/kernel/entry.h Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/entry.h Thu Jun 22 07:09:44 2000 @@ -2,7 +2,64 @@ * Preserved registers that are shared between code in ivt.S and entry.S. Be * careful not to step on these! */ -#define pEOI p1 /* should leave_kernel write EOI? */ #define pKern p2 /* will leave_kernel return to kernel-mode? */ #define pSys p4 /* are we processing a (synchronous) system call? */ #define pNonSys p5 /* complement of pSys */ + +#define PT(f) (IA64_PT_REGS_##f##_OFFSET + 16) +#define SW(f) (IA64_SWITCH_STACK_##f##_OFFSET + 16) + +#define PT_REGS_SAVES(off) \ + UNW(.unwabi @svr4, 'i'); \ + UNW(.fframe IA64_PT_REGS_SIZE+16+(off)); \ + UNW(.spillsp rp, PT(CR_IIP)+(off)); \ + UNW(.spillsp ar.pfs, PT(CR_IFS)+(off)); \ + UNW(.spillsp ar.unat, PT(AR_UNAT)+(off)); \ + UNW(.spillsp ar.fpsr, PT(AR_FPSR)+(off)); \ + UNW(.spillsp pr, PT(PR)+(off)); + +#define PT_REGS_UNWIND_INFO(off) \ + UNW(.prologue); \ + PT_REGS_SAVES(off); \ + UNW(.body) + +#define SWITCH_STACK_SAVES(off) \ + UNW(.savesp ar.unat,SW(CALLER_UNAT)+(off)); UNW(.savesp ar.fpsr,SW(AR_FPSR)+(off)); \ + UNW(.spillsp f2,SW(F2)+(off)); UNW(.spillsp f3,SW(F3)+(off)); \ + UNW(.spillsp f4,SW(F4)+(off)); UNW(.spillsp f5,SW(F5)+(off)); \ + UNW(.spillsp f16,SW(F16)+(off)); UNW(.spillsp f17,SW(F17)+(off)); \ + UNW(.spillsp f18,SW(F18)+(off)); UNW(.spillsp f19,SW(F19)+(off)); \ + UNW(.spillsp f20,SW(F20)+(off)); UNW(.spillsp f21,SW(F21)+(off)); \ + UNW(.spillsp f22,SW(F22)+(off)); UNW(.spillsp f23,SW(F23)+(off)); \ + UNW(.spillsp f24,SW(F24)+(off)); UNW(.spillsp f25,SW(F25)+(off)); \ + UNW(.spillsp f26,SW(F26)+(off)); UNW(.spillsp f27,SW(F27)+(off)); \ + UNW(.spillsp f28,SW(F28)+(off)); UNW(.spillsp f29,SW(F29)+(off)); \ + UNW(.spillsp f30,SW(F30)+(off)); UNW(.spillsp f31,SW(F31)+(off)); \ + UNW(.spillsp r4,SW(R4)+(off)); UNW(.spillsp r5,SW(R5)+(off)); \ + UNW(.spillsp r6,SW(R6)+(off)); UNW(.spillsp r7,SW(R7)+(off)); \ + UNW(.spillsp b0,SW(B0)+(off)); UNW(.spillsp b1,SW(B1)+(off)); \ + UNW(.spillsp b2,SW(B2)+(off)); UNW(.spillsp b3,SW(B3)+(off)); \ + UNW(.spillsp b4,SW(B4)+(off)); UNW(.spillsp b5,SW(B5)+(off)); \ + UNW(.spillsp ar.pfs,SW(AR_PFS)+(off)); UNW(.spillsp ar.lc,SW(AR_LC)+(off)); \ + UNW(.spillsp @priunat,SW(AR_UNAT)+(off)); \ + UNW(.spillsp ar.rnat,SW(AR_RNAT)+(off)); UNW(.spillsp ar.bspstore,SW(AR_BSPSTORE)+(off)); \ + UNW(.spillsp pr,SW(PR)+(off)) + +#define DO_SAVE_SWITCH_STACK \ + movl r28=1f; \ + ;; \ + .fframe IA64_SWITCH_STACK_SIZE; \ + adds sp=-IA64_SWITCH_STACK_SIZE,sp; \ + mov b7=r28; \ + SWITCH_STACK_SAVES(0); \ + br.cond.sptk.many save_switch_stack; \ +1: + +#define DO_LOAD_SWITCH_STACK(extra) \ + movl r28=1f; \ + ;; \ + mov b7=r28; \ + br.cond.sptk.many load_switch_stack; \ +1: UNW(.restore sp); \ + extra; \ + adds sp=IA64_SWITCH_STACK_SIZE,sp diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/fw-emu.c linux/arch/ia64/kernel/fw-emu.c --- v2.4.0-test1/linux/arch/ia64/kernel/fw-emu.c Fri Mar 10 16:40:39 2000 +++ linux/arch/ia64/kernel/fw-emu.c Thu Jun 22 07:09:44 2000 @@ -124,7 +124,18 @@ .proc pal_emulator_static pal_emulator_static: mov r8=-1 - cmp.eq p6,p7=6,r28 /* PAL_PTCE_INFO */ + + mov r9=256 + ;; + cmp.gtu p6,p7=r9,r28 /* r28 <= 255? */ +(p6) br.cond.sptk.few static + ;; + mov r9=512 + ;; + cmp.gtu p6,p7=r9,r28 +(p6) br.cond.sptk.few stacked + ;; +static: cmp.eq p6,p7=6,r28 /* PAL_PTCE_INFO */ (p7) br.cond.sptk.few 1f ;; mov r8=0 /* status = 0 */ @@ -157,7 +168,12 @@ ;; mov ar.lc=r9 mov r8=r0 -1: br.cond.sptk.few rp +1: + br.cond.sptk.few rp + +stacked: + br.ret.sptk.few rp + .endp pal_emulator_static\n"); /* Macro to emulate SAL call using legacy IN and OUT calls to CF8, CFC etc.. */ diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/gate.S linux/arch/ia64/kernel/gate.S --- v2.4.0-test1/linux/arch/ia64/kernel/gate.S Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/kernel/gate.S Thu Jun 22 07:09:44 2000 @@ -3,10 +3,11 @@ * each task's text region. For now, it contains the signal * trampoline code only. * - * Copyright (C) 1999 Hewlett-Packard Co - * Copyright (C) 1999 David Mosberger-Tang + * Copyright (C) 1999-2000 Hewlett-Packard Co + * Copyright (C) 1999-2000 David Mosberger-Tang */ +#include #include #include #include @@ -75,15 +76,12 @@ * [sp+16] = sigframe */ - .global ia64_sigtramp - .proc ia64_sigtramp -ia64_sigtramp: +GLOBAL_ENTRY(ia64_sigtramp) ld8 r10=[r3],8 // get signal handler entry point br.call.sptk.many rp=invoke_sighandler - .endp ia64_sigtramp +END(ia64_sigtramp) - .proc invoke_sighandler -invoke_sighandler: +ENTRY(invoke_sighandler) ld8 gp=[r3] // get signal handler's global pointer mov b6=r10 cover // push args in interrupted frame onto backing store @@ -152,10 +150,9 @@ ldf.fill f15=[base1],32 mov r15=__NR_rt_sigreturn break __BREAK_SYSCALL - .endp invoke_sighandler +END(invoke_sighandler) - .proc setup_rbs -setup_rbs: +ENTRY(setup_rbs) flushrs // must be first in insn mov ar.rsc=r0 // put RSE into enforced lazy mode adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp @@ -167,9 +164,9 @@ mov ar.rsc=0xf // set RSE into eager mode, pl 3 invala // invalidate ALAT br.cond.sptk.many back_from_setup_rbs +END(setup_rbs) - .proc restore_rbs -restore_rbs: +ENTRY(restore_rbs) flushrs mov ar.rsc=r0 // put RSE into enforced lazy mode adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp @@ -181,5 +178,4 @@ mov ar.rsc=0xf // (will be restored later on from sc_ar_rsc) // invala not necessary as that will happen when returning to user-mode br.cond.sptk.many back_from_restore_rbs - - .endp restore_rbs +END(restore_rbs) diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/head.S linux/arch/ia64/kernel/head.S --- v2.4.0-test1/linux/arch/ia64/kernel/head.S Sun Feb 13 19:29:03 2000 +++ linux/arch/ia64/kernel/head.S Thu Jun 22 07:09:44 2000 @@ -16,6 +16,7 @@ #include +#include #include #include #include @@ -54,10 +55,12 @@ stringz "Halting kernel\n" .text - .align 16 - .global _start - .proc _start -_start: + +GLOBAL_ENTRY(_start) + UNW(.prologue) + UNW(.save rp, r4) // terminate unwind chain with a NULL rp + UNW(mov r4=r0) + UNW(.body) // set IVT entry point---can't access I/O ports without it movl r3=ia64_ivt ;; @@ -156,12 +159,9 @@ ld8 out0=[r2] br.call.sptk.few b0=console_print self: br.sptk.few self // endless loop - .endp _start +END(_start) - .align 16 - .global ia64_save_debug_regs - .proc ia64_save_debug_regs -ia64_save_debug_regs: +GLOBAL_ENTRY(ia64_save_debug_regs) alloc r16=ar.pfs,1,0,0,0 mov r20=ar.lc // preserve ar.lc mov ar.lc=IA64_NUM_DBG_REGS-1 @@ -177,13 +177,10 @@ br.cloop.sptk.few 1b ;; mov ar.lc=r20 // restore ar.lc - br.ret.sptk.few b0 - .endp ia64_save_debug_regs + br.ret.sptk.few rp +END(ia64_save_debug_regs) - .align 16 - .global ia64_load_debug_regs - .proc ia64_load_debug_regs -ia64_load_debug_regs: +GLOBAL_ENTRY(ia64_load_debug_regs) alloc r16=ar.pfs,1,0,0,0 lfetch.nta [in0] mov r20=ar.lc // preserve ar.lc @@ -200,13 +197,10 @@ br.cloop.sptk.few 1b ;; mov ar.lc=r20 // restore ar.lc - br.ret.sptk.few b0 - .endp ia64_load_debug_regs + br.ret.sptk.few rp +END(ia64_load_debug_regs) - .align 16 - .global __ia64_save_fpu - .proc __ia64_save_fpu -__ia64_save_fpu: +GLOBAL_ENTRY(__ia64_save_fpu) alloc r2=ar.pfs,1,0,0,0 adds r3=16,in0 ;; @@ -354,12 +348,9 @@ stf.spill.nta [in0]=f126,32 stf.spill.nta [ r3]=f127,32 br.ret.sptk.few rp - .endp __ia64_save_fpu +END(__ia64_save_fpu) - .align 16 - .global __ia64_load_fpu - .proc __ia64_load_fpu -__ia64_load_fpu: +GLOBAL_ENTRY(__ia64_load_fpu) alloc r2=ar.pfs,1,0,0,0 adds r3=16,in0 ;; @@ -507,12 +498,9 @@ ldf.fill.nta f126=[in0],32 ldf.fill.nta f127=[ r3],32 br.ret.sptk.few rp - .endp __ia64_load_fpu +END(__ia64_load_fpu) - .align 16 - .global __ia64_init_fpu - .proc __ia64_init_fpu -__ia64_init_fpu: +GLOBAL_ENTRY(__ia64_init_fpu) alloc r2=ar.pfs,0,0,0,0 stf.spill [sp]=f0 mov f32=f0 @@ -644,4 +632,74 @@ ldf.fill f126=[sp] mov f127=f0 br.ret.sptk.few rp - .endp __ia64_init_fpu +END(__ia64_init_fpu) + +/* + * Switch execution mode from virtual to physical or vice versa. + * + * Inputs: + * r16 = new psr to establish + * + * Note: RSE must already be in enforced lazy mode + */ +GLOBAL_ENTRY(ia64_switch_mode) + { + alloc r2=ar.pfs,0,0,0,0 + rsm psr.i | psr.ic // disable interrupts and interrupt collection + mov r15=ip + } + ;; + { + flushrs // must be first insn in group + srlz.i + shr.u r19=r15,61 // r19 <- top 3 bits of current IP + } + ;; + mov cr.ipsr=r16 // set new PSR + add r3=1f-ia64_switch_mode,r15 + xor r15=0x7,r19 // flip the region bits + + mov r17=ar.bsp + mov r14=rp // get return address into a general register + + // switch RSE backing store: + ;; + dep r17=r15,r17,61,3 // make ar.bsp physical or virtual + mov r18=ar.rnat // save ar.rnat + ;; + mov ar.bspstore=r17 // this steps on ar.rnat + dep r3=r15,r3,61,3 // make rfi return address physical or virtual + ;; + mov cr.iip=r3 + mov cr.ifs=r0 + dep sp=r15,sp,61,3 // make stack pointer physical or virtual + ;; + mov ar.rnat=r18 // restore ar.rnat + dep r14=r15,r14,61,3 // make function return address physical or virtual + rfi // must be last insn in group + ;; +1: mov rp=r14 + br.ret.sptk.few rp +END(ia64_switch_mode) + +#ifdef CONFIG_IA64_BRL_EMU + +/* + * Assembly routines used by brl_emu.c to set preserved register state. + */ + +#define SET_REG(reg) \ + GLOBAL_ENTRY(ia64_set_##reg); \ + alloc r16=ar.pfs,1,0,0,0; \ + mov reg=r32; \ + ;; \ + br.ret.sptk rp; \ + END(ia64_set_##reg) + +SET_REG(b1); +SET_REG(b2); +SET_REG(b3); +SET_REG(b4); +SET_REG(b5); + +#endif /* CONFIG_IA64_BRL_EMU */ diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/ia64_ksyms.c linux/arch/ia64/kernel/ia64_ksyms.c --- v2.4.0-test1/linux/arch/ia64/kernel/ia64_ksyms.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/ia64_ksyms.c Thu Jun 22 07:09:44 2000 @@ -0,0 +1,72 @@ +/* + * Architecture-specific kernel symbols + */ + +#include +#include + +#include +EXPORT_SYMBOL_NOVERS(memset); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL_NOVERS(memcpy); +EXPORT_SYMBOL(memmove); +EXPORT_SYMBOL(strcat); +EXPORT_SYMBOL(strchr); +EXPORT_SYMBOL(strcmp); +EXPORT_SYMBOL(strcpy); +EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(strncat); +EXPORT_SYMBOL(strncmp); +EXPORT_SYMBOL(strncpy); +EXPORT_SYMBOL(strtok); + +#include +EXPORT_SYMBOL(pci_alloc_consistent); +EXPORT_SYMBOL(pci_free_consistent); + +#include +#include +EXPORT_SYMBOL(csum_partial_copy_nocheck); + +#include +EXPORT_SYMBOL(enable_irq); +EXPORT_SYMBOL(disable_irq); + +#include +#include +EXPORT_SYMBOL(irq_stat); + +#include +EXPORT_SYMBOL(cpu_data); +EXPORT_SYMBOL(kernel_thread); + +#ifdef CONFIG_SMP +EXPORT_SYMBOL(synchronize_irq); + +#include +EXPORT_SYMBOL(kernel_flag); + +#include +EXPORT_SYMBOL(__global_sti); +EXPORT_SYMBOL(__global_cli); +EXPORT_SYMBOL(__global_save_flags); +EXPORT_SYMBOL(__global_restore_flags); + +#endif + +#include +EXPORT_SYMBOL(__copy_user); + +#include +EXPORT_SYMBOL(__ia64_syscall); + +/* from arch/ia64/lib */ +extern void __divdi3(void); +extern void __udivdi3(void); +extern void __moddi3(void); +extern void __umoddi3(void); + +EXPORT_SYMBOL_NOVERS(__divdi3); +EXPORT_SYMBOL_NOVERS(__udivdi3); +EXPORT_SYMBOL_NOVERS(__moddi3); +EXPORT_SYMBOL_NOVERS(__umoddi3); diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/irq.c linux/arch/ia64/kernel/irq.c --- v2.4.0-test1/linux/arch/ia64/kernel/irq.c Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/kernel/irq.c Thu Jun 22 07:09:44 2000 @@ -201,10 +201,14 @@ printk(" %d",local_bh_count(i)); printk(" ]\nStack dumps:"); -#ifdef __ia64__ - printk(" ]\nStack dumps: "); - /* for now we don't have stack dumping support... */ -#elif __i386__ +#if defined(__ia64__) + /* + * We can't unwind the stack of another CPU without access to + * the registers of that CPU. And sending an IPI when we're + * in a potentially wedged state doesn't sound like a smart + * idea. + */ +#elif defined(__i386__) for(i=0;i< smp_num_cpus;i++) { unsigned long esp; if(i==cpu) @@ -227,9 +231,7 @@ You lose... #endif printk("\nCPU %d:",cpu); -#ifdef __i386__ show_stack(NULL); -#endif printk("\n"); } @@ -582,7 +584,8 @@ if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { action = desc->action; status &= ~IRQ_PENDING; /* we commit to handling */ - status |= IRQ_INPROGRESS; /* we are handling it */ + if (!(status & IRQ_PER_CPU)) + status |= IRQ_INPROGRESS; /* we are handling it */ } desc->status = status; diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/irq_ia64.c linux/arch/ia64/kernel/irq_ia64.c --- v2.4.0-test1/linux/arch/ia64/kernel/irq_ia64.c Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/kernel/irq_ia64.c Thu Jun 22 07:09:44 2000 @@ -33,7 +33,9 @@ #include #include -#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC +#define IRQ_DEBUG 0 + +#ifdef CONFIG_ITANIUM_A1_SPECIFIC spinlock_t ivr_read_lock; #endif @@ -49,7 +51,7 @@ 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x40, 0x41 }; -#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC +#ifdef CONFIG_ITANIUM_A1_SPECIFIC int usbfix; @@ -63,7 +65,7 @@ __setup("usbfix", usbfix_option); -#endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC */ +#endif /* CONFIG_ITANIUM_A1_SPECIFIC */ /* * That's where the IVT branches when we get an external @@ -73,13 +75,8 @@ void ia64_handle_irq (unsigned long vector, struct pt_regs *regs) { - unsigned long bsp, sp, saved_tpr; - -#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC -# ifndef CONFIG_SMP - static unsigned int max_prio = 0; - unsigned int prev_prio; -# endif + unsigned long saved_tpr; +#ifdef CONFIG_ITANIUM_A1_SPECIFIC unsigned long eoi_ptr; # ifdef CONFIG_USB @@ -95,18 +92,14 @@ spin_lock(&ivr_read_lock); { unsigned int tmp; - /* * Disable PCI writes */ outl(0x80ff81c0, 0xcf8); tmp = inl(0xcfc); outl(tmp | 0x400, 0xcfc); - eoi_ptr = inl(0xcfc); - vector = ia64_get_ivr(); - /* * Enable PCI writes */ @@ -118,75 +111,61 @@ if (usbfix) reenable_usb(); # endif +#endif /* CONFIG_ITANIUM_A1_SPECIFIC */ -# ifndef CONFIG_SMP - prev_prio = max_prio; - if (vector < max_prio) { - printk ("ia64_handle_irq: got vector %lu while %u was in progress!\n", - vector, max_prio); - - } else - max_prio = vector; -# endif /* !CONFIG_SMP */ -#endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC */ - - /* - * Always set TPR to limit maximum interrupt nesting depth to - * 16 (without this, it would be ~240, which could easily lead - * to kernel stack overflows. - */ - saved_tpr = ia64_get_tpr(); - ia64_srlz_d(); - ia64_set_tpr(vector); - ia64_srlz_d(); +#if IRQ_DEBUG + { + unsigned long bsp, sp; - asm ("mov %0=ar.bsp" : "=r"(bsp)); - asm ("mov %0=sp" : "=r"(sp)); + asm ("mov %0=ar.bsp" : "=r"(bsp)); + asm ("mov %0=sp" : "=r"(sp)); - if ((sp - bsp) < 1024) { - static long last_time; - static unsigned char count; - - if (count > 5 && jiffies - last_time > 5*HZ) - count = 0; - if (++count < 5) { - last_time = jiffies; - printk("ia64_handle_irq: DANGER: less than 1KB of free stack space!!\n" - "(bsp=0x%lx, sp=%lx)\n", bsp, sp); + if ((sp - bsp) < 1024) { + static unsigned char count; + static long last_time; + + if (count > 5 && jiffies - last_time > 5*HZ) + count = 0; + if (++count < 5) { + last_time = jiffies; + printk("ia64_handle_irq: DANGER: less than " + "1KB of free stack space!!\n" + "(bsp=0x%lx, sp=%lx)\n", bsp, sp); + } } } +#endif /* IRQ_DEBUG */ /* - * The interrupt is now said to be in service + * Always set TPR to limit maximum interrupt nesting depth to + * 16 (without this, it would be ~240, which could easily lead + * to kernel stack overflows). */ - if (vector >= NR_IRQS) { - printk("handle_irq: invalid vector %lu\n", vector); - goto out; - } - - do_IRQ(vector, regs); - out: -#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC - { - long pEOI; - - asm ("mov %0=0;; (p1) mov %0=1" : "=r"(pEOI)); - if (!pEOI) { - printk("Yikes: ia64_handle_irq() without pEOI!!\n"); - asm volatile ("cmp.eq p1,p0=r0,r0" : "=r"(pEOI)); + saved_tpr = ia64_get_tpr(); + ia64_srlz_d(); + do { + if (vector >= NR_IRQS) { + printk("handle_irq: invalid vector %lu\n", vector); + ia64_set_tpr(saved_tpr); + ia64_srlz_d(); + return; } - } + ia64_set_tpr(vector); + ia64_srlz_d(); - local_irq_disable(); -# ifndef CONFIG_SMP - if (max_prio == vector) - max_prio = prev_prio; -# endif /* !CONFIG_SMP */ -#endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC */ + do_IRQ(vector, regs); - ia64_srlz_d(); - ia64_set_tpr(saved_tpr); - ia64_srlz_d(); + /* + * Disable interrupts and send EOI: + */ + local_irq_disable(); + ia64_set_tpr(saved_tpr); + ia64_eoi(); +#ifdef CONFIG_ITANIUM_A1_SPECIFIC + break; +#endif + vector = ia64_get_ivr(); + } while (vector != IA64_SPURIOUS_INT); } #ifdef CONFIG_SMP @@ -210,12 +189,12 @@ ia64_set_lrr0(0, 1); ia64_set_lrr1(0, 1); - irq_desc[TIMER_IRQ].handler = &irq_type_ia64_sapic; irq_desc[IA64_SPURIOUS_INT].handler = &irq_type_ia64_sapic; #ifdef CONFIG_SMP /* * Configure the IPI vector and handler */ + irq_desc[IPI_IRQ].status |= IRQ_PER_CPU; irq_desc[IPI_IRQ].handler = &irq_type_ia64_sapic; setup_irq(IPI_IRQ, &ipi_irqaction); #endif @@ -234,7 +213,7 @@ { unsigned long ipi_addr; unsigned long ipi_data; -#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC +#ifdef CONFIG_ITANIUM_A1_SPECIFIC unsigned long flags; #endif # define EID 0 @@ -242,13 +221,13 @@ ipi_data = (delivery_mode << 8) | (vector & 0xff); ipi_addr = ipi_base_addr | ((cpu << 8 | EID) << 4) | ((redirect & 1) << 3); -#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC +#ifdef CONFIG_ITANIUM_A1_SPECIFIC spin_lock_irqsave(&ivr_read_lock, flags); -#endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC */ +#endif writeq(ipi_data, ipi_addr); -#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC +#ifdef CONFIG_ITANIUM_A1_SPECIFIC spin_unlock_irqrestore(&ivr_read_lock, flags); #endif } diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/ivt.S linux/arch/ia64/kernel/ivt.S --- v2.4.0-test1/linux/arch/ia64/kernel/ivt.S Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/kernel/ivt.S Thu Jun 22 07:09:44 2000 @@ -170,9 +170,31 @@ * The ITLB basically does the same as the VHPT handler except * that we always insert exactly one instruction TLB entry. */ +#if 0 + /* + * This code works, but I don't want to enable it until I have numbers + * that prove this to be a win. + */ + mov r31=pr // save predicates + ;; + thash r17=r16 // compute virtual address of L3 PTE + ;; + ld8.s r18=[r17] // try to read L3 PTE + ;; + tnat.nz p6,p0=r18 // did read succeed? +(p6) br.cond.spnt.many 1f + ;; + itc.i r18 + ;; + mov pr=r31,-1 + rfi + +1: rsm psr.dt // use physical addressing for data +#else mov r16=cr.ifa // get address that caused the TLB miss ;; rsm psr.dt // use physical addressing for data +#endif mov r31=pr // save the predicate registers mov r19=ar.k7 // get page table base address shl r21=r16,3 // shift bit 60 into sign bit @@ -222,9 +244,31 @@ * that we always insert exactly one data TLB entry. */ mov r16=cr.ifa // get address that caused the TLB miss +#if 0 + /* + * This code works, but I don't want to enable it until I have numbers + * that prove this to be a win. + */ + mov r31=pr // save predicates + ;; + thash r17=r16 // compute virtual address of L3 PTE + ;; + ld8.s r18=[r17] // try to read L3 PTE + ;; + tnat.nz p6,p0=r18 // did read succeed? +(p6) br.cond.spnt.many 1f + ;; + itc.d r18 ;; + mov pr=r31,-1 + rfi + +1: rsm psr.dt // use physical addressing for data +#else rsm psr.dt // use physical addressing for data mov r31=pr // save the predicate registers + ;; +#endif mov r19=ar.k7 // get page table base address shl r21=r16,3 // shift bit 60 into sign bit shr.u r17=r16,61 // get the region number into r17 @@ -265,37 +309,6 @@ mov pr=r31,-1 // restore predicate registers rfi - //----------------------------------------------------------------------------------- - // call do_page_fault (predicates are in r31, psr.dt is off, r16 is faulting address) -page_fault: - SAVE_MIN_WITH_COVER - // - // Copy control registers to temporary registers, then turn on psr bits, - // then copy the temporary regs to the output regs. We have to do this - // because the "alloc" can cause a mandatory store which could lead to - // an "Alt DTLB" fault which we can handle only if psr.ic is on. - // - mov r8=cr.ifa - mov r9=cr.isr - adds r3=8,r2 // set up second base pointer - ;; - ssm psr.ic | psr.dt - ;; - srlz.i // guarantee that interrupt collection is enabled - ;; -(p15) ssm psr.i // restore psr.i - movl r14=ia64_leave_kernel - ;; - alloc r15=ar.pfs,0,0,3,0 // must be first in insn group - mov out0=r8 - mov out1=r9 - ;; - SAVE_REST - mov rp=r14 - ;; - adds out2=16,r12 // out2 = pointer to pt_regs - br.call.sptk.few b6=ia64_do_page_fault // ignore return address - .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x0c00 Entry 3 (size 64 bundles) Alt ITLB (19) @@ -303,7 +316,7 @@ movl r17=__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RX ;; shr.u r18=r16,57 // move address bit 61 to bit 4 - dep r16=0,r16,IA64_PHYS_BITS,(64-IA64_PHYS_BITS) // clear ed, resvd, and unimpl. phys bits + dep r16=0,r16,IA64_MAX_PHYS_BITS,(64-IA64_MAX_PHYS_BITS) // clear ed & reserved bits ;; andcm r18=0x10,r18 // bit 4=~address-bit(61) dep r16=r17,r16,0,12 // insert PTE control bits into r16 @@ -318,18 +331,58 @@ // 0x1000 Entry 4 (size 64 bundles) Alt DTLB (7,46) mov r16=cr.ifa // get address that caused the TLB miss movl r17=__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RW + mov r20=cr.isr + mov r21=cr.ipsr + mov r19=pr ;; + tbit.nz p6,p7=r20,IA64_ISR_SP_BIT // is speculation bit on? shr.u r18=r16,57 // move address bit 61 to bit 4 - dep r16=0,r16,IA64_PHYS_BITS,(64-IA64_PHYS_BITS) // clear ed, resvd, and unimpl. phys bits + dep r16=0,r16,IA64_MAX_PHYS_BITS,(64-IA64_MAX_PHYS_BITS) // clear ed & reserved bits ;; + dep r21=-1,r21,IA64_PSR_ED_BIT,1 andcm r18=0x10,r18 // bit 4=~address-bit(61) dep r16=r17,r16,0,12 // insert PTE control bits into r16 ;; or r16=r16,r18 // set bit 4 (uncached) if the access was to region 6 +(p6) mov cr.ipsr=r21 ;; - itc.d r16 // insert the TLB entry +(p7) itc.d r16 // insert the TLB entry + mov pr=r19,-1 rfi + ;; + + //----------------------------------------------------------------------------------- + // call do_page_fault (predicates are in r31, psr.dt is off, r16 is faulting address) +page_fault: + SAVE_MIN_WITH_COVER + // + // Copy control registers to temporary registers, then turn on psr bits, + // then copy the temporary regs to the output regs. We have to do this + // because the "alloc" can cause a mandatory store which could lead to + // an "Alt DTLB" fault which we can handle only if psr.ic is on. + // + mov r8=cr.ifa + mov r9=cr.isr + adds r3=8,r2 // set up second base pointer + ;; + ssm psr.ic | psr.dt + ;; + srlz.i // guarantee that interrupt collection is enabled + ;; +(p15) ssm psr.i // restore psr.i + movl r14=ia64_leave_kernel + ;; + alloc r15=ar.pfs,0,0,3,0 // must be first in insn group + mov out0=r8 + mov out1=r9 + ;; + SAVE_REST + mov rp=r14 + ;; + adds out2=16,r12 // out2 = pointer to pt_regs + br.call.sptk.few b6=ia64_do_page_fault // ignore return address + .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x1400 Entry 5 (size 64 bundles) Data nested TLB (6,45) @@ -338,7 +391,7 @@ // Access-bit, or Data Access-bit faults cause a nested fault because the // dTLB entry for the virtual page table isn't present. In such a case, // we lookup the pte for the faulting address by walking the page table - // and return to the contination point passed in register r30. + // and return to the continuation point passed in register r30. // In accessing the page tables, we don't need to check for NULL entries // because if the page tables didn't map the faulting address, it would not // be possible to receive one of the above faults. @@ -441,9 +494,6 @@ tbit.z p6,p0=r17,IA64_PSR_IS_BIT // IA64 instruction set? ;; (p6) mov r16=r18 // if so, use cr.iip instead of cr.ifa -#if 0 - ;; -#endif mov pr=r31,-1 #endif /* CONFIG_ITANIUM */ movl r30=1f // load continuation point in case of nested fault @@ -489,7 +539,6 @@ ;; srlz.d // ensure everyone knows psr.dt is off... cmp.eq p0,p7=r16,r17 // is this a system call? (p7 <- false, if so) - #if 1 // Allow syscalls via the old system call number for the time being. This is // so we can transition to the new syscall number in a relatively smooth @@ -498,7 +547,6 @@ ;; (p7) cmp.eq.or.andcm p0,p7=r16,r17 // is this the old syscall number? #endif - (p7) br.cond.spnt.many non_syscall SAVE_MIN // uses r31; defines r2: @@ -575,13 +623,12 @@ ssm psr.ic | psr.dt // turn interrupt collection and data translation back on ;; adds r3=8,r2 // set up second base pointer for SAVE_REST - cmp.eq pEOI,p0=r0,r0 // set pEOI flag so that ia64_leave_kernel writes cr.eoi srlz.i // ensure everybody knows psr.ic and psr.dt are back on ;; SAVE_REST ;; alloc r14=ar.pfs,0,0,2,0 // must be first in an insn group -#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC +#ifdef CONFIG_ITANIUM_A1_SPECIFIC mov out0=r0 // defer reading of cr.ivr to handle_irq... #else mov out0=cr.ivr // pass cr.ivr as first arg @@ -609,6 +656,50 @@ // 0x3c00 Entry 15 (size 64 bundles) Reserved FAULT(15) +// +// Squatting in this space ... +// +// This special case dispatcher for illegal operation faults +// allows preserved registers to be modified through a +// callback function (asm only) that is handed back from +// the fault handler in r8. Up to three arguments can be +// passed to the callback function by returning an aggregate +// with the callback as its first element, followed by the +// arguments. +// +dispatch_illegal_op_fault: + SAVE_MIN_WITH_COVER + // + // The "alloc" can cause a mandatory store which could lead to + // an "Alt DTLB" fault which we can handle only if psr.ic is on. + // + ssm psr.ic | psr.dt + ;; + srlz.i // guarantee that interrupt collection is enabled + ;; +(p15) ssm psr.i // restore psr.i + adds r3=8,r2 // set up second base pointer for SAVE_REST + ;; + alloc r14=ar.pfs,0,0,1,0 // must be first in insn group + mov out0=ar.ec + ;; + SAVE_REST + ;; + br.call.sptk.few rp=ia64_illegal_op_fault + ;; + alloc r14=ar.pfs,0,0,3,0 // must be first in insn group + mov out0=r9 + mov out1=r10 + mov out2=r11 + movl r15=ia64_leave_kernel + ;; + mov rp=r15 + mov b6=r8 + ;; + cmp.ne p6,p0=0,r8 +(p6) br.call.dpnt b6=b6 // call returns to ia64_leave_kernel + br.sptk ia64_leave_kernel + .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x4000 Entry 16 (size 64 bundles) Reserved @@ -643,14 +734,17 @@ (p6) br.call.dpnt.few b6=non_ia32_syscall adds r14=IA64_PT_REGS_R8_OFFSET + 16,sp // 16 byte hole per SW conventions - + adds r15=IA64_PT_REGS_R1_OFFSET + 16,sp + ;; + cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0 + st8 [r15]=r8 // save orignal EAX in r1 (IA32 procs don't use the GP) ;; alloc r15=ar.pfs,0,0,6,0 // must first in an insn group ;; ld4 r8=[r14],8 // r8 == EAX (syscall number) - mov r15=0xff + mov r15=190 // sys_vfork - last implemented system call ;; - cmp.ltu.unc p6,p7=r8,r15 + cmp.leu.unc p6,p7=r8,r15 ld4 out1=[r14],8 // r9 == ecx ;; ld4 out2=[r14],8 // r10 == edx @@ -868,7 +962,16 @@ .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x5400 Entry 24 (size 16 bundles) General Exception (5,32,34,36,38,39) - FAULT(24) + mov r16=cr.isr + mov r31=pr + rsm psr.dt // avoid nested faults due to TLB misses... + ;; + srlz.d // ensure everyone knows psr.dt is off... + cmp4.eq p6,p0=0,r16 +(p6) br.sptk dispatch_illegal_op_fault + ;; + mov r19=24 // fault number + br.cond.sptk.many dispatch_to_fault_handler .align 256 ///////////////////////////////////////////////////////////////////////////////////////// @@ -939,7 +1042,6 @@ mov r31=pr // prepare to save predicates ;; srlz.d // ensure everyone knows psr.dt is off - mov r19=30 // error vector for fault_handler (when kernel) br.cond.sptk.many dispatch_unaligned_handler .align 256 diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/mca.c linux/arch/ia64/kernel/mca.c --- v2.4.0-test1/linux/arch/ia64/kernel/mca.c Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/kernel/mca.c Fri Jun 23 21:11:20 2000 @@ -9,15 +9,16 @@ * Copyright (C) 1999 Silicon Graphics, Inc. * Copyright (C) Vijay Chander(vijay@engr.sgi.com) * - * 00/03/29 C. Fleckenstein Fixed PAL/SAL update issues, began MCA bug fixes, logging issues, + * 00/03/29 C. Fleckenstein Fixed PAL/SAL update issues, began MCA bug fixes, + * logging issues, * added min save state dump, added INIT handler. */ +#include #include #include #include #include #include -#include #include #include diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/mca_asm.S linux/arch/ia64/kernel/mca_asm.S --- v2.4.0-test1/linux/arch/ia64/kernel/mca_asm.S Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/kernel/mca_asm.S Thu Jun 22 07:09:44 2000 @@ -6,7 +6,6 @@ // 00/03/29 cfleck Added code to save INIT handoff state in pt_regs format, switch to temp kstack, // switch modes, jump to C INIT handler // -#include #include #include #include diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/minstate.h linux/arch/ia64/kernel/minstate.h --- v2.4.0-test1/linux/arch/ia64/kernel/minstate.h Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/kernel/minstate.h Thu Jun 22 07:09:44 2000 @@ -101,7 +101,6 @@ ;; \ st8 [r16]=r18,16; /* save ar.rsc value for "loadrs" */ \ st8.spill [r17]=rR1,16; /* save original r1 */ \ - cmp.ne pEOI,p0=r0,r0 /* clear pEOI by default */ \ ;; \ .mem.offset 0,0; st8.spill [r16]=r2,16; \ .mem.offset 8,0; st8.spill [r17]=r3,16; \ diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/pal.S linux/arch/ia64/kernel/pal.S --- v2.4.0-test1/linux/arch/ia64/kernel/pal.S Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/pal.S Thu Jun 22 07:09:44 2000 @@ -4,9 +4,16 @@ * * Copyright (C) 1999 Don Dugger * Copyright (C) 1999 Walt Drummond - * Copyright (C) 1999 David Mosberger + * Copyright (C) 1999-2000 David Mosberger + * Copyright (C) 2000 Stephane Eranian + * + * 05/22/2000 eranian Added support for stacked register calls + * 05/24/2000 eranian Added support for physical mode static calls */ +#include +#include + .text .psr abi64 .psr lsb @@ -24,29 +31,23 @@ * * in0 Address of the PAL entry point (text address, NOT a function descriptor). */ - .align 16 - .global ia64_pal_handler_init - .proc ia64_pal_handler_init -ia64_pal_handler_init: +GLOBAL_ENTRY(ia64_pal_handler_init) alloc r3=ar.pfs,1,0,0,0 movl r2=pal_entry_point ;; st8 [r2]=in0 br.ret.sptk.few rp - - .endp ia64_pal_handler_init +END(ia64_pal_handler_init) /* * Default PAL call handler. This needs to be coded in assembly because it uses * the static calling convention, i.e., the RSE may not be used and calls are * done via "br.cond" (not "br.call"). */ - .align 16 - .global ia64_pal_default_handler - .proc ia64_pal_default_handler -ia64_pal_default_handler: +GLOBAL_ENTRY(ia64_pal_default_handler) mov r8=-1 br.cond.sptk.few rp +END(ia64_pal_default_handler) /* * Make a PAL call using the static calling convention. @@ -56,64 +57,139 @@ * in2 - in4 Remaning PAL arguments * */ +GLOBAL_ENTRY(ia64_pal_call_static) + UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(6)) + alloc loc1 = ar.pfs,6,90,0,0 + movl loc2 = pal_entry_point +1: { + mov r28 = in0 + mov r29 = in1 + mov r8 = ip + } + ;; + ld8 loc2 = [loc2] // loc2 <- entry point + mov r30 = in2 + mov r31 = in3 + ;; + mov loc3 = psr + mov loc0 = rp + UNW(.body) + adds r8 = .ret0-1b,r8 + ;; + rsm psr.i + mov b7 = loc2 + mov rp = r8 + ;; + br.cond.sptk.few b7 +.ret0: mov psr.l = loc3 + mov ar.pfs = loc1 + mov rp = loc0 + ;; + srlz.d // seralize restoration of psr.l + br.ret.sptk.few b0 +END(ia64_pal_call_static) -#ifdef __GCC_MULTIREG_RETVALS__ -# define arg0 in0 -# define arg1 in1 -# define arg2 in2 -# define arg3 in3 -# define arg4 in4 -#else -# define arg0 in1 -# define arg1 in2 -# define arg2 in3 -# define arg3 in4 -# define arg4 in5 -#endif +/* + * Make a PAL call using the stacked registers calling convention. + * + * Inputs: + * in0 Index of PAL service + * in2 - in3 Remaning PAL arguments + */ +GLOBAL_ENTRY(ia64_pal_call_stacked) + UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5)) + alloc loc1 = ar.pfs,5,4,87,0 + movl loc2 = pal_entry_point + + mov r28 = in0 // Index MUST be copied to r28 + mov out0 = in0 // AND in0 of PAL function + mov loc0 = rp + UNW(.body) + ;; + ld8 loc2 = [loc2] // loc2 <- entry point + mov out1 = in1 + mov out2 = in2 + mov out3 = in3 + mov loc3 = psr + ;; + rsm psr.i + mov b7 = loc2 + ;; + br.call.sptk.many rp=b7 // now make the call +.ret2: + mov psr.l = loc3 + mov ar.pfs = loc1 + mov rp = loc0 + ;; + srlz.d // serialize restoration of psr.l + br.ret.sptk.few b0 +END(ia64_pal_call_stacked) - .text - .psr abi64 - .psr lsb - .lsb +/* + * Make a physical mode PAL call using the static registers calling convention. + * + * Inputs: + * in0 Index of PAL service + * in2 - in3 Remaning PAL arguments + * + * PSR_DB, PSR_LP, PSR_TB, PSR_ID, PSR_DA are never set by the kernel. + * So we don't need to clear them. + */ +#define PAL_PSR_BITS_TO_CLEAR \ + (IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | IA64_PSR_RT | \ + IA64_PSR_DD | IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | \ + IA64_PSR_DFL | IA64_PSR_DFH) + +#define PAL_PSR_BITS_TO_SET \ + (IA64_PSR_BN) - .align 16 - .global ia64_pal_call_static - .proc ia64_pal_call_static -ia64_pal_call_static: - alloc loc0 = ar.pfs,6,90,0,0 - movl loc2 = pal_entry_point + +GLOBAL_ENTRY(ia64_pal_call_phys_static) + UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(6)) + alloc loc1 = ar.pfs,6,90,0,0 + movl loc2 = pal_entry_point 1: { - mov r28 = arg0 - mov r29 = arg1 - mov r8 = ip + mov r28 = in0 // copy procedure index + mov r8 = ip // save ip to compute branch + mov loc0 = rp // save rp } + UNW(.body) ;; - ld8 loc2 = [loc2] // loc2 <- entry point - mov r30 = arg2 - mov r31 = arg3 - ;; - mov loc3 = psr - mov loc1 = rp - adds r8 = .ret0-1b,r8 - ;; - rsm psr.i - mov b7 = loc2 - mov rp = r8 + ld8 loc2 = [loc2] // loc2 <- entry point + mov r29 = in1 // first argument + mov r30 = in2 // copy arg2 + mov r31 = in3 // copy arg3 + ;; + mov loc3 = psr // save psr + adds r8 = .ret4-1b,r8 // calculate return address for call ;; + mov loc4=ar.rsc // save RSE configuration + dep.z loc2=loc2,0,61 // convert pal entry point to physical + dep.z r8=r8,0,61 // convert rp to physical + ;; + mov b7 = loc2 // install target to branch reg + mov ar.rsc=r0 // put RSE in enforced lazy, LE mode + movl r16=PAL_PSR_BITS_TO_CLEAR + movl r17=PAL_PSR_BITS_TO_SET + ;; + or loc3=loc3,r17 // add in psr the bits to set + ;; + andcm r16=loc3,r16 // removes bits to clear from psr + br.call.sptk.few rp=ia64_switch_mode +.ret3: + mov rp = r8 // install return address (physical) br.cond.sptk.few b7 -.ret0: mov psr.l = loc3 -#ifndef __GCC_MULTIREG_RETVALS__ - st8 [in0] = r8, 8 - ;; - st8 [in0] = r9, 8 - ;; - st8 [in0] = r10, 8 - ;; - st8 [in0] = r11, 8 -#endif - mov ar.pfs = loc0 - mov rp = loc1 +.ret4: + mov ar.rsc=r0 // put RSE in enforced lazy, LE mode + mov r16=loc3 // r16= original psr + br.call.sptk.few rp=ia64_switch_mode // return to virtual mode + +.ret5: mov psr.l = loc3 // restore init PSR + + mov ar.pfs = loc1 + mov rp = loc0 ;; + mov ar.rsc=loc4 // restore RSE configuration srlz.d // seralize restoration of psr.l br.ret.sptk.few b0 - .endp ia64_pal_call_static +END(ia64_pal_call_phys_static) diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/palinfo.c linux/arch/ia64/kernel/palinfo.c --- v2.4.0-test1/linux/arch/ia64/kernel/palinfo.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/palinfo.c Thu Jun 22 07:09:44 2000 @@ -0,0 +1,780 @@ +/* + * palinfo.c + * + * Prints processor specific information reported by PAL. + * This code is based on specification of PAL as of the + * Intel IA-64 Architecture Software Developer's Manual v1.0. + * + * + * Copyright (C) 2000 Hewlett-Packard Co + * Copyright (C) 2000 Stephane Eranian + * + * 05/26/2000 S.Eranian initial release + * + * ISSUES: + * - because of some PAL bugs, some calls return invalid results or + * are empty for now. + * - remove hack to avoid problem with <= 256M RAM for itr. + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * Hope to get rid of these in a near future +*/ +#define IA64_PAL_VERSION_BUG 1 + +#define PALINFO_VERSION "0.1" + +typedef int (*palinfo_func_t)(char*); + +typedef struct { + const char *name; /* name of the proc entry */ + palinfo_func_t proc_read; /* function to call for reading */ + struct proc_dir_entry *entry; /* registered entry (removal) */ +} palinfo_entry_t; + +static struct proc_dir_entry *palinfo_dir; + +/* + * A bunch of string array to get pretty printing + */ + +static char *cache_types[] = { + "", /* not used */ + "Instruction", + "Data", + "Data/Instruction" /* unified */ +}; + +static const char *cache_mattrib[]={ + "WriteThrough", + "WriteBack", + "", /* reserved */ + "" /* reserved */ +}; + +static const char *cache_st_hints[]={ + "Temporal, level 1", + "Reserved", + "Reserved", + "Non-temporal, all levels", + "Reserved", + "Reserved", + "Reserved", + "Reserved" +}; + +static const char *cache_ld_hints[]={ + "Temporal, level 1", + "Non-temporal, level 1", + "Reserved", + "Non-temporal, all levels", + "Reserved", + "Reserved", + "Reserved", + "Reserved" +}; + +static const char *rse_hints[]={ + "enforced lazy", + "eager stores", + "eager loads", + "eager loads and stores" +}; + +#define RSE_HINTS_COUNT (sizeof(rse_hints)/sizeof(const char *)) + +/* + * The current resvision of the Volume 2 of + * IA-64 Architecture Software Developer's Manual is wrong. + * Table 4-10 has invalid information concerning the ma field: + * Correct table is: + * bit 0 - 001 - UC + * bit 4 - 100 - UC + * bit 5 - 101 - UCE + * bit 6 - 110 - WC + * bit 7 - 111 - NatPage + */ +static const char *mem_attrib[]={ + "Write Back (WB)", /* 000 */ + "Uncacheable (UC)", /* 001 */ + "Reserved", /* 010 */ + "Reserved", /* 011 */ + "Uncacheable (UC)", /* 100 */ + "Uncacheable Exported (UCE)", /* 101 */ + "Write Coalescing (WC)", /* 110 */ + "NaTPage" /* 111 */ +}; + + + +/* + * Allocate a buffer suitable for calling PAL code in Virtual mode + * + * The documentation (PAL2.6) requires thius buffer to have a pinned + * translation to avoid any DTLB faults. For this reason we allocate + * a page (large enough to hold any possible reply) and use a DTC + * to hold the translation during the call. A call the free_palbuffer() + * is required to release ALL resources (page + translation). + * + * The size of the page allocated is based on the PAGE_SIZE defined + * at compile time for the kernel, i.e. >= 4Kb. + * + * Return: a pointer to the newly allocated page (virtual address) + */ +static void * +get_palcall_buffer(void) +{ + void *tmp; + + tmp = (void *)__get_free_page(GFP_KERNEL); + if (tmp == 0) { + printk(KERN_ERR "%s: can't get a buffer page\n", __FUNCTION__); + } else if ( ((u64)tmp - PAGE_OFFSET) > (1<<_PAGE_SIZE_256M) ) { /* XXX: temporary hack */ + unsigned long flags; + + /* PSR.ic must be zero to insert new DTR */ + ia64_clear_ic(flags); + + /* + * we only insert of DTR + * + * XXX: we need to figure out a way to "allocate" TR(s) to avoid + * conflicts. Maybe something in an include file like pgtable.h + * page.h or processor.h + * + * ITR0/DTR0: used for kernel code/data + * ITR1/DTR1: used by HP simulator + * ITR2/DTR2: used to map PAL code + */ + ia64_itr(0x2, 3, (u64)tmp, + pte_val(mk_pte_phys(__pa(tmp), __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RW))), PAGE_SHIFT); + + ia64_srlz_d (); + + __restore_flags(flags); + } + + return tmp; +} + +/* + * Free a palcall buffer allocated with the previous call + * + * The translation is also purged. + */ +static void +free_palcall_buffer(void *addr) +{ + __free_page(addr); + ia64_ptr(0x2, (u64)addr, PAGE_SHIFT); + ia64_srlz_d (); +} + +/* + * Take a 64bit vector and produces a string such that + * if bit n is set then 2^n in clear text is generated. The adjustment + * to the right unit is also done. + * + * Input: + * - a pointer to a buffer to hold the string + * - a 64-bit vector + * Ouput: + * - a pointer to the end of the buffer + * + */ +static char * +bitvector_process(char *p, u64 vector) +{ + int i,j; + const char *units[]={ "", "K", "M", "G", "T" }; + + for (i=0, j=0; i < 64; i++ , j=i/10) { + if (vector & 0x1) { + p += sprintf(p, "%d%s ", 1 << (i-j*10), units[j]); + } + vector >>= 1; + } + return p; +} + +/* + * Take a 64bit vector and produces a string such that + * if bit n is set then register n is present. The function + * takes into account consecutive registers and prints out ranges. + * + * Input: + * - a pointer to a buffer to hold the string + * - a 64-bit vector + * Ouput: + * - a pointer to the end of the buffer + * + */ +static char * +bitregister_process(char *p, u64 *reg_info, int max) +{ + int i, begin, skip = 0; + u64 value = reg_info[0]; + + value >>= i = begin = ffs(value) - 1; + + for(; i < max; i++ ) { + + if (i != 0 && (i%64) == 0) value = *++reg_info; + + if ((value & 0x1) == 0 && skip == 0) { + if (begin <= i - 2) + p += sprintf(p, "%d-%d ", begin, i-1); + else + p += sprintf(p, "%d ", i-1); + skip = 1; + begin = -1; + } else if ((value & 0x1) && skip == 1) { + skip = 0; + begin = i; + } + value >>=1; + } + if (begin > -1) { + if (begin < 127) + p += sprintf(p, "%d-127", begin); + else + p += sprintf(p, "127"); + } + + return p; +} + +static int +power_info(char *page) +{ + s64 status; + char *p = page; + pal_power_mgmt_info_u_t *halt_info; + int i; + + halt_info = get_palcall_buffer(); + if (halt_info == 0) return 0; + + status = ia64_pal_halt_info(halt_info); + if (status != 0) { + free_palcall_buffer(halt_info); + return 0; + } + + for (i=0; i < 8 ; i++ ) { + if (halt_info[i].pal_power_mgmt_info_s.im == 1) { + p += sprintf(p, "Power level %d:\n" \ + "\tentry_latency : %d cycles\n" \ + "\texit_latency : %d cycles\n" \ + "\tpower consumption : %d mW\n" \ + "\tCache+TLB coherency : %s\n", i, + halt_info[i].pal_power_mgmt_info_s.entry_latency, + halt_info[i].pal_power_mgmt_info_s.exit_latency, + halt_info[i].pal_power_mgmt_info_s.power_consumption, + halt_info[i].pal_power_mgmt_info_s.co ? "Yes" : "No"); + } else { + p += sprintf(p,"Power level %d: not implemented\n",i); + } + } + + free_palcall_buffer(halt_info); + + return p - page; +} + +static int +cache_info(char *page) +{ + char *p = page; + u64 levels, unique_caches; + pal_cache_config_info_t cci; + int i,j, k; + s64 status; + + if ((status=ia64_pal_cache_summary(&levels, &unique_caches)) != 0) { + printk("ia64_pal_cache_summary=%ld\n", status); + return 0; + } + + p += sprintf(p, "Cache levels : %ld\n" \ + "Unique caches : %ld\n\n", + levels, + unique_caches); + + for (i=0; i < levels; i++) { + + for (j=2; j >0 ; j--) { + + /* even without unification some level may not be present */ + if ((status=ia64_pal_cache_config_info(i,j, &cci)) != 0) { + continue; + } + p += sprintf(p, "%s Cache level %d:\n" \ + "\tSize : %ld bytes\n" \ + "\tAttributes : ", + cache_types[j+cci.pcci_unified], i+1, + cci.pcci_cache_size); + + if (cci.pcci_unified) p += sprintf(p, "Unified "); + + p += sprintf(p, "%s\n", cache_mattrib[cci.pcci_cache_attr]); + + p += sprintf(p, "\tAssociativity : %d\n" \ + "\tLine size : %d bytes\n" \ + "\tStride : %d bytes\n", + cci.pcci_assoc, + 1<>=1; + } + p += sprintf(p, "\n\tLoad hints : "); + + for(k=0; k < 8; k++ ) { + if ( cci.pcci_ld_hints & 0x1) p += sprintf(p, "[%s]", cache_ld_hints[k]); + cci.pcci_ld_hints >>=1; + } + p += sprintf(p, "\n\tAlias boundary : %d byte(s)\n" \ + "\tTag LSB : %d\n" \ + "\tTag MSB : %d\n", + 1<0 ; j--) { + tc_pages = 0; /* just in case */ + + + /* even without unification, some levels may not be present */ + if ((status=ia64_pal_vm_info(i,j, &tc_info, &tc_pages)) != 0) { + continue; + } + + p += sprintf(p, "\n%s Translation Cache Level %d:\n" \ + "\tHash sets : %d\n" \ + "\tAssociativity : %d\n" \ + "\tNumber of entries : %d\n" \ + "\tFlags : ", + cache_types[j+tc_info.tc_unified], i+1, + tc_info.tc_num_sets, + tc_info.tc_associativity, + tc_info.tc_num_entries); + + if (tc_info.tc_pf) p += sprintf(p, "PreferredPageSizeOptimized "); + if (tc_info.tc_unified) p += sprintf(p, "Unified "); + if (tc_info.tc_reduce_tr) p += sprintf(p, "TCReduction"); + + p += sprintf(p, "\n\tSupported page sizes: "); + + p = bitvector_process(p, tc_pages); + + /* when unified date (j=2) is enough */ + if (tc_info.tc_unified) break; + } + } + p += sprintf(p, "\n"); + + return p - page; +} + + +static int +register_info(char *page) +{ + char *p = page; + u64 reg_info[2]; + u64 info; + u64 phys_stacked; + pal_hints_u_t hints; + u64 iregs, dregs; + char *info_type[]={ + "Implemented AR(s)", + "AR(s) with read side-effects", + "Implemented CR(s)", + "CR(s) with read side-effects", + }; + + for(info=0; info < 4; info++) { + + if (ia64_pal_register_info(info, ®_info[0], ®_info[1]) != 0) return 0; + + p += sprintf(p, "%-32s : ", info_type[info]); + + p = bitregister_process(p, reg_info, 128); + + p += sprintf(p, "\n"); + } + + if (ia64_pal_rse_info(&phys_stacked, &hints) != 0) return 0; + + p += sprintf(p, "RSE stacked physical registers : %ld\n" \ + "RSE load/store hints : %ld (%s)\n", + phys_stacked, + hints.ph_data, + hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(??)"); + + if (ia64_pal_debug_info(&iregs, &dregs)) return 0; + + p += sprintf(p, "Instruction debug register pairs : %ld\n" \ + "Data debug register pairs : %ld\n", + iregs, dregs); + + return p - page; +} + +static const char *proc_features[]={ + NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, + NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL, + NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, + NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL, + NULL,NULL,NULL,NULL,NULL, + "XIP,XPSR,XFS implemented", + "XR1-XR3 implemented", + "Disable dynamic predicate prediction", + "Disable processor physical number", + "Disable dynamic data cache prefetch", + "Disable dynamic inst cache prefetch", + "Disable dynamic branch prediction", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "Disable BINIT on processor time-out", + "Disable dynamic power management (DPM)", + "Disable coherency", + "Disable cache", + "Enable CMCI promotion", + "Enable MCA to BINIT promotion", + "Enable MCA promotion", + "Enable BEER promotion" +}; + + +static int +processor_info(char *page) +{ + char *p = page; + const char **v = proc_features; + u64 avail=1, status=1, control=1; + int i; + s64 ret; + + /* must be in physical mode */ + if ((ret=ia64_pal_proc_get_features(&avail, &status, &control)) != 0) return 0; + + for(i=0; i < 64; i++, v++,avail >>=1, status >>=1, control >>=1) { + if ( ! *v ) continue; + p += sprintf(p, "%-40s : %s%s %s\n", *v, + avail & 0x1 ? "" : "NotImpl", + avail & 0x1 ? (status & 0x1 ? "On" : "Off"): "", + avail & 0x1 ? (control & 0x1 ? "Ctrl" : "NoCtrl"): ""); + } + return p - page; +} + +/* + * physical mode call for PAL_VERSION is working fine. + * This function is meant to go away once PAL get fixed. + */ +static inline s64 +ia64_pal_version_phys(pal_version_u_t *pal_min_version, pal_version_u_t *pal_cur_version) +{ + struct ia64_pal_retval iprv; + PAL_CALL_PHYS(iprv, PAL_VERSION, 0, 0, 0); + if (pal_min_version) + pal_min_version->pal_version_val = iprv.v0; + if (pal_cur_version) + pal_cur_version->pal_version_val = iprv.v1; + return iprv.status; +} + +static int +version_info(char *page) +{ + s64 status; + pal_version_u_t min_ver, cur_ver; + char *p = page; + +#ifdef IA64_PAL_VERSION_BUG + /* The virtual mode call is buggy. But the physical mode call seems + * to be ok. Until they fix virtual mode, we do physical. + */ + status = ia64_pal_version_phys(&min_ver, &cur_ver); +#else + /* The system crashes if you enable this code with the wrong PAL + * code + */ + status = ia64_pal_version(&min_ver, &cur_ver); +#endif + if (status != 0) return 0; + + p += sprintf(p, "PAL_vendor : 0x%x (min=0x%x)\n" \ + "PAL_A revision : 0x%x (min=0x%x)\n" \ + "PAL_A model : 0x%x (min=0x%x)\n" \ + "PAL_B mode : 0x%x (min=0x%x)\n" \ + "PAL_B revision : 0x%x (min=0x%x)\n", + cur_ver.pal_version_s.pv_pal_vendor, + min_ver.pal_version_s.pv_pal_vendor, + cur_ver.pal_version_s.pv_pal_a_rev, + cur_ver.pal_version_s.pv_pal_a_rev, + cur_ver.pal_version_s.pv_pal_a_model, + min_ver.pal_version_s.pv_pal_a_model, + cur_ver.pal_version_s.pv_pal_b_rev, + min_ver.pal_version_s.pv_pal_b_rev, + cur_ver.pal_version_s.pv_pal_b_model, + min_ver.pal_version_s.pv_pal_b_model); + + return p - page; +} + +static int +perfmon_info(char *page) +{ + char *p = page; + u64 *pm_buffer; + pal_perf_mon_info_u_t pm_info; + + pm_buffer = (u64 *)get_palcall_buffer(); + if (pm_buffer == 0) return 0; + + if (ia64_pal_perf_mon_info(pm_buffer, &pm_info) != 0) { + free_palcall_buffer(pm_buffer); + return 0; + } + +#ifdef IA64_PAL_PERF_MON_INFO_BUG + pm_buffer[5]=0x3; + pm_info.pal_perf_mon_info_s.cycles = 0x12; + pm_info.pal_perf_mon_info_s.retired = 0x08; +#endif + + p += sprintf(p, "PMC/PMD pairs : %d\n" \ + "Counter width : %d bits\n" \ + "Cycle event number : %d\n" \ + "Retired event number : %d\n" \ + "Implemented PMC : ", + pm_info.pal_perf_mon_info_s.generic, + pm_info.pal_perf_mon_info_s.width, + pm_info.pal_perf_mon_info_s.cycles, + pm_info.pal_perf_mon_info_s.retired); + + p = bitregister_process(p, pm_buffer, 256); + + p += sprintf(p, "\nImplemented PMD : "); + + p = bitregister_process(p, pm_buffer+4, 256); + + p += sprintf(p, "\nCycles count capable : "); + + p = bitregister_process(p, pm_buffer+8, 256); + + p += sprintf(p, "\nRetired bundles count capable : "); + + p = bitregister_process(p, pm_buffer+12, 256); + + p += sprintf(p, "\n"); + + free_palcall_buffer(pm_buffer); + + return p - page; +} + +static int +frequency_info(char *page) +{ + char *p = page; + struct pal_freq_ratio proc, itc, bus; + u64 base; + + if (ia64_pal_freq_base(&base) == -1) + p += sprintf(p, "Output clock : not implemented\n"); + else + p += sprintf(p, "Output clock : %ld ticks/s\n", base); + + if (ia64_pal_freq_ratios(&proc, &bus, &itc) != 0) return 0; + + p += sprintf(p, "Processor/Clock ratio : %ld/%ld\n" \ + "Bus/Clock ratio : %ld/%ld\n" \ + "ITC/Clock ratio : %ld/%ld\n", + proc.num, proc.den, + bus.num, bus.den, + itc.num, itc.den); + + return p - page; +} + + +/* + * Entry point routine: all calls go trhough this function + */ +static int +palinfo_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + palinfo_func_t info = (palinfo_func_t)data; + int len = info(page); + + if (len <= off+count) *eof = 1; + + *start = page + off; + len -= off; + + if (len>count) len = count; + if (len<0) len = 0; + + return len; +} + +/* + * List names,function pairs for every entry in /proc/palinfo + * Must be terminated with the NULL,NULL entry. + */ +static palinfo_entry_t palinfo_entries[]={ + { "version_info", version_info, }, + { "vm_info", vm_info, }, + { "cache_info", cache_info, }, + { "power_info", power_info, }, + { "register_info", register_info, }, + { "processor_info", processor_info, }, + { "perfmon_info", perfmon_info, }, + { "frequency_info", frequency_info, }, + { NULL, NULL,} +}; + + +static int __init +palinfo_init(void) +{ + palinfo_entry_t *p; + + printk(KERN_INFO "PAL Information Facility v%s\n", PALINFO_VERSION); + + palinfo_dir = create_proc_entry("palinfo", S_IFDIR | S_IRUGO | S_IXUGO, NULL); + + for (p = palinfo_entries; p->name ; p++){ + p->entry = create_proc_read_entry (p->name, 0, palinfo_dir, + palinfo_read_entry, p->proc_read); + } + + return 0; +} + +static int __exit +palinfo_exit(void) +{ + palinfo_entry_t *p; + + for (p = palinfo_entries; p->name ; p++){ + remove_proc_entry (p->name, palinfo_dir); + } + remove_proc_entry ("palinfo", 0); + + return 0; +} + +module_init(palinfo_init); +module_exit(palinfo_exit); diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/pci-dma.c linux/arch/ia64/kernel/pci-dma.c --- v2.4.0-test1/linux/arch/ia64/kernel/pci-dma.c Wed Feb 16 17:03:51 2000 +++ linux/arch/ia64/kernel/pci-dma.c Thu Jun 22 07:09:44 2000 @@ -23,8 +23,8 @@ void *ret; int gfp = GFP_ATOMIC; - if (!hwdev || hwdev->dma_mask != 0xffffffff) - gfp |= GFP_DMA; + if (!hwdev || hwdev->dma_mask == 0xffffffff) + gfp |= GFP_DMA; /* XXX fix me: should change this to GFP_32BIT or ZONE_32BIT */ ret = (void *)__get_free_pages(gfp, get_order(size)); if (ret) { diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/pci.c linux/arch/ia64/kernel/pci.c --- v2.4.0-test1/linux/arch/ia64/kernel/pci.c Fri Mar 10 16:40:39 2000 +++ linux/arch/ia64/kernel/pci.c Thu Jun 22 07:09:44 2000 @@ -133,7 +133,7 @@ * Initialization. Uses the SAL interface */ -#define PCI_BUSSES_TO_SCAN 2 /* On "real" ;) hardware this will be 255 */ +#define PCI_BUSES_TO_SCAN 255 void __init pcibios_init(void) @@ -147,7 +147,7 @@ } printk("PCI: Probing PCI hardware\n"); - for (i = 0; i < PCI_BUSSES_TO_SCAN; i++) + for (i = 0; i < PCI_BUSES_TO_SCAN; i++) pci_scan_bus(i, ops, NULL); platform_pci_fixup(); return; @@ -197,7 +197,7 @@ ranges->mem_end -= bus->resource[1]->start; } -int __init +int pcibios_enable_device (struct pci_dev *dev) { /* Not needed, since we enable all devices at startup. */ diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/process.c linux/arch/ia64/kernel/process.c --- v2.4.0-test1/linux/arch/ia64/kernel/process.c Fri Mar 10 16:40:39 2000 +++ linux/arch/ia64/kernel/process.c Thu Jun 22 07:09:44 2000 @@ -23,8 +23,40 @@ #include #include #include +#include #include +static void +do_show_stack (struct unw_frame_info *info, void *arg) +{ + unsigned long ip, sp, bsp; + + printk("\nCall Trace: "); + do { + unw_get_ip(info, &ip); + if (ip == 0) + break; + + unw_get_sp(info, &sp); + unw_get_bsp(info, &bsp); + printk("[<%016lx>] sp=0x%016lx bsp=0x%016lx\n", ip, sp, bsp); + } while (unw_unwind(info) >= 0); +} + +void +show_stack (struct task_struct *task) +{ +#ifdef CONFIG_IA64_NEW_UNWIND + if (!task) + unw_init_running(do_show_stack, 0); + else { + struct unw_frame_info info; + + unw_init_from_blocked_task(&info, task); + do_show_stack(&info, 0); + } +#endif +} void show_regs (struct pt_regs *regs) @@ -71,6 +103,10 @@ ((i == sof - 1) || (i % 3) == 2) ? "\n" : " "); } } +#ifdef CONFIG_IA64_NEW_UNWIND + if (!user_mode(regs)) + show_stack(0); +#endif } void __attribute__((noreturn)) @@ -98,16 +134,49 @@ if (pm_idle) (*pm_idle)(); #ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC - if (ia64_get_itm() < ia64_get_itc()) { - extern void ia64_reset_itm (void); - - printk("cpu_idle: ITM in past, resetting it...\n"); - ia64_reset_itm(); + local_irq_disable(); + { + u64 itc, itm; + + itc = ia64_get_itc(); + itm = ia64_get_itm(); + if (time_after(itc, itm + 1000)) { + extern void ia64_reset_itm (void); + + printk("cpu_idle: ITM in past (itc=%lx,itm=%lx:%lums)\n", + itc, itm, (itc - itm)/500000); + ia64_reset_itm(); + } } + local_irq_enable(); #endif } } +void +ia64_save_extra (struct task_struct *task) +{ + extern void ia64_save_debug_regs (unsigned long *save_area); + extern void ia32_save_state (struct thread_struct *thread); + + if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) + ia64_save_debug_regs(&task->thread.dbr[0]); + if (IS_IA32_PROCESS(ia64_task_regs(task))) + ia32_save_state(&task->thread); +} + +void +ia64_load_extra (struct task_struct *task) +{ + extern void ia64_load_debug_regs (unsigned long *save_area); + extern void ia32_load_state (struct thread_struct *thread); + + if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) + ia64_load_debug_regs(&task->thread.dbr[0]); + if (IS_IA32_PROCESS(ia64_task_regs(task))) + ia32_load_state(&task->thread); +} + /* * Copy the state of an ia-64 thread. * @@ -234,9 +303,103 @@ return 0; } +#ifdef CONFIG_IA64_NEW_UNWIND + +void +do_copy_regs (struct unw_frame_info *info, void *arg) +{ + unsigned long ar_bsp, ndirty, *krbs, addr, mask, sp, nat_bits = 0, ip; + elf_greg_t *dst = arg; + struct pt_regs *pt; + char nat; + long val; + int i; + + memset(dst, 0, sizeof(elf_gregset_t)); /* don't leak any kernel bits to user-level */ + + if (unw_unwind_to_user(info) < 0) + return; + + unw_get_sp(info, &sp); + pt = (struct pt_regs *) (sp + 16); + + krbs = (unsigned long *) current + IA64_RBS_OFFSET/8; + ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 19)); + ar_bsp = (unsigned long) ia64_rse_skip_regs((long *) pt->ar_bspstore, ndirty); + + /* + * Write portion of RSE backing store living on the kernel + * stack to the VM of the process. + */ + for (addr = pt->ar_bspstore; addr < ar_bsp; addr += 8) + if (ia64_peek(pt, current, addr, &val) == 0) + access_process_vm(current, addr, &val, sizeof(val), 1); + + /* r0 is zero */ + for (i = 1, mask = (1UL << i); i < 32; ++i) { + unw_get_gr(info, i, &dst[i], &nat); + if (nat) + nat_bits |= mask; + mask <<= 1; + } + dst[32] = nat_bits; + unw_get_pr(info, &dst[33]); + + for (i = 0; i < 8; ++i) + unw_get_br(info, i, &dst[34 + i]); + + unw_get_rp(info, &ip); + dst[42] = ip + ia64_psr(pt)->ri; + dst[43] = pt->cr_ifs & 0x3fffffffff; + dst[44] = pt->cr_ipsr & IA64_PSR_UM; + + unw_get_ar(info, UNW_AR_RSC, &dst[45]); + /* + * For bsp and bspstore, unw_get_ar() would return the kernel + * addresses, but we need the user-level addresses instead: + */ + dst[46] = ar_bsp; + dst[47] = pt->ar_bspstore; + unw_get_ar(info, UNW_AR_RNAT, &dst[48]); + unw_get_ar(info, UNW_AR_CCV, &dst[49]); + unw_get_ar(info, UNW_AR_UNAT, &dst[50]); + unw_get_ar(info, UNW_AR_FPSR, &dst[51]); + dst[52] = pt->ar_pfs; /* UNW_AR_PFS is == to pt->cr_ifs for interrupt frames */ + unw_get_ar(info, UNW_AR_LC, &dst[53]); + unw_get_ar(info, UNW_AR_EC, &dst[54]); +} + +void +do_dump_fpu (struct unw_frame_info *info, void *arg) +{ + struct task_struct *fpu_owner = ia64_get_fpu_owner(); + elf_fpreg_t *dst = arg; + int i; + + memset(dst, 0, sizeof(elf_fpregset_t)); /* don't leak any "random" bits */ + + if (unw_unwind_to_user(info) < 0) + return; + + /* f0 is 0.0, f1 is 1.0 */ + + for (i = 2; i < 32; ++i) + unw_get_fr(info, i, dst + i); + + if ((fpu_owner == current) || (current->thread.flags & IA64_THREAD_FPH_VALID)) { + ia64_sync_fph(current); + memcpy(dst + 32, current->thread.fph, 96*16); + } +} + +#endif /* CONFIG_IA64_NEW_UNWIND */ + void ia64_elf_core_copy_regs (struct pt_regs *pt, elf_gregset_t dst) { +#ifdef CONFIG_IA64_NEW_UNWIND + unw_init_running(do_copy_regs, dst); +#else struct switch_stack *sw = ((struct switch_stack *) pt) - 1; unsigned long ar_ec, cfm, ar_bsp, ndirty, *krbs, addr; @@ -270,7 +433,7 @@ * ar.rsc ar.bsp ar.bspstore ar.rnat * ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec */ - memset(dst, 0, sizeof (dst)); /* don't leak any "random" bits */ + memset(dst, 0, sizeof(dst)); /* don't leak any "random" bits */ /* r0 is zero */ dst[ 1] = pt->r1; dst[ 2] = pt->r2; dst[ 3] = pt->r3; dst[ 4] = sw->r4; dst[ 5] = sw->r5; dst[ 6] = sw->r6; dst[ 7] = sw->r7; @@ -285,17 +448,22 @@ dst[34] = pt->b0; dst[35] = sw->b1; dst[36] = sw->b2; dst[37] = sw->b3; dst[38] = sw->b4; dst[39] = sw->b5; dst[40] = pt->b6; dst[41] = pt->b7; - dst[42] = pt->cr_iip; dst[43] = pt->cr_ifs; - dst[44] = pt->cr_ipsr; /* XXX perhaps we should filter out some bits here? --davidm */ + dst[42] = pt->cr_iip + ia64_psr(pt)->ri; + dst[43] = pt->cr_ifs; + dst[44] = pt->cr_ipsr & IA64_PSR_UM; dst[45] = pt->ar_rsc; dst[46] = ar_bsp; dst[47] = pt->ar_bspstore; dst[48] = pt->ar_rnat; dst[49] = pt->ar_ccv; dst[50] = pt->ar_unat; dst[51] = sw->ar_fpsr; dst[52] = pt->ar_pfs; dst[53] = sw->ar_lc; dst[54] = (sw->ar_pfs >> 52) & 0x3f; +#endif /* !CONFIG_IA64_NEW_UNWIND */ } int dump_fpu (struct pt_regs *pt, elf_fpregset_t dst) { +#ifdef CONFIG_IA64_NEW_UNWIND + unw_init_running(do_dump_fpu, dst); +#else struct switch_stack *sw = ((struct switch_stack *) pt) - 1; struct task_struct *fpu_owner = ia64_get_fpu_owner(); @@ -312,6 +480,7 @@ } memcpy(dst + 32, current->thread.fph, 96*16); } +#endif return 1; /* f0-f31 are always valid so we always return 1 */ } @@ -384,7 +553,7 @@ unsigned long get_wchan (struct task_struct *p) { - struct ia64_frame_info info; + struct unw_frame_info info; unsigned long ip; int count = 0; /* @@ -403,11 +572,11 @@ * gracefully if the process wasn't really blocked after all. * --davidm 99/12/15 */ - ia64_unwind_init_from_blocked_task(&info, p); + unw_init_from_blocked_task(&info, p); do { - if (ia64_unwind_to_previous_frame(&info) < 0) + if (unw_unwind(&info) < 0) return 0; - ip = ia64_unwind_get_ip(&info); + unw_get_ip(&info, &ip); if (ip < first_sched || ip >= last_sched) return ip; } while (count++ < 16); diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/ptrace.c linux/arch/ia64/kernel/ptrace.c --- v2.4.0-test1/linux/arch/ia64/kernel/ptrace.c Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/kernel/ptrace.c Fri Jun 23 21:11:20 2000 @@ -7,6 +7,7 @@ * Derived from the x86 and Alpha versions. Most of the code in here * could actually be factored into a common set of routines. */ +#include #include #include #include @@ -29,8 +30,74 @@ * id (instruction debug fault disable; one bit) * dd (data debug fault disable; one bit) * ri (restart instruction; two bits) + * is (instruction set; one bit) */ -#define CR_IPSR_CHANGE_MASK 0x06a00100003eUL +#define IPSR_WRITE_MASK \ + (IA64_PSR_UM | IA64_PSR_DB | IA64_PSR_IS | IA64_PSR_ID | IA64_PSR_DD | IA64_PSR_RI) +#define IPSR_READ_MASK IPSR_WRITE_MASK + +#ifdef CONFIG_IA64_NEW_UNWIND + +#define PTRACE_DEBUG 1 + +#if PTRACE_DEBUG +# define dprintk(format...) printk(format) +# define inline +#else +# define dprintk(format...) +#endif + +/* + * Collect the NaT bits for r1-r31 from scratch_unat and return a NaT + * bitset where bit i is set iff the NaT bit of register i is set. + */ +unsigned long +ia64_get_scratch_nat_bits (struct pt_regs *pt, unsigned long scratch_unat) +{ +# define GET_BITS(first, last, unat) \ + ({ \ + unsigned long bit = ia64_unat_pos(&pt->r##first); \ + unsigned long mask = ((1UL << (last - first + 1)) - 1) << first; \ + (ia64_rotl(unat, first) >> bit) & mask; \ + }) + unsigned long val; + + val = GET_BITS( 1, 3, scratch_unat); + val |= GET_BITS(12, 15, scratch_unat); + val |= GET_BITS( 8, 11, scratch_unat); + val |= GET_BITS(16, 31, scratch_unat); + return val; + +# undef GET_BITS +} + +/* + * Set the NaT bits for the scratch registers according to NAT and + * return the resulting unat (assuming the scratch registers are + * stored in PT). + */ +unsigned long +ia64_put_scratch_nat_bits (struct pt_regs *pt, unsigned long nat) +{ + unsigned long scratch_unat; + +# define PUT_BITS(first, last, nat) \ + ({ \ + unsigned long bit = ia64_unat_pos(&pt->r##first); \ + unsigned long mask = ((1UL << (last - first + 1)) - 1) << bit; \ + (ia64_rotr(nat, first) << bit) & mask; \ + }) + scratch_unat = PUT_BITS( 1, 3, nat); + scratch_unat |= PUT_BITS(12, 15, nat); + scratch_unat |= PUT_BITS( 8, 11, nat); + scratch_unat |= PUT_BITS(16, 31, nat); + + return scratch_unat; + +# undef PUT_BITS +} + +#else /* !CONFIG_IA64_NEW_UNWIND */ /* * Collect the NaT bits for r1-r31 from sw->caller_unat and @@ -79,28 +146,26 @@ # undef PUT_BITS } -#define IA64_MLI_TEMPLATE 0x2 +#endif /* !CONFIG_IA64_NEW_UNWIND */ + +#define IA64_MLX_TEMPLATE 0x2 #define IA64_MOVL_OPCODE 6 void ia64_increment_ip (struct pt_regs *regs) { - unsigned long w0, w1, ri = ia64_psr(regs)->ri + 1; + unsigned long w0, ri = ia64_psr(regs)->ri + 1; if (ri > 2) { ri = 0; regs->cr_iip += 16; } else if (ri == 2) { get_user(w0, (char *) regs->cr_iip + 0); - get_user(w1, (char *) regs->cr_iip + 8); - if (((w0 >> 1) & 0xf) == IA64_MLI_TEMPLATE && (w1 >> 60) == IA64_MOVL_OPCODE) { + if (((w0 >> 1) & 0xf) == IA64_MLX_TEMPLATE) { /* - * rfi'ing to slot 2 of an MLI bundle causes + * rfi'ing to slot 2 of an MLX bundle causes * an illegal operation fault. We don't want - * that to happen... Note that we check the - * opcode only. "movl" has a vc bit of 0, but - * since a vc bit of 1 is currently reserved, - * we might just as well treat it like a movl. + * that to happen... */ ri = 0; regs->cr_iip += 16; @@ -112,21 +177,17 @@ void ia64_decrement_ip (struct pt_regs *regs) { - unsigned long w0, w1, ri = ia64_psr(regs)->ri - 1; + unsigned long w0, ri = ia64_psr(regs)->ri - 1; if (ia64_psr(regs)->ri == 0) { regs->cr_iip -= 16; ri = 2; get_user(w0, (char *) regs->cr_iip + 0); - get_user(w1, (char *) regs->cr_iip + 8); - if (((w0 >> 1) & 0xf) == IA64_MLI_TEMPLATE && (w1 >> 60) == IA64_MOVL_OPCODE) { + if (((w0 >> 1) & 0xf) == IA64_MLX_TEMPLATE) { /* - * rfi'ing to slot 2 of an MLI bundle causes + * rfi'ing to slot 2 of an MLX bundle causes * an illegal operation fault. We don't want - * that to happen... Note that we check the - * opcode only. "movl" has a vc bit of 0, but - * since a vc bit of 1 is currently reserved, - * we might just as well treat it like a movl. + * that to happen... */ ri = 1; } @@ -291,7 +352,11 @@ laddr = (unsigned long *) addr; child_regs = ia64_task_regs(child); +#ifdef CONFIG_IA64_NEW_UNWIND + child_stack = (struct switch_stack *) (child->thread.ksp + 16); +#else child_stack = (struct switch_stack *) child_regs - 1; +#endif bspstore = (unsigned long *) child_regs->ar_bspstore; krbs = (unsigned long *) child + IA64_RBS_OFFSET/8; krbs_num_regs = ia64_rse_num_regs(krbs, (unsigned long *) child_stack->ar_bspstore); @@ -335,7 +400,11 @@ laddr = (unsigned long *) addr; child_regs = ia64_task_regs(child); +#ifdef CONFIG_IA64_NEW_UNWIND + child_stack = (struct switch_stack *) (child->thread.ksp + 16); +#else child_stack = (struct switch_stack *) child_regs - 1; +#endif bspstore = (unsigned long *) child_regs->ar_bspstore; krbs = (unsigned long *) child + IA64_RBS_OFFSET/8; krbs_num_regs = ia64_rse_num_regs(krbs, (unsigned long *) child_stack->ar_bspstore); @@ -394,21 +463,43 @@ long new_bsp, int force_loadrs_to_zero) { - unsigned long *krbs, bspstore, bsp, krbs_num_regs, rbs_end, addr, val; - long ndirty, ret; - struct pt_regs *child_regs; + unsigned long *krbs, bspstore, *kbspstore, bsp, rbs_end, addr, val; + long ndirty, ret = 0; + struct pt_regs *child_regs = ia64_task_regs(child); + +#ifdef CONFIG_IA64_NEW_UNWIND + struct unw_frame_info info; + unsigned long cfm, sof; + + unw_init_from_blocked_task(&info, child); + if (unw_unwind_to_user(&info) < 0) + return -1; + + unw_get_bsp(&info, (unsigned long *) &kbspstore); + + krbs = (unsigned long *) child + IA64_RBS_OFFSET/8; + ndirty = ia64_rse_num_regs(krbs, krbs + (child_regs->loadrs >> 19)); + bspstore = child_regs->ar_bspstore; + bsp = (long) ia64_rse_skip_regs((long *)bspstore, ndirty); + + cfm = child_regs->cr_ifs; + if (!(cfm & (1UL << 63))) + unw_get_cfm(&info, &cfm); + sof = (cfm & 0x7f); + rbs_end = (long) ia64_rse_skip_regs((long *)bspstore, sof); +#else struct switch_stack *child_stack; + unsigned long krbs_num_regs; - ret = 0; - child_regs = ia64_task_regs(child); child_stack = (struct switch_stack *) child_regs - 1; - + kbspstore = (unsigned long *) child_stack->ar_bspstore; krbs = (unsigned long *) child + IA64_RBS_OFFSET/8; ndirty = ia64_rse_num_regs(krbs, krbs + (child_regs->loadrs >> 19)); bspstore = child_regs->ar_bspstore; bsp = (long) ia64_rse_skip_regs((long *)bspstore, ndirty); - krbs_num_regs = ia64_rse_num_regs(krbs, (unsigned long *) child_stack->ar_bspstore); + krbs_num_regs = ia64_rse_num_regs(krbs, kbspstore); rbs_end = (long) ia64_rse_skip_regs((long *)bspstore, krbs_num_regs); +#endif /* Return early if nothing to do */ if (bsp == new_bsp) @@ -437,13 +528,15 @@ } static void -sync_thread_rbs (struct task_struct *child, int make_writable) +sync_thread_rbs (struct task_struct *child, struct mm_struct *mm, int make_writable) { struct task_struct *p; read_lock(&tasklist_lock); - for_each_task(p) { - if (p->mm == child->mm && p->state != TASK_RUNNING) - sync_kernel_register_backing_store(p, 0, make_writable); + { + for_each_task(p) { + if (p->mm == mm && p->state != TASK_RUNNING) + sync_kernel_register_backing_store(p, 0, make_writable); + } } read_unlock(&tasklist_lock); child->thread.flags |= IA64_THREAD_KRBS_SYNCED; @@ -452,10 +545,11 @@ /* * Ensure the state in child->thread.fph is up-to-date. */ -static void -sync_fph (struct task_struct *child) +void +ia64_sync_fph (struct task_struct *child) { if (ia64_psr(ia64_task_regs(child))->mfh && ia64_get_fpu_owner() == child) { + ia64_set_fpu_owner(0); ia64_save_fpu(&child->thread.fph[0]); child->thread.flags |= IA64_THREAD_FPH_VALID; } @@ -465,15 +559,383 @@ } } +#ifdef CONFIG_IA64_NEW_UNWIND + +#include + +static int +access_fr (struct unw_frame_info *info, int regnum, int hi, unsigned long *data, int write_access) +{ + struct ia64_fpreg fpval; + int ret; + + ret = unw_get_fr(info, regnum, &fpval); + if (ret < 0) + return ret; + + if (write_access) { + fpval.u.bits[hi] = *data; + ret = unw_set_fr(info, regnum, fpval); + } else + *data = fpval.u.bits[hi]; + return ret; +} + +static int +access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data, int write_access) +{ + unsigned long *ptr, *rbs, *bspstore, ndirty, regnum; + struct switch_stack *sw; + struct unw_frame_info info; + struct pt_regs *pt; + + pt = ia64_task_regs(child); + sw = (struct switch_stack *) (child->thread.ksp + 16); + + if ((addr & 0x7) != 0) { + dprintk("ptrace: unaligned register address 0x%lx\n", addr); + return -1; + } + + if (addr < PT_F127 + 16) { + /* accessing fph */ + ia64_sync_fph(child); + ptr = (unsigned long *) ((unsigned long) &child->thread.fph + addr); + } else if (addr >= PT_F10 && addr < PT_F15 + 16) { + /* scratch registers untouched by kernel (saved in switch_stack) */ + ptr = (unsigned long *) ((long) sw + addr - PT_NAT_BITS); + } else if (addr < PT_AR_LC + 8) { + /* preserved state: */ + unsigned long nat_bits, scratch_unat, dummy = 0; + struct unw_frame_info info; + char nat = 0; + int ret; + + unw_init_from_blocked_task(&info, child); + if (unw_unwind_to_user(&info) < 0) + return -1; + + switch (addr) { + case PT_NAT_BITS: + if (write_access) { + nat_bits = *data; + scratch_unat = ia64_put_scratch_nat_bits(pt, nat_bits); + if (unw_set_ar(&info, UNW_AR_UNAT, scratch_unat) < 0) { + dprintk("ptrace: failed to set ar.unat\n"); + return -1; + } + for (regnum = 4; regnum <= 7; ++regnum) { + unw_get_gr(&info, regnum, &dummy, &nat); + unw_set_gr(&info, regnum, dummy, (nat_bits >> regnum) & 1); + } + } else { + if (unw_get_ar(&info, UNW_AR_UNAT, &scratch_unat) < 0) { + dprintk("ptrace: failed to read ar.unat\n"); + return -1; + } + nat_bits = ia64_get_scratch_nat_bits(pt, scratch_unat); + for (regnum = 4; regnum <= 7; ++regnum) { + unw_get_gr(&info, regnum, &dummy, &nat); + nat_bits |= (nat != 0) << regnum; + } + *data = nat_bits; + } + return 0; + + case PT_R4: case PT_R5: case PT_R6: case PT_R7: + if (write_access) { + /* read NaT bit first: */ + ret = unw_get_gr(&info, (addr - PT_R4)/8 + 4, data, &nat); + if (ret < 0) + return ret; + } + return unw_access_gr(&info, (addr - PT_R4)/8 + 4, data, &nat, + write_access); + + case PT_B1: case PT_B2: case PT_B3: case PT_B4: case PT_B5: + return unw_access_br(&info, (addr - PT_B1)/8 + 1, data, write_access); + + case PT_AR_LC: + return unw_access_ar(&info, UNW_AR_LC, data, write_access); + + default: + if (addr >= PT_F2 && addr < PT_F5 + 16) + return access_fr(&info, (addr - PT_F2)/16 + 2, (addr & 8) != 0, + data, write_access); + else if (addr >= PT_F16 && addr < PT_F31 + 16) + return access_fr(&info, (addr - PT_F16)/16 + 16, (addr & 8) != 0, + data, write_access); + else { + dprintk("ptrace: rejecting access to register address 0x%lx\n", + addr); + return -1; + } + } + } else if (addr < PT_F9+16) { + /* scratch state */ + switch (addr) { + case PT_AR_BSP: + if (write_access) + /* FIXME? Account for lack of ``cover'' in the syscall case */ + return sync_kernel_register_backing_store(child, *data, 1); + else { + rbs = (unsigned long *) child + IA64_RBS_OFFSET/8; + bspstore = (unsigned long *) pt->ar_bspstore; + ndirty = ia64_rse_num_regs(rbs, rbs + (pt->loadrs >> 19)); + + /* + * If we're in a system call, no ``cover'' was done. So to + * make things uniform, we'll add the appropriate displacement + * onto bsp if we're in a system call. + */ + if (!(pt->cr_ifs & (1UL << 63))) { + struct unw_frame_info info; + unsigned long cfm; + + unw_init_from_blocked_task(&info, child); + if (unw_unwind_to_user(&info) < 0) + return -1; + + unw_get_cfm(&info, &cfm); + ndirty += cfm & 0x7f; + } + *data = (unsigned long) ia64_rse_skip_regs(bspstore, ndirty); + return 0; + } + + case PT_CFM: + if (pt->cr_ifs & (1UL << 63)) { + if (write_access) + pt->cr_ifs = ((pt->cr_ifs & ~0x3fffffffffUL) + | (*data & 0x3fffffffffUL)); + else + *data = pt->cr_ifs & 0x3fffffffffUL; + } else { + /* kernel was entered through a system call */ + unsigned long cfm; + + unw_init_from_blocked_task(&info, child); + if (unw_unwind_to_user(&info) < 0) + return -1; + + unw_get_cfm(&info, &cfm); + if (write_access) + unw_set_cfm(&info, ((cfm & ~0x3fffffffffU) + | (*data & 0x3fffffffffUL))); + else + *data = cfm; + } + return 0; + + case PT_CR_IPSR: + if (write_access) + pt->cr_ipsr = ((*data & IPSR_WRITE_MASK) + | (pt->cr_ipsr & ~IPSR_WRITE_MASK)); + else + *data = (pt->cr_ipsr & IPSR_READ_MASK); + return 0; + + case PT_R1: case PT_R2: case PT_R3: + case PT_R8: case PT_R9: case PT_R10: case PT_R11: + case PT_R12: case PT_R13: case PT_R14: case PT_R15: + case PT_R16: case PT_R17: case PT_R18: case PT_R19: + case PT_R20: case PT_R21: case PT_R22: case PT_R23: + case PT_R24: case PT_R25: case PT_R26: case PT_R27: + case PT_R28: case PT_R29: case PT_R30: case PT_R31: + case PT_B0: case PT_B6: case PT_B7: + case PT_F6: case PT_F6+8: case PT_F7: case PT_F7+8: + case PT_F8: case PT_F8+8: case PT_F9: case PT_F9+8: + case PT_AR_BSPSTORE: + case PT_AR_RSC: case PT_AR_UNAT: case PT_AR_PFS: case PT_AR_RNAT: + case PT_AR_CCV: case PT_AR_FPSR: case PT_CR_IIP: case PT_PR: + /* scratch register */ + ptr = (unsigned long *) ((long) pt + addr - PT_CR_IPSR); + break; + + default: + /* disallow accessing anything else... */ + dprintk("ptrace: rejecting access to register address 0x%lx\n", + addr); + return -1; + } + } else { + /* access debug registers */ + + if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) { + child->thread.flags |= IA64_THREAD_DBG_VALID; + memset(child->thread.dbr, 0, sizeof(child->thread.dbr)); + memset(child->thread.ibr, 0, sizeof( child->thread.ibr)); + } + if (addr >= PT_IBR) { + regnum = (addr - PT_IBR) >> 3; + ptr = &child->thread.ibr[0]; + } else { + regnum = (addr - PT_DBR) >> 3; + ptr = &child->thread.dbr[0]; + } + + if (regnum >= 8) { + dprintk("ptrace: rejecting access to register address 0x%lx\n", addr); + return -1; + } + + ptr += regnum; + } + if (write_access) + *ptr = *data; + else + *data = *ptr; + return 0; +} + +#else /* !CONFIG_IA64_NEW_UNWIND */ + +static int +access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data, int write_access) +{ + unsigned long *ptr, *rbs, *bspstore, ndirty, regnum; + struct switch_stack *sw; + struct pt_regs *pt; + + if ((addr & 0x7) != 0) + return -1; + + if (addr < PT_F127+16) { + /* accessing fph */ + ia64_sync_fph(child); + ptr = (unsigned long *) ((unsigned long) &child->thread.fph + addr); + } else if (addr < PT_F9+16) { + /* accessing switch_stack or pt_regs: */ + pt = ia64_task_regs(child); + sw = (struct switch_stack *) pt - 1; + + switch (addr) { + case PT_NAT_BITS: + if (write_access) + ia64_put_nat_bits(pt, sw, *data); + else + *data = ia64_get_nat_bits(pt, sw); + return 0; + + case PT_AR_BSP: + if (write_access) + /* FIXME? Account for lack of ``cover'' in the syscall case */ + return sync_kernel_register_backing_store(child, *data, 1); + else { + rbs = (unsigned long *) child + IA64_RBS_OFFSET/8; + bspstore = (unsigned long *) pt->ar_bspstore; + ndirty = ia64_rse_num_regs(rbs, rbs + (pt->loadrs >> 19)); + + /* + * If we're in a system call, no ``cover'' was done. So to + * make things uniform, we'll add the appropriate displacement + * onto bsp if we're in a system call. + */ + if (!(pt->cr_ifs & (1UL << 63))) + ndirty += sw->ar_pfs & 0x7f; + *data = (unsigned long) ia64_rse_skip_regs(bspstore, ndirty); + return 0; + } + + case PT_CFM: + if (write_access) { + if (pt->cr_ifs & (1UL << 63)) + pt->cr_ifs = ((pt->cr_ifs & ~0x3fffffffffUL) + | (*data & 0x3fffffffffUL)); + else + sw->ar_pfs = ((sw->ar_pfs & ~0x3fffffffffUL) + | (*data & 0x3fffffffffUL)); + return 0; + } else { + if ((pt->cr_ifs & (1UL << 63)) == 0) + *data = sw->ar_pfs; + else + /* return only the CFM */ + *data = pt->cr_ifs & 0x3fffffffffUL; + return 0; + } + + case PT_CR_IPSR: + if (write_access) + pt->cr_ipsr = ((*data & IPSR_WRITE_MASK) + | (pt->cr_ipsr & ~IPSR_WRITE_MASK)); + else + *data = (pt->cr_ipsr & IPSR_READ_MASK); + return 0; + + case PT_R1: case PT_R2: case PT_R3: + case PT_R4: case PT_R5: case PT_R6: case PT_R7: + case PT_R8: case PT_R9: case PT_R10: case PT_R11: + case PT_R12: case PT_R13: case PT_R14: case PT_R15: + case PT_R16: case PT_R17: case PT_R18: case PT_R19: + case PT_R20: case PT_R21: case PT_R22: case PT_R23: + case PT_R24: case PT_R25: case PT_R26: case PT_R27: + case PT_R28: case PT_R29: case PT_R30: case PT_R31: + case PT_B0: case PT_B1: case PT_B2: case PT_B3: + case PT_B4: case PT_B5: case PT_B6: case PT_B7: + case PT_F2: case PT_F2+8: case PT_F3: case PT_F3+8: + case PT_F4: case PT_F4+8: case PT_F5: case PT_F5+8: + case PT_F6: case PT_F6+8: case PT_F7: case PT_F7+8: + case PT_F8: case PT_F8+8: case PT_F9: case PT_F9+8: + case PT_F10: case PT_F10+8: case PT_F11: case PT_F11+8: + case PT_F12: case PT_F12+8: case PT_F13: case PT_F13+8: + case PT_F14: case PT_F14+8: case PT_F15: case PT_F15+8: + case PT_F16: case PT_F16+8: case PT_F17: case PT_F17+8: + case PT_F18: case PT_F18+8: case PT_F19: case PT_F19+8: + case PT_F20: case PT_F20+8: case PT_F21: case PT_F21+8: + case PT_F22: case PT_F22+8: case PT_F23: case PT_F23+8: + case PT_F24: case PT_F24+8: case PT_F25: case PT_F25+8: + case PT_F26: case PT_F26+8: case PT_F27: case PT_F27+8: + case PT_F28: case PT_F28+8: case PT_F29: case PT_F29+8: + case PT_F30: case PT_F30+8: case PT_F31: case PT_F31+8: + case PT_AR_BSPSTORE: + case PT_AR_RSC: case PT_AR_UNAT: case PT_AR_PFS: case PT_AR_RNAT: + case PT_AR_CCV: case PT_AR_FPSR: case PT_CR_IIP: case PT_PR: + case PT_AR_LC: + ptr = (unsigned long *) ((long) sw + addr - PT_NAT_BITS); + break; + + default: + /* disallow accessing anything else... */ + return -1; + } + } else { + /* access debug registers */ + + if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) { + child->thread.flags |= IA64_THREAD_DBG_VALID; + memset(child->thread.dbr, 0, sizeof child->thread.dbr); + memset(child->thread.ibr, 0, sizeof child->thread.ibr); + } + if (addr >= PT_IBR) { + regnum = (addr - PT_IBR) >> 3; + ptr = &child->thread.ibr[0]; + } else { + regnum = (addr - PT_DBR) >> 3; + ptr = &child->thread.dbr[0]; + } + + if (regnum >= 8) + return -1; + + ptr += regnum; + } + if (write_access) + *ptr = *data; + else + *data = *ptr; + return 0; +} + +#endif /* !CONFIG_IA64_NEW_UNWIND */ + asmlinkage long sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data, long arg4, long arg5, long arg6, long arg7, long stack) { struct pt_regs *regs = (struct pt_regs *) &stack; - struct switch_stack *child_stack; - struct pt_regs *child_regs; struct task_struct *child; - unsigned long flags, regnum, *base; + unsigned long flags; long ret; lock_kernel(); @@ -489,17 +951,21 @@ ret = -ESRCH; read_lock(&tasklist_lock); - child = find_task_by_pid(pid); + { + 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) /* no messing around with init! */ - goto out; + goto out_tsk; if (request == PTRACE_ATTACH) { if (child == current) - goto out; + goto out_tsk; if ((!child->dumpable || (current->uid != child->euid) || (current->uid != child->suid) || @@ -508,10 +974,10 @@ (current->gid != child->sgid) || (!cap_issubset(child->cap_permitted, current->cap_permitted)) || (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) - goto out; + goto out_tsk; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) - goto out; + goto out_tsk; child->flags |= PF_PTRACED; if (child->p_pptr != current) { unsigned long flags; @@ -524,199 +990,98 @@ } send_sig(SIGSTOP, child, 1); ret = 0; - goto out; + goto out_tsk; } ret = -ESRCH; if (!(child->flags & PF_PTRACED)) - goto out; + goto out_tsk; if (child->state != TASK_STOPPED) { if (request != PTRACE_KILL) - goto out; + goto out_tsk; } if (child->p_pptr != current) - goto out; + goto out_tsk; switch (request) { case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: /* read word at location addr */ - if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED) - && atomic_read(&child->mm->mm_users) > 1) - sync_thread_rbs(child, 0); + if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)) { + struct mm_struct *mm; + long do_sync; + + task_lock(child); + { + mm = child->mm; + do_sync = mm && (atomic_read(&mm->mm_users) > 1); + } + task_unlock(child); + if (do_sync) + sync_thread_rbs(child, mm, 0); + } ret = ia64_peek(regs, child, addr, &data); if (ret == 0) { ret = data; regs->r8 = 0; /* ensure "ret" is not mistaken as an error code */ } - goto out; + goto out_tsk; case PTRACE_POKETEXT: case PTRACE_POKEDATA: /* write the word at location addr */ - if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED) - && atomic_read(&child->mm->mm_users) > 1) - sync_thread_rbs(child, 1); + if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)) { + struct mm_struct *mm; + long do_sync; + + task_lock(child); + { + mm = child->mm; + do_sync = mm && (atomic_read(&child->mm->mm_users) > 1); + } + task_unlock(child); + if (do_sync) + sync_thread_rbs(child, mm, 1); + } ret = ia64_poke(regs, child, addr, data); - goto out; + goto out_tsk; case PTRACE_PEEKUSR: /* read the word at addr in the USER area */ - ret = -EIO; - if ((addr & 0x7) != 0) - goto out; - - if (addr < PT_CALLER_UNAT) { - /* accessing fph */ - sync_fph(child); - addr += (unsigned long) &child->thread.fph; - ret = *(unsigned long *) addr; - } else if (addr < PT_F9+16) { - /* accessing switch_stack or pt_regs: */ - child_regs = ia64_task_regs(child); - child_stack = (struct switch_stack *) child_regs - 1; - ret = *(unsigned long *) ((long) child_stack + addr - PT_CALLER_UNAT); - - if (addr == PT_AR_BSP) { - /* ret currently contains pt_regs.loadrs */ - unsigned long *rbs, *bspstore, ndirty; - - rbs = (unsigned long *) child + IA64_RBS_OFFSET/8; - bspstore = (unsigned long *) child_regs->ar_bspstore; - ndirty = ia64_rse_num_regs(rbs, rbs + (ret >> 19)); - ret = (unsigned long) ia64_rse_skip_regs(bspstore, ndirty); - - /* - * If we're in a system call, no ``cover'' was done. So - * to make things uniform, we'll add the appropriate - * displacement onto bsp if we're in a system call. - * - * Note: It may be better to leave the system call case - * alone and subtract the amount of the cover for the - * non-syscall case. That way the reported bsp value - * would actually be the correct bsp for the child - * process. - */ - if (!(child_regs->cr_ifs & (1UL << 63))) { - ret = (unsigned long) - ia64_rse_skip_regs((unsigned long *) ret, - child_stack->ar_pfs & 0x7f); - } - } else if (addr == PT_CFM) { - /* ret currently contains pt_regs.cr_ifs */ - if ((ret & (1UL << 63)) == 0) - ret = child_stack->ar_pfs; - ret &= 0x3fffffffffUL; /* return only the CFM */ - } - } else { - if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) { - child->thread.flags |= IA64_THREAD_DBG_VALID; - memset(child->thread.dbr, 0, sizeof child->thread.dbr); - memset(child->thread.ibr, 0, sizeof child->thread.ibr); - } - if (addr >= PT_IBR) { - regnum = (addr - PT_IBR) >> 3; - base = &child->thread.ibr[0]; - } else { - regnum = (addr - PT_DBR) >> 3; - base = &child->thread.dbr[0]; - } - if (regnum >= 8) - goto out; - ret = base[regnum]; + if (access_uarea(child, addr, &data, 0) < 0) { + ret = -EIO; + goto out_tsk; } + ret = data; regs->r8 = 0; /* ensure "ret" is not mistaken as an error code */ - goto out; + goto out_tsk; case PTRACE_POKEUSR: /* write the word at addr in the USER area */ - ret = -EIO; - if ((addr & 0x7) != 0) - goto out; - - if (addr < PT_CALLER_UNAT) { - /* accessing fph */ - sync_fph(child); - addr += (unsigned long) &child->thread.fph; - *(unsigned long *) addr = data; - } else if (addr == PT_AR_BSPSTORE || addr == PT_CALLER_UNAT - || addr == PT_KERNEL_FPSR || addr == PT_K_B0 || addr == PT_K_AR_PFS - || (PT_K_AR_UNAT <= addr && addr <= PT_K_PR)) { - /* - * Don't permit changes to certain registers. - * - * We don't allow bspstore to be modified because doing - * so would mess up any modifications to bsp. (See - * sync_kernel_register_backing_store for the details.) - */ - goto out; - } else if (addr == PT_AR_BSP) { - /* FIXME? Account for lack of ``cover'' in the syscall case */ - ret = sync_kernel_register_backing_store(child, data, 1); - goto out; - } else if (addr == PT_CFM) { - child_regs = ia64_task_regs(child); - child_stack = (struct switch_stack *) child_regs - 1; - - if (child_regs->cr_ifs & (1UL << 63)) { - child_regs->cr_ifs = (child_regs->cr_ifs & ~0x3fffffffffUL) - | (data & 0x3fffffffffUL); - } else { - child_stack->ar_pfs = (child_stack->ar_pfs & ~0x3fffffffffUL) - | (data & 0x3fffffffffUL); - } - } else if (addr < PT_F9+16) { - /* accessing switch_stack or pt_regs */ - child_regs = ia64_task_regs(child); - child_stack = (struct switch_stack *) child_regs - 1; - - if (addr == PT_CR_IPSR) - data = (data & CR_IPSR_CHANGE_MASK) - | (child_regs->cr_ipsr & ~CR_IPSR_CHANGE_MASK); - - *(unsigned long *) ((long) child_stack + addr - PT_CALLER_UNAT) = data; - } else { - if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) { - child->thread.flags |= IA64_THREAD_DBG_VALID; - memset(child->thread.dbr, 0, sizeof child->thread.dbr); - memset(child->thread.ibr, 0, sizeof child->thread.ibr); - } - - if (addr >= PT_IBR) { - regnum = (addr - PT_IBR) >> 3; - base = &child->thread.ibr[0]; - } else { - regnum = (addr - PT_DBR) >> 3; - base = &child->thread.dbr[0]; - } - if (regnum >= 8) - goto out; - if (regnum & 1) { - /* force breakpoint to be effective only for user-level: */ - data &= ~(0x7UL << 56); - } - base[regnum] = data; + if (access_uarea(child, addr, &data, 1) < 0) { + ret = -EIO; + goto out_tsk; } ret = 0; - goto out; + goto out_tsk; case PTRACE_GETSIGINFO: ret = -EIO; if (!access_ok(VERIFY_WRITE, data, sizeof (siginfo_t)) || child->thread.siginfo == 0) - goto out; + goto out_tsk; copy_to_user((siginfo_t *) data, child->thread.siginfo, sizeof (siginfo_t)); ret = 0; - goto out; + goto out_tsk; break; case PTRACE_SETSIGINFO: ret = -EIO; if (!access_ok(VERIFY_READ, data, sizeof (siginfo_t)) || child->thread.siginfo == 0) - goto out; + goto out_tsk; copy_from_user(child->thread.siginfo, (siginfo_t *) data, sizeof (siginfo_t)); ret = 0; - goto out; + goto out_tsk; case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: /* restart after signal. */ ret = -EIO; if (data > _NSIG) - goto out; + goto out_tsk; if (request == PTRACE_SYSCALL) child->flags |= PF_TRACESYS; else @@ -732,7 +1097,7 @@ wake_up_process(child); ret = 0; - goto out; + goto out_tsk; case PTRACE_KILL: /* @@ -741,7 +1106,7 @@ * that it wants to exit. */ if (child->state == TASK_ZOMBIE) /* already dead */ - goto out; + goto out_tsk; child->exit_code = SIGKILL; /* make sure the single step/take-branch tra bits are not set: */ @@ -753,13 +1118,13 @@ wake_up_process(child); ret = 0; - goto out; + goto out_tsk; case PTRACE_SINGLESTEP: /* let child execute for one instruction */ case PTRACE_SINGLEBLOCK: ret = -EIO; if (data > _NSIG) - goto out; + goto out_tsk; child->flags &= ~PF_TRACESYS; if (request == PTRACE_SINGLESTEP) { @@ -775,12 +1140,12 @@ /* give it a chance to run. */ wake_up_process(child); ret = 0; - goto out; + goto out_tsk; case PTRACE_DETACH: /* detach a process that was attached. */ ret = -EIO; if (data > _NSIG) - goto out; + goto out_tsk; child->flags &= ~(PF_PTRACED|PF_TRACESYS); child->exit_code = data; @@ -799,12 +1164,14 @@ wake_up_process(child); ret = 0; - goto out; + goto out_tsk; default: ret = -EIO; - goto out; + goto out_tsk; } + out_tsk: + free_task_struct(child); out: unlock_kernel(); return ret; diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/sal_stub.S linux/arch/ia64/kernel/sal_stub.S --- v2.4.0-test1/linux/arch/ia64/kernel/sal_stub.S Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/kernel/sal_stub.S Wed Dec 31 16:00:00 1969 @@ -1,118 +0,0 @@ -/* - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang - */ -#ifndef __GCC_MULTIREG_RETVALS__ - /* - * gcc currently does not conform to the ia-64 calling - * convention as far as returning function values are - * concerned. Instead of returning values up to 32 bytes in - * size in r8-r11, gcc returns any value bigger than a - * doubleword via a structure that's allocated by the caller - * and whose address is passed into the function. Since - * SAL_PROC returns values according to the calling - * convention, this stub takes care of copying r8-r11 to the - * place where gcc expects them. - */ - .text - .psr abi64 - .psr lsb - .lsb - - .align 16 - .global ia64_sal_stub -ia64_sal_stub: - /* - * Sheesh, the Cygnus backend passes the pointer to a return value structure in - * in0 whereas the HP backend passes it in r8. Don't you hate those little - * differences... - */ -#ifdef GCC_RETVAL_POINTER_IN_R8 - adds r2=-24,sp - adds sp=-48,sp - mov r14=rp - ;; - st8 [r2]=r8,8 // save pointer to return value - addl r3=@ltoff(ia64_sal),gp - ;; - ld8 r3=[r3] - st8 [r2]=gp,8 // save global pointer - ;; - ld8 r3=[r3] // fetch the value of ia64_sal - st8 [r2]=r14 // save return pointer - ;; - ld8 r2=[r3],8 // load function's entry point - ;; - ld8 gp=[r3] // load function's global pointer - ;; - mov b6=r2 - br.call.sptk.few rp=b6 -.ret0: adds r2=24,sp - ;; - ld8 r3=[r2],8 // restore pointer to return value - ;; - ld8 gp=[r2],8 // restore global pointer - st8 [r3]=r8,8 - ;; - ld8 r14=[r2] // restore return pointer - st8 [r3]=r9,8 - ;; - mov rp=r14 - st8 [r3]=r10,8 - ;; - st8 [r3]=r11,8 - adds sp=48,sp - br.sptk.few rp -#else - /* - * On input: - * in0 = pointer to return value structure - * in1 = index of SAL function to call - * in2..inN = remaining args to SAL call - */ - /* - * We allocate one input and eight output register such that the br.call instruction - * will rename in1-in7 to in0-in6---exactly what we want because SAL doesn't want to - * see the pointer to the return value structure. - */ - alloc r15=ar.pfs,1,0,8,0 - - adds r2=-24,sp - adds sp=-48,sp - mov r14=rp - ;; - st8 [r2]=r15,8 // save ar.pfs - addl r3=@ltoff(ia64_sal),gp - ;; - ld8 r3=[r3] // get address of ia64_sal - st8 [r2]=gp,8 // save global pointer - ;; - ld8 r3=[r3] // get value of ia64_sal - st8 [r2]=r14,8 // save return address (rp) - ;; - ld8 r2=[r3],8 // load function's entry point - ;; - ld8 gp=[r3] // load function's global pointer - mov b6=r2 - br.call.sptk.few rp=b6 // make SAL call -.ret0: adds r2=24,sp - ;; - ld8 r15=[r2],8 // restore ar.pfs - ;; - ld8 gp=[r2],8 // restore global pointer - st8 [in0]=r8,8 // store 1. dword of return value - ;; - ld8 r14=[r2] // restore return address (rp) - st8 [in0]=r9,8 // store 2. dword of return value - ;; - mov rp=r14 - st8 [in0]=r10,8 // store 3. dword of return value - ;; - st8 [in0]=r11,8 - adds sp=48,sp // pop stack frame - mov ar.pfs=r15 - br.ret.sptk.few rp -#endif - - .endp ia64_sal_stub -#endif /* __GCC_MULTIREG_RETVALS__ */ diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/setup.c linux/arch/ia64/kernel/setup.c --- v2.4.0-test1/linux/arch/ia64/kernel/setup.c Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/kernel/setup.c Thu Jun 22 07:09:44 2000 @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -36,6 +37,10 @@ #include #include +#ifdef CONFIG_BLK_DEV_RAM +# include +#endif + extern char _end; /* cpu_data[bootstrap_processor] is data for the bootstrap processor: */ @@ -108,6 +113,8 @@ { unsigned long max_pfn, bootmap_start, bootmap_size; + unw_init(); + /* * The secondary bootstrap loader passes us the boot * parameters at the beginning of the ZERO_PAGE, so let's @@ -125,11 +132,22 @@ * change APIs, they'd do things for the better. Grumble... */ bootmap_start = PAGE_ALIGN(__pa(&_end)); + if (ia64_boot_param.initrd_size) + bootmap_start = PAGE_ALIGN(bootmap_start + ia64_boot_param.initrd_size); bootmap_size = init_bootmem(bootmap_start >> PAGE_SHIFT, max_pfn); efi_memmap_walk(free_available_memory, 0); reserve_bootmem(bootmap_start, bootmap_size); +#ifdef CONFIG_BLK_DEV_INITRD + initrd_start = ia64_boot_param.initrd_start; + if (initrd_start) { + initrd_end = initrd_start+ia64_boot_param.initrd_size; + printk("Initial ramdisk at: 0x%p (%lu bytes)\n", + (void *) initrd_start, ia64_boot_param.initrd_size); + reserve_bootmem(virt_to_phys(initrd_start), ia64_boot_param.initrd_size); + } +#endif #if 0 /* XXX fix me */ init_mm.start_code = (unsigned long) &_stext; @@ -155,10 +173,8 @@ #ifdef CONFIG_SMP bootstrap_processor = hard_smp_processor_id(); current->processor = bootstrap_processor; -#else - cpu_init(); - identify_cpu(&cpu_data[0]); #endif + cpu_init(); /* initialize the bootstrap CPU */ if (efi.acpi) { /* Parse the ACPI tables */ @@ -270,35 +286,18 @@ u64 features; } field; } cpuid; + pal_vm_info_1_u_t vm1; + pal_vm_info_2_u_t vm2; + pal_status_t status; + unsigned long impl_va_msb = 50, phys_addr_size = 44; /* Itanium defaults */ int i; - for (i = 0; i < 5; ++i) { + for (i = 0; i < 5; ++i) cpuid.bits[i] = ia64_get_cpuid(i); - } -#ifdef CONFIG_SMP - /* - * XXX Instead of copying the ITC info from the bootstrap - * processor, ia64_init_itm() should be done per CPU. That - * should get you the right info. --davidm 1/24/00 - */ - if (c != &cpu_data[bootstrap_processor]) { - memset(c, 0, sizeof(struct cpuinfo_ia64)); - c->proc_freq = cpu_data[bootstrap_processor].proc_freq; - c->itc_freq = cpu_data[bootstrap_processor].itc_freq; - c->cyc_per_usec = cpu_data[bootstrap_processor].cyc_per_usec; - c->usec_per_cyc = cpu_data[bootstrap_processor].usec_per_cyc; - } -#else memset(c, 0, sizeof(struct cpuinfo_ia64)); -#endif memcpy(c->vendor, cpuid.field.vendor, 16); -#ifdef CONFIG_IA64_SOFTSDV_HACKS - /* BUG: SoftSDV doesn't support the cpuid registers. */ - if (c->vendor[0] == '\0') - memcpy(c->vendor, "Intel", 6); -#endif c->ppn = cpuid.field.ppn; c->number = cpuid.field.number; c->revision = cpuid.field.revision; @@ -306,8 +305,29 @@ c->family = cpuid.field.family; c->archrev = cpuid.field.archrev; c->features = cpuid.field.features; -#ifdef CONFIG_SMP - c->loops_per_sec = loops_per_sec; + + status = ia64_pal_vm_summary(&vm1, &vm2); + if (status == PAL_STATUS_SUCCESS) { +#if 1 + /* + * XXX the current PAL code returns IMPL_VA_MSB==60, which is dead-wrong. + * --davidm 00/05/26 + s*/ + impl_va_msb = 50; +#else + impl_va_msb = vm2.pal_vm_info_2_s.impl_va_msb; +#endif + phys_addr_size = vm1.pal_vm_info_1_s.phys_add_size; + } + printk("processor implements %lu virtual and %lu physical address bits\n", + impl_va_msb + 1, phys_addr_size); + c->unimpl_va_mask = ~((7L<<61) | ((1L << (impl_va_msb + 1)) - 1)); + c->unimpl_pa_mask = ~((1L<<63) | ((1L << phys_addr_size) - 1)); + +#ifdef CONFIG_IA64_SOFTSDV_HACKS + /* BUG: SoftSDV doesn't support the cpuid registers. */ + if (c->vendor[0] == '\0') + memcpy(c->vendor, "Intel", 6); #endif } @@ -318,6 +338,11 @@ void cpu_init (void) { + extern void __init ia64_rid_init (void); + extern void __init ia64_tlb_init (void); + + identify_cpu(&my_cpu_data); + /* Clear the stack memory reserved for pt_regs: */ memset(ia64_task_regs(current), 0, sizeof(struct pt_regs)); @@ -331,6 +356,21 @@ */ ia64_set_dcr(IA64_DCR_DR | IA64_DCR_DK | IA64_DCR_DX | IA64_DCR_PP); ia64_set_fpu_owner(0); /* initialize ar.k5 */ + atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; + + ia64_rid_init(); + ia64_tlb_init(); + +#ifdef CONFIG_IA32_SUPPORT + /* initialize global ia32 state - CR0 and CR4 */ + __asm__("mov ar.cflg = %0" + : /* no outputs */ + : "r" (((ulong) IA32_CR4 << 32) | IA32_CR0)); +#endif + +#ifdef CONFIG_SMP + normal_xtp(); +#endif } diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/signal.c linux/arch/ia64/kernel/signal.c --- v2.4.0-test1/linux/arch/ia64/kernel/signal.c Mon Jun 19 16:31:57 2000 +++ linux/arch/ia64/kernel/signal.c Thu Jun 22 07:09:44 2000 @@ -37,16 +37,26 @@ # define GET_SIGSET(k,u) __get_user((k)->sig[0], &(u)->sig[0]) #endif +struct sigscratch { +#ifdef CONFIG_IA64_NEW_UNWIND + unsigned long scratch_unat; /* ar.unat for the general registers saved in pt */ + unsigned long pad; +#else + struct switch_stack sw; +#endif + struct pt_regs pt; +}; + struct sigframe { struct siginfo info; struct sigcontext sc; }; extern long sys_wait4 (int, int *, int, struct rusage *); -extern long ia64_do_signal (sigset_t *, struct pt_regs *, long); /* forward decl */ +extern long ia64_do_signal (sigset_t *, struct sigscratch *, long); /* forward decl */ long -ia64_rt_sigsuspend (sigset_t *uset, size_t sigsetsize, struct pt_regs *pt) +ia64_rt_sigsuspend (sigset_t *uset, size_t sigsetsize, struct sigscratch *scr) { sigset_t oldset, set; @@ -71,12 +81,19 @@ * pre-set the correct error code here to ensure that the right values * get saved in sigcontext by ia64_do_signal. */ - pt->r8 = EINTR; - pt->r10 = -1; +#ifdef CONFIG_IA32_SUPPORT + if (IS_IA32_PROCESS(&scr->pt)) { + scr->pt.r8 = -EINTR; + } else +#endif + { + scr->pt.r8 = EINTR; + scr->pt.r10 = -1; + } while (1) { set_current_state(TASK_INTERRUPTIBLE); schedule(); - if (ia64_do_signal(&oldset, pt, 1)) + if (ia64_do_signal(&oldset, scr, 1)) return -EINTR; } } @@ -91,9 +108,8 @@ } static long -restore_sigcontext (struct sigcontext *sc, struct pt_regs *pt) +restore_sigcontext (struct sigcontext *sc, struct sigscratch *scr) { - struct switch_stack *sw = (struct switch_stack *) pt - 1; unsigned long ip, flags, nat, um, cfm; long err; @@ -104,28 +120,32 @@ err |= __get_user(ip, &sc->sc_ip); /* instruction pointer */ err |= __get_user(cfm, &sc->sc_cfm); err |= __get_user(um, &sc->sc_um); /* user mask */ - err |= __get_user(pt->ar_rsc, &sc->sc_ar_rsc); - err |= __get_user(pt->ar_ccv, &sc->sc_ar_ccv); - err |= __get_user(pt->ar_unat, &sc->sc_ar_unat); - err |= __get_user(pt->ar_fpsr, &sc->sc_ar_fpsr); - err |= __get_user(pt->ar_pfs, &sc->sc_ar_pfs); - err |= __get_user(pt->pr, &sc->sc_pr); /* predicates */ - err |= __get_user(pt->b0, &sc->sc_br[0]); /* b0 (rp) */ - err |= __get_user(pt->b6, &sc->sc_br[6]); /* b6 */ - err |= __get_user(pt->b7, &sc->sc_br[7]); /* b7 */ - err |= __copy_from_user(&pt->r1, &sc->sc_gr[1], 3*8); /* r1-r3 */ - err |= __copy_from_user(&pt->r8, &sc->sc_gr[8], 4*8); /* r8-r11 */ - err |= __copy_from_user(&pt->r12, &sc->sc_gr[12], 4*8); /* r12-r15 */ - err |= __copy_from_user(&pt->r16, &sc->sc_gr[16], 16*8); /* r16-r31 */ + err |= __get_user(scr->pt.ar_rsc, &sc->sc_ar_rsc); + err |= __get_user(scr->pt.ar_ccv, &sc->sc_ar_ccv); + err |= __get_user(scr->pt.ar_unat, &sc->sc_ar_unat); + err |= __get_user(scr->pt.ar_fpsr, &sc->sc_ar_fpsr); + err |= __get_user(scr->pt.ar_pfs, &sc->sc_ar_pfs); + err |= __get_user(scr->pt.pr, &sc->sc_pr); /* predicates */ + err |= __get_user(scr->pt.b0, &sc->sc_br[0]); /* b0 (rp) */ + err |= __get_user(scr->pt.b6, &sc->sc_br[6]); /* b6 */ + err |= __get_user(scr->pt.b7, &sc->sc_br[7]); /* b7 */ + err |= __copy_from_user(&scr->pt.r1, &sc->sc_gr[1], 3*8); /* r1-r3 */ + err |= __copy_from_user(&scr->pt.r8, &sc->sc_gr[8], 4*8); /* r8-r11 */ + err |= __copy_from_user(&scr->pt.r12, &sc->sc_gr[12], 4*8); /* r12-r15 */ + err |= __copy_from_user(&scr->pt.r16, &sc->sc_gr[16], 16*8); /* r16-r31 */ - pt->cr_ifs = cfm | (1UL << 63); + scr->pt.cr_ifs = cfm | (1UL << 63); /* establish new instruction pointer: */ - pt->cr_iip = ip & ~0x3UL; - ia64_psr(pt)->ri = ip & 0x3; - pt->cr_ipsr = (pt->cr_ipsr & ~IA64_PSR_UM) | (um & IA64_PSR_UM); - - ia64_put_nat_bits (pt, sw, nat); /* restore the original scratch NaT bits */ + scr->pt.cr_iip = ip & ~0x3UL; + ia64_psr(&scr->pt)->ri = ip & 0x3; + scr->pt.cr_ipsr = (scr->pt.cr_ipsr & ~IA64_PSR_UM) | (um & IA64_PSR_UM); + +#ifdef CONFIG_IA64_NEW_UNWIND + scr->scratch_unat = ia64_put_scratch_nat_bits(&scr->pt, nat); +#else + ia64_put_nat_bits(&scr->pt, &scr->sw, nat); /* restore the original scratch NaT bits */ +#endif if (flags & IA64_SC_FLAG_FPH_VALID) { struct task_struct *fpu_owner = ia64_get_fpu_owner(); @@ -138,7 +158,8 @@ return err; } -int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +int +copy_siginfo_to_user (siginfo_t *to, siginfo_t *from) { if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) return -EFAULT; @@ -147,43 +168,39 @@ else { int err; - /* If you change siginfo_t structure, please be sure - this code is fixed accordingly. - It should never copy any pad contained in the structure - to avoid security leaks, but must copy the generic - 3 ints plus the relevant union member. */ + /* + * If you change siginfo_t structure, please be sure + * this code is fixed accordingly. It should never + * copy any pad contained in the structure to avoid + * security leaks, but must copy the generic 3 ints + * plus the relevant union member. + */ err = __put_user(from->si_signo, &to->si_signo); err |= __put_user(from->si_errno, &to->si_errno); err |= __put_user((short)from->si_code, &to->si_code); switch (from->si_code >> 16) { - case __SI_FAULT >> 16: - case __SI_POLL >> 16: + case __SI_FAULT >> 16: + err |= __put_user(from->si_isr, &to->si_isr); + case __SI_POLL >> 16: err |= __put_user(from->si_addr, &to->si_addr); err |= __put_user(from->si_imm, &to->si_imm); break; - case __SI_CHLD >> 16: + case __SI_CHLD >> 16: err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_stime, &to->si_stime); err |= __put_user(from->si_status, &to->si_status); - default: + default: err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_pid, &to->si_pid); break; - /* case __SI_RT: This is not generated by the kernel as of now. */ + /* case __SI_RT: This is not generated by the kernel as of now. */ } return err; } } -/* - * When we get here, ((struct switch_stack *) pt - 1) is a - * switch_stack frame that has no defined value. Upon return, we - * expect sw->caller_unat to contain the new unat value. The reason - * we use a full switch_stack frame is so everything is symmetric - * with ia64_do_signal(). - */ long -ia64_rt_sigreturn (struct pt_regs *pt) +ia64_rt_sigreturn (struct sigscratch *scr) { extern char ia64_strace_leave_kernel, ia64_leave_kernel; struct sigcontext *sc; @@ -191,7 +208,7 @@ sigset_t set; long retval; - sc = &((struct sigframe *) (pt->r12 + 16))->sc; + sc = &((struct sigframe *) (scr->pt.r12 + 16))->sc; /* * When we return to the previously executing context, r8 and @@ -200,9 +217,15 @@ * must not touch r8 or r10 as otherwise user-level stat could * be corrupted. */ - retval = (long) &ia64_leave_kernel | 1; - if ((current->flags & PF_TRACESYS) - && (sc->sc_flags & IA64_SC_FLAG_IN_SYSCALL)) + retval = (long) &ia64_leave_kernel; + if (current->flags & PF_TRACESYS) + /* + * strace expects to be notified after sigreturn + * returns even though the context to which we return + * may not be in the middle of a syscall. Thus, the + * return-value that strace displays for sigreturn is + * meaningless. + */ retval = (long) &ia64_strace_leave_kernel; if (!access_ok(VERIFY_READ, sc, sizeof(*sc))) @@ -217,18 +240,18 @@ recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); - if (restore_sigcontext(sc, pt)) + if (restore_sigcontext(sc, scr)) goto give_sigsegv; #if DEBUG_SIG printk("SIG return (%s:%d): sp=%lx ip=%lx\n", - current->comm, current->pid, pt->r12, pt->cr_iip); + current->comm, current->pid, scr->pt.r12, scr->pt.cr_iip); #endif /* * It is more difficult to avoid calling this function than to * call it and ignore errors. */ - do_sigaltstack(&sc->sc_stack, 0, pt->r12); + do_sigaltstack(&sc->sc_stack, 0, scr->pt.r12); return retval; give_sigsegv: @@ -249,14 +272,13 @@ * trampoline starts. Everything else is done at the user-level. */ static long -setup_sigcontext (struct sigcontext *sc, sigset_t *mask, struct pt_regs *pt) +setup_sigcontext (struct sigcontext *sc, sigset_t *mask, struct sigscratch *scr) { - struct switch_stack *sw = (struct switch_stack *) pt - 1; struct task_struct *fpu_owner = ia64_get_fpu_owner(); unsigned long flags = 0, ifs, nat; long err; - ifs = pt->cr_ifs; + ifs = scr->pt.cr_ifs; if (on_sig_stack((unsigned long) sc)) flags |= IA64_SC_FLAG_ONSTACK; @@ -276,46 +298,49 @@ * Note: sw->ar_unat is UNDEFINED unless the process is being * PTRACED. However, this is OK because the NaT bits of the * preserved registers (r4-r7) are never being looked at by - * the signal handler (register r4-r7 are used instead). + * the signal handler (registers r4-r7 are used instead). */ - nat = ia64_get_nat_bits(pt, sw); +#ifdef CONFIG_IA64_NEW_UNWIND + nat = ia64_get_scratch_nat_bits(&scr->pt, scr->scratch_unat); +#else + nat = ia64_get_nat_bits(&scr->pt, &scr->sw); +#endif err = __put_user(flags, &sc->sc_flags); err |= __put_user(nat, &sc->sc_nat); err |= PUT_SIGSET(mask, &sc->sc_mask); - err |= __put_user(pt->cr_ipsr & IA64_PSR_UM, &sc->sc_um); - err |= __put_user(pt->ar_rsc, &sc->sc_ar_rsc); - err |= __put_user(pt->ar_ccv, &sc->sc_ar_ccv); - err |= __put_user(pt->ar_unat, &sc->sc_ar_unat); /* ar.unat */ - err |= __put_user(pt->ar_fpsr, &sc->sc_ar_fpsr); /* ar.fpsr */ - err |= __put_user(pt->ar_pfs, &sc->sc_ar_pfs); - err |= __put_user(pt->pr, &sc->sc_pr); /* predicates */ - err |= __put_user(pt->b0, &sc->sc_br[0]); /* b0 (rp) */ - err |= __put_user(pt->b6, &sc->sc_br[6]); /* b6 */ - err |= __put_user(pt->b7, &sc->sc_br[7]); /* b7 */ - - err |= __copy_to_user(&sc->sc_gr[1], &pt->r1, 3*8); /* r1-r3 */ - err |= __copy_to_user(&sc->sc_gr[8], &pt->r8, 4*8); /* r8-r11 */ - err |= __copy_to_user(&sc->sc_gr[12], &pt->r12, 4*8); /* r12-r15 */ - err |= __copy_to_user(&sc->sc_gr[16], &pt->r16, 16*8); /* r16-r31 */ + err |= __put_user(scr->pt.cr_ipsr & IA64_PSR_UM, &sc->sc_um); + err |= __put_user(scr->pt.ar_rsc, &sc->sc_ar_rsc); + err |= __put_user(scr->pt.ar_ccv, &sc->sc_ar_ccv); + err |= __put_user(scr->pt.ar_unat, &sc->sc_ar_unat); /* ar.unat */ + err |= __put_user(scr->pt.ar_fpsr, &sc->sc_ar_fpsr); /* ar.fpsr */ + err |= __put_user(scr->pt.ar_pfs, &sc->sc_ar_pfs); + err |= __put_user(scr->pt.pr, &sc->sc_pr); /* predicates */ + err |= __put_user(scr->pt.b0, &sc->sc_br[0]); /* b0 (rp) */ + err |= __put_user(scr->pt.b6, &sc->sc_br[6]); /* b6 */ + err |= __put_user(scr->pt.b7, &sc->sc_br[7]); /* b7 */ + + err |= __copy_to_user(&sc->sc_gr[1], &scr->pt.r1, 3*8); /* r1-r3 */ + err |= __copy_to_user(&sc->sc_gr[8], &scr->pt.r8, 4*8); /* r8-r11 */ + err |= __copy_to_user(&sc->sc_gr[12], &scr->pt.r12, 4*8); /* r12-r15 */ + err |= __copy_to_user(&sc->sc_gr[16], &scr->pt.r16, 16*8); /* r16-r31 */ - err |= __put_user(pt->cr_iip + ia64_psr(pt)->ri, &sc->sc_ip); - err |= __put_user(pt->r12, &sc->sc_gr[12]); /* r12 */ + err |= __put_user(scr->pt.cr_iip + ia64_psr(&scr->pt)->ri, &sc->sc_ip); return err; } static long -setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *pt) +setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, + struct sigscratch *scr) { - struct switch_stack *sw = (struct switch_stack *) pt - 1; extern char ia64_sigtramp[], __start_gate_section[]; unsigned long tramp_addr, new_rbs = 0; struct sigframe *frame; struct siginfo si; long err; - frame = (void *) pt->r12; + frame = (void *) scr->pt.r12; tramp_addr = GATE_ADDR + (ia64_sigtramp - __start_gate_section); if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && !on_sig_stack((unsigned long) frame)) { new_rbs = (current->sas_ss_sp + sizeof(long) - 1) & ~(sizeof(long) - 1); @@ -331,31 +356,39 @@ err |= __put_user(current->sas_ss_sp, &frame->sc.sc_stack.ss_sp); err |= __put_user(current->sas_ss_size, &frame->sc.sc_stack.ss_size); - err |= __put_user(sas_ss_flags(pt->r12), &frame->sc.sc_stack.ss_flags); - err |= setup_sigcontext(&frame->sc, set, pt); + err |= __put_user(sas_ss_flags(scr->pt.r12), &frame->sc.sc_stack.ss_flags); + err |= setup_sigcontext(&frame->sc, set, scr); if (err) goto give_sigsegv; - pt->r12 = (unsigned long) frame - 16; /* new stack pointer */ - pt->r2 = sig; /* signal number */ - pt->r3 = (unsigned long) ka->sa.sa_handler; /* addr. of handler's proc. descriptor */ - pt->r15 = new_rbs; - pt->ar_fpsr = FPSR_DEFAULT; /* reset fpsr for signal handler */ - pt->cr_iip = tramp_addr; - ia64_psr(pt)->ri = 0; /* start executing in first slot */ + scr->pt.r12 = (unsigned long) frame - 16; /* new stack pointer */ + scr->pt.r2 = sig; /* signal number */ + scr->pt.r3 = (unsigned long) ka->sa.sa_handler; /* addr. of handler's proc desc */ + scr->pt.r15 = new_rbs; + scr->pt.ar_fpsr = FPSR_DEFAULT; /* reset fpsr for signal handler */ + scr->pt.cr_iip = tramp_addr; + ia64_psr(&scr->pt)->ri = 0; /* start executing in first slot */ +#ifdef CONFIG_IA64_NEW_UNWIND /* * Note: this affects only the NaT bits of the scratch regs - * (the ones saved in pt_regs, which is exactly what we want. + * (the ones saved in pt_regs), which is exactly what we want. + */ + scr->scratch_unat = 0; /* ensure NaT bits of at least r2, r3, r12, and r15 are clear */ +#else + /* + * Note: this affects only the NaT bits of the scratch regs + * (the ones saved in pt_regs), which is exactly what we want. * The NaT bits for the preserved regs (r4-r7) are in * sw->ar_unat iff this process is being PTRACED. */ - sw->caller_unat = 0; /* ensure NaT bits of at least r2, r3, r12, and r15 are clear */ + scr->sw.caller_unat = 0; /* ensure NaT bits of at least r2, r3, r12, and r15 are clear */ +#endif #if DEBUG_SIG printk("SIG deliver (%s:%d): sig=%d sp=%lx ip=%lx handler=%lx\n", - current->comm, current->pid, sig, pt->r12, pt->cr_iip, pt->r3); + current->comm, current->pid, sig, scr->pt.r12, scr->pt.cr_iip, scr->pt.r3); #endif return 1; @@ -374,17 +407,17 @@ static long handle_signal (unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, - struct pt_regs *pt) + struct sigscratch *scr) { #ifdef CONFIG_IA32_SUPPORT - if (IS_IA32_PROCESS(pt)) { + if (IS_IA32_PROCESS(&scr->pt)) { /* send signal to IA-32 process */ - if (!ia32_setup_frame1(sig, ka, info, oldset, pt)) + if (!ia32_setup_frame1(sig, ka, info, oldset, &scr->pt)) return 0; } else #endif /* send signal to IA-64 process */ - if (!setup_frame(sig, ka, info, oldset, pt)) + if (!setup_frame(sig, ka, info, oldset, scr)) return 0; if (ka->sa.sa_flags & SA_ONESHOT) @@ -401,12 +434,6 @@ } /* - * When we get here, `pt' points to struct pt_regs and ((struct - * switch_stack *) pt - 1) points to a switch stack structure. - * HOWEVER, in the normal case, the ONLY value valid in the - * switch_stack is the caller_unat field. The entire switch_stack is - * valid ONLY if current->flags has PF_PTRACED set. - * * 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. @@ -416,24 +443,35 @@ * user-level signal handling stack-frames in one go after that. */ long -ia64_do_signal (sigset_t *oldset, struct pt_regs *pt, long in_syscall) +ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall) { struct k_sigaction *ka; siginfo_t info; long restart = in_syscall; + long errno = scr->pt.r8; /* * In the ia64_leave_kernel code path, 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(pt)) + if (!user_mode(&scr->pt)) return 0; if (!oldset) oldset = ¤t->blocked; - if (pt->r10 != -1) { +#ifdef CONFIG_IA32_SUPPORT + if (IS_IA32_PROCESS(&scr->pt)) { + if (in_syscall) { + if (errno >= 0) + restart = 0; + else + errno = -errno; + } + } else +#endif + if (scr->pt.r10 != -1) { /* * A system calls has to be restarted only if one of * the error codes ERESTARTNOHAND, ERESTARTSYS, or @@ -527,7 +565,7 @@ case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: - if (do_coredump(signr, pt)) + if (do_coredump(signr, &scr->pt)) exit_code |= 0x80; /* FALLTHRU */ @@ -542,39 +580,54 @@ } if (restart) { - switch (pt->r8) { + switch (errno) { case ERESTARTSYS: if ((ka->sa.sa_flags & SA_RESTART) == 0) { case ERESTARTNOHAND: - pt->r8 = EINTR; - /* note: pt->r10 is already -1 */ +#ifdef CONFIG_IA32_SUPPORT + if (IS_IA32_PROCESS(&scr->pt)) + scr->pt.r8 = -EINTR; + else +#endif + scr->pt.r8 = EINTR; + /* note: scr->pt.r10 is already -1 */ break; } case ERESTARTNOINTR: - ia64_decrement_ip(pt); +#ifdef CONFIG_IA32_SUPPORT + if (IS_IA32_PROCESS(&scr->pt)) { + scr->pt.r8 = scr->pt.r1; + scr->pt.cr_iip -= 2; + } else +#endif + ia64_decrement_ip(&scr->pt); } } /* Whee! Actually deliver the signal. If the delivery failed, we need to continue to iterate in this loop so we can deliver the SIGSEGV... */ - if (handle_signal(signr, ka, &info, oldset, pt)) + if (handle_signal(signr, ka, &info, oldset, scr)) return 1; } /* Did we come from a system call? */ if (restart) { /* Restart the system call - no handlers present */ - if (pt->r8 == ERESTARTNOHAND || - pt->r8 == ERESTARTSYS || - pt->r8 == ERESTARTNOINTR) { + if (errno == ERESTARTNOHAND || errno == ERESTARTSYS || errno == ERESTARTNOINTR) { +#ifdef CONFIG_IA32_SUPPORT + if (IS_IA32_PROCESS(&scr->pt)) { + scr->pt.r8 = scr->pt.r1; + scr->pt.cr_iip -= 2; + } else +#endif /* * Note: the syscall number is in r15 which is * saved in pt_regs so all we need to do here * is adjust ip so that the "break" * instruction gets re-executed. */ - ia64_decrement_ip(pt); + ia64_decrement_ip(&scr->pt); } } return 0; diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/smp.c linux/arch/ia64/kernel/smp.c --- v2.4.0-test1/linux/arch/ia64/kernel/smp.c Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/kernel/smp.c Thu Jun 22 07:09:44 2000 @@ -21,11 +21,13 @@ #include #include #include +#include #include #include #include #include + #include #include #include @@ -39,6 +41,7 @@ extern int cpu_idle(void * unused); extern void _start(void); +extern void machine_halt(void); extern int cpu_now_booting; /* Used by head.S to find idle task */ extern volatile unsigned long cpu_online_map; /* Bitmap of available cpu's */ @@ -66,15 +69,18 @@ atomic_t unstarted_count; atomic_t unfinished_count; }; -static struct smp_call_struct *smp_call_function_data; +static volatile struct smp_call_struct *smp_call_function_data; -#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC +#ifdef CONFIG_ITANIUM_A1_SPECIFIC extern spinlock_t ivr_read_lock; #endif #define IPI_RESCHEDULE 0 #define IPI_CALL_FUNC 1 #define IPI_CPU_STOP 2 +#ifndef CONFIG_ITANIUM_PTCG +# define IPI_FLUSH_TLB 3 +#endif /*!CONFIG_ITANIUM_PTCG */ /* * Setup routine for controlling SMP activation @@ -126,6 +132,22 @@ } +static inline int +pointer_lock(void *lock, void *data, int retry) +{ + again: + if (cmpxchg_acq((void **) lock, 0, data) == 0) + return 0; + + if (!retry) + return -EBUSY; + + while (*(void **) lock) + ; + + goto again; +} + void handle_IPI(int irq, void *dev_id, struct pt_regs *regs) { @@ -160,13 +182,14 @@ void *info; int wait; + /* release the 'pointer lock' */ data = smp_call_function_data; func = data->func; info = data->info; wait = data->wait; mb(); - atomic_dec (&data->unstarted_count); + atomic_dec(&data->unstarted_count); /* At this point the structure may be gone unless wait is true. */ (*func)(info); @@ -174,7 +197,7 @@ /* Notify the sending CPU that the task is done. */ mb(); if (wait) - atomic_dec (&data->unfinished_count); + atomic_dec(&data->unfinished_count); } break; @@ -182,6 +205,51 @@ halt_processor(); break; +#ifndef CONFIG_ITANIUM_PTCG + case IPI_FLUSH_TLB: + { + extern unsigned long flush_start, flush_end, flush_nbits, flush_rid; + extern atomic_t flush_cpu_count; + unsigned long saved_rid = ia64_get_rr(flush_start); + unsigned long end = flush_end; + unsigned long start = flush_start; + unsigned long nbits = flush_nbits; + + /* + * Current CPU may be running with different + * RID so we need to reload the RID of flushed + * address. Purging the translation also + * needs ALAT invalidation; we do not need + * "invala" here since it is done in + * ia64_leave_kernel. + */ + ia64_srlz_d(); + if (saved_rid != flush_rid) { + ia64_set_rr(flush_start, flush_rid); + ia64_srlz_d(); + } + + do { + /* + * Purge local TLB entries. + */ + __asm__ __volatile__ ("ptc.l %0,%1" :: + "r"(start), "r"(nbits<<2) : "memory"); + start += (1UL << nbits); + } while (start < end); + + ia64_insn_group_barrier(); + ia64_srlz_i(); /* srlz.i implies srlz.d */ + + if (saved_rid != flush_rid) { + ia64_set_rr(flush_start, saved_rid); + ia64_srlz_d(); + } + atomic_dec(&flush_cpu_count); + break; + } +#endif /* !CONFIG_ITANIUM_PTCG */ + default: printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which); break; @@ -199,7 +267,7 @@ if (dest_cpu == -1) return; - ipi_op[dest_cpu] |= (1 << op); + set_bit(op, &ipi_op[dest_cpu]); ipi_send(dest_cpu, IPI_IRQ, IA64_IPI_DM_INT, 0); } @@ -243,6 +311,14 @@ send_IPI_allbutself(IPI_CPU_STOP); } +#ifndef CONFIG_ITANIUM_PTCG +void +smp_send_flush_tlb(void) +{ + send_IPI_allbutself(IPI_FLUSH_TLB); +} +#endif /* !CONFIG_ITANIUM_PTCG */ + /* * Run a function on all other CPUs. * The function to run. This must be fast and non-blocking. @@ -260,63 +336,35 @@ { struct smp_call_struct data; long timeout; - static spinlock_t lock = SPIN_LOCK_UNLOCKED; + int cpus = smp_num_cpus - 1; + + if (cpus == 0) + return 0; data.func = func; data.info = info; data.wait = wait; - atomic_set(&data.unstarted_count, smp_num_cpus - 1); - atomic_set(&data.unfinished_count, smp_num_cpus - 1); + atomic_set(&data.unstarted_count, cpus); + atomic_set(&data.unfinished_count, cpus); - if (retry) { - while (1) { - if (smp_call_function_data) { - schedule (); /* Give a mate a go */ - continue; - } - spin_lock (&lock); - if (smp_call_function_data) { - spin_unlock (&lock); /* Bad luck */ - continue; - } - /* Mine, all mine! */ - break; - } - } - else { - if (smp_call_function_data) - return -EBUSY; - spin_lock (&lock); - if (smp_call_function_data) { - spin_unlock (&lock); - return -EBUSY; - } - } + if (pointer_lock(&smp_call_function_data, &data, retry)) + return -EBUSY; - smp_call_function_data = &data; - spin_unlock (&lock); - data.func = func; - data.info = info; - atomic_set (&data.unstarted_count, smp_num_cpus - 1); - data.wait = wait; - if (wait) - atomic_set (&data.unfinished_count, smp_num_cpus - 1); - /* Send a message to all other CPUs and wait for them to respond */ send_IPI_allbutself(IPI_CALL_FUNC); /* Wait for response */ timeout = jiffies + HZ; - while ( (atomic_read (&data.unstarted_count) > 0) && - time_before (jiffies, timeout) ) - barrier (); - if (atomic_read (&data.unstarted_count) > 0) { + while ((atomic_read(&data.unstarted_count) > 0) && time_before(jiffies, timeout)) + barrier(); + if (atomic_read(&data.unstarted_count) > 0) { smp_call_function_data = NULL; return -ETIMEDOUT; } if (wait) - while (atomic_read (&data.unfinished_count) > 0) - barrier (); + while (atomic_read(&data.unfinished_count) > 0) + barrier(); + /* unlock pointer */ smp_call_function_data = NULL; return 0; } @@ -382,17 +430,21 @@ } } - -/* - * Called by both boot and secondaries to move global data into - * per-processor storage. - */ static inline void __init -smp_store_cpu_info(int cpuid) +smp_calibrate_delay(int cpuid) { struct cpuinfo_ia64 *c = &cpu_data[cpuid]; - - identify_cpu(c); +#if 0 + unsigned long old = loops_per_sec; + extern void calibrate_delay(void); + + loops_per_sec = 0; + calibrate_delay(); + c->loops_per_sec = loops_per_sec; + loops_per_sec = old; +#else + c->loops_per_sec = loops_per_sec; +#endif } /* @@ -446,34 +498,26 @@ extern void ia64_init_itm(void); extern void ia64_cpu_local_tick(void); - ia64_set_dcr(IA64_DCR_DR | IA64_DCR_DK | IA64_DCR_DX | IA64_DCR_PP); - ia64_set_fpu_owner(0); - ia64_rid_init(); /* initialize region ids */ - cpu_init(); - __flush_tlb_all(); - smp_store_cpu_info(smp_processor_id()); smp_setup_percpu_timer(smp_processor_id()); - if (test_and_set_bit(smp_processor_id(), &cpu_online_map)) { - printk("CPU#%d already initialized!\n", smp_processor_id()); - machine_halt(); - } - while (!smp_threads_ready) - mb(); - - normal_xtp(); - /* setup the CPU local timer tick */ - ia64_cpu_local_tick(); + ia64_init_itm(); /* Disable all local interrupts */ ia64_set_lrr0(0, 1); ia64_set_lrr1(0, 1); - __sti(); /* Interrupts have been off till now. */ + if (test_and_set_bit(smp_processor_id(), &cpu_online_map)) { + printk("CPU#%d already initialized!\n", smp_processor_id()); + machine_halt(); + } + while (!smp_threads_ready) + mb(); + local_irq_enable(); /* Interrupts have been off until now */ + smp_calibrate_delay(smp_processor_id()); printk("SMP: CPU %d starting idle loop\n", smp_processor_id()); cpu_idle(NULL); @@ -583,16 +627,8 @@ /* Setup BSP mappings */ __cpu_number_map[bootstrap_processor] = 0; __cpu_logical_map[0] = bootstrap_processor; - current->processor = bootstrap_processor; - - /* Mark BSP booted and get active_mm context */ - cpu_init(); - - /* reset XTP for interrupt routing */ - normal_xtp(); - /* And generate an entry in cpu_data */ - smp_store_cpu_info(bootstrap_processor); + smp_calibrate_delay(smp_processor_id()); #if 0 smp_tune_scheduling(); #endif diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/sys_ia64.c linux/arch/ia64/kernel/sys_ia64.c --- v2.4.0-test1/linux/arch/ia64/kernel/sys_ia64.c Sun Feb 13 19:29:03 2000 +++ linux/arch/ia64/kernel/sys_ia64.c Thu Jun 22 07:09:44 2000 @@ -14,6 +14,9 @@ #include /* doh, must come after sched.h... */ #include #include +#include + +#include asmlinkage long ia64_getpriority (int which, int who, long arg2, long arg3, long arg4, long arg5, long arg6, @@ -94,7 +97,11 @@ static inline unsigned long do_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, unsigned long pgoff) { + long start_low, end_low, starting_region, ending_region; + unsigned long loff, hoff; struct file *file = 0; + /* the virtual address space that is mappable in each region: */ +# define OCTANT_SIZE ((PTRS_PER_PGD<= OCTANT_SIZE/2 + && (len | hoff | (hoff + len)) >= OCTANT_SIZE/2) return -EINVAL; - <> -#endif + /* Don't permit mappings that would cross a region boundary: */ + + starting_region = REGION_NUMBER(addr); + ending_region = REGION_NUMBER(addr + len); + if (starting_region != ending_region) + return -EINVAL; flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); if (!(flags & MAP_ANONYMOUS)) { @@ -156,6 +167,9 @@ { struct pt_regs *regs = (struct pt_regs *) &stack; + if ((off & ~PAGE_MASK) != 0) + return -EINVAL; + addr = do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT); if (!IS_ERR(addr)) regs->r8 = 0; /* ensure large addresses are not mistaken as failures... */ @@ -196,6 +210,150 @@ return -ENOSYS; } +asmlinkage unsigned long +ia64_create_module (const char *name_user, size_t size, long arg2, long arg3, + long arg4, long arg5, long arg6, long arg7, long stack) +{ + extern unsigned long sys_create_module (const char *, size_t); + struct pt_regs *regs = (struct pt_regs *) &stack; + unsigned long addr; + + addr = sys_create_module (name_user, size); + if (!IS_ERR(addr)) + regs->r8 = 0; /* ensure large addresses are not mistaken as failures... */ + return addr; +} + +#if 1 +/* + * This is here for a while to keep compatibillity with the old stat() + * call - it will be removed later once everybody migrates to the new + * kernel stat structure that matches the glibc one - Jes + */ +static __inline__ int +do_revalidate (struct dentry *dentry) +{ + struct inode * inode = dentry->d_inode; + if (inode->i_op && inode->i_op->revalidate) + return inode->i_op->revalidate(dentry); + return 0; +} + +static int +cp_ia64_old_stat (struct inode *inode, struct ia64_oldstat *statbuf) +{ + struct ia64_oldstat tmp; + unsigned int blocks, indirect; + + memset(&tmp, 0, sizeof(tmp)); + tmp.st_dev = kdev_t_to_nr(inode->i_dev); + tmp.st_ino = inode->i_ino; + tmp.st_mode = inode->i_mode; + tmp.st_nlink = inode->i_nlink; + SET_STAT_UID(tmp, inode->i_uid); + SET_STAT_GID(tmp, inode->i_gid); + tmp.st_rdev = kdev_t_to_nr(inode->i_rdev); + tmp.st_size = inode->i_size; + tmp.st_atime = inode->i_atime; + tmp.st_mtime = inode->i_mtime; + tmp.st_ctime = inode->i_ctime; +/* + * st_blocks and st_blksize are approximated with a simple algorithm if + * they aren't supported directly by the filesystem. The minix and msdos + * filesystems don't keep track of blocks, so they would either have to + * be counted explicitly (by delving into the file itself), or by using + * this simple algorithm to get a reasonable (although not 100% accurate) + * value. + */ + +/* + * Use minix fs values for the number of direct and indirect blocks. The + * count is now exact for the minix fs except that it counts zero blocks. + * Everything is in units of BLOCK_SIZE until the assignment to + * tmp.st_blksize. + */ +#define D_B 7 +#define I_B (BLOCK_SIZE / sizeof(unsigned short)) + + if (!inode->i_blksize) { + blocks = (tmp.st_size + BLOCK_SIZE - 1) / BLOCK_SIZE; + if (blocks > D_B) { + indirect = (blocks - D_B + I_B - 1) / I_B; + blocks += indirect; + if (indirect > 1) { + indirect = (indirect - 1 + I_B - 1) / I_B; + blocks += indirect; + if (indirect > 1) + blocks++; + } + } + tmp.st_blocks = (BLOCK_SIZE / 512) * blocks; + tmp.st_blksize = BLOCK_SIZE; + } else { + tmp.st_blocks = inode->i_blocks; + tmp.st_blksize = inode->i_blksize; + } + return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; +} + +asmlinkage long +ia64_oldstat (char *filename, struct ia64_oldstat *statbuf) +{ + struct nameidata nd; + int error; + + lock_kernel(); + error = user_path_walk(filename, &nd); + if (!error) { + error = do_revalidate(nd.dentry); + if (!error) + error = cp_ia64_old_stat(nd.dentry->d_inode, statbuf); + path_release(&nd); + } + unlock_kernel(); + return error; +} + + +asmlinkage long +ia64_oldlstat (char *filename, struct ia64_oldstat *statbuf) { + struct nameidata nd; + int error; + + lock_kernel(); + error = user_path_walk_link(filename, &nd); + if (!error) { + error = do_revalidate(nd.dentry); + if (!error) + error = cp_ia64_old_stat(nd.dentry->d_inode, statbuf); + path_release(&nd); + } + unlock_kernel(); + return error; +} + +asmlinkage long +ia64_oldfstat (unsigned int fd, struct ia64_oldstat *statbuf) +{ + struct file * f; + int err = -EBADF; + + lock_kernel(); + f = fget(fd); + if (f) { + struct dentry * dentry = f->f_dentry; + + err = do_revalidate(dentry); + if (!err) + err = cp_ia64_old_stat(dentry->d_inode, statbuf); + fput(f); + } + unlock_kernel(); + return err; +} + +#endif + #ifndef CONFIG_PCI asmlinkage long @@ -211,6 +369,5 @@ { return -ENOSYS; } - #endif /* CONFIG_PCI */ diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/time.c linux/arch/ia64/kernel/time.c --- v2.4.0-test1/linux/arch/ia64/kernel/time.c Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/kernel/time.c Thu Jun 22 07:09:44 2000 @@ -34,7 +34,10 @@ static struct { unsigned long delta; - unsigned long next[NR_CPUS]; + union { + unsigned long count; + unsigned char pad[SMP_CACHE_BYTES]; + } next[NR_CPUS]; } itm; static void @@ -69,16 +72,27 @@ static inline unsigned long gettimeoffset (void) { - unsigned long now = ia64_get_itc(); - unsigned long elapsed_cycles, lost; - - elapsed_cycles = now - (itm.next[smp_processor_id()] - itm.delta); - - lost = lost_ticks; - if (lost) - elapsed_cycles += lost*itm.delta; +#ifdef CONFIG_SMP + /* + * The code below doesn't work for SMP because only CPU 0 + * keeps track of the time. + */ + return 0; +#else + unsigned long now = ia64_get_itc(), last_tick; + unsigned long elapsed_cycles, lost = lost_ticks; + last_tick = (itm.next[smp_processor_id()].count - (lost+1)*itm.delta); +# if 1 + if ((long) (now - last_tick) < 0) { + printk("Yikes: now < last_tick (now=0x%lx,last_tick=%lx)! No can do.\n", + now, last_tick); + return 0; + } +# endif + elapsed_cycles = now - last_tick; return (elapsed_cycles*my_cpu_data.usec_per_cyc) >> IA64_USEC_PER_CYC_SHIFT; +#endif } void @@ -137,6 +151,7 @@ static unsigned long last_time; static unsigned char count; int cpu = smp_processor_id(); + unsigned long new_itm; int printed = 0; /* @@ -146,6 +161,12 @@ * xtime_lock. */ write_lock(&xtime_lock); + new_itm = itm.next[cpu].count; + + if (!time_after(ia64_get_itc(), new_itm)) + printk("Oops: timer tick before it's due (itc=%lx,itm=%lx)\n", + ia64_get_itc(), new_itm); + while (1) { /* * Do kernel PC profiling here. We multiply the @@ -164,18 +185,10 @@ do_timer(regs); #endif - itm.next[cpu] += itm.delta; - /* - * There is a race condition here: to be on the "safe" - * side, we process timer ticks until itm.next is - * ahead of the itc by at least half the timer - * interval. This should give us enough time to set - * the new itm value without losing a timer tick. - */ - if (time_after(itm.next[cpu], ia64_get_itc() + itm.delta/2)) { - ia64_set_itm(itm.next[cpu]); + new_itm += itm.delta; + itm.next[cpu].count = new_itm; + if (time_after(new_itm, ia64_get_itc())) break; - } #if !(defined(CONFIG_IA64_SOFTSDV_HACKS) && defined(CONFIG_SMP)) /* @@ -188,28 +201,39 @@ last_time = jiffies; if (!printed) { printk("Lost clock tick on CPU %d (now=%lx, next=%lx)!!\n", - cpu, ia64_get_itc(), itm.next[cpu]); + cpu, ia64_get_itc(), itm.next[cpu].count); printed = 1; - } # ifdef CONFIG_IA64_DEBUG_IRQ - printk("last_cli_ip=%lx\n", last_cli_ip); + printk("last_cli_ip=%lx\n", last_cli_ip); # endif + } } #endif } write_unlock(&xtime_lock); + + /* + * If we're too close to the next clock tick for comfort, we + * increase the saftey margin by intentionally dropping the + * next tick(s). We do NOT update itm.next accordingly + * because that would force us to call do_timer() which in + * turn would let our clock run too fast (with the potentially + * devastating effect of losing monotony of time). + */ + while (!time_after(new_itm, ia64_get_itc() + itm.delta/2)) + new_itm += itm.delta; + ia64_set_itm(new_itm); } -#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC +#if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_IA64_SOFTSDV_HACKS) -void +/* + * Interrupts must be disabled before calling this routine. + */ +void ia64_reset_itm (void) { - unsigned long flags; - - local_irq_save(flags); timer_interrupt(0, 0, ia64_task_regs(current)); - local_irq_restore(flags); } #endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC */ @@ -220,11 +244,14 @@ void __init ia64_cpu_local_tick(void) { +#ifdef CONFIG_IA64_SOFTSDV_HACKS + ia64_set_itc(0); +#endif + /* arrange for the cycle counter to generate a timer interrupt: */ ia64_set_itv(TIMER_IRQ, 0); - ia64_set_itc(0); - itm.next[smp_processor_id()] = ia64_get_itc() + itm.delta; - ia64_set_itm(itm.next[smp_processor_id()]); + itm.next[smp_processor_id()].count = ia64_get_itc() + itm.delta; + ia64_set_itm(itm.next[smp_processor_id()].count); } void __init @@ -254,25 +281,7 @@ itc_ratio.num = 3; itc_ratio.den = 1; } -#if defined(CONFIG_IA64_LION_HACKS) - /* Our Lion currently returns base freq 104.857MHz, which - ain't right (it really is 100MHz). */ - printk("SAL/PAL returned: base-freq=%lu, itc-ratio=%lu/%lu, proc-ratio=%lu/%lu\n", - platform_base_freq, itc_ratio.num, itc_ratio.den, - proc_ratio.num, proc_ratio.den); - platform_base_freq = 100000000; -#elif 0 && defined(CONFIG_IA64_BIGSUR_HACKS) - /* BigSur with 991020 firmware returned itc-ratio=9/2 and base - freq 75MHz, which wasn't right. The 991119 firmware seems - to return the right values, so this isn't necessary - anymore... */ - printk("SAL/PAL returned: base-freq=%lu, itc-ratio=%lu/%lu, proc-ratio=%lu/%lu\n", - platform_base_freq, itc_ratio.num, itc_ratio.den, - proc_ratio.num, proc_ratio.den); - platform_base_freq = 100000000; - proc_ratio.num = 5; proc_ratio.den = 1; - itc_ratio.num = 5; itc_ratio.den = 1; -#elif defined(CONFIG_IA64_SOFTSDV_HACKS) +#ifdef CONFIG_IA64_SOFTSDV_HACKS platform_base_freq = 10000000; proc_ratio.num = 4; proc_ratio.den = 1; itc_ratio.num = 4; itc_ratio.den = 1; @@ -290,8 +299,9 @@ itc_freq = (platform_base_freq*itc_ratio.num)/itc_ratio.den; itm.delta = itc_freq / HZ; - printk("timer: base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, ITC freq=%lu.%03luMHz\n", - platform_base_freq / 1000000, (platform_base_freq / 1000) % 1000, + printk("timer: CPU %d base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, ITC freq=%lu.%03luMHz\n", + smp_processor_id(), + platform_base_freq / 1000000, (platform_base_freq / 1000) % 1000, itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000); my_cpu_data.proc_freq = (platform_base_freq*proc_ratio.num)/proc_ratio.den; @@ -313,6 +323,8 @@ time_init (void) { /* we can't do request_irq() here because the kmalloc() would fail... */ + irq_desc[TIMER_IRQ].status |= IRQ_PER_CPU; + irq_desc[TIMER_IRQ].handler = &irq_type_ia64_sapic; setup_irq(TIMER_IRQ, &timer_irqaction); efi_gettimeofday(&xtime); diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/traps.c linux/arch/ia64/kernel/traps.c --- v2.4.0-test1/linux/arch/ia64/kernel/traps.c Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/kernel/traps.c Thu Jun 22 07:09:44 2000 @@ -3,8 +3,12 @@ * * Copyright (C) 1998-2000 Hewlett-Packard Co * Copyright (C) 1998-2000 David Mosberger-Tang + * + * 05/12/00 grao : added isr in siginfo for SIGFPE */ +#define FPSWA_DEBUG 1 + /* * The fpu_fault() handler needs to be able to access and update all * floating point registers. Those saved in pt_regs can be accessed @@ -168,7 +172,7 @@ siginfo.si_signo = sig; siginfo.si_errno = 0; siginfo.si_code = code; - send_sig_info(sig, &siginfo, current); + force_sig_info(sig, &siginfo, current); } /* @@ -300,6 +304,7 @@ if (copy_from_user(bundle, (void *) fault_ip, sizeof(bundle))) return -1; +#ifdef FPSWA_DEBUG if (fpu_swa_count > 5 && jiffies - last_time > 5*HZ) fpu_swa_count = 0; if (++fpu_swa_count < 5) { @@ -307,7 +312,7 @@ printk("%s(%d): floating-point assist fault at ip %016lx\n", current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri); } - +#endif exception = fp_emulate(fp_fault, bundle, ®s->cr_ipsr, ®s->ar_fpsr, &isr, ®s->pr, ®s->cr_ifs, regs); if (fp_fault) { @@ -331,7 +336,8 @@ } else if (isr & 0x44) { siginfo.si_code = FPE_FLTDIV; } - send_sig_info(SIGFPE, &siginfo, current); + siginfo.si_isr = isr; + force_sig_info(SIGFPE, &siginfo, current); } } else { if (exception == -1) { @@ -350,12 +356,49 @@ } else if (isr & 0x2200) { siginfo.si_code = FPE_FLTRES; } - send_sig_info(SIGFPE, &siginfo, current); + siginfo.si_isr = isr; + force_sig_info(SIGFPE, &siginfo, current); } } return 0; } +struct illegal_op_return { + unsigned long fkt, arg1, arg2, arg3; +}; + +struct illegal_op_return +ia64_illegal_op_fault (unsigned long ec, unsigned long arg1, unsigned long arg2, + unsigned long arg3, unsigned long arg4, unsigned long arg5, + unsigned long arg6, unsigned long arg7, unsigned long stack) +{ + struct pt_regs *regs = (struct pt_regs *) &stack; + struct illegal_op_return rv; + struct siginfo si; + char buf[128]; + +#ifdef CONFIG_IA64_BRL_EMU + { + extern struct illegal_op_return ia64_emulate_brl (struct pt_regs *, unsigned long); + + rv = ia64_emulate_brl(regs, ec); + if (rv.fkt != (unsigned long) -1) + return rv; + } +#endif + + sprintf(buf, "IA-64 Illegal operation fault"); + die_if_kernel(buf, regs, 0); + + memset(&si, 0, sizeof(si)); + si.si_signo = SIGILL; + si.si_code = ILL_ILLOPC; + si.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + force_sig_info(SIGILL, &si, current); + rv.fkt = 0; + return rv; +} + void ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, unsigned long iim, unsigned long itir, unsigned long arg5, @@ -449,11 +492,6 @@ siginfo.si_errno = 0; force_sig_info(SIGTRAP, &siginfo, current); return; - - case 30: /* Unaligned fault */ - sprintf(buf, "Kernel unaligned trap accessing %016lx (ip=%016lx)!", - ifa, regs->cr_iip + ia64_psr(regs)->ri); - break; case 32: /* fp fault */ case 33: /* fp trap */ diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/unaligned.c linux/arch/ia64/kernel/unaligned.c --- v2.4.0-test1/linux/arch/ia64/kernel/unaligned.c Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/kernel/unaligned.c Thu Jun 22 07:09:44 2000 @@ -1,8 +1,8 @@ /* * Architecture-specific unaligned trap handling. * - * Copyright (C) 1999 Hewlett-Packard Co - * Copyright (C) 1999 Stephane Eranian + * Copyright (C) 1999-2000 Hewlett-Packard Co + * Copyright (C) 1999-2000 Stephane Eranian */ #include #include @@ -460,32 +460,15 @@ * enabled. * * The registers [32-127] are ususally saved in the tss. When get here, - * they are NECESSARY live because they are only saved explicitely. + * they are NECESSARILY live because they are only saved explicitely. * We have 3 ways of updating the values: force a save of the range * in tss, use a gigantic switch/case statement or generate code on the * fly to store to the right register. * For now, we are using the (slow) save/restore way. */ if (regnum >= IA64_FIRST_ROTATING_FR) { - /* - * force a save of [32-127] to tss - * we use the __() form to avoid fiddling with the dfh bit - */ - __ia64_save_fpu(¤t->thread.fph[0]); - + ia64_sync_fph(current); current->thread.fph[IA64_FPH_OFFS(regnum)] = *fpval; - - __ia64_load_fpu(¤t->thread.fph[0]); - - /* - * mark the high partition as being used now - * - * This is REQUIRED because the disabled_fph_fault() does - * not set it, it's relying on the faulting instruction to - * do it. In our case the faulty instruction never gets executed - * completely, so we need to toggle the bit. - */ - regs->cr_ipsr |= IA64_PSR_MFH; } else { /* * pt_regs or switch_stack ? @@ -544,15 +527,8 @@ * See discussion in setfpreg() for reasons and other ways of doing this. */ if (regnum >= IA64_FIRST_ROTATING_FR) { - - /* - * force a save of [32-127] to tss - * we use the__ia64_save_fpu() form to avoid fiddling with - * the dfh bit. - */ - __ia64_save_fpu(¤t->thread.fph[0]); - - *fpval = current->thread.fph[IA64_FPH_OFFS(regnum)]; + ia64_sync_fph(current); + *fpval = current->thread.fph[IA64_FPH_OFFS(regnum)]; } else { /* * f0 = 0.0, f1= 1.0. Those registers are constant and are thus @@ -1410,6 +1386,25 @@ die_if_kernel("Unaligned reference while in kernel\n", regs, 30); /* NOT_REACHED */ } + /* + * For now, we don't support user processes running big-endian + * which do unaligned accesses + */ + if (ia64_psr(regs)->be) { + struct siginfo si; + + printk(KERN_ERR "%s(%d): big-endian unaligned access %016lx (ip=%016lx) not " + "yet supported\n", + current->comm, current->pid, ifa, regs->cr_iip + ipsr->ri); + + si.si_signo = SIGBUS; + si.si_errno = 0; + si.si_code = BUS_ADRALN; + si.si_addr = (void *) ifa; + force_sig_info(SIGBUS, &si, current); + return; + } + if (current->thread.flags & IA64_THREAD_UAC_SIGBUS) { struct siginfo si; @@ -1417,7 +1412,7 @@ si.si_errno = 0; si.si_code = BUS_ADRALN; si.si_addr = (void *) ifa; - send_sig_info (SIGBUS, &si, current); + force_sig_info(SIGBUS, &si, current); return; } diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/unwind.c linux/arch/ia64/kernel/unwind.c --- v2.4.0-test1/linux/arch/ia64/kernel/unwind.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/unwind.c Thu Jun 22 07:09:44 2000 @@ -1,16 +1,1796 @@ /* - * Copyright (C) 1999 Hewlett-Packard Co - * Copyright (C) 1999 David Mosberger-Tang + * Copyright (C) 1999-2000 Hewlett-Packard Co + * Copyright (C) 1999-2000 David Mosberger-Tang */ +/* + * This file implements call frame unwind support for the Linux + * kernel. Parsing and processing the unwind information is + * time-consuming, so this implementation translates the the unwind + * descriptors into unwind scripts. These scripts are very simple + * (basically a sequence of assignments) and efficient to execute. + * They are cached for later re-use. Each script is specific for a + * given instruction pointer address and the set of predicate values + * that the script depends on (most unwind descriptors are + * unconditional and scripts often do not depend on predicates at + * all). This code is based on the unwind conventions described in + * the "IA-64 Software Conventions and Runtime Architecture" manual. + * + * SMP conventions: + * o updates to the global unwind data (in structure "unw") are serialized + * by the unw.lock spinlock + * o each unwind script has its own read-write lock; a thread must acquire + * a read lock before executing a script and must acquire a write lock + * before modifying a script + * o if both the unw.lock spinlock and a script's read-write lock must be + * acquired, then the read-write lock must be acquired first. + */ +#include #include #include +#include #include +#ifdef CONFIG_IA64_NEW_UNWIND + +#include +#include +#include +#include +#include +#include + +#include "entry.h" +#include "unwind_i.h" + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define p5 5 + +/* + * The unwind tables are supposed to be sorted, but the GNU toolchain + * currently fails to produce a sorted table in the presence of + * functions that go into sections other than .text. For example, the + * kernel likes to put initialization code into .text.init, which + * messes up the sort order. Hopefully, this will get fixed sometime + * soon. --davidm 00/05/23 + */ +#define UNWIND_TABLE_SORT_BUG + +#define UNW_LOG_CACHE_SIZE 7 /* each unw_script is ~256 bytes in size */ +#define UNW_CACHE_SIZE (1 << UNW_LOG_CACHE_SIZE) + +#define UNW_LOG_HASH_SIZE (UNW_LOG_CACHE_SIZE + 1) +#define UNW_HASH_SIZE (1 << UNW_LOG_HASH_SIZE) + +#define UNW_DEBUG 1 +#define UNW_STATS 0 /* WARNING: this disabled interrupts for long time-spans!! */ + +#if UNW_DEBUG +# define dprintk(format...) printk(format) +# define inline +#else +# define dprintk(format...) +#endif + +#if UNW_STATS +# define STAT(x...) x +#else +# define STAT(x...) +#endif + +#define alloc_reg_state() kmalloc(sizeof(struct unw_state_record), GFP_ATOMIC) +#define free_reg_state(usr) kfree(usr) + +typedef unsigned long unw_word; +typedef unsigned char unw_hash_index_t; + +#define struct_offset(str,fld) ((char *)&((str *)NULL)->fld - (char *) 0) + +static struct { + spinlock_t lock; /* spinlock for unwind data */ + + /* list of unwind tables (one per load-module) */ + struct unw_table *tables; + + /* table of registers that prologues can save (and order in which they're saved): */ + const unsigned char save_order[8]; + + /* maps a preserved register index (preg_index) to corresponding switch_stack offset: */ + unsigned short sw_off[sizeof(struct unw_frame_info) / 8]; + + unsigned short lru_head; /* index of lead-recently used script */ + unsigned short lru_tail; /* index of most-recently used script */ + + /* index into unw_frame_info for preserved register i */ + unsigned short preg_index[UNW_NUM_REGS]; + + /* unwind table for the kernel: */ + struct unw_table kernel_table; + + /* hash table that maps instruction pointer to script index: */ + unw_hash_index_t hash[UNW_HASH_SIZE]; + + /* script cache: */ + struct unw_script cache[UNW_CACHE_SIZE]; + +# if UNW_DEBUG + const char *preg_name[UNW_NUM_REGS]; +# endif +# if UNW_STATS + struct { + struct { + int lookups; + int hinted_hits; + int normal_hits; + int collision_chain_traversals; + } cache; + struct { + unsigned long build_time; + unsigned long run_time; + unsigned long parse_time; + int builds; + int news; + int collisions; + int runs; + } script; + struct { + unsigned long init_time; + unsigned long unwind_time; + int inits; + int unwinds; + } api; + } stat; +# endif +} unw = { + tables: &unw.kernel_table, + lock: SPIN_LOCK_UNLOCKED, + save_order: { + UNW_REG_RP, UNW_REG_PFS, UNW_REG_PSP, UNW_REG_PR, + UNW_REG_UNAT, UNW_REG_LC, UNW_REG_FPSR, UNW_REG_PRI_UNAT_GR + }, + preg_index: { + struct_offset(struct unw_frame_info, pri_unat)/8, /* PRI_UNAT_GR */ + struct_offset(struct unw_frame_info, pri_unat)/8, /* PRI_UNAT_MEM */ + struct_offset(struct unw_frame_info, pbsp)/8, + struct_offset(struct unw_frame_info, bspstore)/8, + struct_offset(struct unw_frame_info, pfs)/8, + struct_offset(struct unw_frame_info, rnat)/8, + struct_offset(struct unw_frame_info, psp)/8, + struct_offset(struct unw_frame_info, rp)/8, + struct_offset(struct unw_frame_info, r4)/8, + struct_offset(struct unw_frame_info, r5)/8, + struct_offset(struct unw_frame_info, r6)/8, + struct_offset(struct unw_frame_info, r7)/8, + struct_offset(struct unw_frame_info, unat)/8, + struct_offset(struct unw_frame_info, pr)/8, + struct_offset(struct unw_frame_info, lc)/8, + struct_offset(struct unw_frame_info, fpsr)/8, + struct_offset(struct unw_frame_info, b1)/8, + struct_offset(struct unw_frame_info, b2)/8, + struct_offset(struct unw_frame_info, b3)/8, + struct_offset(struct unw_frame_info, b4)/8, + struct_offset(struct unw_frame_info, b5)/8, + struct_offset(struct unw_frame_info, f2)/8, + struct_offset(struct unw_frame_info, f3)/8, + struct_offset(struct unw_frame_info, f4)/8, + struct_offset(struct unw_frame_info, f5)/8, + struct_offset(struct unw_frame_info, fr[16 - 16])/8, + struct_offset(struct unw_frame_info, fr[17 - 16])/8, + struct_offset(struct unw_frame_info, fr[18 - 16])/8, + struct_offset(struct unw_frame_info, fr[19 - 16])/8, + struct_offset(struct unw_frame_info, fr[20 - 16])/8, + struct_offset(struct unw_frame_info, fr[21 - 16])/8, + struct_offset(struct unw_frame_info, fr[22 - 16])/8, + struct_offset(struct unw_frame_info, fr[23 - 16])/8, + struct_offset(struct unw_frame_info, fr[24 - 16])/8, + struct_offset(struct unw_frame_info, fr[25 - 16])/8, + struct_offset(struct unw_frame_info, fr[26 - 16])/8, + struct_offset(struct unw_frame_info, fr[27 - 16])/8, + struct_offset(struct unw_frame_info, fr[28 - 16])/8, + struct_offset(struct unw_frame_info, fr[29 - 16])/8, + struct_offset(struct unw_frame_info, fr[30 - 16])/8, + struct_offset(struct unw_frame_info, fr[31 - 16])/8, + }, + hash : { [0 ... UNW_HASH_SIZE - 1] = -1 }, +#if UNW_DEBUG + preg_name: { + "pri_unat_gr", "pri_unat_mem", "bsp", "bspstore", "ar.pfs", "ar.rnat", "psp", "rp", + "r4", "r5", "r6", "r7", + "ar.unat", "pr", "ar.lc", "ar.fpsr", + "b1", "b2", "b3", "b4", "b5", + "f2", "f3", "f4", "f5", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31" + } +#endif +}; + + +/* Unwind accessors. */ + +int +unw_access_gr (struct unw_frame_info *info, int regnum, unsigned long *val, char *nat, int write) +{ + unsigned long *addr, *nat_addr, nat_mask = 0, dummy_nat; + struct unw_ireg *ireg; + struct pt_regs *pt; + + if ((unsigned) regnum - 1 >= 127) { + dprintk("unwind: trying to access non-existent r%u\n", regnum); + return -1; + } + + if (regnum < 32) { + if (regnum >= 4 && regnum <= 7) { + /* access a preserved register */ + ireg = &info->r4 + (regnum - 4); + addr = ireg->loc; + if (addr) { + nat_addr = addr + ireg->nat.off; + switch (ireg->nat.type) { + case UNW_NAT_VAL: + /* simulate getf.sig/setf.sig */ + if (write) { + if (*nat) { + /* write NaTVal and be done with it */ + addr[0] = 0; + addr[1] = 0x1fffe; + return 0; + } + addr[1] = 0x1003e; + } else { + if (addr[0] == 0 && addr[1] == 0x1ffe) { + /* return NaT and be done with it */ + *val = 0; + *nat = 1; + return 0; + } + } + /* fall through */ + case UNW_NAT_NONE: + nat_addr = &dummy_nat; + break; + + case UNW_NAT_SCRATCH: + if (info->pri_unat) + nat_addr = info->pri_unat; + else + nat_addr = &info->sw->caller_unat; + case UNW_NAT_PRI_UNAT: + nat_mask = (1UL << ((long) addr & 0x1f8)/8); + break; + + case UNW_NAT_STACKED: + nat_addr = ia64_rse_rnat_addr(addr); + if ((unsigned long) addr < info->regstk.limit + || (unsigned long) addr >= info->regstk.top) + { + dprintk("unwind: 0x%p outside of regstk " + "[0x%lx-0x%lx)\n", addr, + info->regstk.limit, info->regstk.top); + return -1; + } + if ((unsigned long) nat_addr >= info->regstk.top) + nat_addr = &info->sw->ar_rnat; + nat_mask = (1UL << ia64_rse_slot_num(addr)); + break; + } + } else { + addr = &info->sw->r4 + (regnum - 4); + nat_addr = &info->sw->ar_unat; + nat_mask = (1UL << ((long) addr & 0x1f8)/8); + } + } else { + /* access a scratch register */ + if (info->flags & UNW_FLAG_INTERRUPT_FRAME) + pt = (struct pt_regs *) info->psp - 1; + else + pt = (struct pt_regs *) info->sp - 1; + if (regnum <= 3) + addr = &pt->r1 + (regnum - 1); + else if (regnum <= 11) + addr = &pt->r8 + (regnum - 8); + else if (regnum <= 15) + addr = &pt->r12 + (regnum - 12); + else + addr = &pt->r16 + (regnum - 16); + if (info->pri_unat) + nat_addr = info->pri_unat; + else + nat_addr = &info->sw->caller_unat; + nat_mask = (1UL << ((long) addr & 0x1f8)/8); + } + } else { + /* access a stacked register */ + addr = ia64_rse_skip_regs((unsigned long *) info->bsp, regnum); + nat_addr = ia64_rse_rnat_addr(addr); + if ((unsigned long) addr < info->regstk.limit + || (unsigned long) addr >= info->regstk.top) + { + dprintk("unwind: ignoring attempt to access register outside of rbs\n"); + return -1; + } + if ((unsigned long) nat_addr >= info->regstk.top) + nat_addr = &info->sw->ar_rnat; + nat_mask = (1UL << ia64_rse_slot_num(addr)); + } + + if (write) { + *addr = *val; + *nat_addr = (*nat_addr & ~nat_mask) | nat_mask; + } else { + *val = *addr; + *nat = (*nat_addr & nat_mask) != 0; + } + return 0; +} + +int +unw_access_br (struct unw_frame_info *info, int regnum, unsigned long *val, int write) +{ + unsigned long *addr; + struct pt_regs *pt; + + if (info->flags & UNW_FLAG_INTERRUPT_FRAME) + pt = (struct pt_regs *) info->psp - 1; + else + pt = (struct pt_regs *) info->sp - 1; + switch (regnum) { + /* scratch: */ + case 0: addr = &pt->b0; break; + case 6: addr = &pt->b6; break; + case 7: addr = &pt->b7; break; + + /* preserved: */ + case 1: case 2: case 3: case 4: case 5: + addr = *(&info->b1 + (regnum - 1)); + if (!addr) + addr = &info->sw->b1 + (regnum - 1); + break; + + default: + dprintk("unwind: trying to access non-existent b%u\n", regnum); + return -1; + } + if (write) + *addr = *val; + else + *val = *addr; + return 0; +} + +int +unw_access_fr (struct unw_frame_info *info, int regnum, struct ia64_fpreg *val, int write) +{ + struct ia64_fpreg *addr = 0; + struct pt_regs *pt; + + if ((unsigned) (regnum - 2) >= 126) { + dprintk("unwind: trying to access non-existent f%u\n", regnum); + return -1; + } + + if (info->flags & UNW_FLAG_INTERRUPT_FRAME) + pt = (struct pt_regs *) info->psp - 1; + else + pt = (struct pt_regs *) info->sp - 1; + + if (regnum <= 5) { + addr = *(&info->f2 + (regnum - 2)); + if (!addr) + addr = &info->sw->f2 + (regnum - 2); + } else if (regnum <= 15) { + if (regnum <= 9) + addr = &pt->f6 + (regnum - 6); + else + addr = &info->sw->f10 + (regnum - 10); + } else if (regnum <= 31) { + addr = info->fr[regnum - 16]; + if (!addr) + addr = &info->sw->f16 + (regnum - 16); + } else { + struct task_struct *t = info->task; + + ia64_sync_fph(t); + addr = t->thread.fph + (regnum - 32); + } + + if (write) + *addr = *val; + else + *val = *addr; + return 0; +} + +int +unw_access_ar (struct unw_frame_info *info, int regnum, unsigned long *val, int write) +{ + unsigned long *addr; + struct pt_regs *pt; + + if (info->flags & UNW_FLAG_INTERRUPT_FRAME) + pt = (struct pt_regs *) info->psp - 1; + else + pt = (struct pt_regs *) info->sp - 1; + + switch (regnum) { + case UNW_AR_BSP: + addr = info->pbsp; + if (!addr) + addr = &info->sw->ar_bspstore; + break; + + case UNW_AR_BSPSTORE: + addr = info->bspstore; + if (!addr) + addr = &info->sw->ar_bspstore; + break; + + case UNW_AR_PFS: + addr = info->pfs; + if (!addr) + addr = &info->sw->ar_pfs; + break; + + case UNW_AR_RNAT: + addr = info->rnat; + if (!addr) + addr = &info->sw->ar_rnat; + break; + + case UNW_AR_UNAT: + addr = info->unat; + if (!addr) + addr = &info->sw->ar_unat; + break; + + case UNW_AR_LC: + addr = info->lc; + if (!addr) + addr = &info->sw->ar_lc; + break; + + case UNW_AR_EC: + if (!info->cfm) + return -1; + if (write) + *info->cfm = (*info->cfm & ~(0x3fUL << 52)) | ((*val & 0x3f) << 52); + else + *val = (*info->cfm >> 52) & 0x3f; + return 0; + + case UNW_AR_FPSR: + addr = info->fpsr; + if (!addr) + addr = &info->sw->ar_fpsr; + break; + + case UNW_AR_RSC: + addr = &pt->ar_rsc; + break; + + case UNW_AR_CCV: + addr = &pt->ar_ccv; + break; + + default: + dprintk("unwind: trying to access non-existent ar%u\n", regnum); + return -1; + } + + if (write) + *addr = *val; + else + *val = *addr; + return 0; +} + +inline int +unw_access_pr (struct unw_frame_info *info, unsigned long *val, int write) +{ + unsigned long *addr; + + addr = info->pr; + if (!addr) + addr = &info->sw->pr; + + if (write) + *addr = *val; + else + *val = *addr; + return 0; +} + + +/* Unwind decoder routines */ + +static inline void +push (struct unw_state_record *sr) +{ + struct unw_reg_state *rs; + + rs = alloc_reg_state(); + memcpy(rs, &sr->curr, sizeof(*rs)); + rs->next = sr->stack; + sr->stack = rs; +} + +static void +pop (struct unw_state_record *sr) +{ + struct unw_reg_state *rs; + + if (!sr->stack) { + printk ("unwind: stack underflow!\n"); + return; + } + rs = sr->stack; + sr->stack = rs->next; + free_reg_state(rs); +} + +static enum unw_register_index __attribute__((const)) +decode_abreg (unsigned char abreg, int memory) +{ + switch (abreg) { + case 0x04 ... 0x07: return UNW_REG_R4 + (abreg - 0x04); + case 0x22 ... 0x25: return UNW_REG_F2 + (abreg - 0x22); + case 0x30 ... 0x3f: return UNW_REG_F16 + (abreg - 0x30); + case 0x41 ... 0x45: return UNW_REG_B1 + (abreg - 0x41); + case 0x60: return UNW_REG_PR; + case 0x61: return UNW_REG_PSP; + case 0x62: return memory ? UNW_REG_PRI_UNAT_MEM : UNW_REG_PRI_UNAT_GR; + case 0x63: return UNW_REG_RP; + case 0x64: return UNW_REG_BSP; + case 0x65: return UNW_REG_BSPSTORE; + case 0x66: return UNW_REG_RNAT; + case 0x67: return UNW_REG_UNAT; + case 0x68: return UNW_REG_FPSR; + case 0x69: return UNW_REG_PFS; + case 0x6a: return UNW_REG_LC; + default: + break; + } + dprintk("unwind: bad abreg=0x%x\n", abreg); + return UNW_REG_LC; +} + +static void +set_reg (struct unw_reg_info *reg, enum unw_where where, int when, unsigned long val) +{ + reg->val = val; + reg->where = where; + if (reg->when == UNW_WHEN_NEVER) + reg->when = when; +} + +static void +alloc_spill_area (unsigned long *offp, unsigned long regsize, + struct unw_reg_info *lo, struct unw_reg_info *hi) +{ + struct unw_reg_info *reg; + + for (reg = hi; reg >= lo; --reg) { + if (reg->where == UNW_WHERE_SPILL_HOME) { + reg->where = UNW_WHERE_PSPREL; + reg->val = 0x10 - *offp; + *offp += regsize; + } + } +} + +static inline void +spill_next_when (struct unw_reg_info **regp, struct unw_reg_info *lim, unw_word t) +{ + struct unw_reg_info *reg; + + for (reg = *regp; reg <= lim; ++reg) { + if (reg->where == UNW_WHERE_SPILL_HOME) { + reg->when = t; + *regp = reg + 1; + return; + } + } + dprintk("unwind: excess spill!\n"); +} + +static inline void +finish_prologue (struct unw_state_record *sr) +{ + struct unw_reg_info *reg; + unsigned long off; + int i; + + /* + * First, resolve implicit register save locations + * (see Section "11.4.2.3 Rules for Using Unwind + * Descriptors", rule 3): + */ + for (i = 0; i < (int) sizeof(unw.save_order)/sizeof(unw.save_order[0]); ++i) { + reg = sr->curr.reg + unw.save_order[i]; + if (reg->where == UNW_WHERE_GR_SAVE) { + reg->where = UNW_WHERE_GR; + reg->val = sr->gr_save_loc++; + } + } + + /* + * Next, compute when the fp, general, and branch registers get + * saved. This must come before alloc_spill_area() because + * we need to know which registers are spilled to their home + * locations. + */ + if (sr->imask) { + unsigned char kind, mask = 0, *cp = sr->imask; + unsigned long t; + static const unsigned char limit[3] = { + UNW_REG_F31, UNW_REG_R7, UNW_REG_B5 + }; + struct unw_reg_info *(regs[3]); + + regs[0] = sr->curr.reg + UNW_REG_F2; + regs[1] = sr->curr.reg + UNW_REG_R4; + regs[2] = sr->curr.reg + UNW_REG_B1; + + for (t = 0; t < sr->region_len; ++t) { + if ((t & 3) == 0) + mask = *cp++; + kind = (mask >> 2*(3-(t & 3))) & 3; + if (kind > 0) + spill_next_when(®s[kind - 1], sr->curr.reg + limit[kind - 1], + sr->region_start + t); + } + } + /* + * Next, lay out the memory stack spill area: + */ + if (sr->any_spills) { + off = sr->spill_offset; + alloc_spill_area(&off, 16, sr->curr.reg + UNW_REG_F2, sr->curr.reg + UNW_REG_F31); + alloc_spill_area(&off, 8, sr->curr.reg + UNW_REG_B1, sr->curr.reg + UNW_REG_B5); + alloc_spill_area(&off, 8, sr->curr.reg + UNW_REG_R4, sr->curr.reg + UNW_REG_R7); + } +} + +/* + * Region header descriptors. + */ + +static void +desc_prologue (int body, unw_word rlen, unsigned char mask, unsigned char grsave, + struct unw_state_record *sr) +{ + int i; + + if (!(sr->in_body || sr->first_region)) + finish_prologue(sr); + sr->first_region = 0; + + /* check if we're done: */ + if (body && sr->when_target < sr->region_start + sr->region_len) { + sr->done = 1; + return; + } + + for (i = 0; i < sr->epilogue_count; ++i) + pop(sr); + sr->epilogue_count = 0; + sr->epilogue_start = UNW_WHEN_NEVER; + + if (!body) + push(sr); + + sr->region_start += sr->region_len; + sr->region_len = rlen; + sr->in_body = body; + + if (!body) { + for (i = 0; i < 4; ++i) { + if (mask & 0x8) + set_reg(sr->curr.reg + unw.save_order[i], UNW_WHERE_GR, + sr->region_start + sr->region_len - 1, grsave++); + mask <<= 1; + } + sr->gr_save_loc = grsave; + sr->any_spills = 0; + sr->imask = 0; + sr->spill_offset = 0x10; /* default to psp+16 */ + } +} + +/* + * Prologue descriptors. + */ + +static inline void +desc_abi (unsigned char abi, unsigned char context, struct unw_state_record *sr) +{ + if (abi == 0 && context == 'i') + sr->flags |= UNW_FLAG_INTERRUPT_FRAME; + else + dprintk("unwind: ignoring unwabi(abi=0x%x,context=0x%x)\n", abi, context); +} + +static inline void +desc_br_gr (unsigned char brmask, unsigned char gr, struct unw_state_record *sr) +{ + int i; + + for (i = 0; i < 5; ++i) { + if (brmask & 1) + set_reg(sr->curr.reg + UNW_REG_B1 + i, UNW_WHERE_GR, + sr->region_start + sr->region_len - 1, gr++); + brmask >>= 1; + } +} + +static inline void +desc_br_mem (unsigned char brmask, struct unw_state_record *sr) +{ + int i; + + for (i = 0; i < 5; ++i) { + if (brmask & 1) { + set_reg(sr->curr.reg + UNW_REG_B1 + i, UNW_WHERE_SPILL_HOME, + sr->region_start + sr->region_len - 1, 0); + sr->any_spills = 1; + } + brmask >>= 1; + } +} + +static inline void +desc_frgr_mem (unsigned char grmask, unw_word frmask, struct unw_state_record *sr) +{ + int i; + + for (i = 0; i < 4; ++i) { + if ((grmask & 1) != 0) { + set_reg(sr->curr.reg + UNW_REG_R4 + i, UNW_WHERE_SPILL_HOME, + sr->region_start + sr->region_len - 1, 0); + sr->any_spills = 1; + } + grmask >>= 1; + } + for (i = 0; i < 20; ++i) { + if ((frmask & 1) != 0) { + set_reg(sr->curr.reg + UNW_REG_F2 + i, UNW_WHERE_SPILL_HOME, + sr->region_start + sr->region_len - 1, 0); + sr->any_spills = 1; + } + frmask >>= 1; + } +} + +static inline void +desc_fr_mem (unsigned char frmask, struct unw_state_record *sr) +{ + int i; + + for (i = 0; i < 4; ++i) { + if ((frmask & 1) != 0) { + set_reg(sr->curr.reg + UNW_REG_F2 + i, UNW_WHERE_SPILL_HOME, + sr->region_start + sr->region_len - 1, 0); + sr->any_spills = 1; + } + frmask >>= 1; + } +} + +static inline void +desc_gr_gr (unsigned char grmask, unsigned char gr, struct unw_state_record *sr) +{ + int i; + + for (i = 0; i < 4; ++i) { + if ((grmask & 1) != 0) + set_reg(sr->curr.reg + UNW_REG_R4 + i, UNW_WHERE_GR, + sr->region_start + sr->region_len - 1, gr++); + grmask >>= 1; + } +} + +static inline void +desc_gr_mem (unsigned char grmask, struct unw_state_record *sr) +{ + int i; + + for (i = 0; i < 4; ++i) { + if ((grmask & 1) != 0) { + set_reg(sr->curr.reg + UNW_REG_R4 + i, UNW_WHERE_SPILL_HOME, + sr->region_start + sr->region_len - 1, 0); + sr->any_spills = 1; + } + grmask >>= 1; + } +} + +static inline void +desc_mem_stack_f (unw_word t, unw_word size, struct unw_state_record *sr) +{ + set_reg(sr->curr.reg + UNW_REG_PSP, UNW_WHERE_NONE, + sr->region_start + MIN((int)t, sr->region_len - 1), 16*size); +} + +static inline void +desc_mem_stack_v (unw_word t, struct unw_state_record *sr) +{ + sr->curr.reg[UNW_REG_PSP].when = sr->region_start + MIN((int)t, sr->region_len - 1); +} + +static inline void +desc_reg_gr (unsigned char reg, unsigned char dst, struct unw_state_record *sr) +{ + set_reg(sr->curr.reg + reg, UNW_WHERE_GR, sr->region_start + sr->region_len - 1, dst); +} + +static inline void +desc_reg_psprel (unsigned char reg, unw_word pspoff, struct unw_state_record *sr) +{ + set_reg(sr->curr.reg + reg, UNW_WHERE_PSPREL, sr->region_start + sr->region_len - 1, + 0x10 - 4*pspoff); +} + +static inline void +desc_reg_sprel (unsigned char reg, unw_word spoff, struct unw_state_record *sr) +{ + set_reg(sr->curr.reg + reg, UNW_WHERE_SPREL, sr->region_start + sr->region_len - 1, + 4*spoff); +} + +static inline void +desc_rp_br (unsigned char dst, struct unw_state_record *sr) +{ + sr->return_link_reg = dst; +} + +static inline void +desc_reg_when (unsigned char regnum, unw_word t, struct unw_state_record *sr) +{ + struct unw_reg_info *reg = sr->curr.reg + regnum; + + if (reg->where == UNW_WHERE_NONE) + reg->where = UNW_WHERE_GR_SAVE; + reg->when = sr->region_start + MIN((int)t, sr->region_len - 1); +} + +static inline void +desc_spill_base (unw_word pspoff, struct unw_state_record *sr) +{ + sr->spill_offset = 0x10 - 4*pspoff; +} + +static inline unsigned char * +desc_spill_mask (unsigned char *imaskp, struct unw_state_record *sr) +{ + sr->imask = imaskp; + return imaskp + (2*sr->region_len + 7)/8; +} + +/* + * Body descriptors. + */ +static inline void +desc_epilogue (unw_word t, unw_word ecount, struct unw_state_record *sr) +{ + sr->epilogue_start = sr->region_start + sr->region_len - 1 - t; + sr->epilogue_count = ecount + 1; +} + +static inline void +desc_copy_state (unw_word label, struct unw_state_record *sr) +{ + struct unw_reg_state *rs; + + for (rs = sr->reg_state_list; rs; rs = rs->next) { + if (rs->label == label) { + memcpy (&sr->curr, rs, sizeof(sr->curr)); + return; + } + } + printk("unwind: failed to find state labelled 0x%lx\n", label); +} + +static inline void +desc_label_state (unw_word label, struct unw_state_record *sr) +{ + struct unw_reg_state *rs; + + rs = alloc_reg_state(); + memcpy(rs, &sr->curr, sizeof(*rs)); + rs->label = label; + rs->next = sr->reg_state_list; + sr->reg_state_list = rs; +} + +/* + * General descriptors. + */ + +static inline int +desc_is_active (unsigned char qp, unw_word t, struct unw_state_record *sr) +{ + if (sr->when_target <= sr->region_start + MIN((int)t, sr->region_len - 1)) + return 0; + if (qp > 0) { + if ((sr->pr_val & (1UL << qp)) == 0) + return 0; + sr->pr_mask |= (1UL << qp); + } + return 1; +} + +static inline void +desc_restore_p (unsigned char qp, unw_word t, unsigned char abreg, struct unw_state_record *sr) +{ + struct unw_reg_info *r; + + if (!desc_is_active(qp, t, sr)) + return; + + r = sr->curr.reg + decode_abreg(abreg, 0); + r->where = UNW_WHERE_NONE; + r->when = sr->region_start + MIN((int)t, sr->region_len - 1); + r->val = 0; +} + +static inline void +desc_spill_reg_p (unsigned char qp, unw_word t, unsigned char abreg, unsigned char x, + unsigned char ytreg, struct unw_state_record *sr) +{ + enum unw_where where = UNW_WHERE_GR; + struct unw_reg_info *r; + + if (!desc_is_active(qp, t, sr)) + return; + + if (x) + where = UNW_WHERE_BR; + else if (ytreg & 0x80) + where = UNW_WHERE_FR; + + r = sr->curr.reg + decode_abreg(abreg, 0); + r->where = where; + r->when = sr->region_start + MIN((int)t, sr->region_len - 1); + r->val = (ytreg & 0x7f); +} + +static inline void +desc_spill_psprel_p (unsigned char qp, unw_word t, unsigned char abreg, unw_word pspoff, + struct unw_state_record *sr) +{ + struct unw_reg_info *r; + + if (!desc_is_active(qp, t, sr)) + return; + + r = sr->curr.reg + decode_abreg(abreg, 1); + r->where = UNW_WHERE_PSPREL; + r->when = sr->region_start + MIN((int)t, sr->region_len - 1); + r->val = 0x10 - 4*pspoff; +} + +static inline void +desc_spill_sprel_p (unsigned char qp, unw_word t, unsigned char abreg, unw_word spoff, + struct unw_state_record *sr) +{ + struct unw_reg_info *r; + + if (!desc_is_active(qp, t, sr)) + return; + + r = sr->curr.reg + decode_abreg(abreg, 1); + r->where = UNW_WHERE_SPREL; + r->when = sr->region_start + MIN((int)t, sr->region_len - 1); + r->val = 4*spoff; +} + +#define UNW_DEC_BAD_CODE(code) printk("unwind: unknown code 0x%02x\n", code); + +/* + * region headers: + */ +#define UNW_DEC_PROLOGUE_GR(fmt,r,m,gr,arg) desc_prologue(0,r,m,gr,arg) +#define UNW_DEC_PROLOGUE(fmt,b,r,arg) desc_prologue(b,r,0,32,arg) +/* + * prologue descriptors: + */ +#define UNW_DEC_ABI(fmt,a,c,arg) desc_abi(a,c,arg) +#define UNW_DEC_BR_GR(fmt,b,g,arg) desc_br_gr(b,g,arg) +#define UNW_DEC_BR_MEM(fmt,b,arg) desc_br_mem(b,arg) +#define UNW_DEC_FRGR_MEM(fmt,g,f,arg) desc_frgr_mem(g,f,arg) +#define UNW_DEC_FR_MEM(fmt,f,arg) desc_fr_mem(f,arg) +#define UNW_DEC_GR_GR(fmt,m,g,arg) desc_gr_gr(m,g,arg) +#define UNW_DEC_GR_MEM(fmt,m,arg) desc_gr_mem(m,arg) +#define UNW_DEC_MEM_STACK_F(fmt,t,s,arg) desc_mem_stack_f(t,s,arg) +#define UNW_DEC_MEM_STACK_V(fmt,t,arg) desc_mem_stack_v(t,arg) +#define UNW_DEC_REG_GR(fmt,r,d,arg) desc_reg_gr(r,d,arg) +#define UNW_DEC_REG_PSPREL(fmt,r,o,arg) desc_reg_psprel(r,o,arg) +#define UNW_DEC_REG_SPREL(fmt,r,o,arg) desc_reg_sprel(r,o,arg) +#define UNW_DEC_REG_WHEN(fmt,r,t,arg) desc_reg_when(r,t,arg) +#define UNW_DEC_PRIUNAT_WHEN_GR(fmt,t,arg) desc_reg_when(UNW_REG_PRI_UNAT_GR,t,arg) +#define UNW_DEC_PRIUNAT_WHEN_MEM(fmt,t,arg) desc_reg_when(UNW_REG_PRI_UNAT_MEM,t,arg) +#define UNW_DEC_PRIUNAT_GR(fmt,r,arg) desc_reg_gr(UNW_REG_PRI_UNAT_GR,r,arg) +#define UNW_DEC_PRIUNAT_PSPREL(fmt,o,arg) desc_reg_psprel(UNW_REG_PRI_UNAT_MEM,o,arg) +#define UNW_DEC_PRIUNAT_SPREL(fmt,o,arg) desc_reg_sprel(UNW_REG_PRI_UNAT_MEM,o,arg) +#define UNW_DEC_RP_BR(fmt,d,arg) desc_rp_br(d,arg) +#define UNW_DEC_SPILL_BASE(fmt,o,arg) desc_spill_base(o,arg) +#define UNW_DEC_SPILL_MASK(fmt,m,arg) (m = desc_spill_mask(m,arg)) +/* + * body descriptors: + */ +#define UNW_DEC_EPILOGUE(fmt,t,c,arg) desc_epilogue(t,c,arg) +#define UNW_DEC_COPY_STATE(fmt,l,arg) desc_copy_state(l,arg) +#define UNW_DEC_LABEL_STATE(fmt,l,arg) desc_label_state(l,arg) +/* + * general unwind descriptors: + */ +#define UNW_DEC_SPILL_REG_P(f,p,t,a,x,y,arg) desc_spill_reg_p(p,t,a,x,y,arg) +#define UNW_DEC_SPILL_REG(f,t,a,x,y,arg) desc_spill_reg_p(0,t,a,x,y,arg) +#define UNW_DEC_SPILL_PSPREL_P(f,p,t,a,o,arg) desc_spill_psprel_p(p,t,a,o,arg) +#define UNW_DEC_SPILL_PSPREL(f,t,a,o,arg) desc_spill_psprel_p(0,t,a,o,arg) +#define UNW_DEC_SPILL_SPREL_P(f,p,t,a,o,arg) desc_spill_sprel_p(p,t,a,o,arg) +#define UNW_DEC_SPILL_SPREL(f,t,a,o,arg) desc_spill_sprel_p(0,t,a,o,arg) +#define UNW_DEC_RESTORE_P(f,p,t,a,arg) desc_restore_p(p,t,a,arg) +#define UNW_DEC_RESTORE(f,t,a,arg) desc_restore_p(0,t,a,arg) + +#include "unwind_decoder.c" + + +/* Unwind scripts. */ + +static inline unw_hash_index_t +hash (unsigned long ip) +{ +# define magic 0x9e3779b97f4a7c16 /* (sqrt(5)/2-1)*2^64 */ + + return (ip >> 4)*magic >> (64 - UNW_LOG_HASH_SIZE); +} + +static inline long +cache_match (struct unw_script *script, unsigned long ip, unsigned long pr_val) +{ + read_lock(&script->lock); + if ((ip) == (script)->ip && (((pr_val) ^ (script)->pr_val) & (script)->pr_mask) == 0) + /* keep the read lock... */ + return 1; + read_unlock(&script->lock); + return 0; +} + +static inline struct unw_script * +script_lookup (struct unw_frame_info *info) +{ + struct unw_script *script = unw.cache + info->hint; + unsigned long ip, pr_val; + + STAT(++unw.stat.cache.lookups); + + ip = info->ip; + pr_val = info->pr_val; + + if (cache_match(script, ip, pr_val)) { + STAT(++unw.stat.cache.hinted_hits); + return script; + } + + script = unw.cache + unw.hash[hash(ip)]; + while (1) { + if (cache_match(script, ip, pr_val)) { + /* update hint; no locking required as single-word writes are atomic */ + STAT(++unw.stat.cache.normal_hits); + unw.cache[info->prev_script].hint = script - unw.cache; + return script; + } + if (script->coll_chain >= UNW_HASH_SIZE) + return 0; + script = unw.cache + script->coll_chain; + STAT(++unw.stat.cache.collision_chain_traversals); + } +} + +/* + * On returning, a write lock for the SCRIPT is still being held. + */ +static inline struct unw_script * +script_new (unsigned long ip) +{ + struct unw_script *script, *prev, *tmp; + unsigned long flags; + unsigned char index; + unsigned short head; + + STAT(++unw.stat.script.news); + + /* + * Can't (easily) use cmpxchg() here because of ABA problem + * that is intrinsic in cmpxchg()... + */ + spin_lock_irqsave(&unw.lock, flags); + { + head = unw.lru_head; + script = unw.cache + head; + unw.lru_head = script->lru_chain; + } + spin_unlock(&unw.lock); + + /* + * XXX We'll deadlock here if we interrupt a thread that is + * holding a read lock on script->lock. A try_write_lock() + * might be mighty handy here... Alternatively, we could + * disable interrupts whenever we hold a read-lock, but that + * seems silly. + */ + write_lock(&script->lock); + + spin_lock(&unw.lock); + { + /* re-insert script at the tail of the LRU chain: */ + unw.cache[unw.lru_tail].lru_chain = head; + unw.lru_tail = head; + + /* remove the old script from the hash table (if it's there): */ + index = hash(script->ip); + tmp = unw.cache + unw.hash[index]; + prev = 0; + while (1) { + if (tmp == script) { + if (prev) + prev->coll_chain = tmp->coll_chain; + else + unw.hash[index] = tmp->coll_chain; + break; + } else + prev = tmp; + if (tmp->coll_chain >= UNW_CACHE_SIZE) + /* old script wasn't in the hash-table */ + break; + tmp = unw.cache + tmp->coll_chain; + } + + /* enter new script in the hash table */ + index = hash(ip); + script->coll_chain = unw.hash[index]; + unw.hash[index] = script - unw.cache; + + script->ip = ip; /* set new IP while we're holding the locks */ + + STAT(if (script->coll_chain < UNW_CACHE_SIZE) ++unw.stat.script.collisions); + } + spin_unlock_irqrestore(&unw.lock, flags); + + script->flags = 0; + script->hint = 0; + script->count = 0; + return script; +} + +static void +script_finalize (struct unw_script *script, struct unw_state_record *sr) +{ + script->pr_mask = sr->pr_mask; + script->pr_val = sr->pr_val; + /* + * We could down-grade our write-lock on script->lock here but + * the rwlock API doesn't offer atomic lock downgrading, so + * we'll just keep the write-lock and release it later when + * we're done using the script. + */ +} + +static inline void +script_emit (struct unw_script *script, struct unw_insn insn) +{ + if (script->count >= UNW_MAX_SCRIPT_LEN) { + dprintk("unwind: script exceeds maximum size of %u instructions!\n", + UNW_MAX_SCRIPT_LEN); + return; + } + script->insn[script->count++] = insn; +} + +static inline void +emit_nat_info (struct unw_state_record *sr, int i, struct unw_script *script) +{ + struct unw_reg_info *r = sr->curr.reg + i; + enum unw_insn_opcode opc; + struct unw_insn insn; + unsigned long val; + + switch (r->where) { + case UNW_WHERE_GR: + if (r->val >= 32) { + /* register got spilled to a stacked register */ + opc = UNW_INSN_SETNAT_TYPE; + val = UNW_NAT_STACKED; + } else { + /* register got spilled to a scratch register */ + opc = UNW_INSN_SETNAT_TYPE; + val = UNW_NAT_SCRATCH; + } + break; + + case UNW_WHERE_FR: + opc = UNW_INSN_SETNAT_TYPE; + val = UNW_NAT_VAL; + break; + + case UNW_WHERE_BR: + opc = UNW_INSN_SETNAT_TYPE; + val = UNW_NAT_NONE; + break; + + case UNW_WHERE_PSPREL: + case UNW_WHERE_SPREL: + opc = UNW_INSN_SETNAT_PRI_UNAT; + val = 0; + break; + + default: + dprintk("unwind: don't know how to emit nat info for where = %u\n", r->where); + return; + } + insn.opc = opc; + insn.dst = unw.preg_index[i]; + insn.val = val; + script_emit(script, insn); +} + +static void +compile_reg (struct unw_state_record *sr, int i, struct unw_script *script) +{ + struct unw_reg_info *r = sr->curr.reg + i; + enum unw_insn_opcode opc; + unsigned long val, rval; + struct unw_insn insn; + long need_nat_info; + + if (r->where == UNW_WHERE_NONE || r->when >= sr->when_target) + return; + + opc = UNW_INSN_MOVE; + val = rval = r->val; + need_nat_info = (i >= UNW_REG_R4 && i <= UNW_REG_R7); + + switch (r->where) { + case UNW_WHERE_GR: + if (rval >= 32) { + opc = UNW_INSN_MOVE_STACKED; + val = rval - 32; + } else if (rval >= 4 && rval <= 7) { + if (need_nat_info) { + opc = UNW_INSN_MOVE2; + need_nat_info = 0; + } + val = unw.preg_index[UNW_REG_R4 + (rval - 4)]; + } else { + opc = UNW_INSN_LOAD_SPREL; + val = -sizeof(struct pt_regs); + if (rval >= 1 && rval <= 3) + val += struct_offset(struct pt_regs, r1) + 8*(rval - 1); + else if (rval <= 11) + val += struct_offset(struct pt_regs, r8) + 8*(rval - 8); + else if (rval <= 15) + val += struct_offset(struct pt_regs, r12) + 8*(rval - 12); + else if (rval <= 31) + val += struct_offset(struct pt_regs, r16) + 8*(rval - 16); + else + dprintk("unwind: bad scratch reg r%lu\n", rval); + } + break; + + case UNW_WHERE_FR: + if (rval <= 5) + val = unw.preg_index[UNW_REG_F2 + (rval - 1)]; + else if (rval >= 16 && rval <= 31) + val = unw.preg_index[UNW_REG_F16 + (rval - 16)]; + else { + opc = UNW_INSN_LOAD_SPREL; + val = -sizeof(struct pt_regs); + if (rval <= 9) + val += struct_offset(struct pt_regs, f6) + 16*(rval - 6); + else + dprintk("unwind: kernel may not touch f%lu\n", rval); + } + break; + + case UNW_WHERE_BR: + if (rval >= 1 && rval <= 5) + val = unw.preg_index[UNW_REG_B1 + (rval - 1)]; + else { + opc = UNW_INSN_LOAD_SPREL; + val = -sizeof(struct pt_regs); + if (rval == 0) + val += struct_offset(struct pt_regs, b0); + else if (rval == 6) + val += struct_offset(struct pt_regs, b6); + else + val += struct_offset(struct pt_regs, b7); + } + break; + + case UNW_WHERE_SPREL: + opc = UNW_INSN_LOAD_SPREL; + break; + + case UNW_WHERE_PSPREL: + opc = UNW_INSN_LOAD_PSPREL; + break; + + default: + dprintk("unwind: register %u has unexpected `where' value of %u\n", i, r->where); + break; + } + insn.opc = opc; + insn.dst = unw.preg_index[i]; + insn.val = val; + script_emit(script, insn); + if (need_nat_info) + emit_nat_info(sr, i, script); +} + +static inline struct unw_table_entry * +lookup (struct unw_table *table, unsigned long rel_ip) +{ + struct unw_table_entry *e = 0; + unsigned long lo, hi, mid; + + /* do a binary search for right entry: */ + for (lo = 0, hi = table->length; lo < hi; ) { + mid = (lo + hi) / 2; + e = &table->array[mid]; + if (rel_ip < e->start_offset) + hi = mid; + else if (rel_ip >= e->end_offset) + lo = mid + 1; + else + break; + } + return e; +} + +/* + * Build an unwind script that unwinds from state OLD_STATE to the + * entrypoint of the function that called OLD_STATE. + */ +static inline struct unw_script * +build_script (struct unw_frame_info *info) +{ + struct unw_reg_state *rs, *next; + struct unw_table_entry *e = 0; + struct unw_script *script = 0; + unsigned long ip = info->ip; + struct unw_state_record sr; + struct unw_table *table; + struct unw_reg_info *r; + struct unw_insn insn; + u8 *dp, *desc_end; + u64 hdr; + int i; + STAT(unsigned long start, parse_start;) + + STAT(++unw.stat.script.builds; start = ia64_get_itc()); + + /* build state record */ + memset(&sr, 0, sizeof(sr)); + for (r = sr.curr.reg; r < sr.curr.reg + UNW_NUM_REGS; ++r) + r->when = UNW_WHEN_NEVER; + sr.pr_val = info->pr_val; + + script = script_new(ip); + if (!script) { + dprintk("unwind: failed to create unwind script\n"); + STAT(unw.stat.script.build_time += ia64_get_itc() - start); + return 0; + } + unw.cache[info->prev_script].hint = script - unw.cache; + + /* search the kernels and the modules' unwind tables for IP: */ + + STAT(parse_start = ia64_get_itc()); + + for (table = unw.tables; table; table = table->next) { + if (ip >= table->start && ip < table->end) { + e = lookup(table, ip - table->segment_base); + break; + } + } + if (!e) { + /* no info, return default unwinder (leaf proc, no mem stack, no saved regs) */ + dprintk("unwind: no unwind info for ip=0x%lx (prev ip=0x%lx)\n", ip, + unw.cache[info->prev_script].ip); + sr.curr.reg[UNW_REG_RP].where = UNW_WHERE_BR; + sr.curr.reg[UNW_REG_RP].when = -1; + sr.curr.reg[UNW_REG_RP].val = 0; + compile_reg(&sr, UNW_REG_RP, script); + script_finalize(script, &sr); + STAT(unw.stat.script.parse_time += ia64_get_itc() - parse_start); + STAT(unw.stat.script.build_time += ia64_get_itc() - start); + return script; + } + + sr.when_target = (3*((ip & ~0xfUL) - (table->segment_base + e->start_offset))/16 + + (ip & 0xfUL)); + hdr = *(u64 *) (table->segment_base + e->info_offset); + dp = (u8 *) (table->segment_base + e->info_offset + 8); + desc_end = dp + 8*UNW_LENGTH(hdr); + + while (!sr.done && dp < desc_end) + dp = unw_decode(dp, sr.in_body, &sr); + + if (sr.when_target > sr.epilogue_start) { + /* + * sp has been restored and all values on the memory stack below + * psp also have been restored. + */ + sr.curr.reg[UNW_REG_PSP].where = UNW_WHERE_NONE; + sr.curr.reg[UNW_REG_PSP].val = 0; + for (r = sr.curr.reg; r < sr.curr.reg + UNW_NUM_REGS; ++r) + if ((r->where == UNW_WHERE_PSPREL && r->val <= 0x10) + || r->where == UNW_WHERE_SPREL) + r->where = UNW_WHERE_NONE; + } + + script->flags = sr.flags; + + /* + * If RP did't get saved, generate entry for the return link + * register. + */ + if (sr.curr.reg[UNW_REG_RP].when >= sr.when_target) { + sr.curr.reg[UNW_REG_RP].where = UNW_WHERE_BR; + sr.curr.reg[UNW_REG_RP].when = -1; + sr.curr.reg[UNW_REG_RP].val = sr.return_link_reg; + } + +#if UNW_DEBUG + printk ("unwind: state record for func 0x%lx, t=%u:\n", + table->segment_base + e->start_offset, sr.when_target); + for (r = sr.curr.reg; r < sr.curr.reg + UNW_NUM_REGS; ++r) { + if (r->where != UNW_WHERE_NONE || r->when != UNW_WHEN_NEVER) { + printk(" %s <- ", unw.preg_name[r - sr.curr.reg]); + switch (r->where) { + case UNW_WHERE_GR: printk("r%lu", r->val); break; + case UNW_WHERE_FR: printk("f%lu", r->val); break; + case UNW_WHERE_BR: printk("b%lu", r->val); break; + case UNW_WHERE_SPREL: printk("[sp+0x%lx]", r->val); break; + case UNW_WHERE_PSPREL: printk("[psp+0x%lx]", r->val); break; + case UNW_WHERE_NONE: + printk("%s+0x%lx", unw.preg_name[r - sr.curr.reg], r->val); + break; + default: printk("BADWHERE(%d)", r->where); break; + } + printk ("\t\t%d\n", r->when); + } + } +#endif + + STAT(unw.stat.script.parse_time += ia64_get_itc() - parse_start); + + /* translate state record into unwinder instructions: */ + + if (sr.curr.reg[UNW_REG_PSP].where == UNW_WHERE_NONE + && sr.when_target > sr.curr.reg[UNW_REG_PSP].when && sr.curr.reg[UNW_REG_PSP].val != 0) + { + /* new psp is sp plus frame size */ + insn.opc = UNW_INSN_ADD; + insn.dst = unw.preg_index[UNW_REG_PSP]; + insn.val = sr.curr.reg[UNW_REG_PSP].val; + script_emit(script, insn); + } + + /* determine where the primary UNaT is: */ + if (sr.when_target < sr.curr.reg[UNW_REG_PRI_UNAT_GR].when) + i = UNW_REG_PRI_UNAT_MEM; + else if (sr.when_target < sr.curr.reg[UNW_REG_PRI_UNAT_MEM].when) + i = UNW_REG_PRI_UNAT_GR; + else if (sr.curr.reg[UNW_REG_PRI_UNAT_MEM].when > sr.curr.reg[UNW_REG_PRI_UNAT_GR].when) + i = UNW_REG_PRI_UNAT_MEM; + else + i = UNW_REG_PRI_UNAT_GR; + + compile_reg(&sr, i, script); + + for (i = UNW_REG_BSP; i < UNW_NUM_REGS; ++i) + compile_reg(&sr, i, script); + + /* free labelled register states & stack: */ + + STAT(parse_start = ia64_get_itc()); + for (rs = sr.reg_state_list; rs; rs = next) { + next = rs->next; + free_reg_state(rs); + } + while (sr.stack) + pop(&sr); + STAT(unw.stat.script.parse_time += ia64_get_itc() - parse_start); + + script_finalize(script, &sr); + STAT(unw.stat.script.build_time += ia64_get_itc() - start); + return script; +} + +/* + * Apply the unwinding actions represented by OPS and update SR to + * reflect the state that existed upon entry to the function that this + * unwinder represents. + */ +static inline void +run_script (struct unw_script *script, struct unw_frame_info *state) +{ + struct unw_insn *ip, *limit, next_insn; + unsigned long opc, dst, val, off; + unsigned long *s = (unsigned long *) state; + STAT(unsigned long start;) + + STAT(++unw.stat.script.runs; start = ia64_get_itc()); + state->flags = script->flags; + ip = script->insn; + limit = script->insn + script->count; + next_insn = *ip; + + while (ip++ < limit) { + opc = next_insn.opc; + dst = next_insn.dst; + val = next_insn.val; + next_insn = *ip; + + redo: + switch (opc) { + case UNW_INSN_ADD: + s[dst] += val; + break; + + case UNW_INSN_MOVE2: + if (!s[val]) + goto lazy_init; + s[dst+1] = s[val+1]; + s[dst] = s[val]; + break; + + case UNW_INSN_MOVE: + if (!s[val]) + goto lazy_init; + s[dst] = s[val]; + break; + + case UNW_INSN_MOVE_STACKED: + s[dst] = (unsigned long) ia64_rse_skip_regs((unsigned long *)state->bsp, + val); + break; + + case UNW_INSN_LOAD_PSPREL: + s[dst] = state->psp + val; + break; + + case UNW_INSN_LOAD_SPREL: + s[dst] = state->sp + val; + break; + + case UNW_INSN_SETNAT_PRI_UNAT: + if (!state->pri_unat) + state->pri_unat = &state->sw->caller_unat; + s[dst+1] = ((*state->pri_unat - s[dst]) << 32) | UNW_NAT_PRI_UNAT; + break; + + case UNW_INSN_SETNAT_TYPE: + s[dst+1] = val; + break; + } + } + STAT(unw.stat.script.run_time += ia64_get_itc() - start); + return; + + lazy_init: + off = unw.sw_off[val]; + s[val] = (unsigned long) state->sw + off; + if (off >= struct_offset (struct unw_frame_info, r4) + && off <= struct_offset (struct unw_frame_info, r7)) + /* + * We're initializing a general register: init NaT info, too. Note that we + * rely on the fact that call_unat is the first field in struct switch_stack: + */ + s[val+1] = (-off << 32) | UNW_NAT_PRI_UNAT; + goto redo; +} + +static int +find_save_locs (struct unw_frame_info *info) +{ + int have_write_lock = 0; + struct unw_script *scr; + + if ((info->ip & (my_cpu_data.unimpl_va_mask | 0xf)) + || REGION_NUMBER(info->ip) != REGION_KERNEL) + { + /* don't let obviously bad addresses pollute the cache */ + dprintk("unwind: rejecting bad ip=0x%lx\n", info->ip); + info->rp = 0; + return -1; + } + + scr = script_lookup(info); + if (!scr) { + scr = build_script(info); + if (!scr) { + dprintk("unwind: failed to locate/build unwind script for ip %lx\n", + info->ip); + return -1; + } + have_write_lock = 1; + } + info->hint = scr->hint; + info->prev_script = scr - unw.cache; + + run_script(scr, info); + + if (have_write_lock) + write_unlock(&scr->lock); + else + read_unlock(&scr->lock); + return 0; +} + +int +unw_unwind (struct unw_frame_info *info) +{ + unsigned long prev_ip, prev_sp, prev_bsp; + unsigned long ip, pr, num_regs; + STAT(unsigned long start, flags;) + int retval; + + STAT(local_irq_save(flags); ++unw.stat.api.unwinds; start = ia64_get_itc()); + + prev_ip = info->ip; + prev_sp = info->sp; + prev_bsp = info->bsp; + + /* restore the ip */ + if (!info->rp) { + dprintk("unwind: failed to locate return link (ip=0x%lx)!\n", info->ip); + STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags)); + return -1; + } + ip = info->ip = *info->rp; + if (ip < GATE_ADDR + PAGE_SIZE) { + /* + * We don't have unwind info for the gate page, so we consider that part + * of user-space for the purpose of unwinding. + */ + dprintk("unwind: reached user-space (ip=0x%lx)\n", ip); + STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags)); + return -1; + } + + /* restore the cfm: */ + if (!info->pfs) { + dprintk("unwind: failed to locate ar.pfs!\n"); + STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags)); + return -1; + } + info->cfm = info->pfs; + + /* restore the bsp: */ + pr = info->pr_val; + num_regs = 0; + if ((info->flags & UNW_FLAG_INTERRUPT_FRAME)) { + if ((pr & (1UL << pNonSys)) != 0) + num_regs = *info->cfm & 0x7f; /* size of frame */ + info->pfs = + (unsigned long *) (info->sp + 16 + struct_offset(struct pt_regs, ar_pfs)); + } else + num_regs = (*info->cfm >> 7) & 0x7f; /* size of locals */ + info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->bsp, -num_regs); + if (info->bsp < info->regstk.limit || info->bsp > info->regstk.top) { + dprintk("unwind: bsp (0x%lx) out of range [0x%lx-0x%lx]\n", + info->bsp, info->regstk.limit, info->regstk.top); + STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags)); + return -1; + } + + /* restore the sp: */ + info->sp = info->psp; + if (info->sp < info->memstk.top || info->sp > info->memstk.limit) { + dprintk("unwind: sp (0x%lx) out of range [0x%lx-0x%lx]\n", + info->sp, info->regstk.top, info->regstk.limit); + STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags)); + return -1; + } + + if (info->ip == prev_ip && info->sp == prev_sp && info->bsp == prev_bsp) { + dprintk("unwind: ip, sp, bsp remain unchanged; stopping here (ip=0x%lx)\n", ip); + STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags)); + return -1; + } + + /* finally, restore the predicates: */ + unw_get_pr(info, &info->pr_val); + + retval = find_save_locs(info); + STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags)); + return retval; +} + +int +unw_unwind_to_user (struct unw_frame_info *info) +{ + unsigned long ip; + + while (unw_unwind(info) >= 0) { + if (unw_get_rp(info, &ip) < 0) { + unw_get_ip(info, &ip); + dprintk("unwind: failed to read return pointer (ip=0x%lx)\n", ip); + return -1; + } + /* + * We don't have unwind info for the gate page, so we consider that part + * of user-space for the purpose of unwinding. + */ + if (ip < GATE_ADDR + PAGE_SIZE) + return 0; + } + unw_get_ip(info, &ip); + dprintk("unwind: failed to unwind to user-level (ip=0x%lx)\n", ip); + return -1; +} + +void +unw_init_frame_info (struct unw_frame_info *info, struct task_struct *t, struct switch_stack *sw) +{ + unsigned long rbslimit, rbstop, stklimit, stktop, sol; + STAT(unsigned long start, flags;) + + STAT(local_irq_save(flags); ++unw.stat.api.inits; start = ia64_get_itc()); + + /* + * Subtle stuff here: we _could_ unwind through the + * switch_stack frame but we don't want to do that because it + * would be slow as each preserved register would have to be + * processed. Instead, what we do here is zero out the frame + * info and start the unwind process at the function that + * created the switch_stack frame. When a preserved value in + * switch_stack needs to be accessed, run_script() will + * initialize the appropriate pointer on demand. + */ + memset(info, 0, sizeof(*info)); + + rbslimit = (unsigned long) t + IA64_RBS_OFFSET; + rbstop = sw->ar_bspstore; + if (rbstop - (unsigned long) t >= IA64_STK_OFFSET) + rbstop = rbslimit; + + stklimit = (unsigned long) t + IA64_STK_OFFSET; + stktop = (unsigned long) sw - 16; + if (stktop <= rbstop) + stktop = rbstop; + + info->regstk.limit = rbslimit; + info->regstk.top = rbstop; + info->memstk.limit = stklimit; + info->memstk.top = stktop; + info->task = t; + info->sw = sw; + info->sp = info->psp = (unsigned long) (sw + 1) - 16; + info->cfm = &sw->ar_pfs; + sol = (*info->cfm >> 7) & 0x7f; + info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sol); + info->ip = sw->b0; + info->pr_val = sw->pr; + + find_save_locs(info); + STAT(unw.stat.api.init_time += ia64_get_itc() - start; local_irq_restore(flags)); +} + +#endif /* CONFIG_IA64_NEW_UNWIND */ + void -ia64_unwind_init_from_blocked_task (struct ia64_frame_info *info, struct task_struct *t) +unw_init_from_blocked_task (struct unw_frame_info *info, struct task_struct *t) { struct switch_stack *sw = (struct switch_stack *) (t->thread.ksp + 16); + +#ifdef CONFIG_IA64_NEW_UNWIND + unw_init_frame_info(info, t, sw); +#else unsigned long sol, limit, top; memset(info, 0, sizeof(*info)); @@ -22,17 +1802,25 @@ if (top - (unsigned long) t >= IA64_STK_OFFSET) top = limit; - info->regstk.limit = (unsigned long *) limit; - info->regstk.top = (unsigned long *) top; - info->bsp = ia64_rse_skip_regs(info->regstk.top, -sol); - info->top_rnat = sw->ar_rnat; - info->cfm = sw->ar_pfs; - info->ip = sw->b0; + info->regstk.limit = limit; + info->regstk.top = top; + info->sw = sw; + info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sol); + info->cfm = &sw->ar_pfs; + info->ip = sw->b0; +#endif } void -ia64_unwind_init_from_current (struct ia64_frame_info *info, struct pt_regs *regs) +unw_init_from_current (struct unw_frame_info *info, struct pt_regs *regs) { +#ifdef CONFIG_IA64_NEW_UNWIND + struct switch_stack *sw = (struct switch_stack *) regs - 1; + + unw_init_frame_info(info, current, sw); + /* skip over interrupt frame: */ + unw_unwind(info); +#else struct switch_stack *sw = (struct switch_stack *) regs - 1; unsigned long sol, sof, *bsp, limit, top; @@ -44,34 +1832,40 @@ memset(info, 0, sizeof(*info)); sol = (sw->ar_pfs >> 7) & 0x7f; /* size of frame */ - info->regstk.limit = (unsigned long *) limit; - info->regstk.top = (unsigned long *) top; - info->top_rnat = sw->ar_rnat; /* this gives us the bsp top level frame (kdb interrupt frame): */ bsp = ia64_rse_skip_regs((unsigned long *) top, -sol); /* now skip past the interrupt frame: */ sof = regs->cr_ifs & 0x7f; /* size of frame */ - info->cfm = regs->cr_ifs; - info->bsp = ia64_rse_skip_regs(bsp, -sof); + + info->regstk.limit = limit; + info->regstk.top = top; + info->sw = sw; + info->bsp = (unsigned long) ia64_rse_skip_regs(bsp, -sof); + info->cfm = ®s->cr_ifs; info->ip = regs->cr_iip; +#endif } +#ifndef CONFIG_IA64_NEW_UNWIND + static unsigned long -read_reg (struct ia64_frame_info *info, int regnum, int *is_nat) +read_reg (struct unw_frame_info *info, int regnum, int *is_nat) { unsigned long *addr, *rnat_addr, rnat; - addr = ia64_rse_skip_regs(info->bsp, regnum); - if (addr < info->regstk.limit || addr >= info->regstk.top || ((long) addr & 0x7) != 0) { + addr = ia64_rse_skip_regs((unsigned long *) info->bsp, regnum); + if ((unsigned long) addr < info->regstk.limit + || (unsigned long) addr >= info->regstk.top || ((long) addr & 0x7) != 0) + { *is_nat = 1; return 0xdeadbeefdeadbeef; } rnat_addr = ia64_rse_rnat_addr(addr); - if (rnat_addr >= info->regstk.top) - rnat = info->top_rnat; + if ((unsigned long) rnat_addr >= info->regstk.top) + rnat = info->sw->ar_rnat; else rnat = *rnat_addr; *is_nat = (rnat & (1UL << ia64_rse_slot_num(addr))) != 0; @@ -83,9 +1877,9 @@ * store for r32. */ int -ia64_unwind_to_previous_frame (struct ia64_frame_info *info) +unw_unwind (struct unw_frame_info *info) { - unsigned long sol, cfm = info->cfm; + unsigned long sol, cfm = *info->cfm; int is_nat; sol = (cfm >> 7) & 0x7f; /* size of locals */ @@ -103,16 +1897,187 @@ return -1; info->ip = read_reg(info, sol - 2, &is_nat); - if (is_nat) + if (is_nat || (info->ip & (my_cpu_data.unimpl_va_mask | 0xf))) + /* reject let obviously bad addresses */ return -1; + info->cfm = ia64_rse_skip_regs((unsigned long *) info->bsp, sol - 1); cfm = read_reg(info, sol - 1, &is_nat); if (is_nat) return -1; sol = (cfm >> 7) & 0x7f; - info->cfm = cfm; - info->bsp = ia64_rse_skip_regs(info->bsp, -sol); + info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->bsp, -sol); return 0; +} +#endif /* !CONFIG_IA64_NEW_UNWIND */ + +#ifdef CONFIG_IA64_NEW_UNWIND + +static void +init_unwind_table (struct unw_table *table, const char *name, unsigned long segment_base, + unsigned long gp, void *table_start, void *table_end) +{ + struct unw_table_entry *start = table_start, *end = table_end; + +#ifdef UNWIND_TABLE_SORT_BUG + { + struct unw_table_entry *e1, *e2, tmp; + + /* stupid bubble sort... */ + + for (e1 = start; e1 < end; ++e1) { + for (e2 = e1 + 1; e2 < end; ++e2) { + if (e2->start_offset < e1->start_offset) { + tmp = *e1; + *e1 = *e2; + *e2 = tmp; + } + } + } + } +#endif + table->name = name; + table->segment_base = segment_base; + table->gp = gp; + table->start = segment_base + start[0].start_offset; + table->end = segment_base + end[-1].end_offset; + table->array = start; + table->length = end - start; +} + +void * +unw_add_unwind_table (const char *name, unsigned long segment_base, unsigned long gp, + void *table_start, void *table_end) +{ + struct unw_table_entry *start = table_start, *end = table_end; + struct unw_table *table; + unsigned long flags; + + if (end - start <= 0) { + dprintk("unwind: ignoring attempt to insert empty unwind table\n"); + return 0; + } + + table = kmalloc(sizeof(*table), GFP_USER); + if (!table) + return 0; + + init_unwind_table(table, name, segment_base, gp, table_start, table_end); + + spin_lock_irqsave(&unw.lock, flags); + { + /* keep kernel unwind table at the front (it's searched most commonly): */ + table->next = unw.tables->next; + unw.tables->next = table; + } + spin_unlock_irqrestore(&unw.lock, flags); + + return table; +} + +void +unw_remove_unwind_table (void *handle) +{ + struct unw_table *table, *prevt; + struct unw_script *tmp, *prev; + unsigned long flags; + long index; + + if (!handle) { + dprintk("unwind: ignoring attempt to remove non-existent unwind table\n"); + return; + } + + table = handle; + if (table == &unw.kernel_table) { + dprintk("unwind: sorry, freeing the kernel's unwind table is a no-can-do!\n"); + return; + } + + spin_lock_irqsave(&unw.lock, flags); + { + /* first, delete the table: */ + + for (prevt = (struct unw_table *) &unw.tables; prevt; prevt = prevt->next) + if (prevt->next == table) + break; + if (!prevt) { + dprintk("unwind: failed to find unwind table %p\n", table); + spin_unlock_irqrestore(&unw.lock, flags); + return; + } + prevt->next = table->next; + + /* next, remove hash table entries for this table */ + + for (index = 0; index <= UNW_HASH_SIZE; ++index) { + if (unw.hash[index] >= UNW_CACHE_SIZE) + continue; + + tmp = unw.cache + unw.hash[index]; + prev = 0; + while (1) { + write_lock(&tmp->lock); + { + if (tmp->ip >= table->start && tmp->ip < table->end) { + if (prev) + prev->coll_chain = tmp->coll_chain; + else + unw.hash[index] = -1; + tmp->ip = 0; + } else + prev = tmp; + } + write_unlock(&tmp->lock); + } + } + } + spin_unlock_irqrestore(&unw.lock, flags); + + kfree(table); +} +#endif /* CONFIG_IA64_NEW_UNWIND */ + +void +unw_init (void) +{ +#ifdef CONFIG_IA64_NEW_UNWIND + extern int ia64_unw_start, ia64_unw_end, __gp; + extern void unw_hash_index_t_is_too_narrow (void); + long i, off; + + if (8*sizeof(unw_hash_index_t) < UNW_LOG_HASH_SIZE) + unw_hash_index_t_is_too_narrow(); + + unw.sw_off[unw.preg_index[UNW_REG_PRI_UNAT_GR]] = SW(AR_UNAT); + unw.sw_off[unw.preg_index[UNW_REG_BSPSTORE]] = SW(AR_BSPSTORE); + unw.sw_off[unw.preg_index[UNW_REG_PFS]] = SW(AR_UNAT); + unw.sw_off[unw.preg_index[UNW_REG_RP]] = SW(B0); + unw.sw_off[unw.preg_index[UNW_REG_UNAT]] = SW(AR_UNAT); + unw.sw_off[unw.preg_index[UNW_REG_PR]] = SW(PR); + unw.sw_off[unw.preg_index[UNW_REG_LC]] = SW(AR_LC); + unw.sw_off[unw.preg_index[UNW_REG_FPSR]] = SW(AR_FPSR); + for (i = UNW_REG_R4, off = SW(R4); i <= UNW_REG_R7; ++i, off += 8) + unw.sw_off[unw.preg_index[i]] = off; + for (i = UNW_REG_B1, off = SW(B1); i <= UNW_REG_B5; ++i, off += 8) + unw.sw_off[unw.preg_index[i]] = off; + for (i = UNW_REG_F2, off = SW(F2); i <= UNW_REG_F5; ++i, off += 16) + unw.sw_off[unw.preg_index[i]] = off; + for (i = UNW_REG_F16, off = SW(F16); i <= UNW_REG_F31; ++i, off += 16) + unw.sw_off[unw.preg_index[i]] = off; + + unw.cache[0].coll_chain = -1; + for (i = 1; i < UNW_CACHE_SIZE; ++i) { + unw.cache[i].lru_chain = (i - 1); + unw.cache[i].coll_chain = -1; + unw.cache[i].lock = RW_LOCK_UNLOCKED; + } + unw.lru_head = UNW_CACHE_SIZE - 1; + unw.lru_tail = 0; + + init_unwind_table(&unw.kernel_table, "kernel", KERNEL_START, (unsigned long) &__gp, + &ia64_unw_start, &ia64_unw_end); +#endif /* CONFIG_IA64_NEW_UNWIND */ } diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/unwind_decoder.c linux/arch/ia64/kernel/unwind_decoder.c --- v2.4.0-test1/linux/arch/ia64/kernel/unwind_decoder.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/unwind_decoder.c Thu Jun 22 07:09:44 2000 @@ -0,0 +1,459 @@ +/* + * Copyright (C) 2000 Hewlett-Packard Co + * Copyright (C) 2000 David Mosberger-Tang + * + * Generic IA-64 unwind info decoder. + * + * This file is used both by the Linux kernel and objdump. Please keep + * the two copies of this file in sync. + * + * You need to customize the decoder by defining the following + * macros/constants before including this file: + * + * Types: + * unw_word Unsigned integer type with at least 64 bits + * + * Register names: + * UNW_REG_BSP + * UNW_REG_BSPSTORE + * UNW_REG_FPSR + * UNW_REG_LC + * UNW_REG_PFS + * UNW_REG_PR + * UNW_REG_RNAT + * UNW_REG_PSP + * UNW_REG_RP + * UNW_REG_UNAT + * + * Decoder action macros: + * UNW_DEC_BAD_CODE(code) + * UNW_DEC_ABI(fmt,abi,context,arg) + * UNW_DEC_BR_GR(fmt,brmask,gr,arg) + * UNW_DEC_BR_MEM(fmt,brmask,arg) + * UNW_DEC_COPY_STATE(fmt,label,arg) + * UNW_DEC_EPILOGUE(fmt,t,ecount,arg) + * UNW_DEC_FRGR_MEM(fmt,grmask,frmask,arg) + * UNW_DEC_FR_MEM(fmt,frmask,arg) + * UNW_DEC_GR_GR(fmt,grmask,gr,arg) + * UNW_DEC_GR_MEM(fmt,grmask,arg) + * UNW_DEC_LABEL_STATE(fmt,label,arg) + * UNW_DEC_MEM_STACK_F(fmt,t,size,arg) + * UNW_DEC_MEM_STACK_V(fmt,t,arg) + * UNW_DEC_PRIUNAT_GR(fmt,r,arg) + * UNW_DEC_PRIUNAT_WHEN_GR(fmt,t,arg) + * UNW_DEC_PRIUNAT_WHEN_MEM(fmt,t,arg) + * UNW_DEC_PRIUNAT_WHEN_PSPREL(fmt,pspoff,arg) + * UNW_DEC_PRIUNAT_WHEN_SPREL(fmt,spoff,arg) + * UNW_DEC_PROLOGUE(fmt,body,rlen,arg) + * UNW_DEC_PROLOGUE_GR(fmt,rlen,mask,grsave,arg) + * UNW_DEC_REG_PSPREL(fmt,reg,pspoff,arg) + * UNW_DEC_REG_REG(fmt,src,dst,arg) + * UNW_DEC_REG_SPREL(fmt,reg,spoff,arg) + * UNW_DEC_REG_WHEN(fmt,reg,t,arg) + * UNW_DEC_RESTORE(fmt,t,abreg,arg) + * UNW_DEC_RESTORE_P(fmt,qp,t,abreg,arg) + * UNW_DEC_SPILL_BASE(fmt,pspoff,arg) + * UNW_DEC_SPILL_MASK(fmt,imaskp,arg) + * UNW_DEC_SPILL_PSPREL(fmt,t,abreg,pspoff,arg) + * UNW_DEC_SPILL_PSPREL_P(fmt,qp,t,abreg,pspoff,arg) + * UNW_DEC_SPILL_REG(fmt,t,abreg,x,ytreg,arg) + * UNW_DEC_SPILL_REG_P(fmt,qp,t,abreg,x,ytreg,arg) + * UNW_DEC_SPILL_SPREL(fmt,t,abreg,spoff,arg) + * UNW_DEC_SPILL_SPREL_P(fmt,qp,t,abreg,pspoff,arg) + */ + +static unw_word +unw_decode_uleb128 (unsigned char **dpp) +{ + unsigned shift = 0; + unw_word byte, result = 0; + unsigned char *bp = *dpp; + + while (1) + { + byte = *bp++; + result |= (byte & 0x7f) << shift; + if ((byte & 0x80) == 0) + break; + shift += 7; + } + *dpp = bp; + return result; +} + +static unsigned char * +unw_decode_x1 (unsigned char *dp, unsigned char code, void *arg) +{ + unsigned char byte1, abreg; + unw_word t, off; + + byte1 = *dp++; + t = unw_decode_uleb128 (&dp); + off = unw_decode_uleb128 (&dp); + abreg = (byte1 & 0x7f); + if (byte1 & 0x80) + UNW_DEC_SPILL_SPREL(X1, t, abreg, off, arg); + else + UNW_DEC_SPILL_PSPREL(X1, t, abreg, off, arg); + return dp; +} + +static unsigned char * +unw_decode_x2 (unsigned char *dp, unsigned char code, void *arg) +{ + unsigned char byte1, byte2, abreg, x, ytreg; + unw_word t; + + byte1 = *dp++; byte2 = *dp++; + t = unw_decode_uleb128 (&dp); + abreg = (byte1 & 0x7f); + ytreg = byte2; + x = (byte1 >> 7) & 1; + if ((byte1 & 0x80) == 0 && ytreg == 0) + UNW_DEC_RESTORE(X2, t, abreg, arg); + else + UNW_DEC_SPILL_REG(X2, t, abreg, x, ytreg, arg); + return dp; +} + +static unsigned char * +unw_decode_x3 (unsigned char *dp, unsigned char code, void *arg) +{ + unsigned char byte1, byte2, abreg, qp; + unw_word t, off; + + byte1 = *dp++; byte2 = *dp++; + t = unw_decode_uleb128 (&dp); + off = unw_decode_uleb128 (&dp); + + qp = (byte1 & 0x3f); + abreg = (byte2 & 0x7f); + + if (byte1 & 0x80) + UNW_DEC_SPILL_SPREL_P(X3, qp, t, abreg, off, arg); + else + UNW_DEC_SPILL_PSPREL_P(X3, qp, t, abreg, off, arg); + return dp; +} + +static unsigned char * +unw_decode_x4 (unsigned char *dp, unsigned char code, void *arg) +{ + unsigned char byte1, byte2, byte3, qp, abreg, x, ytreg; + unw_word t; + + byte1 = *dp++; byte2 = *dp++; byte3 = *dp++; + t = unw_decode_uleb128 (&dp); + + qp = (byte1 & 0x3f); + abreg = (byte2 & 0x7f); + x = (byte2 >> 7) & 1; + ytreg = byte3; + + if ((byte2 & 0x80) == 0 && byte3 == 0) + UNW_DEC_RESTORE_P(X4, qp, t, abreg, arg); + else + UNW_DEC_SPILL_REG_P(X4, qp, t, abreg, x, ytreg, arg); + return dp; +} + +static unsigned char * +unw_decode_r1 (unsigned char *dp, unsigned char code, void *arg) +{ + int body = (code & 0x20) != 0; + unw_word rlen; + + rlen = (code & 0x1f); + UNW_DEC_PROLOGUE(R1, body, rlen, arg); + return dp; +} + +static unsigned char * +unw_decode_r2 (unsigned char *dp, unsigned char code, void *arg) +{ + unsigned char byte1, mask, grsave; + unw_word rlen; + + byte1 = *dp++; + + mask = ((code & 0x7) << 1) | ((byte1 >> 7) & 1); + grsave = (byte1 & 0x7f); + rlen = unw_decode_uleb128 (&dp); + UNW_DEC_PROLOGUE_GR(R2, rlen, mask, grsave, arg); + return dp; +} + +static unsigned char * +unw_decode_r3 (unsigned char *dp, unsigned char code, void *arg) +{ + unw_word rlen; + + rlen = unw_decode_uleb128 (&dp); + UNW_DEC_PROLOGUE(R3, ((code & 0x3) == 1), rlen, arg); + return dp; +} + +static unsigned char * +unw_decode_p1 (unsigned char *dp, unsigned char code, void *arg) +{ + unsigned char brmask = (code & 0x1f); + + UNW_DEC_BR_MEM(P1, brmask, arg); + return dp; +} + +static unsigned char * +unw_decode_p2_p5 (unsigned char *dp, unsigned char code, void *arg) +{ + if ((code & 0x10) == 0) + { + unsigned char byte1 = *dp++; + + UNW_DEC_BR_GR(P2, ((code & 0xf) << 1) | ((byte1 >> 7) & 1), + (byte1 & 0x7f), arg); + } + else if ((code & 0x08) == 0) + { + unsigned char byte1 = *dp++, r, dst; + + r = ((code & 0x7) << 1) | ((byte1 >> 7) & 1); + dst = (byte1 & 0x7f); + switch (r) + { + case 0: UNW_DEC_REG_GR(P3, UNW_REG_PSP, dst, arg); break; + case 1: UNW_DEC_REG_GR(P3, UNW_REG_RP, dst, arg); break; + case 2: UNW_DEC_REG_GR(P3, UNW_REG_PFS, dst, arg); break; + case 3: UNW_DEC_REG_GR(P3, UNW_REG_PR, dst, arg); break; + case 4: UNW_DEC_REG_GR(P3, UNW_REG_UNAT, dst, arg); break; + case 5: UNW_DEC_REG_GR(P3, UNW_REG_LC, dst, arg); break; + case 6: UNW_DEC_RP_BR(P3, dst, arg); break; + case 7: UNW_DEC_REG_GR(P3, UNW_REG_RNAT, dst, arg); break; + case 8: UNW_DEC_REG_GR(P3, UNW_REG_BSP, dst, arg); break; + case 9: UNW_DEC_REG_GR(P3, UNW_REG_BSPSTORE, dst, arg); break; + case 10: UNW_DEC_REG_GR(P3, UNW_REG_FPSR, dst, arg); break; + case 11: UNW_DEC_PRIUNAT_GR(P3, dst, arg); break; + default: UNW_DEC_BAD_CODE(r); break; + } + } + else if ((code & 0x7) == 0) + UNW_DEC_SPILL_MASK(P4, dp, arg); + else if ((code & 0x7) == 1) + { + unw_word grmask, frmask, byte1, byte2, byte3; + + byte1 = *dp++; byte2 = *dp++; byte3 = *dp++; + grmask = ((byte1 >> 4) & 0xf); + frmask = ((byte1 & 0xf) << 16) | (byte2 << 8) | byte3; + UNW_DEC_FRGR_MEM(P5, grmask, frmask, arg); + } + else + UNW_DEC_BAD_CODE(code); + return dp; +} + +static unsigned char * +unw_decode_p6 (unsigned char *dp, unsigned char code, void *arg) +{ + int gregs = (code & 0x10) != 0; + unsigned char mask = (code & 0x0f); + + if (gregs) + UNW_DEC_GR_MEM(P6, mask, arg); + else + UNW_DEC_FR_MEM(P6, mask, arg); + return dp; +} + +static unsigned char * +unw_decode_p7_p10 (unsigned char *dp, unsigned char code, void *arg) +{ + unsigned char r, byte1, byte2; + unw_word t, size; + + if ((code & 0x10) == 0) + { + r = (code & 0xf); + t = unw_decode_uleb128 (&dp); + switch (r) + { + case 0: + size = unw_decode_uleb128 (&dp); + UNW_DEC_MEM_STACK_F(P7, t, size, arg); + break; + + case 1: UNW_DEC_MEM_STACK_V(P7, t, arg); break; + case 2: UNW_DEC_SPILL_BASE(P7, t, arg); break; + case 3: UNW_DEC_REG_SPREL(P7, UNW_REG_PSP, t, arg); break; + case 4: UNW_DEC_REG_WHEN(P7, UNW_REG_RP, t, arg); break; + case 5: UNW_DEC_REG_PSPREL(P7, UNW_REG_RP, t, arg); break; + case 6: UNW_DEC_REG_WHEN(P7, UNW_REG_PFS, t, arg); break; + case 7: UNW_DEC_REG_PSPREL(P7, UNW_REG_PFS, t, arg); break; + case 8: UNW_DEC_REG_WHEN(P7, UNW_REG_PR, t, arg); break; + case 9: UNW_DEC_REG_PSPREL(P7, UNW_REG_PR, t, arg); break; + case 10: UNW_DEC_REG_WHEN(P7, UNW_REG_LC, t, arg); break; + case 11: UNW_DEC_REG_PSPREL(P7, UNW_REG_LC, t, arg); break; + case 12: UNW_DEC_REG_WHEN(P7, UNW_REG_UNAT, t, arg); break; + case 13: UNW_DEC_REG_PSPREL(P7, UNW_REG_UNAT, t, arg); break; + case 14: UNW_DEC_REG_WHEN(P7, UNW_REG_FPSR, t, arg); break; + case 15: UNW_DEC_REG_PSPREL(P7, UNW_REG_FPSR, t, arg); break; + default: UNW_DEC_BAD_CODE(r); break; + } + } + else + { + switch (code & 0xf) + { + case 0x0: /* p8 */ + { + r = *dp++; + t = unw_decode_uleb128 (&dp); + switch (r) + { + case 1: UNW_DEC_REG_SPREL(P8, UNW_REG_RP, t, arg); break; + case 2: UNW_DEC_REG_SPREL(P8, UNW_REG_PFS, t, arg); break; + case 3: UNW_DEC_REG_SPREL(P8, UNW_REG_PR, t, arg); break; + case 4: UNW_DEC_REG_SPREL(P8, UNW_REG_LC, t, arg); break; + case 5: UNW_DEC_REG_SPREL(P8, UNW_REG_UNAT, t, arg); break; + case 6: UNW_DEC_REG_SPREL(P8, UNW_REG_FPSR, t, arg); break; + case 7: UNW_DEC_REG_WHEN(P8, UNW_REG_BSP, t, arg); break; + case 8: UNW_DEC_REG_PSPREL(P8, UNW_REG_BSP, t, arg); break; + case 9: UNW_DEC_REG_SPREL(P8, UNW_REG_BSP, t, arg); break; + case 10: UNW_DEC_REG_WHEN(P8, UNW_REG_BSPSTORE, t, arg); break; + case 11: UNW_DEC_REG_PSPREL(P8, UNW_REG_BSPSTORE, t, arg); break; + case 12: UNW_DEC_REG_SPREL(P8, UNW_REG_BSPSTORE, t, arg); break; + case 13: UNW_DEC_REG_WHEN(P8, UNW_REG_RNAT, t, arg); break; + case 14: UNW_DEC_REG_PSPREL(P8, UNW_REG_RNAT, t, arg); break; + case 15: UNW_DEC_REG_SPREL(P8, UNW_REG_RNAT, t, arg); break; + case 16: UNW_DEC_PRIUNAT_WHEN_GR(P8, t, arg); break; + case 17: UNW_DEC_PRIUNAT_PSPREL(P8, t, arg); break; + case 18: UNW_DEC_PRIUNAT_SPREL(P8, t, arg); break; + case 19: UNW_DEC_PRIUNAT_WHEN_MEM(P8, t, arg); break; + default: UNW_DEC_BAD_CODE(r); break; + } + } + break; + + case 0x1: + byte1 = *dp++; byte2 = *dp++; + UNW_DEC_GR_GR(P9, (byte1 & 0xf), (byte2 & 0x7f), arg); + break; + + case 0xf: /* p10 */ + byte1 = *dp++; byte2 = *dp++; + UNW_DEC_ABI(P10, byte1, byte2, arg); + break; + + case 0x9: + return unw_decode_x1 (dp, code, arg); + + case 0xa: + return unw_decode_x2 (dp, code, arg); + + case 0xb: + return unw_decode_x3 (dp, code, arg); + + case 0xc: + return unw_decode_x4 (dp, code, arg); + + default: + UNW_DEC_BAD_CODE(code); + break; + } + } + return dp; +} + +static unsigned char * +unw_decode_b1 (unsigned char *dp, unsigned char code, void *arg) +{ + unw_word label = (code & 0x1f); + + if ((code & 0x20) != 0) + UNW_DEC_COPY_STATE(B1, label, arg); + else + UNW_DEC_LABEL_STATE(B1, label, arg); + return dp; +} + +static unsigned char * +unw_decode_b2 (unsigned char *dp, unsigned char code, void *arg) +{ + unw_word t; + + t = unw_decode_uleb128 (&dp); + UNW_DEC_EPILOGUE(B2, t, (code & 0x1f), arg); + return dp; +} + +static unsigned char * +unw_decode_b3_x4 (unsigned char *dp, unsigned char code, void *arg) +{ + unw_word t, ecount, label; + + if ((code & 0x10) == 0) + { + t = unw_decode_uleb128 (&dp); + ecount = unw_decode_uleb128 (&dp); + UNW_DEC_EPILOGUE(B3, t, ecount, arg); + } + else if ((code & 0x07) == 0) + { + label = unw_decode_uleb128 (&dp); + if ((code & 0x08) != 0) + UNW_DEC_COPY_STATE(B4, label, arg); + else + UNW_DEC_LABEL_STATE(B4, label, arg); + } + else + switch (code & 0x7) + { + case 1: return unw_decode_x1 (dp, code, arg); + case 2: return unw_decode_x2 (dp, code, arg); + case 3: return unw_decode_x3 (dp, code, arg); + case 4: return unw_decode_x4 (dp, code, arg); + default: UNW_DEC_BAD_CODE(code); break; + } + return dp; +} + +typedef unsigned char *(*unw_decoder) (unsigned char *, unsigned char, void *); + +static unw_decoder unw_decode_table[2][8] = +{ + /* prologue table: */ + { + unw_decode_r1, /* 0 */ + unw_decode_r1, + unw_decode_r2, + unw_decode_r3, + unw_decode_p1, /* 4 */ + unw_decode_p2_p5, + unw_decode_p6, + unw_decode_p7_p10 + }, + { + unw_decode_r1, /* 0 */ + unw_decode_r1, + unw_decode_r2, + unw_decode_r3, + unw_decode_b1, /* 4 */ + unw_decode_b1, + unw_decode_b2, + unw_decode_b3_x4 + } +}; + +/* + * Decode one descriptor and return address of next descriptor. + */ +static inline unsigned char * +unw_decode (unsigned char *dp, int inside_body, void *arg) +{ + unw_decoder decoder; + unsigned char code; + + code = *dp++; + decoder = unw_decode_table[inside_body][code >> 5]; + dp = (*decoder) (dp, code, arg); + return dp; +} diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/kernel/unwind_i.h linux/arch/ia64/kernel/unwind_i.h --- v2.4.0-test1/linux/arch/ia64/kernel/unwind_i.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/unwind_i.h Thu Jun 22 07:09:44 2000 @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2000 Hewlett-Packard Co + * Copyright (C) 2000 David Mosberger-Tang + * + * Kernel unwind support. + */ + +#define UNW_VER(x) ((x) >> 48) +#define UNW_FLAG_MASK 0x0000ffff00000000 +#define UNW_FLAG_OSMASK 0x0000f00000000000 +#define UNW_FLAG_EHANDLER(x) ((x) & 0x0000000100000000L) +#define UNW_FLAG_UHANDLER(x) ((x) & 0x0000000200000000L) +#define UNW_LENGTH(x) ((x) & 0x00000000ffffffffL) + +enum unw_register_index { + /* primary unat: */ + UNW_REG_PRI_UNAT_GR, + UNW_REG_PRI_UNAT_MEM, + + /* register stack */ + UNW_REG_BSP, /* register stack pointer */ + UNW_REG_BSPSTORE, + UNW_REG_PFS, /* previous function state */ + UNW_REG_RNAT, + /* memory stack */ + UNW_REG_PSP, /* previous memory stack pointer */ + /* return pointer: */ + UNW_REG_RP, + + /* preserved registers: */ + UNW_REG_R4, UNW_REG_R5, UNW_REG_R6, UNW_REG_R7, + UNW_REG_UNAT, UNW_REG_PR, UNW_REG_LC, UNW_REG_FPSR, + UNW_REG_B1, UNW_REG_B2, UNW_REG_B3, UNW_REG_B4, UNW_REG_B5, + UNW_REG_F2, UNW_REG_F3, UNW_REG_F4, UNW_REG_F5, + UNW_REG_F16, UNW_REG_F17, UNW_REG_F18, UNW_REG_F19, + UNW_REG_F20, UNW_REG_F21, UNW_REG_F22, UNW_REG_F23, + UNW_REG_F24, UNW_REG_F25, UNW_REG_F26, UNW_REG_F27, + UNW_REG_F28, UNW_REG_F29, UNW_REG_F30, UNW_REG_F31, + UNW_NUM_REGS +}; + +struct unw_info_block { + u64 header; + u64 desc[0]; /* unwind descriptors */ + /* personality routine and language-specific data follow behind descriptors */ +}; + +struct unw_table_entry { + u64 start_offset; + u64 end_offset; + u64 info_offset; +}; + +struct unw_table { + struct unw_table *next; /* must be first member! */ + const char *name; + unsigned long gp; /* global pointer for this load-module */ + unsigned long segment_base; /* base for offsets in the unwind table entries */ + unsigned long start; + unsigned long end; + struct unw_table_entry *array; + unsigned long length; +}; + +enum unw_where { + UNW_WHERE_NONE, /* register isn't saved at all */ + UNW_WHERE_GR, /* register is saved in a general register */ + UNW_WHERE_FR, /* register is saved in a floating-point register */ + UNW_WHERE_BR, /* register is saved in a branch register */ + UNW_WHERE_SPREL, /* register is saved on memstack (sp-relative) */ + UNW_WHERE_PSPREL, /* register is saved on memstack (psp-relative) */ + /* + * At the end of each prologue these locations get resolved to + * UNW_WHERE_PSPREL and UNW_WHERE_GR, respectively: + */ + UNW_WHERE_SPILL_HOME, /* register is saved in its spill home */ + UNW_WHERE_GR_SAVE /* register is saved in next general register */ +}; + +#define UNW_WHEN_NEVER 0x7fffffff + +struct unw_reg_info { + unsigned long val; /* save location: register number or offset */ + enum unw_where where; /* where the register gets saved */ + int when; /* when the register gets saved */ +}; + +struct unw_state_record { + unsigned int first_region : 1; /* is this the first region? */ + unsigned int done : 1; /* are we done scanning descriptors? */ + unsigned int any_spills : 1; /* got any register spills? */ + unsigned int in_body : 1; /* are we inside a body (as opposed to a prologue)? */ + unsigned long flags; /* see UNW_FLAG_* in unwind.h */ + + u8 *imask; /* imask of of spill_mask record or NULL */ + unsigned long pr_val; /* predicate values */ + unsigned long pr_mask; /* predicate mask */ + long spill_offset; /* psp-relative offset for spill base */ + int region_start; + int region_len; + int epilogue_start; + int epilogue_count; + int when_target; + + u8 gr_save_loc; /* next general register to use for saving a register */ + u8 return_link_reg; /* branch register in which the return link is passed */ + + struct unw_reg_state { + struct unw_reg_state *next; + unsigned long label; /* label of this state record */ + struct unw_reg_info reg[UNW_NUM_REGS]; + } curr, *stack, *reg_state_list; +}; + +enum unw_nat_type { + UNW_NAT_NONE, /* NaT not represented */ + UNW_NAT_VAL, /* NaT represented by NaT value (fp reg) */ + UNW_NAT_PRI_UNAT, /* NaT value is in unat word at offset OFF */ + UNW_NAT_SCRATCH, /* NaT value is in scratch.pri_unat */ + UNW_NAT_STACKED /* NaT is in rnat */ +}; + +enum unw_insn_opcode { + UNW_INSN_ADD, /* s[dst] += val */ + UNW_INSN_MOVE, /* s[dst] = s[val] */ + UNW_INSN_MOVE2, /* s[dst] = s[val]; s[dst+1] = s[val+1] */ + UNW_INSN_MOVE_STACKED, /* s[dst] = ia64_rse_skip(*s.bsp, val) */ + UNW_INSN_LOAD_PSPREL, /* s[dst] = *(*s.psp + 8*val) */ + UNW_INSN_LOAD_SPREL, /* s[dst] = *(*s.sp + 8*val) */ + UNW_INSN_SETNAT_PRI_UNAT, /* s[dst+1].nat.type = PRI_UNAT; + s[dst+1].nat.off = *s.pri_unat - s[dst] */ + UNW_INSN_SETNAT_TYPE /* s[dst+1].nat.type = val */ +}; + +struct unw_insn { + unsigned int opc : 4; + unsigned int dst : 9; + signed int val : 19; +}; + +/* + * Preserved general static registers (r2-r5) give rise to two script + * instructions; everything else yields at most one instruction; at + * the end of the script, the psp gets popped, accounting for one more + * instruction. + */ +#define UNW_MAX_SCRIPT_LEN (UNW_NUM_REGS + 5) + +struct unw_script { + unsigned long ip; /* ip this script is for */ + unsigned long pr_mask; /* mask of predicates script depends on */ + unsigned long pr_val; /* predicate values this script is for */ + rwlock_t lock; + unsigned int flags; /* see UNW_FLAG_* in unwind.h */ + unsigned short lru_chain; /* used for least-recently-used chain */ + unsigned short coll_chain; /* used for hash collisions */ + unsigned short hint; /* hint for next script to try (or -1) */ + unsigned short count; /* number of instructions in script */ + struct unw_insn insn[UNW_MAX_SCRIPT_LEN]; +}; diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/lib/Makefile linux/arch/ia64/lib/Makefile --- v2.4.0-test1/linux/arch/ia64/lib/Makefile Tue Apr 11 15:09:13 2000 +++ linux/arch/ia64/lib/Makefile Thu Jun 22 07:09:44 2000 @@ -5,15 +5,21 @@ .S.o: $(CC) $(AFLAGS) -c $< -o $@ -OBJS = __divdi3.o __divsi3.o __udivdi3.o __udivsi3.o \ +L_TARGET = lib.a + +L_OBJS = __divdi3.o __divsi3.o __udivdi3.o __udivsi3.o \ __moddi3.o __modsi3.o __umoddi3.o __umodsi3.o \ checksum.o clear_page.o csum_partial_copy.o copy_page.o \ copy_user.o clear_user.o memset.o strncpy_from_user.o \ strlen.o strlen_user.o strnlen_user.o \ flush.o do_csum.o -lib.a: $(OBJS) - $(AR) rcs lib.a $(OBJS) +LX_OBJS = io.o + +IGNORE_FLAGS_OBJS = __divdi3.o __divsi3.o __udivdi3.o __udivsi3.o \ + __moddi3.o __modsi3.o __umoddi3.o __umodsi3.o + +include $(TOPDIR)/Rules.make __divdi3.o: idiv.S $(CC) $(AFLAGS) -c -o $@ $< @@ -38,5 +44,3 @@ __umodsi3.o: idiv.S $(CC) $(AFLAGS) -c -DMODULO -DUNSIGNED -DSINGLE -c -o $@ $< - -include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/lib/clear_page.S linux/arch/ia64/lib/clear_page.S --- v2.4.0-test1/linux/arch/ia64/lib/clear_page.S Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/lib/clear_page.S Thu Jun 22 07:09:44 2000 @@ -10,10 +10,11 @@ * Output: * none * - * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999-2000 Hewlett-Packard Co * Copyright (C) 1999 Stephane Eranian - * Copyright (C) 1999 David Mosberger-Tang + * Copyright (C) 1999-2000 David Mosberger-Tang */ +#include #include .text @@ -21,12 +22,14 @@ .psr lsb .lsb - .align 32 - .global clear_page - .proc clear_page -clear_page: +GLOBAL_ENTRY(clear_page) + UNW(.prologue) alloc r11=ar.pfs,1,0,0,0 + UNW(.save ar.lc, r16) mov r16=ar.lc // slow + + UNW(.body) + mov r17=PAGE_SIZE/32-1 // -1 = repeat/until ;; adds r18=16,in0 @@ -38,5 +41,4 @@ ;; mov ar.lc=r16 // restore lc br.ret.sptk.few rp - - .endp clear_page +END(clear_page) diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/lib/clear_user.S linux/arch/ia64/lib/clear_user.S --- v2.4.0-test1/linux/arch/ia64/lib/clear_user.S Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/lib/clear_user.S Thu Jun 22 07:09:44 2000 @@ -11,6 +11,8 @@ * Copyright (C) 1999 Stephane Eranian */ +#include + // // arguments // @@ -23,11 +25,10 @@ #define cnt r16 #define buf2 r17 #define saved_lc r18 -#define saved_pr r19 -#define saved_pfs r20 -#define tmp r21 -#define len2 r22 -#define len3 r23 +#define saved_pfs r19 +#define tmp r20 +#define len2 r21 +#define len3 r22 // // Theory of operations: @@ -65,14 +66,14 @@ .psr lsb .lsb - .align 32 - .global __do_clear_user - .proc __do_clear_user - -__do_clear_user: +GLOBAL_ENTRY(__do_clear_user) + UNW(.prologue) + UNW(.save ar.pfs, saved_pfs) alloc saved_pfs=ar.pfs,2,0,0,0 cmp.eq p6,p0=r0,len // check for zero length + UNW(.save ar.lc, saved_lc) mov saved_lc=ar.lc // preserve ar.lc (slow) + .body ;; // avoid WAW on CFM adds tmp=-1,len // br.ctop is repeat/until mov ret0=len // return value is length at this point @@ -222,4 +223,4 @@ mov ret0=len mov ar.lc=saved_lc br.ret.dptk.few rp - .endp +END(__do_clear_user) diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/lib/copy_page.S linux/arch/ia64/lib/copy_page.S --- v2.4.0-test1/linux/arch/ia64/lib/copy_page.S Fri Mar 10 16:40:39 2000 +++ linux/arch/ia64/lib/copy_page.S Thu Jun 22 07:09:44 2000 @@ -13,6 +13,7 @@ * Copyright (C) 1999 Hewlett-Packard Co * Copyright (C) 1999 Stephane Eranian */ +#include #include #define PIPE_DEPTH 6 @@ -32,19 +33,21 @@ .psr lsb .lsb - .align 32 - .global copy_page - .proc copy_page - -copy_page: +GLOBAL_ENTRY(copy_page) + UNW(.prologue) + UNW(.save ar.pfs, saved_pfs) alloc saved_pfs=ar.pfs,3,((2*PIPE_DEPTH+7)&~7),0,((2*PIPE_DEPTH+7)&~7) .rotr t1[PIPE_DEPTH], t2[PIPE_DEPTH] .rotp p[PIPE_DEPTH] + UNW(.save ar.lc, saved_lc) mov saved_lc=ar.lc // save ar.lc ahead of time + UNW(.save pr, saved_pr) mov saved_pr=pr // rotating predicates are preserved // resgisters we must save. + UNW(.body) + mov src1=in1 // initialize 1st stream source adds src2=8,in1 // initialize 2nd stream source mov lcount=PAGE_SIZE/16-1 // as many 16bytes as there are on a page @@ -87,5 +90,4 @@ mov ar.pfs=saved_pfs // restore ar.ec mov ar.lc=saved_lc // restore saved lc br.ret.sptk.few rp // bye... - - .endp copy_page +END(copy_page) diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/lib/copy_user.S linux/arch/ia64/lib/copy_user.S --- v2.4.0-test1/linux/arch/ia64/lib/copy_user.S Fri Mar 10 16:40:39 2000 +++ linux/arch/ia64/lib/copy_user.S Thu Jun 22 07:09:44 2000 @@ -29,6 +29,8 @@ * - fix extraneous stop bit introduced by the EX() macro. */ +#include + // The label comes first because our store instruction contains a comma // and confuse the preprocessor otherwise // @@ -81,10 +83,9 @@ .psr abi64 .psr lsb - .align 16 - .global __copy_user - .proc __copy_user -__copy_user: +GLOBAL_ENTRY(__copy_user) + UNW(.prologue) + UNW(.save ar.pfs, saved_pfs) alloc saved_pfs=ar.pfs,3,((2*PIPE_DEPTH+7)&~7),0,((2*PIPE_DEPTH+7)&~7) .rotr val1[PIPE_DEPTH],val2[PIPE_DEPTH] @@ -95,13 +96,17 @@ ;; // RAW of cfm when len=0 cmp.eq p8,p0=r0,len // check for zero length + UNW(.save ar.lc, saved_lc) mov saved_lc=ar.lc // preserve ar.lc (slow) (p8) br.ret.spnt.few rp // empty mempcy() ;; add enddst=dst,len // first byte after end of source add endsrc=src,len // first byte after end of destination + UNW(.save pr, saved_pr) mov saved_pr=pr // preserve predicates + UNW(.body) + mov dst1=dst // copy because of rotation mov ar.ec=PIPE_DEPTH mov pr.rot=1<<16 // p16=true all others are false @@ -400,7 +405,4 @@ mov ar.pfs=saved_pfs br.ret.dptk.few rp - - - .endp __copy_user - +END(__copy_user) diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/lib/do_csum.S linux/arch/ia64/lib/do_csum.S --- v2.4.0-test1/linux/arch/ia64/lib/do_csum.S Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/lib/do_csum.S Thu Jun 22 07:09:44 2000 @@ -13,6 +13,8 @@ * */ +#include + // // Theory of operations: // The goal is to go as quickly as possible to the point where @@ -100,10 +102,9 @@ // unsigned long do_csum(unsigned char *buf,int len) - .align 32 - .global do_csum - .proc do_csum -do_csum: +GLOBAL_ENTRY(do_csum) + UNW(.prologue) + UNW(.save ar.pfs, saved_pfs) alloc saved_pfs=ar.pfs,2,8,0,8 .rotr p[4], result[3] @@ -125,6 +126,7 @@ ;; and lastoff=7,tmp1 // how many bytes off for last element andcm last=tmp2,tmp3 // address of word containing last byte + UNW(.save pr, saved_pr) mov saved_pr=pr // preserve predicates (rotation) ;; sub tmp3=last,first // tmp3=distance from first to last @@ -145,8 +147,12 @@ shl hmask=hmask,tmp2 // build head mask, mask off [0,firstoff[ ;; shr.u tmask=tmask,tmp1 // build tail mask, mask off ]8,lastoff] + UNW(.save ar.lc, saved_lc) mov saved_lc=ar.lc // save lc ;; + + UNW(.body) + (p8) and hmask=hmask,tmask // apply tail mask to head mask if 1 word only (p9) and p[1]=lastval,tmask // mask last it as appropriate shr.u tmp3=tmp3,3 // we do 8 bytes per loop @@ -228,3 +234,4 @@ mov ar.lc=saved_lc (p10) shr.u ret0=ret0,64-16 // + shift back to position = swap bytes br.ret.sptk.few rp +END(do_csum) diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/lib/flush.S linux/arch/ia64/lib/flush.S --- v2.4.0-test1/linux/arch/ia64/lib/flush.S Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/lib/flush.S Thu Jun 22 07:09:44 2000 @@ -1,9 +1,10 @@ /* * Cache flushing routines. * - * Copyright (C) 1999 Hewlett-Packard Co - * Copyright (C) 1999 David Mosberger-Tang + * Copyright (C) 1999-2000 Hewlett-Packard Co + * Copyright (C) 1999-2000 David Mosberger-Tang */ +#include #include .text @@ -11,12 +12,14 @@ .psr lsb .lsb - .align 16 - .global ia64_flush_icache_page - .proc ia64_flush_icache_page -ia64_flush_icache_page: +GLOBAL_ENTRY(ia64_flush_icache_page) + UNW(.prologue) alloc r2=ar.pfs,1,0,0,0 + UNW(.save ar.lc, r3) mov r3=ar.lc // save ar.lc + + .body + mov r8=PAGE_SIZE/64-1 // repeat/until loop ;; mov ar.lc=r8 @@ -34,4 +37,4 @@ ;; mov ar.lc=r3 // restore ar.lc br.ret.sptk.few rp - .endp ia64_flush_icache_page +END(ia64_flush_icache_page) diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/lib/idiv.S linux/arch/ia64/lib/idiv.S --- v2.4.0-test1/linux/arch/ia64/lib/idiv.S Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/lib/idiv.S Thu Jun 22 07:09:44 2000 @@ -31,6 +31,7 @@ nops while maximizing parallelism */ +#include #include .text @@ -73,12 +74,10 @@ #define PASTE(a,b) PASTE1(a,b) #define NAME PASTE(PASTE(__,SGN),PASTE(OP,PASTE(PREC,3))) - .align 32 - .global NAME - .proc NAME -NAME: - +GLOBAL_ENTRY(NAME) + UNW(.prologue) alloc r2=ar.pfs,2,6,0,8 + UNW(.save pr, r18) mov r18=pr #ifdef SINGLE # ifdef UNSIGNED @@ -101,6 +100,10 @@ #endif setf.sig f8=in0 + UNW(.save ar.lc, r3) + + UNW(.body) + mov r3=ar.lc // save ar.lc setf.sig f9=in1 ;; @@ -156,3 +159,4 @@ mov ar.lc=r3 // restore ar.lc mov pr=r18,0xffffffffffff0000 // restore p16-p63 br.ret.sptk.few rp +END(NAME) diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/lib/io.c linux/arch/ia64/lib/io.c --- v2.4.0-test1/linux/arch/ia64/lib/io.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/lib/io.c Thu Jun 22 07:09:44 2000 @@ -0,0 +1,54 @@ +#include +#include + +#include + +/* + * Copy data from IO memory space to "real" memory space. + * This needs to be optimized. + */ +void +__ia64_memcpy_fromio (void * to, unsigned long from, long count) +{ + while (count) { + count--; + *(char *) to = readb(from); + ((char *) to)++; + from++; + } +} + +/* + * Copy data from "real" memory space to IO memory space. + * This needs to be optimized. + */ +void +__ia64_memcpy_toio (unsigned long to, void * from, long count) +{ + while (count) { + count--; + writeb(*(char *) from, to); + ((char *) from)++; + to++; + } +} + +/* + * "memset" on IO memory space. + * This needs to be optimized. + */ +void +__ia64_memset_c_io (unsigned long dst, unsigned long c, long count) +{ + unsigned char ch = (char)(c & 0xff); + + while (count) { + count--; + writeb(ch, dst); + dst++; + } +} + +EXPORT_SYMBOL(__ia64_memcpy_fromio); +EXPORT_SYMBOL(__ia64_memcpy_toio); +EXPORT_SYMBOL(__ia64_memset_c_io); diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/lib/memset.S linux/arch/ia64/lib/memset.S --- v2.4.0-test1/linux/arch/ia64/lib/memset.S Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/lib/memset.S Thu Jun 22 07:09:44 2000 @@ -14,6 +14,7 @@ * Copyright (C) 1999 Stephane Eranian */ +#include // arguments // @@ -28,22 +29,23 @@ #define cnt r18 #define buf2 r19 #define saved_lc r20 -#define saved_pr r21 -#define tmp r22 +#define tmp r21 .text .psr abi64 .psr lsb - .align 16 - .global memset - .proc memset - -memset: +GLOBAL_ENTRY(memset) + UNW(.prologue) + UNW(.save ar.pfs, saved_pfs) alloc saved_pfs=ar.pfs,3,0,0,0 // cnt is sink here cmp.eq p8,p0=r0,len // check for zero length + UNW(.save ar.lc, saved_lc) mov saved_lc=ar.lc // preserve ar.lc (slow) ;; + + UNW(.body) + adds tmp=-1,len // br.ctop is repeat/until tbit.nz p6,p0=buf,0 // odd alignment (p8) br.ret.spnt.few rp @@ -108,4 +110,4 @@ ;; (p6) st1 [buf]=val // only 1 byte left br.ret.dptk.few rp - .endp +END(memset) diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/lib/strlen.S linux/arch/ia64/lib/strlen.S --- v2.4.0-test1/linux/arch/ia64/lib/strlen.S Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/lib/strlen.S Thu Jun 22 07:09:44 2000 @@ -16,6 +16,8 @@ * 09/24/99 S.Eranian add speculation recovery code */ +#include + // // // This is an enhanced version of the basic strlen. it includes a combination @@ -82,10 +84,9 @@ .psr lsb .lsb - .align 32 - .global strlen - .proc strlen -strlen: +GLOBAL_ENTRY(strlen) + UNW(.prologue) + UNW(.save ar.pfs, saved_pfs) alloc saved_pfs=ar.pfs,11,0,0,8 // rotating must be multiple of 8 .rotr v[2], w[2] // declares our 4 aliases @@ -93,8 +94,12 @@ extr.u tmp=in0,0,3 // tmp=least significant 3 bits mov orig=in0 // keep trackof initial byte address dep src=0,in0,0,3 // src=8byte-aligned in0 address + UNW(.save pr, saved_pr) mov saved_pr=pr // preserve predicates (rotation) ;; + + UNW(.body) + ld8 v[1]=[src],8 // must not speculate: can fail here shl tmp=tmp,3 // multiply by 8bits/byte mov mask=-1 // our mask @@ -194,5 +199,4 @@ sub ret0=ret0,tmp // length=now - back -1 mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what br.ret.sptk.few rp // end of sucessful recovery code - - .endp strlen +END(strlen) diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/lib/strlen_user.S linux/arch/ia64/lib/strlen_user.S --- v2.4.0-test1/linux/arch/ia64/lib/strlen_user.S Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/lib/strlen_user.S Thu Jun 22 07:09:44 2000 @@ -15,6 +15,8 @@ * 09/24/99 S.Eranian added speculation recovery code */ +#include + // // int strlen_user(char *) // ------------------------ @@ -93,10 +95,9 @@ .psr lsb .lsb - .align 32 - .global __strlen_user - .proc __strlen_user -__strlen_user: +GLOBAL_ENTRY(__strlen_user) + UNW(.prologue) + UNW(.save ar.pfs, saved_pfs) alloc saved_pfs=ar.pfs,11,0,0,8 .rotr v[2], w[2] // declares our 4 aliases @@ -104,8 +105,12 @@ extr.u tmp=in0,0,3 // tmp=least significant 3 bits mov orig=in0 // keep trackof initial byte address dep src=0,in0,0,3 // src=8byte-aligned in0 address + UNW(.save pr, saved_pr) mov saved_pr=pr // preserve predicates (rotation) ;; + + .body + ld8.s v[1]=[src],8 // load the initial 8bytes (must speculate) shl tmp=tmp,3 // multiply by 8bits/byte mov mask=-1 // our mask @@ -209,5 +214,4 @@ mov pr=saved_pr,0xffffffffffff0000 mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what br.ret.sptk.few rp - - .endp __strlen_user +END(__strlen_user) diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/lib/strncpy_from_user.S linux/arch/ia64/lib/strncpy_from_user.S --- v2.4.0-test1/linux/arch/ia64/lib/strncpy_from_user.S Fri Mar 10 16:40:40 2000 +++ linux/arch/ia64/lib/strncpy_from_user.S Thu Jun 22 07:09:44 2000 @@ -16,6 +16,8 @@ * by Andreas Schwab ). */ +#include + #define EX(x...) \ 99: x; \ .section __ex_table,"a"; \ @@ -28,10 +30,7 @@ .psr lsb .lsb - .align 32 - .global __strncpy_from_user - .proc __strncpy_from_user -__strncpy_from_user: +GLOBAL_ENTRY(__strncpy_from_user) alloc r2=ar.pfs,3,0,0,0 mov r8=0 mov r9=in1 @@ -53,5 +52,4 @@ .Lexit: br.ret.sptk.few rp - - .endp __strncpy_from_user +END(__strncpy_from_user) diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/lib/strnlen_user.S linux/arch/ia64/lib/strnlen_user.S --- v2.4.0-test1/linux/arch/ia64/lib/strnlen_user.S Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/lib/strnlen_user.S Thu Jun 22 07:09:44 2000 @@ -12,6 +12,8 @@ * Copyright (C) 1999 David Mosberger-Tang */ +#include + /* If a fault occurs, r8 gets set to -EFAULT and r9 gets cleared. */ #define EX(x...) \ .section __ex_table,"a"; \ @@ -25,12 +27,14 @@ .psr lsb .lsb - .align 32 - .global __strnlen_user - .proc __strnlen_user -__strnlen_user: +GLOBAL_ENTRY(__strnlen_user) + UNW(.prologue) alloc r2=ar.pfs,2,0,0,0 + UNW(.save ar.lc, r16) mov r16=ar.lc // preserve ar.lc + + UNW(.body) + add r3=-1,in1 ;; mov ar.lc=r3 @@ -51,5 +55,4 @@ mov r8=r9 mov ar.lc=r16 // restore ar.lc br.ret.sptk.few rp - - .endp __strnlen_user +END(__strnlen_user) diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/mm/fault.c linux/arch/ia64/mm/fault.c --- v2.4.0-test1/linux/arch/ia64/mm/fault.c Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/mm/fault.c Thu Jun 22 07:09:45 2000 @@ -1,8 +1,8 @@ /* * MMU fault handling support. * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Copyright (C) 1998-2000 Hewlett-Packard Co + * Copyright (C) 1998-2000 David Mosberger-Tang */ #include #include @@ -94,7 +94,14 @@ * sure we exit gracefully rather than endlessly redo the * fault. */ - if (!handle_mm_fault(mm, vma, address, (isr & IA64_ISR_W) != 0)) { + switch (handle_mm_fault(mm, vma, address, (mask & VM_WRITE) != 0)) { + case 1: + ++current->min_flt; + break; + case 2: + ++current->maj_flt; + break; + case 0: /* * We ran out of memory, or some other thing happened * to us that made us unable to handle the page fault @@ -102,6 +109,8 @@ */ signal = SIGBUS; goto bad_area; + default: + goto out_of_memory; } up(&mm->mmap_sem); return; @@ -128,15 +137,11 @@ return; } if (user_mode(regs)) { -#if 0 -printk("%s(%d): segfault accessing %lx\n", current->comm, current->pid, address); -show_regs(regs); -#endif si.si_signo = signal; si.si_errno = 0; si.si_code = SI_KERNEL; si.si_addr = (void *) address; - force_sig_info(SIGSEGV, &si, current); + force_sig_info(signal, &si, current); return; } @@ -161,4 +166,11 @@ die_if_kernel("Oops", regs, isr); do_exit(SIGKILL); return; + + out_of_memory: + up(&mm->mmap_sem); + printk("VM: killing process %s\n", current->comm); + if (user_mode(regs)) + do_exit(SIGKILL); + goto no_context; } diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/mm/init.c linux/arch/ia64/mm/init.c --- v2.4.0-test1/linux/arch/ia64/mm/init.c Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/mm/init.c Thu Jun 22 07:09:45 2000 @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -182,6 +183,19 @@ } void +free_initrd_mem(unsigned long start, unsigned long end) +{ + if (start < end) + printk ("Freeing initrd memory: %ldkB freed\n", (end - start) >> 10); + for (; start < end; start += PAGE_SIZE) { + clear_bit(PG_reserved, &mem_map[MAP_NR(start)].flags); + set_page_count(&mem_map[MAP_NR(start)], 1); + free_page(start); + ++totalram_pages; + } +} + +void si_meminfo (struct sysinfo *val) { val->totalram = totalram_pages; @@ -265,7 +279,7 @@ void __init ia64_rid_init (void) { - unsigned long flags, rid, pta; + unsigned long flags, rid, pta, impl_va_msb; /* Set up the kernel identity mappings (regions 6 & 7) and the vmalloc area (region 5): */ ia64_clear_ic(flags); @@ -300,11 +314,15 @@ # define ld_max_addr_space_size (ld_max_addr_space_pages + PAGE_SHIFT) # define ld_max_vpt_size (ld_max_addr_space_pages + ld_pte_size) # define POW2(n) (1ULL << (n)) -# define IMPL_VA_MSB 50 - if (POW2(ld_max_addr_space_size - 1) + POW2(ld_max_vpt_size) > POW2(IMPL_VA_MSB)) + impl_va_msb = ffz(~my_cpu_data.unimpl_va_mask) - 1; + + if (impl_va_msb < 50 || impl_va_msb > 60) + panic("Bogus impl_va_msb value of %lu!\n", impl_va_msb); + + if (POW2(ld_max_addr_space_size - 1) + POW2(ld_max_vpt_size) > POW2(impl_va_msb)) panic("mm/init: overlap between virtually mapped linear page table and " "mapped kernel space!"); - pta = POW2(61) - POW2(IMPL_VA_MSB); + pta = POW2(61) - POW2(impl_va_msb); /* * Set the (virtually mapped linear) page table address. Bit * 8 selects between the short and long format, bits 2-7 the @@ -314,54 +332,6 @@ ia64_set_pta(pta | (0<<8) | ((3*(PAGE_SHIFT-3)+3)<<2) | 1); } -#ifdef CONFIG_IA64_VIRTUAL_MEM_MAP - -static int -create_mem_map_page_table (u64 start, u64 end, void *arg) -{ - unsigned long address, start_page, end_page; - struct page *map_start, *map_end; - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - void *page; - - map_start = mem_map + MAP_NR(start); - map_end = mem_map + MAP_NR(end); - - start_page = (unsigned long) map_start & PAGE_MASK; - end_page = PAGE_ALIGN((unsigned long) map_end); - - printk("[%lx,%lx) -> %lx-%lx\n", start, end, start_page, end_page); - - for (address = start_page; address < end_page; address += PAGE_SIZE) { - pgd = pgd_offset_k(address); - if (pgd_none(*pgd)) { - pmd = alloc_bootmem_pages(PAGE_SIZE); - clear_page(pmd); - pgd_set(pgd, pmd); - pmd += (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1); - } else - pmd = pmd_offset(pgd, address); - if (pmd_none(*pmd)) { - pte = alloc_bootmem_pages(PAGE_SIZE); - clear_page(pte); - pmd_set(pmd, pte); - pte += (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - } else - pte = pte_offset(pmd, address); - - if (pte_none(*pte)) { - page = alloc_bootmem_pages(PAGE_SIZE); - clear_page(page); - set_pte(pte, mk_pte_phys(__pa(page), PAGE_KERNEL)); - } - } - return 0; -} - -#endif /* CONFIG_IA64_VIRTUAL_MEM_MAP */ - /* * Set up the page tables. */ @@ -372,14 +342,11 @@ clear_page((void *) ZERO_PAGE_ADDR); - ia64_rid_init(); - __flush_tlb_all(); - /* initialize mem_map[] */ memset(zones_size, 0, sizeof(zones_size)); - max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS); + max_dma = (PAGE_ALIGN(MAX_DMA_ADDRESS) >> PAGE_SHIFT); if (max_low_pfn < max_dma) zones_size[ZONE_DMA] = max_low_pfn; else { @@ -426,8 +393,6 @@ max_mapnr = max_low_pfn; high_memory = __va(max_low_pfn * PAGE_SIZE); - - ia64_tlb_init(); totalram_pages += free_all_bootmem(); diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/mm/tlb.c linux/arch/ia64/mm/tlb.c --- v2.4.0-test1/linux/arch/ia64/mm/tlb.c Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/mm/tlb.c Thu Jun 22 07:09:45 2000 @@ -42,6 +42,70 @@ */ spinlock_t ptcg_lock = SPIN_LOCK_UNLOCKED; /* see */ +#if defined(CONFIG_SMP) && !defined(CONFIG_ITANIUM_PTCG) + +#include + +unsigned long flush_end, flush_start, flush_nbits, flush_rid; +atomic_t flush_cpu_count; + +/* + * flush_tlb_no_ptcg is called with ptcg_lock locked + */ +static inline void +flush_tlb_no_ptcg (unsigned long start, unsigned long end, unsigned long nbits) +{ + extern void smp_send_flush_tlb (void); + unsigned long saved_tpr = 0; + unsigned long flags; + + /* + * Some times this is called with interrupts disabled and causes + * dead-lock; to avoid this we enable interrupt and raise the TPR + * to enable ONLY IPI. + */ + __save_flags(flags); + if (!(flags & IA64_PSR_I)) { + saved_tpr = ia64_get_tpr(); + ia64_srlz_d(); + ia64_set_tpr(IPI_IRQ - 16); + ia64_srlz_d(); + local_irq_enable(); + } + + spin_lock(&ptcg_lock); + flush_rid = ia64_get_rr(start); + ia64_srlz_d(); + flush_start = start; + flush_end = end; + flush_nbits = nbits; + atomic_set(&flush_cpu_count, smp_num_cpus - 1); + smp_send_flush_tlb(); + /* + * Purge local TLB entries. ALAT invalidation is done in ia64_leave_kernel. + */ + do { + asm volatile ("ptc.l %0,%1" :: "r"(start), "r"(nbits<<2) : "memory"); + start += (1UL << nbits); + } while (start < end); + + ia64_srlz_i(); /* srlz.i implies srlz.d */ + + /* + * Wait for other CPUs to finish purging entries. + */ + while (atomic_read(&flush_cpu_count)) { + /* Nothing */ + } + if (!(flags & IA64_PSR_I)) { + local_irq_disable(); + ia64_set_tpr(saved_tpr); + ia64_srlz_d(); + } +} + +#endif /* CONFIG_SMP && !CONFIG_ITANIUM_PTCG */ + void get_new_mmu_context (struct mm_struct *mm) { @@ -97,7 +161,7 @@ stride0 = ia64_ptce_info.stride[0]; stride1 = ia64_ptce_info.stride[1]; - __save_and_cli(flags); + local_irq_save(flags); for (i = 0; i < count0; ++i) { for (j = 0; j < count1; ++j) { asm volatile ("ptc.e %0" :: "r"(addr)); @@ -105,7 +169,7 @@ } addr += stride0; } - __restore_flags(flags); + local_irq_restore(flags); ia64_insn_group_barrier(); ia64_srlz_i(); /* srlz.i implies srlz.d */ ia64_insn_group_barrier(); @@ -142,23 +206,29 @@ } start &= ~((1UL << nbits) - 1); +#if defined(CONFIG_SMP) && !defined(CONFIG_ITANIUM_PTCG) + flush_tlb_no_ptcg(start, end, nbits); +#else spin_lock(&ptcg_lock); do { -#ifdef CONFIG_SMP - __asm__ __volatile__ ("ptc.g %0,%1;;srlz.i;;" - :: "r"(start), "r"(nbits<<2) : "memory"); -#else - __asm__ __volatile__ ("ptc.l %0,%1" :: "r"(start), "r"(nbits<<2) : "memory"); -#endif +# ifdef CONFIG_SMP + /* + * Flush ALAT entries also. + */ + asm volatile ("ptc.ga %0,%1;;srlz.i;;" :: "r"(start), "r"(nbits<<2) : "memory"); +# else + asm volatile ("ptc.l %0,%1" :: "r"(start), "r"(nbits<<2) : "memory"); +# endif start += (1UL << nbits); } while (start < end); +#endif /* CONFIG_SMP && !defined(CONFIG_ITANIUM_PTCG) */ spin_unlock(&ptcg_lock); ia64_insn_group_barrier(); ia64_srlz_i(); /* srlz.i implies srlz.d */ ia64_insn_group_barrier(); } -void +void __init ia64_tlb_init (void) { ia64_get_ptce(&ia64_ptce_info); diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/tools/Makefile linux/arch/ia64/tools/Makefile --- v2.4.0-test1/linux/arch/ia64/tools/Makefile Fri May 12 14:18:55 2000 +++ linux/arch/ia64/tools/Makefile Thu Jun 22 07:09:45 2000 @@ -44,4 +44,4 @@ endif -.PHONY: all +.PHONY: all modules diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/tools/print_offsets.c linux/arch/ia64/tools/print_offsets.c --- v2.4.0-test1/linux/arch/ia64/tools/print_offsets.c Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/tools/print_offsets.c Thu Jun 22 07:09:45 2000 @@ -45,6 +45,9 @@ { "IA64_PT_REGS_SIZE", sizeof (struct pt_regs) }, { "IA64_SWITCH_STACK_SIZE", sizeof (struct switch_stack) }, { "IA64_SIGINFO_SIZE", sizeof (struct siginfo) }, +#ifdef CONFIG_IA64_NEW_UNWIND + { "UNW_FRAME_INFO_SIZE", sizeof (struct unw_frame_info) }, +#endif { "", 0 }, /* spacer */ { "IA64_TASK_FLAGS_OFFSET", offsetof (struct task_struct, flags) }, { "IA64_TASK_SIGPENDING_OFFSET", offsetof (struct task_struct, sigpending) }, @@ -58,11 +61,95 @@ { "IA64_TASK_PID_OFFSET", offsetof (struct task_struct, pid) }, { "IA64_TASK_MM_OFFSET", offsetof (struct task_struct, mm) }, { "IA64_PT_REGS_CR_IPSR_OFFSET", offsetof (struct pt_regs, cr_ipsr) }, + { "IA64_PT_REGS_CR_IIP_OFFSET", offsetof (struct pt_regs, cr_iip) }, + { "IA64_PT_REGS_CR_IFS_OFFSET", offsetof (struct pt_regs, cr_ifs) }, + { "IA64_PT_REGS_AR_UNAT_OFFSET", offsetof (struct pt_regs, ar_unat) }, + { "IA64_PT_REGS_AR_PFS_OFFSET", offsetof (struct pt_regs, ar_pfs) }, + { "IA64_PT_REGS_AR_RSC_OFFSET", offsetof (struct pt_regs, ar_rsc) }, + { "IA64_PT_REGS_AR_RNAT_OFFSET", offsetof (struct pt_regs, ar_rnat) }, + { "IA64_PT_REGS_AR_BSPSTORE_OFFSET",offsetof (struct pt_regs, ar_bspstore) }, + { "IA64_PT_REGS_PR_OFFSET", offsetof (struct pt_regs, pr) }, + { "IA64_PT_REGS_B6_OFFSET", offsetof (struct pt_regs, b6) }, + { "IA64_PT_REGS_LOADRS_OFFSET", offsetof (struct pt_regs, loadrs) }, + { "IA64_PT_REGS_R1_OFFSET", offsetof (struct pt_regs, r1) }, + { "IA64_PT_REGS_R2_OFFSET", offsetof (struct pt_regs, r2) }, + { "IA64_PT_REGS_R3_OFFSET", offsetof (struct pt_regs, r3) }, { "IA64_PT_REGS_R12_OFFSET", offsetof (struct pt_regs, r12) }, + { "IA64_PT_REGS_R13_OFFSET", offsetof (struct pt_regs, r13) }, + { "IA64_PT_REGS_R14_OFFSET", offsetof (struct pt_regs, r14) }, + { "IA64_PT_REGS_R15_OFFSET", offsetof (struct pt_regs, r15) }, { "IA64_PT_REGS_R8_OFFSET", offsetof (struct pt_regs, r8) }, + { "IA64_PT_REGS_R9_OFFSET", offsetof (struct pt_regs, r9) }, + { "IA64_PT_REGS_R10_OFFSET", offsetof (struct pt_regs, r10) }, + { "IA64_PT_REGS_R11_OFFSET", offsetof (struct pt_regs, r11) }, { "IA64_PT_REGS_R16_OFFSET", offsetof (struct pt_regs, r16) }, - { "IA64_SWITCH_STACK_B0_OFFSET", offsetof (struct switch_stack, b0) }, - { "IA64_SWITCH_STACK_CALLER_UNAT_OFFSET", offsetof (struct switch_stack, caller_unat) }, + { "IA64_PT_REGS_R17_OFFSET", offsetof (struct pt_regs, r17) }, + { "IA64_PT_REGS_R18_OFFSET", offsetof (struct pt_regs, r18) }, + { "IA64_PT_REGS_R19_OFFSET", offsetof (struct pt_regs, r19) }, + { "IA64_PT_REGS_R20_OFFSET", offsetof (struct pt_regs, r20) }, + { "IA64_PT_REGS_R21_OFFSET", offsetof (struct pt_regs, r21) }, + { "IA64_PT_REGS_R22_OFFSET", offsetof (struct pt_regs, r22) }, + { "IA64_PT_REGS_R23_OFFSET", offsetof (struct pt_regs, r23) }, + { "IA64_PT_REGS_R24_OFFSET", offsetof (struct pt_regs, r24) }, + { "IA64_PT_REGS_R25_OFFSET", offsetof (struct pt_regs, r25) }, + { "IA64_PT_REGS_R26_OFFSET", offsetof (struct pt_regs, r26) }, + { "IA64_PT_REGS_R27_OFFSET", offsetof (struct pt_regs, r27) }, + { "IA64_PT_REGS_R28_OFFSET", offsetof (struct pt_regs, r28) }, + { "IA64_PT_REGS_R29_OFFSET", offsetof (struct pt_regs, r29) }, + { "IA64_PT_REGS_R30_OFFSET", offsetof (struct pt_regs, r30) }, + { "IA64_PT_REGS_R31_OFFSET", offsetof (struct pt_regs, r31) }, + { "IA64_PT_REGS_AR_CCV_OFFSET", offsetof (struct pt_regs, ar_ccv) }, + { "IA64_PT_REGS_AR_FPSR_OFFSET", offsetof (struct pt_regs, ar_fpsr) }, + { "IA64_PT_REGS_B0_OFFSET", offsetof (struct pt_regs, b0) }, + { "IA64_PT_REGS_B7_OFFSET", offsetof (struct pt_regs, b7) }, + { "IA64_PT_REGS_F6_OFFSET", offsetof (struct pt_regs, f6) }, + { "IA64_PT_REGS_F7_OFFSET", offsetof (struct pt_regs, f7) }, + { "IA64_PT_REGS_F8_OFFSET", offsetof (struct pt_regs, f8) }, + { "IA64_PT_REGS_F9_OFFSET", offsetof (struct pt_regs, f9) }, + { "IA64_SWITCH_STACK_CALLER_UNAT_OFFSET", offsetof (struct switch_stack, caller_unat) }, + { "IA64_SWITCH_STACK_AR_FPSR_OFFSET", offsetof (struct switch_stack, ar_fpsr) }, + { "IA64_SWITCH_STACK_F2_OFFSET", offsetof (struct switch_stack, f2) }, + { "IA64_SWITCH_STACK_F3_OFFSET", offsetof (struct switch_stack, f3) }, + { "IA64_SWITCH_STACK_F4_OFFSET", offsetof (struct switch_stack, f4) }, + { "IA64_SWITCH_STACK_F5_OFFSET", offsetof (struct switch_stack, f5) }, + { "IA64_SWITCH_STACK_F10_OFFSET", offsetof (struct switch_stack, f10) }, + { "IA64_SWITCH_STACK_F11_OFFSET", offsetof (struct switch_stack, f11) }, + { "IA64_SWITCH_STACK_F12_OFFSET", offsetof (struct switch_stack, f12) }, + { "IA64_SWITCH_STACK_F13_OFFSET", offsetof (struct switch_stack, f13) }, + { "IA64_SWITCH_STACK_F14_OFFSET", offsetof (struct switch_stack, f14) }, + { "IA64_SWITCH_STACK_F15_OFFSET", offsetof (struct switch_stack, f15) }, + { "IA64_SWITCH_STACK_F16_OFFSET", offsetof (struct switch_stack, f16) }, + { "IA64_SWITCH_STACK_F17_OFFSET", offsetof (struct switch_stack, f17) }, + { "IA64_SWITCH_STACK_F18_OFFSET", offsetof (struct switch_stack, f18) }, + { "IA64_SWITCH_STACK_F19_OFFSET", offsetof (struct switch_stack, f19) }, + { "IA64_SWITCH_STACK_F20_OFFSET", offsetof (struct switch_stack, f20) }, + { "IA64_SWITCH_STACK_F21_OFFSET", offsetof (struct switch_stack, f21) }, + { "IA64_SWITCH_STACK_F22_OFFSET", offsetof (struct switch_stack, f22) }, + { "IA64_SWITCH_STACK_F23_OFFSET", offsetof (struct switch_stack, f23) }, + { "IA64_SWITCH_STACK_F24_OFFSET", offsetof (struct switch_stack, f24) }, + { "IA64_SWITCH_STACK_F25_OFFSET", offsetof (struct switch_stack, f25) }, + { "IA64_SWITCH_STACK_F26_OFFSET", offsetof (struct switch_stack, f26) }, + { "IA64_SWITCH_STACK_F27_OFFSET", offsetof (struct switch_stack, f27) }, + { "IA64_SWITCH_STACK_F28_OFFSET", offsetof (struct switch_stack, f28) }, + { "IA64_SWITCH_STACK_F29_OFFSET", offsetof (struct switch_stack, f29) }, + { "IA64_SWITCH_STACK_F30_OFFSET", offsetof (struct switch_stack, f30) }, + { "IA64_SWITCH_STACK_F31_OFFSET", offsetof (struct switch_stack, f31) }, + { "IA64_SWITCH_STACK_R4_OFFSET", offsetof (struct switch_stack, r4) }, + { "IA64_SWITCH_STACK_R5_OFFSET", offsetof (struct switch_stack, r5) }, + { "IA64_SWITCH_STACK_R6_OFFSET", offsetof (struct switch_stack, r6) }, + { "IA64_SWITCH_STACK_R7_OFFSET", offsetof (struct switch_stack, r7) }, + { "IA64_SWITCH_STACK_B0_OFFSET", offsetof (struct switch_stack, b0) }, + { "IA64_SWITCH_STACK_B1_OFFSET", offsetof (struct switch_stack, b1) }, + { "IA64_SWITCH_STACK_B2_OFFSET", offsetof (struct switch_stack, b2) }, + { "IA64_SWITCH_STACK_B3_OFFSET", offsetof (struct switch_stack, b3) }, + { "IA64_SWITCH_STACK_B4_OFFSET", offsetof (struct switch_stack, b4) }, + { "IA64_SWITCH_STACK_B5_OFFSET", offsetof (struct switch_stack, b5) }, + { "IA64_SWITCH_STACK_AR_PFS_OFFSET", offsetof (struct switch_stack, ar_pfs) }, + { "IA64_SWITCH_STACK_AR_LC_OFFSET", offsetof (struct switch_stack, ar_lc) }, + { "IA64_SWITCH_STACK_AR_UNAT_OFFSET", offsetof (struct switch_stack, ar_unat) }, + { "IA64_SWITCH_STACK_AR_RNAT_OFFSET", offsetof (struct switch_stack, ar_rnat) }, + { "IA64_SWITCH_STACK_AR_BSPSTORE_OFFSET", offsetof (struct switch_stack, ar_bspstore) }, + { "IA64_SWITCH_STACK_PR_OFFSET", offsetof (struct switch_stack, b0) }, { "IA64_SIGCONTEXT_AR_BSP_OFFSET", offsetof (struct sigcontext, sc_ar_bsp) }, { "IA64_SIGCONTEXT_AR_RNAT_OFFSET", offsetof (struct sigcontext, sc_ar_rnat) }, { "IA64_SIGCONTEXT_FLAGS_OFFSET", offsetof (struct sigcontext, sc_flags) }, diff -u --recursive --new-file v2.4.0-test1/linux/arch/ia64/vmlinux.lds.S linux/arch/ia64/vmlinux.lds.S --- v2.4.0-test1/linux/arch/ia64/vmlinux.lds.S Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/vmlinux.lds.S Thu Jun 22 07:09:45 2000 @@ -32,6 +32,13 @@ #endif _etext = .; + /* Read-only data */ + + __gp = ALIGN(8) + 0x200000; + + /* Global data */ + _data = .; + /* Exception table */ . = ALIGN(16); __start___ex_table = .; @@ -39,19 +46,33 @@ { *(__ex_table) } __stop___ex_table = .; - /* Kernel symbol names for modules: */ + __start___ksymtab = .; /* Kernel symbol table */ + __ksymtab : AT(ADDR(__ksymtab) - PAGE_OFFSET) + { *(__ksymtab) } + __stop___ksymtab = .; + + /* Unwind table */ + ia64_unw_start = .; + .IA_64.unwind : AT(ADDR(.IA_64.unwind) - PAGE_OFFSET) + { *(.IA_64.unwind) } + ia64_unw_end = .; + .IA_64.unwind_info : AT(ADDR(.IA_64.unwind_info) - PAGE_OFFSET) + { *(.IA_64.unwind_info) } + + .rodata : AT(ADDR(.rodata) - PAGE_OFFSET) + { *(.rodata) } .kstrtab : AT(ADDR(.kstrtab) - PAGE_OFFSET) { *(.kstrtab) } + .opd : AT(ADDR(.opd) - PAGE_OFFSET) + { *(.opd) } - /* The initial task and kernel stack */ - . = ALIGN(PAGE_SIZE); - init_task : AT(ADDR(init_task) - PAGE_OFFSET) - { *(init_task) } + /* Initialization code and data: */ - /* Startup code */ + . = ALIGN(PAGE_SIZE); __init_begin = .; .text.init : AT(ADDR(.text.init) - PAGE_OFFSET) { *(.text.init) } + .data.init : AT(ADDR(.data.init) - PAGE_OFFSET) { *(.data.init) } . = ALIGN(16); @@ -66,6 +87,10 @@ . = ALIGN(PAGE_SIZE); __init_end = .; + /* The initial task and kernel stack */ + init_task : AT(ADDR(init_task) - PAGE_OFFSET) + { *(init_task) } + .data.page_aligned : AT(ADDR(.data.page_aligned) - PAGE_OFFSET) { *(.data.idt) } @@ -73,17 +98,12 @@ .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - PAGE_OFFSET) { *(.data.cacheline_aligned) } - /* Global data */ - _data = .; + /* Kernel symbol names for modules: */ + .kstrtab : AT(ADDR(.kstrtab) - PAGE_OFFSET) + { *(.kstrtab) } - .rodata : AT(ADDR(.rodata) - PAGE_OFFSET) - { *(.rodata) } - .opd : AT(ADDR(.opd) - PAGE_OFFSET) - { *(.opd) } .data : AT(ADDR(.data) - PAGE_OFFSET) { *(.data) *(.gnu.linkonce.d*) CONSTRUCTORS } - - __gp = ALIGN (8) + 0x200000; .got : AT(ADDR(.got) - PAGE_OFFSET) { *(.got.plt) *(.got) } diff -u --recursive --new-file v2.4.0-test1/linux/arch/m68k/amiga/amiga_ksyms.c linux/arch/m68k/amiga/amiga_ksyms.c --- v2.4.0-test1/linux/arch/m68k/amiga/amiga_ksyms.c Sat Aug 1 11:33:50 1998 +++ linux/arch/m68k/amiga/amiga_ksyms.c Mon Jun 19 12:56:08 2000 @@ -2,7 +2,9 @@ #include #include #include +#include #include +#include #include extern volatile u_short amiga_audio_min_period; @@ -12,6 +14,7 @@ * Add things here when you find the need for it. */ EXPORT_SYMBOL(amiga_model); +EXPORT_SYMBOL(amiga_chipset); EXPORT_SYMBOL(amiga_hw_present); EXPORT_SYMBOL(amiga_eclock); EXPORT_SYMBOL(amiga_colorclock); @@ -21,6 +24,9 @@ EXPORT_SYMBOL(amiga_chip_size); EXPORT_SYMBOL(amiga_audio_period); EXPORT_SYMBOL(amiga_audio_min_period); +EXPORT_SYMBOL(amiga_do_irq); +EXPORT_SYMBOL(amiga_do_irq_list); +EXPORT_SYMBOL(amiga_intena_vals); #ifdef CONFIG_AMIGA_PCMCIA EXPORT_SYMBOL(pcmcia_reset); diff -u --recursive --new-file v2.4.0-test1/linux/arch/m68k/amiga/amiints.c linux/arch/m68k/amiga/amiints.c --- v2.4.0-test1/linux/arch/m68k/amiga/amiints.c Tue Feb 1 01:35:43 2000 +++ linux/arch/m68k/amiga/amiints.c Mon Jun 19 12:56:08 2000 @@ -58,7 +58,7 @@ /* irq node variables for amiga interrupt sources */ static irq_node_t *ami_irq_list[AMI_STD_IRQS]; -unsigned short ami_intena_vals[AMI_STD_IRQS] = { +unsigned short amiga_intena_vals[AMI_STD_IRQS] = { IF_VERTB, IF_COPER, IF_AUD0, IF_AUD1, IF_AUD2, IF_AUD3, IF_BLIT, IF_DSKSYN, IF_DSKBLK, IF_RBF, IF_TBE, IF_SOFT, IF_PORTS, IF_EXTER }; @@ -230,7 +230,7 @@ /* enable the interrupt */ if (irq < IRQ_AMIGA_PORTS && !ami_ablecount[irq]) - custom.intena = IF_SETCLR | ami_intena_vals[irq]; + custom.intena = IF_SETCLR | amiga_intena_vals[irq]; return error; } @@ -259,7 +259,7 @@ amiga_delete_irq(&ami_irq_list[irq], dev_id); /* if server list empty, disable the interrupt */ if (!ami_irq_list[irq] && irq < IRQ_AMIGA_PORTS) - custom.intena = ami_intena_vals[irq]; + custom.intena = amiga_intena_vals[irq]; } else { if (ami_irq_list[irq]->dev_id != dev_id) printk("%s: removing probably wrong IRQ %d from %s\n", @@ -268,7 +268,7 @@ ami_irq_list[irq]->flags = 0; ami_irq_list[irq]->dev_id = NULL; ami_irq_list[irq]->devname = NULL; - custom.intena = ami_intena_vals[irq]; + custom.intena = amiga_intena_vals[irq]; } } @@ -312,7 +312,7 @@ } /* enable the interrupt */ - custom.intena = IF_SETCLR | ami_intena_vals[irq]; + custom.intena = IF_SETCLR | amiga_intena_vals[irq]; } void amiga_disable_irq(unsigned int irq) @@ -343,7 +343,7 @@ } /* disable the interrupt */ - custom.intena = ami_intena_vals[irq]; + custom.intena = amiga_intena_vals[irq]; } inline void amiga_do_irq(int irq, struct pt_regs *fp) @@ -361,7 +361,7 @@ if (server->count++) server->reentrance = 1; - intena = ami_intena_vals[irq]; + intena = amiga_intena_vals[irq]; custom.intreq = intena; /* serve fast handler if present - there can only be one of these */ diff -u --recursive --new-file v2.4.0-test1/linux/arch/m68k/amiga/chipram.c linux/arch/m68k/amiga/chipram.c --- v2.4.0-test1/linux/arch/m68k/amiga/chipram.c Fri Jan 28 15:09:07 2000 +++ linux/arch/m68k/amiga/chipram.c Mon Jun 19 12:56:08 2000 @@ -42,7 +42,7 @@ if (!AMIGAHW_PRESENT(CHIP_RAM)) return; - chipram.end = amiga_chip_size; + chipram.end = amiga_chip_size-1; request_resource(&iomem_resource, &chipram); /* initialize start boundary */ diff -u --recursive --new-file v2.4.0-test1/linux/arch/m68k/atari/joystick.c linux/arch/m68k/atari/joystick.c --- v2.4.0-test1/linux/arch/m68k/atari/joystick.c Wed Feb 16 17:03:51 2000 +++ linux/arch/m68k/atari/joystick.c Wed Jun 21 22:30:59 2000 @@ -136,7 +136,7 @@ if (devfs_register_chrdev(MAJOR_NR, "Joystick", &atari_joystick_fops)) printk("unable to get major %d for joystick devices\n", MAJOR_NR); devfs_register_series (NULL, "joysticks/digital%u", 2, DEVFS_FL_DEFAULT, - MAJOR_NR, 128, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + MAJOR_NR, 128, S_IFCHR | S_IRUSR | S_IWUSR, &atari_joystick_fops, NULL); return 0; diff -u --recursive --new-file v2.4.0-test1/linux/arch/m68k/config.in linux/arch/m68k/config.in --- v2.4.0-test1/linux/arch/m68k/config.in Tue Apr 11 15:09:13 2000 +++ linux/arch/m68k/config.in Mon Jun 19 12:56:08 2000 @@ -1,6 +1,6 @@ # # For a description of the syntax of this configuration file, -# see the Configure script. +# see Documentation/kbuild/config-language.txt. # define_bool CONFIG_UID16 y diff -u --recursive --new-file v2.4.0-test1/linux/arch/m68k/defconfig linux/arch/m68k/defconfig --- v2.4.0-test1/linux/arch/m68k/defconfig Thu May 11 15:30:06 2000 +++ linux/arch/m68k/defconfig Mon Jun 19 12:56:08 2000 @@ -67,10 +67,6 @@ # CONFIG_AMIGA_Z2RAM is not set # CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE is not set - -# -# Additional Block Devices -# # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set diff -u --recursive --new-file v2.4.0-test1/linux/arch/m68k/kernel/setup.c linux/arch/m68k/kernel/setup.c --- v2.4.0-test1/linux/arch/m68k/kernel/setup.c Fri Jan 28 15:09:07 2000 +++ linux/arch/m68k/kernel/setup.c Mon Jun 19 12:56:08 2000 @@ -111,6 +111,7 @@ #endif #ifdef CONFIG_HEARTBEAT void (*mach_heartbeat) (int) = NULL; +EXPORT_SYMBOL(mach_heartbeat); #endif #ifdef CONFIG_M68K_L2_CACHE void (*mach_l2_flush) (int) = NULL; diff -u --recursive --new-file v2.4.0-test1/linux/arch/m68k/kernel/sys_m68k.c linux/arch/m68k/kernel/sys_m68k.c --- v2.4.0-test1/linux/arch/m68k/kernel/sys_m68k.c Fri Jan 28 15:09:07 2000 +++ linux/arch/m68k/kernel/sys_m68k.c Tue Jun 20 13:58:42 2000 @@ -143,7 +143,6 @@ if ((a.offset >> PAGE_SHIFT) != pgoff) return -EINVAL; - down(¤t->mm->mmap_sem); lock_kernel(); if (!(a.flags & MAP_ANONYMOUS)) { error = -EBADF; @@ -153,12 +152,13 @@ } a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + down(¤t->mm->mmap_sem); error = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, pgoff); + up(¤t->mm->mmap_sem); if (file) fput(file); out: unlock_kernel(); - up(¤t->mm->mmap_sem); return error; } #endif diff -u --recursive --new-file v2.4.0-test1/linux/arch/mips/config.in linux/arch/mips/config.in --- v2.4.0-test1/linux/arch/mips/config.in Tue May 23 15:31:33 2000 +++ linux/arch/mips/config.in Tue Jun 20 07:24:52 2000 @@ -1,6 +1,6 @@ # $Id: config.in,v 1.46 2000/03/26 22:59:01 ralf Exp $ # For a description of the syntax of this configuration file, -# see the Configure script. +# see Documentation/kbuild/config-language.txt. # mainmenu_name "Linux Kernel Configuration" diff -u --recursive --new-file v2.4.0-test1/linux/arch/mips/kernel/irixelf.c linux/arch/mips/kernel/irixelf.c --- v2.4.0-test1/linux/arch/mips/kernel/irixelf.c Tue May 23 15:31:33 2000 +++ linux/arch/mips/kernel/irixelf.c Tue Jun 20 07:24:52 2000 @@ -315,10 +315,12 @@ (unsigned long) elf_prot, (unsigned long) elf_type, (unsigned long) (eppnt->p_offset & 0xfffff000)); #endif + down(¤t->mm->mmap_sem); error = do_mmap(interpreter, vaddr, eppnt->p_filesz + (eppnt->p_vaddr & 0xfff), elf_prot, elf_type, eppnt->p_offset & 0xfffff000); + up(¤t->mm->mmap_sem); if(error < 0 && error > -1024) { printk("Aieee IRIX interp mmap error=%d\n", error); @@ -465,6 +467,7 @@ return 0; dput_and_out: + allow_write_access(file); fput(file); out: kfree(*name); @@ -497,10 +500,12 @@ prot = (epp->p_flags & PF_R) ? PROT_READ : 0; prot |= (epp->p_flags & PF_W) ? PROT_WRITE : 0; prot |= (epp->p_flags & PF_X) ? PROT_EXEC : 0; + down(¤t->mm->mmap_sem); (void) do_mmap(fp, (epp->p_vaddr & 0xfffff000), (epp->p_filesz + (epp->p_vaddr & 0xfff)), prot, EXEC_MAP_FLAGS, (epp->p_offset & 0xfffff000)); + up(¤t->mm->mmap_sem); /* Fixup location tracking vars. */ if((epp->p_vaddr & 0xfffff000) < *estack) @@ -759,8 +764,10 @@ * Since we do not have the power to recompile these, we * emulate the SVr4 behavior. Sigh. */ + down(¤t->mm->mmap_sem); (void) do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, 0); + up(¤t->mm->mmap_sem); #endif start_thread(regs, elf_entry, bprm->p); @@ -771,6 +778,7 @@ return retval; out_free_dentry: + allow_write_access(interpreter); fput(interpreter); out_free_interp: if (elf_interpreter) @@ -910,10 +918,12 @@ prot = (hp->p_flags & PF_R) ? PROT_READ : 0; prot |= (hp->p_flags & PF_W) ? PROT_WRITE : 0; prot |= (hp->p_flags & PF_X) ? PROT_EXEC : 0; + down(¤t->mm->mmap_sem); retval = do_mmap(filp, (hp->p_vaddr & 0xfffff000), (hp->p_filesz + (hp->p_vaddr & 0xfff)), prot, (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), (hp->p_offset & 0xfffff000)); + up(¤t->mm->mmap_sem); if(retval != (hp->p_vaddr & 0xfffff000)) { printk("irix_mapelf: do_mmap fails with %d!\n", retval); diff -u --recursive --new-file v2.4.0-test1/linux/arch/mips/kernel/sysirix.c linux/arch/mips/kernel/sysirix.c --- v2.4.0-test1/linux/arch/mips/kernel/sysirix.c Tue May 23 15:31:33 2000 +++ linux/arch/mips/kernel/sysirix.c Tue Jun 20 07:24:52 2000 @@ -1099,7 +1099,9 @@ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + down(¤t->mm->mmap_sem); retval = do_mmap(file, addr, len, prot, flags, offset); + up(¤t->mm->mmap_sem); if (file) fput(file); diff -u --recursive --new-file v2.4.0-test1/linux/arch/mips64/config.in linux/arch/mips64/config.in --- v2.4.0-test1/linux/arch/mips64/config.in Tue May 23 15:31:33 2000 +++ linux/arch/mips64/config.in Tue Jun 20 07:24:52 2000 @@ -1,7 +1,7 @@ # $Id: config.in,v 1.19 2000/03/27 01:44:45 ralf Exp $ # # For a description of the syntax of this configuration file, -# see the Configure script. +# see Documentation/kbuild/config-language.txt. # mainmenu_name "Linux Kernel Configuration" diff -u --recursive --new-file v2.4.0-test1/linux/arch/mips64/kernel/syscall.c linux/arch/mips64/kernel/syscall.c --- v2.4.0-test1/linux/arch/mips64/kernel/syscall.c Tue May 23 15:31:33 2000 +++ linux/arch/mips64/kernel/syscall.c Tue Jun 20 07:24:52 2000 @@ -56,7 +56,6 @@ struct file * file = NULL; unsigned long error = -EFAULT; - down(¤t->mm->mmap_sem); lock_kernel(); if (!(flags & MAP_ANONYMOUS)) { error = -EBADF; @@ -66,12 +65,13 @@ } flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + down(¤t->mm->mmap_sem); error = do_mmap(file, addr, len, prot, flags, offset); + up(¤t->mm->mmap_sem); if (file) fput(file); out: unlock_kernel(); - up(¤t->mm->mmap_sem); return error; } diff -u --recursive --new-file v2.4.0-test1/linux/arch/mips64/sgi-ip27/ip27-rtc.c linux/arch/mips64/sgi-ip27/ip27-rtc.c --- v2.4.0-test1/linux/arch/mips64/sgi-ip27/ip27-rtc.c Thu Mar 2 14:36:22 2000 +++ linux/arch/mips64/sgi-ip27/ip27-rtc.c Tue Jun 20 07:24:52 2000 @@ -168,8 +168,6 @@ if(rtc_status & RTC_IS_OPEN) return -EBUSY; - MOD_INC_USE_COUNT; - rtc_status |= RTC_IS_OPEN; return 0; } @@ -181,8 +179,6 @@ * in use, and clear the data. */ - MOD_DEC_USE_COUNT; - rtc_status &= ~RTC_IS_OPEN; return 0; } @@ -192,6 +188,7 @@ */ static struct file_operations rtc_fops = { + owner: THIS_MODULE, ioctl: rtc_ioctl, open: rtc_open, release: rtc_release, diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/8260_io/enet.c linux/arch/ppc/8260_io/enet.c --- v2.4.0-test1/linux/arch/ppc/8260_io/enet.c Tue May 23 15:31:33 2000 +++ linux/arch/ppc/8260_io/enet.c Mon Jun 19 13:25:05 2000 @@ -177,7 +177,7 @@ #ifndef final_version if (bdp->cbd_sc & BD_ENET_TX_READY) { /* Ooops. All transmit buffers are full. Bail out. - * This should not happen, since cep->tx_busy should be set. + * This should not happen, since cep->tx_full should be set. */ printk("%s: tx queue full!.\n", dev->name); return 1; @@ -207,12 +207,6 @@ cep->stats.tx_bytes += skb->len; cep->skb_cur = (cep->skb_cur+1) & TX_RING_MOD_MASK; - /* Push the data cache so the CPM does not get stale memory - * data. - */ - flush_dcache_range((unsigned long)(skb->data), - (unsigned long)(skb->data + skb->len)); - spin_lock_irq(&cep->lock); /* Send it on its way. Tell CPM its ready, interrupt when done, @@ -229,8 +223,10 @@ else bdp++; - if (bdp->cbd_sc & BD_ENET_TX_READY) + if (bdp->cbd_sc & BD_ENET_TX_READY) { netif_stop_queue(dev); + cep->tx_full = 1; + } cep->cur_tx = (cbd_t *)bdp; @@ -254,12 +250,14 @@ cep->cur_tx, cep->tx_full ? " (full)" : "", cep->cur_rx); bdp = cep->tx_bd_base; + printk(" Tx @base %p :\n", bdp); for (i = 0 ; i < TX_RING_SIZE; i++, bdp++) printk("%04x %04x %08x\n", bdp->cbd_sc, bdp->cbd_datlen, bdp->cbd_bufaddr); bdp = cep->rx_bd_base; + printk(" Rx @base %p :\n", bdp); for (i = 0 ; i < RX_RING_SIZE; i++, bdp++) printk("%04x %04x %08x\n", bdp->cbd_sc, @@ -368,6 +366,7 @@ * full. */ if (cep->tx_full) { + cep->tx_full = 0; if (netif_queue_stopped(dev)) { netif_wake_queue(dev); } @@ -385,6 +384,7 @@ * _should_ pick up without having to reset any of our * pointers either. */ + cp = cpmp; cp->cp_cpcr = mk_cr_cmd(CPM_ENET_PAGE, CPM_ENET_BLOCK, 0, diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/8260_io/uart.c linux/arch/ppc/8260_io/uart.c --- v2.4.0-test1/linux/arch/ppc/8260_io/uart.c Tue May 23 15:31:34 2000 +++ linux/arch/ppc/8260_io/uart.c Mon Jun 19 12:56:08 2000 @@ -2461,6 +2461,8 @@ if (info) { /*memset(info, 0, sizeof(ser_info_t));*/ __clear_user(info,sizeof(ser_info_t)); + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); info->magic = SERIAL_MAGIC; info->flags = state->flags; info->tqueue.routine = do_softint; diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/8xx_io/Config.in linux/arch/ppc/8xx_io/Config.in --- v2.4.0-test1/linux/arch/ppc/8xx_io/Config.in Sat Oct 9 11:47:50 1999 +++ linux/arch/ppc/8xx_io/Config.in Mon Jun 19 17:59:35 2000 @@ -1,9 +1,10 @@ # # MPC8xx Communication options # +mainmenu_option next_comment +comment 'MPC8xx CPM Options' + if [ "$CONFIG_NET_ETHERNET" = "y" ]; then - mainmenu_option next_comment - comment 'MPC8xx Communication Options' bool 'CPM SCC Ethernet' CONFIG_SCC_ENET if [ "$CONFIG_SCC_ENET" = "y" ]; then bool 'Ethernet on SCC1' CONFIG_SCC1_ENET @@ -12,5 +13,15 @@ fi fi bool '860T FEC Ethernet' CONFIG_FEC_ENET - endmenu + bool 'Use SMC2 for UART' CONFIG_8xxSMC2 + bool 'Enable SCC2 and SCC3 for UART' CONFIG_8xxSCC fi + +# This doesn't really belong here, but it is convenient to ask +# 8xx specific questions. + +comment 'Generic MPC8xx Options' +bool 'Copy-Back Data Cache (else Writethrough)' CONFIG_8xx_COPYBACK +bool 'CPU6 Silicon Errata (860 Pre Rev. C)' CONFIG_8xx_CPU6 + +endmenu diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/8xx_io/commproc.c linux/arch/ppc/8xx_io/commproc.c --- v2.4.0-test1/linux/arch/ppc/8xx_io/commproc.c Thu Nov 18 20:25:37 1999 +++ linux/arch/ppc/8xx_io/commproc.c Mon Jun 19 13:25:06 2000 @@ -94,9 +94,9 @@ */ host_buffer = host_page_addr; /* Host virtual page address */ host_end = host_page_addr + PAGE_SIZE; - pte = find_pte(&init_mm, host_page_addr); + pte = va_to_pte(host_page_addr); pte_val(*pte) |= _PAGE_NO_CACHE; - flush_tlb_page(current->mm->mmap, host_buffer); + flush_tlb_page(init_mm.mmap, host_buffer); /* Tell everyone where the comm processor resides. */ diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/8xx_io/enet.c linux/arch/ppc/8xx_io/enet.c --- v2.4.0-test1/linux/arch/ppc/8xx_io/enet.c Thu May 11 15:30:06 2000 +++ linux/arch/ppc/8xx_io/enet.c Mon Jun 19 13:25:06 2000 @@ -263,8 +263,10 @@ else bdp++; - if (bdp->cbd_sc & BD_ENET_TX_READY) + if (bdp->cbd_sc & BD_ENET_TX_READY) { netif_stop_queue(dev); + cep->tx_full = 1; + } cep->cur_tx = (cbd_t *)bdp; @@ -402,6 +404,7 @@ * full. */ if (cep->tx_full) { + cep->tx_full = 0; if (netif_queue_stopped(dev)) netif_wake_queue(dev); } @@ -835,7 +838,7 @@ /* Make it uncached. */ - pte = find_pte(&init_mm, mem_addr); + pte = va_to_pte(mem_addr); pte_val(*pte) |= _PAGE_NO_CACHE; flush_tlb_page(init_mm.mmap, mem_addr); diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/8xx_io/fec.c linux/arch/ppc/8xx_io/fec.c --- v2.4.0-test1/linux/arch/ppc/8xx_io/fec.c Thu Nov 18 20:25:37 1999 +++ linux/arch/ppc/8xx_io/fec.c Mon Jun 19 13:25:06 2000 @@ -1,5 +1,5 @@ /* - * Fast Ethernet Controller (FECC) driver for Motorola MPC8xx. + * Fast Ethernet Controller (FEC) driver for Motorola MPC8xx. * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) * * This version of the driver is specific to the FADS implementation, @@ -15,7 +15,17 @@ * will be much more memory efficient and will easily handle lots of * small packets. * + * Much better multiple PHY support by Magnus Damm. + * Copyright (c) 2000 Ericsson Radio Systems AB. + * */ + +/* List of PHYs we wish to support. +*/ +#define CONFIG_FEC_LXT970 +#define CONFIG_FEC_LXT971 +#define CONFIG_FEC_QS6612 + #include #include #include @@ -31,6 +41,10 @@ #include #include #include +#include +#ifdef CONFIG_FEC_PACKETHOOK +#include +#endif #include #include @@ -40,6 +54,24 @@ #include #include "commproc.h" +/* Forward declarations of some structures to support different PHYs +*/ + +typedef struct { + uint mii_data; + void (*funct)(uint mii_reg, struct net_device *dev); +} phy_cmd_t; + +typedef struct { + uint id; + char *name; + + const phy_cmd_t *config; + const phy_cmd_t *startup; + const phy_cmd_t *ack_int; + const phy_cmd_t *shutdown; +} phy_info_t; + /* The number of Tx and Rx buffers. These are allocated from the page * pool. The code may assume these are power of two, so it it best * to keep them that size. @@ -103,20 +135,51 @@ cbd_t *dirty_tx; /* The ring entries to be free()ed. */ scc_t *sccp; struct net_device_stats stats; - char tx_full; - unsigned long lock; + uint tx_full; + spinlock_t lock; + + uint phy_id; + uint phy_id_done; + uint phy_status; + uint phy_speed; + phy_info_t *phy; + struct tq_struct phy_task; + + uint sequence_done; + + uint phy_addr; + + int link; + int old_link; + int full_duplex; + +#ifdef CONFIG_FEC_PACKETHOOK + unsigned long ph_lock; + fec_ph_func *ph_rxhandler; + fec_ph_func *ph_txhandler; + __u16 ph_proto; + volatile __u32 *ph_regaddr; + void *ph_priv; +#endif }; static int fec_enet_open(struct net_device *dev); static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); -static int fec_enet_rx(struct net_device *dev); static void fec_enet_mii(struct net_device *dev); -static void fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs); +static void fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs); +#ifdef CONFIG_FEC_PACKETHOOK +static void fec_enet_tx(struct net_device *dev, __u32 regval); +static void fec_enet_rx(struct net_device *dev, __u32 regval); +#else +static void fec_enet_tx(struct net_device *dev); +static void fec_enet_rx(struct net_device *dev); +#endif static int fec_enet_close(struct net_device *dev); static struct net_device_stats *fec_enet_get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); - -static ushort my_enet_addr[] = { 0x0800, 0x3e26, 0x1559 }; +static void fec_restart(struct net_device *dev, int duplex); +static void fec_stop(struct net_device *dev); +static ushort my_enet_addr[3]; /* MII processing. We keep this as simple as possible. Requests are * placed on the list (if there is room). When the request is finished @@ -124,91 +187,133 @@ */ typedef struct mii_list { uint mii_regval; - void (*mii_func)(int val); + void (*mii_func)(uint val, struct net_device *dev); struct mii_list *mii_next; } mii_list_t; -#define NMII 10 +#define NMII 20 mii_list_t mii_cmds[NMII]; mii_list_t *mii_free; mii_list_t *mii_head; mii_list_t *mii_tail; -static int mii_queue(int request, void (*func)(int)); +static int mii_queue(struct net_device *dev, int request, + void (*func)(uint, struct net_device *)); /* Make MII read/write commands for the FEC. */ #define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) #define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | \ (VAL & 0xffff)) +#define mk_mii_end 0 -static int -fec_enet_open(struct net_device *dev) +/* Transmitter timeout. +*/ +#define TX_TIMEOUT (2*HZ) + +/* Register definitions for the PHY. +*/ + +#define MII_REG_CR 0 /* Control Register */ +#define MII_REG_SR 1 /* Status Register */ +#define MII_REG_PHYIR1 2 /* PHY Identification Register 1 */ +#define MII_REG_PHYIR2 3 /* PHY Identification Register 2 */ +#define MII_REG_ANAR 4 /* A-N Advertisement Register */ +#define MII_REG_ANLPAR 5 /* A-N Link Partner Ability Register */ +#define MII_REG_ANER 6 /* A-N Expansion Register */ +#define MII_REG_ANNPTR 7 /* A-N Next Page Transmit Register */ +#define MII_REG_ANLPRNPR 8 /* A-N Link Partner Received Next Page Reg. */ + +/* values for phy_status */ + +#define PHY_CONF_ANE 0x0001 /* 1 auto-negotiation enabled */ +#define PHY_CONF_LOOP 0x0002 /* 1 loopback mode enabled */ +#define PHY_CONF_SPMASK 0x00f0 /* mask for speed */ +#define PHY_CONF_10HDX 0x0010 /* 10 Mbit half duplex supported */ +#define PHY_CONF_10FDX 0x0020 /* 10 Mbit full duplex supported */ +#define PHY_CONF_100HDX 0x0040 /* 100 Mbit half duplex supported */ +#define PHY_CONF_100FDX 0x0080 /* 100 Mbit full duplex supported */ + +#define PHY_STAT_LINK 0x0100 /* 1 up - 0 down */ +#define PHY_STAT_FAULT 0x0200 /* 1 remote fault */ +#define PHY_STAT_ANC 0x0400 /* 1 auto-negotiation complete */ +#define PHY_STAT_SPMASK 0xf000 /* mask for speed */ +#define PHY_STAT_10HDX 0x1000 /* 10 Mbit half duplex selected */ +#define PHY_STAT_10FDX 0x2000 /* 10 Mbit full duplex selected */ +#define PHY_STAT_100HDX 0x4000 /* 100 Mbit half duplex selected */ +#define PHY_STAT_100FDX 0x8000 /* 100 Mbit full duplex selected */ + +#ifdef CONFIG_FEC_PACKETHOOK +int +fec_register_ph(struct net_device *dev, fec_ph_func *rxfun, fec_ph_func *txfun, + __u16 proto, volatile __u32 *regaddr, void *priv) { + struct fec_enet_private *fep; + int retval = 0; - /* I should reset the ring buffers here, but I don't yet know - * a simple way to do that. - */ + fep = dev->priv; + + if (test_and_set_bit(0, (void*)&fep->ph_lock) != 0) { + /* Someone is messing with the packet hook */ + return -EAGAIN; + } + if (fep->ph_rxhandler != NULL || fep->ph_txhandler != NULL) { + retval = -EBUSY; + goto out; + } + fep->ph_rxhandler = rxfun; + fep->ph_txhandler = txfun; + fep->ph_proto = proto; + fep->ph_regaddr = regaddr; + fep->ph_priv = priv; - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + out: + fep->ph_lock = 0; - return 0; /* Always succeed */ + return retval; } -static int -fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct fec_enet_private *fep = (struct fec_enet_private *)dev->priv; - volatile cbd_t *bdp; - unsigned long flags; - /* Transmitter timeout, serious problems. */ - if (dev->tbusy) { - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 20) - return 1; - printk("%s: transmit timed out.\n", dev->name); - fep->stats.tx_errors++; -#ifndef final_version - { - int i; - cbd_t *bdp; - printk(" Ring data dump: cur_tx %x%s cur_rx %x.\n", - fep->cur_tx, fep->tx_full ? " (full)" : "", - fep->cur_rx); - bdp = fep->tx_bd_base; - for (i = 0 ; i < TX_RING_SIZE; i++) - printk("%04x %04x %08x\n", - bdp->cbd_sc, - bdp->cbd_datlen, - bdp->cbd_bufaddr); - bdp = fep->rx_bd_base; - for (i = 0 ; i < RX_RING_SIZE; i++) - printk("%04x %04x %08x\n", - bdp->cbd_sc, - bdp->cbd_datlen, - bdp->cbd_bufaddr); - } -#endif +int +fec_unregister_ph(struct net_device *dev) +{ + struct fec_enet_private *fep; + int retval = 0; - dev->tbusy=0; - dev->trans_start = jiffies; + fep = dev->priv; - return 0; + if (test_and_set_bit(0, (void*)&fep->ph_lock) != 0) { + /* Someone is messing with the packet hook */ + return -EAGAIN; } - /* Block a timer-based transmit from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - printk("%s: Transmitter access conflict.\n", dev->name); - return 1; - } + fep->ph_rxhandler = fep->ph_txhandler = NULL; + fep->ph_proto = 0; + fep->ph_regaddr = NULL; + fep->ph_priv = NULL; + + fep->ph_lock = 0; + + return retval; +} + +EXPORT_SYMBOL(fec_register_ph); +EXPORT_SYMBOL(fec_unregister_ph); + +#endif /* CONFIG_FEC_PACKETHOOK */ + +static int +fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct fec_enet_private *fep; + volatile fec_t *fecp; + volatile cbd_t *bdp; - if (test_and_set_bit(0, (void*)&fep->lock) != 0) { - printk("%s: tx queue lock!.\n", dev->name); - /* don't clear dev->tbusy flag. */ + fep = dev->priv; + fecp = (volatile fec_t*)dev->base_addr; + + if (!fep->link) { + /* Link is down or autonegotiation is in progress. */ return 1; } @@ -221,7 +326,6 @@ * This should not happen, since dev->tbusy should be set. */ printk("%s: tx queue full!.\n", dev->name); - fep->lock = 0; return 1; } #endif @@ -245,38 +349,85 @@ /* Push the data cache so the CPM does not get stale memory * data. */ - flush_dcache_range(skb->data, skb->data + skb->len); + flush_dcache_range((unsigned long)skb->data, + (unsigned long)skb->data + skb->len); + + spin_lock_irq(&fep->lock); - /* Send it on its way. Tell CPM its ready, interrupt when done, + /* Send it on its way. Tell FEC its ready, interrupt when done, * its the last BD of the frame, and to put the CRC on the end. */ - save_flags(flags); - cli(); - bdp->cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_INTR | BD_ENET_TX_LAST | BD_ENET_TX_TC); + bdp->cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_INTR + | BD_ENET_TX_LAST | BD_ENET_TX_TC); dev->trans_start = jiffies; - (&(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec))->fec_x_des_active = 0x01000000; + + /* Trigger transmission start */ + fecp->fec_x_des_active = 0x01000000; /* If this was the last BD in the ring, start at the beginning again. */ - if (bdp->cbd_sc & BD_ENET_TX_WRAP) + if (bdp->cbd_sc & BD_ENET_TX_WRAP) { bdp = fep->tx_bd_base; - else + } else { bdp++; + } - fep->lock = 0; if (bdp->cbd_sc & BD_ENET_TX_READY) - fep->tx_full = 1; - else - dev->tbusy=0; - restore_flags(flags); + netif_stop_queue(dev); fep->cur_tx = (cbd_t *)bdp; + spin_unlock_irq(&fep->lock); + return 0; } +static void +fec_timeout(struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + + printk("%s: transmit timed out.\n", dev->name); + fep->stats.tx_errors++; +#ifndef final_version + { + int i; + cbd_t *bdp; + + printk("Ring data dump: cur_tx %lx%s, dirty_tx %lx cur_rx: %lx\n", + (unsigned long)fep->cur_tx, fep->tx_full ? " (full)" : "", + (unsigned long)fep->dirty_tx, + (unsigned long)fep->cur_rx); + + bdp = fep->tx_bd_base; + printk(" tx: %u buffers\n", TX_RING_SIZE); + for (i = 0 ; i < TX_RING_SIZE; i++) { + printk(" %08x: %04x %04x %08x\n", + (uint) bdp, + bdp->cbd_sc, + bdp->cbd_datlen, + bdp->cbd_bufaddr); + bdp++; + } + + bdp = fep->rx_bd_base; + printk(" rx: %lu buffers\n", RX_RING_SIZE); + for (i = 0 ; i < RX_RING_SIZE; i++) { + printk(" %08x: %04x %04x %08x\n", + (uint) bdp, + bdp->cbd_sc, + bdp->cbd_datlen, + bdp->cbd_bufaddr); + bdp++; + } + } +#endif + if (!fep->tx_full) + netif_wake_queue(dev); +} + /* The interrupt handler. * This is called from the MPC core interrupt. */ @@ -284,136 +435,177 @@ fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs) { struct net_device *dev = dev_id; - struct fec_enet_private *fep; - volatile cbd_t *bdp; - volatile fec_t *ep; + volatile fec_t *fecp; uint int_events; - int c=0; +#ifdef CONFIG_FEC_PACKETHOOK + struct fec_enet_private *fep = dev->priv; + __u32 regval; - fep = (struct fec_enet_private *)dev->priv; - ep = &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec); - if (dev->interrupt) - printk("%s: Re-entering the interrupt handler.\n", dev->name); - dev->interrupt = 1; + if (fep->ph_regaddr) regval = *fep->ph_regaddr; +#endif + + fecp = (volatile fec_t*)dev->base_addr; /* Get the interrupt events that caused us to be here. */ - while ((int_events = ep->fec_ievent) != 0) { - ep->fec_ievent = int_events; - if ((int_events & - (FEC_ENET_HBERR | FEC_ENET_BABR | - FEC_ENET_BABT | FEC_ENET_EBERR)) != 0) - printk("FEC ERROR %x\n", int_events); - - /* Handle receive event in its own function. - */ - if (int_events & (FEC_ENET_RXF | FEC_ENET_RXB)) - fec_enet_rx(dev_id); - - /* Transmit OK, or non-fatal error. Update the buffer descriptors. - * FEC handles all errors, we just discover them as part of the - * transmit process. - */ - if (int_events & (FEC_ENET_TXF | FEC_ENET_TXB)) { - bdp = fep->dirty_tx; - while ((bdp->cbd_sc&BD_ENET_TX_READY)==0) { -#if 1 - if (bdp==fep->cur_tx) - break; + while ((int_events = fecp->fec_ievent) != 0) { + fecp->fec_ievent = int_events; + if ((int_events & (FEC_ENET_HBERR | FEC_ENET_BABR | + FEC_ENET_BABT | FEC_ENET_EBERR)) != 0) { + printk("FEC ERROR %x\n", int_events); + } + + /* Handle receive event in its own function. + */ + if (int_events & FEC_ENET_RXF) { +#ifdef CONFIG_FEC_PACKETHOOK + fec_enet_rx(dev, regval); +#else + fec_enet_rx(dev); +#endif + } + + /* Transmit OK, or non-fatal error. Update the buffer + descriptors. FEC handles all errors, we just discover + them as part of the transmit process. + */ + if (int_events & FEC_ENET_TXF) { +#ifdef CONFIG_FEC_PACKETHOOK + fec_enet_tx(dev, regval); +#else + fec_enet_tx(dev); #endif - if (++c>1) {/*we go here when an it has been lost*/}; + } + if (int_events & FEC_ENET_MII) { + fec_enet_mii(dev); + } + + } +} - if (bdp->cbd_sc & BD_ENET_TX_HB) /* No heartbeat */ - fep->stats.tx_heartbeat_errors++; - if (bdp->cbd_sc & BD_ENET_TX_LC) /* Late collision */ - fep->stats.tx_window_errors++; - if (bdp->cbd_sc & BD_ENET_TX_RL) /* Retrans limit */ - fep->stats.tx_aborted_errors++; - if (bdp->cbd_sc & BD_ENET_TX_UN) /* Underrun */ - fep->stats.tx_fifo_errors++; - if (bdp->cbd_sc & BD_ENET_TX_CSL) /* Carrier lost */ - fep->stats.tx_carrier_errors++; - fep->stats.tx_errors++; - - fep->stats.tx_packets++; - +static void +#ifdef CONFIG_FEC_PACKETHOOK +fec_enet_tx(struct net_device *dev, __u32 regval) +#else +fec_enet_tx(struct net_device *dev) +#endif +{ + struct fec_enet_private *fep; + volatile cbd_t *bdp; + struct sk_buff *skb; + + fep = dev->priv; + spin_lock(&fep->lock); + bdp = fep->dirty_tx; + + while ((bdp->cbd_sc&BD_ENET_TX_READY) == 0) { + if (bdp == fep->cur_tx && fep->tx_full == 0) break; + + skb = fep->tx_skbuff[fep->skb_dirty]; + /* Check for errors. */ + if (bdp->cbd_sc & (BD_ENET_TX_HB | BD_ENET_TX_LC | + BD_ENET_TX_RL | BD_ENET_TX_UN | + BD_ENET_TX_CSL)) { + fep->stats.tx_errors++; + if (bdp->cbd_sc & BD_ENET_TX_HB) /* No heartbeat */ + fep->stats.tx_heartbeat_errors++; + if (bdp->cbd_sc & BD_ENET_TX_LC) /* Late collision */ + fep->stats.tx_window_errors++; + if (bdp->cbd_sc & BD_ENET_TX_RL) /* Retrans limit */ + fep->stats.tx_aborted_errors++; + if (bdp->cbd_sc & BD_ENET_TX_UN) /* Underrun */ + fep->stats.tx_fifo_errors++; + if (bdp->cbd_sc & BD_ENET_TX_CSL) /* Carrier lost */ + fep->stats.tx_carrier_errors++; + } else { +#ifdef CONFIG_FEC_PACKETHOOK + /* Packet hook ... */ + if (fep->ph_txhandler && + ((struct ethhdr *)skb->data)->h_proto + == fep->ph_proto) { + fep->ph_txhandler((__u8*)skb->data, skb->len, + regval, fep->ph_priv); + } +#endif + fep->stats.tx_packets++; + } + #ifndef final_version if (bdp->cbd_sc & BD_ENET_TX_READY) - printk("HEY! Enet xmit interrupt and TX_READY.\n"); + printk("HEY! Enet xmit interrupt and TX_READY.\n"); #endif /* Deferred means some collisions occurred during transmit, * but we eventually sent the packet OK. */ if (bdp->cbd_sc & BD_ENET_TX_DEF) - fep->stats.collisions++; + fep->stats.collisions++; /* Free the sk buffer associated with this last transmit. */ - dev_kfree_skb(fep->tx_skbuff[fep->skb_dirty]/*, FREE_WRITE*/); +#if 0 +printk("TXI: %x %x %x\n", bdp, skb, fep->skb_dirty); +#endif + dev_kfree_skb(skb/*, FREE_WRITE*/); + fep->tx_skbuff[fep->skb_dirty] = NULL; fep->skb_dirty = (fep->skb_dirty + 1) & TX_RING_MOD_MASK; /* Update pointer to next buffer descriptor to be transmitted. */ if (bdp->cbd_sc & BD_ENET_TX_WRAP) - bdp = fep->tx_bd_base; + bdp = fep->tx_bd_base; else - bdp++; + bdp++; /* Since we have freed up a buffer, the ring is no longer * full. */ - if (fep->tx_full && dev->tbusy) { - fep->tx_full = 0; - dev->tbusy = 0; - mark_bh(NET_BH); + if (fep->tx_full) { + fep->tx_full = 0; + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); } - - fep->dirty_tx = (cbd_t *)bdp; -#if 0 - if (bdp==fep->cur_tx) - break; +#ifdef CONFIG_FEC_PACKETHOOK + /* Re-read register. Not exactly guaranteed to be correct, + but... */ + if (fep->ph_regaddr) regval = *fep->ph_regaddr; #endif - }/*while (bdp->cbd_sc&BD_ENET_TX_READY)==0*/ - } /* if tx events */ - - if (int_events & FEC_ENET_MII) - fec_enet_mii(dev_id); - - } /* while any events */ - - dev->interrupt = 0; - - return; + } + fep->dirty_tx = (cbd_t *)bdp; + spin_unlock(&fep->lock); } + /* During a receive, the cur_rx points to the current incoming buffer. * When we update through the ring, if the next incoming buffer has * not been given to the system, we just set the empty indicator, * effectively tossing the packet. */ -static int +static void +#ifdef CONFIG_FEC_PACKETHOOK +fec_enet_rx(struct net_device *dev, __u32 regval) +#else fec_enet_rx(struct net_device *dev) +#endif { struct fec_enet_private *fep; + volatile fec_t *fecp; volatile cbd_t *bdp; struct sk_buff *skb; ushort pkt_len; - volatile fec_t *ep; + __u8 *data; - fep = (struct fec_enet_private *)dev->priv; - ep = &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec); + fep = dev->priv; + fecp = (volatile fec_t*)dev->base_addr; /* First, grab all of the stats for the incoming packet. * These get messed up if we get called due to a busy condition. */ bdp = fep->cur_rx; -for (;;) { - if (bdp->cbd_sc & BD_ENET_RX_EMPTY) - break; - +while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) { + #ifndef final_version /* Since we have allocated space to hold a complete frame, * the last indicator should be set. @@ -422,50 +614,77 @@ printk("FEC ENET: rcv is not +last\n"); #endif - /* Frame too long or too short. - */ - if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) - fep->stats.rx_length_errors++; - if (bdp->cbd_sc & BD_ENET_RX_NO) /* Frame alignment */ - fep->stats.rx_frame_errors++; - if (bdp->cbd_sc & BD_ENET_RX_CR) /* CRC Error */ - fep->stats.rx_crc_errors++; - if (bdp->cbd_sc & BD_ENET_RX_OV) /* FIFO overrun */ - fep->stats.rx_crc_errors++; + /* Check for errors. */ + if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | + BD_ENET_RX_CR | BD_ENET_RX_OV)) { + fep->stats.rx_errors++; + if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) { + /* Frame too long or too short. */ + fep->stats.rx_length_errors++; + } + if (bdp->cbd_sc & BD_ENET_RX_NO) /* Frame alignment */ + fep->stats.rx_frame_errors++; + if (bdp->cbd_sc & BD_ENET_RX_CR) /* CRC Error */ + fep->stats.rx_crc_errors++; + if (bdp->cbd_sc & BD_ENET_RX_OV) /* FIFO overrun */ + fep->stats.rx_crc_errors++; + } /* Report late collisions as a frame error. * On this error, the BD is closed, but we don't know what we * have in the buffer. So, just drop this frame on the floor. */ if (bdp->cbd_sc & BD_ENET_RX_CL) { + fep->stats.rx_errors++; fep->stats.rx_frame_errors++; + goto rx_processing_done; } - else { - /* Process the incoming frame. - */ - fep->stats.rx_packets++; - pkt_len = bdp->cbd_datlen; - fep->stats.rx_bytes += pkt_len; + /* Process the incoming frame. + */ + fep->stats.rx_packets++; + pkt_len = bdp->cbd_datlen; + fep->stats.rx_bytes += pkt_len; + data = (__u8*)__va(bdp->cbd_bufaddr); + +#ifdef CONFIG_FEC_PACKETHOOK + /* Packet hook ... */ + if (fep->ph_rxhandler) { + if (((struct ethhdr *)data)->h_proto == fep->ph_proto) { + switch (fep->ph_rxhandler(data, pkt_len, regval, + fep->ph_priv)) { + case 1: + goto rx_processing_done; + break; + case 0: + break; + default: + fep->stats.rx_errors++; + goto rx_processing_done; + } + } + } - /* This does 16 byte alignment, exactly what we need. - */ - skb = dev_alloc_skb(pkt_len); + /* If it wasn't filtered - copy it to an sk buffer. */ +#endif - if (skb == NULL) { - printk("%s: Memory squeeze, dropping packet.\n", dev->name); - fep->stats.rx_dropped++; - } - else { - skb->dev = dev; - skb_put(skb,pkt_len); /* Make room */ - eth_copy_and_sum(skb, - (unsigned char *)__va(bdp->cbd_bufaddr), - pkt_len, 0); - skb->protocol=eth_type_trans(skb,dev); - netif_rx(skb); - } + /* This does 16 byte alignment, exactly what we need. + */ + skb = dev_alloc_skb(pkt_len); + + if (skb == NULL) { + printk("%s: Memory squeeze, dropping packet.\n", dev->name); + fep->stats.rx_dropped++; + } else { + skb->dev = dev; + skb_put(skb,pkt_len); /* Make room */ + eth_copy_and_sum(skb, + (unsigned char *)__va(bdp->cbd_bufaddr), + pkt_len, 0); + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); } + rx_processing_done: /* Clear the status flags for this buffer. */ @@ -487,9 +706,14 @@ * incoming frames. On a heavily loaded network, we should be * able to keep up at the expense of system resources. */ - ep->fec_r_des_active = 0x01000000; + fecp->fec_r_des_active = 0x01000000; #endif - } +#ifdef CONFIG_FEC_PACKETHOOK + /* Re-read register. Not exactly guaranteed to be correct, + but... */ + if (fep->ph_regaddr) regval = *fep->ph_regaddr; +#endif + } /* while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) */ fep->cur_rx = (cbd_t *)bdp; #if 0 @@ -500,12 +724,11 @@ * our way back to the interrupt return only to come right back * here. */ - ep->fec_r_des_active = 0x01000000; + fecp->fec_r_des_active = 0x01000000; #endif - - return 0; } + static void fec_enet_mii(struct net_device *dev) { @@ -524,7 +747,7 @@ } if (mip->mii_func != NULL) - (*(mip->mii_func))(mii_reg); + (*(mip->mii_func))(mii_reg, dev); mii_head = mip->mii_next; mip->mii_next = mii_free; @@ -535,12 +758,18 @@ } static int -mii_queue(int regval, void (*func)(int)) +mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_device *)) { + struct fec_enet_private *fep; unsigned long flags; mii_list_t *mip; int retval; + /* Add PHY address to register command. + */ + fep = dev->priv; + regval |= fep->phy_addr << 23; + retval = 0; save_flags(flags); @@ -569,199 +798,580 @@ return(retval); } -static void -mii_status(uint mii_reg) +static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c) { - if (((mii_reg >> 18) & 0x1f) == 1) { - /* status register. - */ - printk("fec: "); - if (mii_reg & 0x0004) - printk("link up"); - else - printk("link down"); + int k; - if (mii_reg & 0x0010) - printk(",remote fault"); - if (mii_reg & 0x0020) - printk(",auto complete"); - printk("\n"); - } - if (((mii_reg >> 18) & 0x1f) == 0x14) { - /* Extended chip status register. - */ - printk("fec: "); - if (mii_reg & 0x0800) - printk("100 Mbps"); - else - printk("10 Mbps"); + if(!c) + return; - if (mii_reg & 0x1000) - printk(", Full-Duplex\n"); - else - printk(", Half-Duplex\n"); - } - if (((mii_reg >> 18) & 0x1f) == 0x1f) { - printk("fec: %x\n", mii_reg); - } + for(k = 0; (c+k)->mii_data != mk_mii_end; k++) + mii_queue(dev, (c+k)->mii_data, (c+k)->funct); } -static void -mii_startup_cmds(void) +static void mii_parse_sr(uint mii_reg, struct net_device *dev) { + struct fec_enet_private *fep = dev->priv; + volatile uint *s = &(fep->phy_status); - /* Read status registers to clear any pending interrupt. - */ - mii_queue(mk_mii_read(1), mii_status); -#ifndef CONFIG_RPXCLASSIC - mii_queue(mk_mii_read(18), mii_status); + *s &= ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC); - /* Read extended chip status register. - */ - mii_queue(mk_mii_read(0x14), mii_status); + if (mii_reg & 0x0004) + *s |= PHY_STAT_LINK; + if (mii_reg & 0x0010) + *s |= PHY_STAT_FAULT; + if (mii_reg & 0x0020) + *s |= PHY_STAT_ANC; +} - /* Enable Link status change interrupts. - */ - mii_queue(mk_mii_write(0x11, 0x0002), NULL); +static void mii_parse_cr(uint mii_reg, struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + volatile uint *s = &(fep->phy_status); -#ifdef CONFIG_FADS - /* FADS uses the TRSTE in the BCSR, which is kind of weird. - * This really controls the startup default configuration. - * Changing the state of TRSTE once powered up doesn't do - * anything, you have to whack the control register. - * This of course screws up any autoconfig that was done....... - */ - mii_queue(mk_mii_write(0, 0x1000), NULL); -#endif -#else - /* Experimenting with the QS6612 PHY....not done yet. - */ - mii_queue(mk_mii_read(31), mii_status); -#endif + *s &= ~(PHY_CONF_ANE | PHY_CONF_LOOP); + + if (mii_reg & 0x1000) + *s |= PHY_CONF_ANE; + if (mii_reg & 0x4000) + *s |= PHY_CONF_LOOP; } -/* This supports the mii_link interrupt below. - * We should get called three times. Once for register 1, once for - * register 18, and once for register 20. - */ -static uint mii_saved_reg1; +static void mii_parse_anar(uint mii_reg, struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + volatile uint *s = &(fep->phy_status); -static void -mii_relink(uint mii_reg) + *s &= ~(PHY_CONF_SPMASK); + + if (mii_reg & 0x0020) + *s |= PHY_CONF_10HDX; + if (mii_reg & 0x0040) + *s |= PHY_CONF_10FDX; + if (mii_reg & 0x0080) + *s |= PHY_CONF_100HDX; + if (mii_reg & 0x00100) + *s |= PHY_CONF_100FDX; +} +#if 0 +static void mii_disp_reg(uint mii_reg, struct net_device *dev) { - if (((mii_reg >> 18) & 0x1f) == 1) { - /* Just save the status register and get out. - */ - mii_saved_reg1 = mii_reg; - return; - } - if (((mii_reg >> 18) & 0x1f) == 18) { - /* Not much here, but has to be read to clear the - * interrupt condition. - */ - if ((mii_reg & 0x8000) == 0) - printk("fec: re-link and no IRQ?\n"); - if ((mii_reg & 0x4000) == 0) - printk("fec: no PHY power?\n"); - } - if (((mii_reg >> 18) & 0x1f) == 20) { - /* Extended chip status register. - * OK, now we have it all, so figure out what is going on. - */ - printk("fec: "); - if (mii_saved_reg1 & 0x0004) - printk("link up"); - else - printk("link down"); + printk("reg %u = 0x%04x\n", (mii_reg >> 18) & 0x1f, mii_reg & 0xffff); +} +#endif - if (mii_saved_reg1 & 0x0010) - printk(", remote fault"); - if (mii_saved_reg1 & 0x0020) - printk(", auto complete"); +/* ------------------------------------------------------------------------- */ +/* The Level one LXT970 is used by many boards */ - if (mii_reg & 0x0800) - printk(", 100 Mbps"); - else - printk(", 10 Mbps"); +#ifdef CONFIG_FEC_LXT970 + +#define MII_LXT970_MIRROR 16 /* Mirror register */ +#define MII_LXT970_IER 17 /* Interrupt Enable Register */ +#define MII_LXT970_ISR 18 /* Interrupt Status Register */ +#define MII_LXT970_CONFIG 19 /* Configuration Register */ +#define MII_LXT970_CSR 20 /* Chip Status Register */ + +static void mii_parse_lxt970_csr(uint mii_reg, struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + volatile uint *s = &(fep->phy_status); + *s &= ~(PHY_STAT_SPMASK); + + if (mii_reg & 0x0800) { + if (mii_reg & 0x1000) + *s |= PHY_STAT_100FDX; + else + *s |= PHY_STAT_100HDX; + } + else { if (mii_reg & 0x1000) - printk(", Full-Duplex\n"); + *s |= PHY_STAT_10FDX; else - printk(", Half-Duplex\n"); + *s |= PHY_STAT_10HDX; } } -/* This interrupt occurs when the LTX970 detects a link change. -*/ -static void -mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs) -{ - struct net_device *dev = dev_id; - struct fec_enet_private *fep; - volatile fec_t *ep; - - fep = (struct fec_enet_private *)dev->priv; - ep = &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec); +static phy_info_t phy_info_lxt970 = { + 0x07810000, + "LXT970", - /* We need to sequentially read registers 1 and 18 to clear - * the interrupt. We don't need to do that here because this - * is an edge triggered interrupt that has already been acknowledged - * by the top level handler. We also read the extended status - * register 20. We just queue the commands and let them happen - * as part of the "normal" processing. - */ - mii_queue(mk_mii_read(1), mii_relink); -#ifndef CONFIG_RPXCLASSIC - - /* Unique to LevelOne PHY. - */ - mii_queue(mk_mii_read(18), mii_relink); - mii_queue(mk_mii_read(20), mii_relink); -#else + (const phy_cmd_t []) { /* config */ +#if 0 +// { mk_mii_write(MII_REG_ANAR, 0x0021), NULL }, - /* Unique to QS6612 PHY. - */ - mii_queue(mk_mii_read(6), mii_relink); - mii_queue(mk_mii_read(31), mii_relink); + /* Set default operation of 100-TX....for some reason + * some of these bits are set on power up, which is wrong. + */ + { mk_mii_write(MII_LXT970_CONFIG, 0), NULL }, #endif -} + { mk_mii_read(MII_REG_CR), mii_parse_cr }, + { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* startup - enable interrupts */ + { mk_mii_write(MII_LXT970_IER, 0x0002), NULL }, + { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* ack_int */ + /* read SR and ISR to acknowledge */ + + { mk_mii_read(MII_REG_SR), mii_parse_sr }, + { mk_mii_read(MII_LXT970_ISR), NULL }, -static int -fec_enet_close(struct net_device *dev) -{ - /* Don't know what to do yet. - */ + /* find out the current status */ + + { mk_mii_read(MII_LXT970_CSR), mii_parse_lxt970_csr }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* shutdown - disable interrupts */ + { mk_mii_write(MII_LXT970_IER, 0x0000), NULL }, + { mk_mii_end, } + }, +}; + +#endif /* CONFIG_FEC_LXT970 */ - return 0; -} +/* ------------------------------------------------------------------------- */ +/* The Level one LXT971 is used on some of my custom boards */ -static struct net_device_stats *fec_enet_get_stats(struct net_device *dev) -{ - struct fec_enet_private *fep = (struct fec_enet_private *)dev->priv; +#ifdef CONFIG_FEC_LXT971 - return &fep->stats; -} +/* register definitions for the 971 */ -/* Set or clear the multicast filter for this adaptor. - * Skeleton taken from sunlance driver. - * The CPM Ethernet implementation allows Multicast as well as individual - * MAC address filtering. Some of the drivers check to make sure it is - * a group multicast address, and discard those that are not. I guess I - * will do the same for now, but just remove the test if you want - * individual filtering as well (do the upper net layers want or support - * this kind of feature?). +#define MII_LXT971_PCR 16 /* Port Control Register */ +#define MII_LXT971_SR2 17 /* Status Register 2 */ +#define MII_LXT971_IER 18 /* Interrupt Enable Register */ +#define MII_LXT971_ISR 19 /* Interrupt Status Register */ +#define MII_LXT971_LCR 20 /* LED Control Register */ +#define MII_LXT971_TCR 30 /* Transmit Control Register */ + +/* + * I had some nice ideas of running the MDIO faster... + * The 971 should support 8MHz and I tried it, but things acted really + * wierd, so 2.5 MHz ought to be enough for anyone... */ -static void set_multicast_list(struct net_device *dev) +static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev) { - struct fec_enet_private *fep; - struct dev_mc_list *dmi; - u_char *mcptr, *tdptr; - volatile fec_t *ep; - int i, j; + struct fec_enet_private *fep = dev->priv; + volatile uint *s = &(fep->phy_status); - fep = (struct fec_enet_private *)dev->priv; - ep = &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec); + *s &= ~(PHY_STAT_SPMASK); + + if (mii_reg & 0x4000) { + if (mii_reg & 0x0200) + *s |= PHY_STAT_100FDX; + else + *s |= PHY_STAT_100HDX; + } + else { + if (mii_reg & 0x0200) + *s |= PHY_STAT_10FDX; + else + *s |= PHY_STAT_10HDX; + } + if (mii_reg & 0x0008) + *s |= PHY_STAT_FAULT; +} + +static phy_info_t phy_info_lxt971 = { + 0x0001378e, + "LXT971", + + (const phy_cmd_t []) { /* config */ + /* limit to 10MBit because my protorype board + * doesn't work with 100. */ + + { mk_mii_write(MII_REG_ANAR, 0x061), NULL }, /* 10 MBit */ + { mk_mii_read(MII_REG_CR), mii_parse_cr }, + { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* startup - enable interrupts */ + { mk_mii_write(MII_LXT971_IER, 0x00f2), NULL }, + { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ + + /* Somehow does the 971 tell me that the link is down + * the first read after power-up. + * read here to get a valid value in ack_int */ + + { mk_mii_read(MII_REG_SR), mii_parse_sr }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* ack_int */ + /* find out the current status */ + + { mk_mii_read(MII_REG_SR), mii_parse_sr }, + { mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 }, + + /* we only need to read ISR to acknowledge */ + + { mk_mii_read(MII_LXT971_ISR), NULL }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* shutdown - disable interrupts */ + { mk_mii_write(MII_LXT971_IER, 0x0000), NULL }, + { mk_mii_end, } + }, +}; + +#endif /* CONFIG_FEC_LXT970 */ + + +/* ------------------------------------------------------------------------- */ +/* The Quality Semiconductor QS6612 is used on the RPX CLLF */ + +#ifdef CONFIG_FEC_QS6612 + +/* register definitions */ + +#define MII_QS6612_MCR 17 /* Mode Control Register */ +#define MII_QS6612_FTR 27 /* Factory Test Register */ +#define MII_QS6612_MCO 28 /* Misc. Control Register */ +#define MII_QS6612_ISR 29 /* Interrupt Source Register */ +#define MII_QS6612_IMR 30 /* Interrupt Mask Register */ +#define MII_QS6612_PCR 31 /* 100BaseTx PHY Control Reg. */ + +static void mii_parse_qs6612_pcr(uint mii_reg, struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + volatile uint *s = &(fep->phy_status); + + *s &= ~(PHY_STAT_SPMASK); + + switch((mii_reg >> 2) & 7) { + case 1: *s |= PHY_STAT_10HDX; break; + case 2: *s |= PHY_STAT_100HDX; break; + case 5: *s |= PHY_STAT_10FDX; break; + case 6: *s |= PHY_STAT_100FDX; break; + } +} + +static phy_info_t phy_info_qs6612 = { + 0x00181440, + "QS6612", + + (const phy_cmd_t []) { /* config */ +// { mk_mii_write(MII_REG_ANAR, 0x061), NULL }, /* 10 MBit */ + + /* The PHY powers up isolated on the RPX, + * so send a command to allow operation. + */ + + { mk_mii_write(MII_QS6612_PCR, 0x0dc0), NULL }, + + /* parse cr and anar to get some info */ + + { mk_mii_read(MII_REG_CR), mii_parse_cr }, + { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* startup - enable interrupts */ + { mk_mii_write(MII_QS6612_IMR, 0x003a), NULL }, + { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* ack_int */ + + /* we need to read ISR, SR and ANER to acknowledge */ + + { mk_mii_read(MII_QS6612_ISR), NULL }, + { mk_mii_read(MII_REG_SR), mii_parse_sr }, + { mk_mii_read(MII_REG_ANER), NULL }, + + /* read pcr to get info */ + + { mk_mii_read(MII_QS6612_PCR), mii_parse_qs6612_pcr }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* shutdown - disable interrupts */ + { mk_mii_write(MII_QS6612_IMR, 0x0000), NULL }, + { mk_mii_end, } + }, +}; + + +#endif /* CONFIG_FEC_QS6612 */ + + +static phy_info_t *phy_info[] = { + +#ifdef CONFIG_FEC_LXT970 + &phy_info_lxt970, +#endif /* CONFIG_FEC_LXT970 */ + +#ifdef CONFIG_FEC_LXT971 + &phy_info_lxt971, +#endif /* CONFIG_FEC_LXT971 */ + +#ifdef CONFIG_FEC_QS6612 + &phy_info_qs6612, +#endif /* CONFIG_FEC_LXT971 */ + + NULL +}; + +static void mii_display_status(struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + volatile uint *s = &(fep->phy_status); + + if (!fep->link && !fep->old_link) { + /* Link is still down - don't print anything */ + return; + } + + printk("%s: status: ", dev->name); + + if (!fep->link) { + printk("link down"); + } else { + printk("link up"); + + switch(*s & PHY_STAT_SPMASK) { + case PHY_STAT_100FDX: printk(", 100MBit Full Duplex"); break; + case PHY_STAT_100HDX: printk(", 100MBit Half Duplex"); break; + case PHY_STAT_10FDX: printk(", 10MBit Full Duplex"); break; + case PHY_STAT_10HDX: printk(", 10MBit Half Duplex"); break; + default: + printk(", Unknown speed/duplex"); + } + + if (*s & PHY_STAT_ANC) + printk(", auto-negotiation complete"); + } + + if (*s & PHY_STAT_FAULT) + printk(", remote fault"); + + printk(".\n"); +} + +static void mii_display_config(struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + volatile uint *s = &(fep->phy_status); + + printk("%s: config: auto-negotiation ", dev->name); + + if (*s & PHY_CONF_ANE) + printk("on"); + else + printk("off"); + + if (*s & PHY_CONF_100FDX) + printk(", 100FDX"); + if (*s & PHY_CONF_100HDX) + printk(", 100HDX"); + if (*s & PHY_CONF_10FDX) + printk(", 10FDX"); + if (*s & PHY_CONF_10HDX) + printk(", 10HDX"); + if (!(*s & PHY_CONF_SPMASK)) + printk(", No speed/duplex selected?"); + + if (*s & PHY_CONF_LOOP) + printk(", loopback enabled"); + + printk(".\n"); + + fep->sequence_done = 1; +} + +static void mii_relink(struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + int duplex; + + fep->link = (fep->phy_status & PHY_STAT_LINK) ? 1 : 0; + mii_display_status(dev); + fep->old_link = fep->link; + + if (fep->link) { + duplex = 0; + if (fep->phy_status + & (PHY_STAT_100FDX | PHY_STAT_10FDX)) + duplex = 1; + fec_restart(dev, duplex); + } + else + fec_stop(dev); + +#if 0 + enable_irq(fep->mii_irq); +#endif + +} + +static void mii_queue_relink(uint mii_reg, struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + + fep->phy_task.routine = (void *)mii_relink; + fep->phy_task.data = dev; + queue_task(&fep->phy_task, &tq_scheduler); +} + +static void mii_queue_config(uint mii_reg, struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + + fep->phy_task.routine = (void *)mii_display_config; + fep->phy_task.data = dev; + queue_task(&fep->phy_task, &tq_scheduler); +} + + + +phy_cmd_t phy_cmd_relink[] = { { mk_mii_read(MII_REG_CR), mii_queue_relink }, + { mk_mii_end, } }; +phy_cmd_t phy_cmd_config[] = { { mk_mii_read(MII_REG_CR), mii_queue_config }, + { mk_mii_end, } }; + + + +/* Read remainder of PHY ID. +*/ +static void +mii_discover_phy3(uint mii_reg, struct net_device *dev) +{ + struct fec_enet_private *fep; + int i; + + fep = dev->priv; + fep->phy_id |= (mii_reg & 0xffff); + printk("fec: Phy @ 0x%x, type 0x%08x\n", fep->phy_addr, fep->phy_id); + + for(i = 0; phy_info[i]; i++) + if(phy_info[i]->id == (fep->phy_id >> 4)) + break; + + if(!phy_info[i]) + panic("%s: PHY id 0x%08x is not supported!\n", + dev->name, fep->phy_id); + + fep->phy = phy_info[i]; + fep->phy_id_done = 1; +} + +/* Scan all of the MII PHY addresses looking for someone to respond + * with a valid ID. This usually happens quickly. + */ +static void +mii_discover_phy(uint mii_reg, struct net_device *dev) +{ + struct fec_enet_private *fep; + uint phytype; + + fep = dev->priv; + + if (fep->phy_addr < 32) { + if ((phytype = (mii_reg & 0xffff)) != 0xffff) { + + /* Got first part of ID, now get remainder. + */ + fep->phy_id = phytype << 16; + mii_queue(dev, mk_mii_read(MII_REG_PHYIR2), + mii_discover_phy3); + } + else { + fep->phy_addr++; + mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), + mii_discover_phy); + } + } + else { + printk("FEC: No PHY device found.\n"); + } +} + +/* This interrupt occurs when the PHY detects a link change. +*/ +static void +#ifdef CONFIG_RPXCLASSIC +mii_link_interrupt(void *dev_id) +#else +mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs) +#endif +{ + struct net_device *dev = dev_id; + struct fec_enet_private *fep = dev->priv; + +#if 0 + disable_irq(fep->mii_irq); /* disable now, enable later */ +#endif + + mii_do_cmd(dev, fep->phy->ack_int); + mii_do_cmd(dev, phy_cmd_relink); /* restart and display status */ + +} + +static int +fec_enet_open(struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + + /* I should reset the ring buffers here, but I don't yet know + * a simple way to do that. + */ + + fep->sequence_done = 0; + fep->link = 0; + + if (fep->phy) { + mii_do_cmd(dev, fep->phy->ack_int); + mii_do_cmd(dev, fep->phy->config); + mii_do_cmd(dev, phy_cmd_config); /* display configuration */ + + while(!fep->sequence_done) + schedule(); + + mii_do_cmd(dev, fep->phy->startup); + netif_start_queue(dev); + return 0; /* Success */ + } + + return -ENODEV; /* No PHY we understand */ + +} + +static int +fec_enet_close(struct net_device *dev) +{ + /* Don't know what to do yet. + */ + netif_stop_queue(dev); + fec_stop(dev); + + return 0; +} + +static struct net_device_stats *fec_enet_get_stats(struct net_device *dev) +{ + struct fec_enet_private *fep = (struct fec_enet_private *)dev->priv; + + return &fep->stats; +} + +/* Set or clear the multicast filter for this adaptor. + * Skeleton taken from sunlance driver. + * The CPM Ethernet implementation allows Multicast as well as individual + * MAC address filtering. Some of the drivers check to make sure it is + * a group multicast address, and discard those that are not. I guess I + * will do the same for now, but just remove the test if you want + * individual filtering as well (do the upper net layers want or support + * this kind of feature?). + */ + +static void set_multicast_list(struct net_device *dev) +{ + struct fec_enet_private *fep; + volatile fec_t *ep; + + fep = (struct fec_enet_private *)dev->priv; + ep = &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec); if (dev->flags&IFF_PROMISC) { @@ -826,20 +1436,23 @@ struct net_device *dev; struct fec_enet_private *fep; int i, j; - unsigned char *eap; + unsigned char *eap, *iap; unsigned long mem_addr; pte_t *pte; volatile cbd_t *bdp; cbd_t *cbd_base; volatile immap_t *immap; volatile fec_t *fecp; - unsigned char *iap; bd_t *bd; - - bd = (bd_t *)__res; + extern uint _get_IMMR(void); +#ifdef CONFIG_RPXCLASSIC + unsigned char tmpaddr[6]; +#endif immap = (immap_t *)IMAP_ADDR; /* pointer to internal registers */ + bd = (bd_t *)__res; + /* Allocate some private information. */ fep = (struct fec_enet_private *)kmalloc(sizeof(*fep), GFP_KERNEL); @@ -856,47 +1469,27 @@ fecp->fec_ecntrl = 1; udelay(10); - /* Enable interrupts we wish to service. - */ - fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB | - FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII); - - /* Clear any outstanding interrupt. - */ - fecp->fec_ievent = 0xffc0; - - fecp->fec_ivec = (FEC_INTERRUPT/2) << 29; - - /* Right now, all of the boards supply the ethernet address in - * the board descriptor. If someone doesn't we can just use - * the hard coded address in this driver for testing (this is - * a Motorola address for a board I have, so it is unlikely to - * be used elsewhere). + /* Set the Ethernet address. If using multiple Enets on the 8xx, + * this needs some work to get unique addresses. */ - eap = (unsigned char *)&my_enet_addr[0]; -#if 1 + eap = (unsigned char *)my_enet_addr; iap = bd->bi_enetaddr; + +#ifdef CONFIG_RPXCLASSIC + /* The Embedded Planet boards have only one MAC address in + * the EEPROM, but can have two Ethernet ports. For the + * FEC port, we create another address by setting one of + * the address bits above something that would have (up to + * now) been allocated. + */ for (i=0; i<6; i++) - dev->dev_addr[i] = *eap++ = *iap++; -#else - for (i=0; i<6; i++) - dev->dev_addr[i] = *eap++; + tmpaddr[i] = *iap++; + tmpaddr[3] |= 0x80; + iap = tmpaddr; #endif - /* Set station address. - */ - fecp->fec_addr_low = (my_enet_addr[0] << 16) | my_enet_addr[1]; - fecp->fec_addr_high = my_enet_addr[2]; - - /* Reset all multicast. - */ - fecp->fec_hash_table_high = 0; - fecp->fec_hash_table_low = 0; - - /* Set maximum receive buffer size. - */ - fecp->fec_r_buff_size = PKT_MAXBLR_SIZE; - fecp->fec_r_hash = PKT_MAXBUF_SIZE; + for (i=0; i<6; i++) + dev->dev_addr[i] = *eap++ = *iap++; /* Allocate memory for buffer descriptors. */ @@ -910,15 +1503,13 @@ /* Make it uncached. */ - pte = find_pte(&init_mm, (int)mem_addr); + pte = va_to_pte(mem_addr); pte_val(*pte) |= _PAGE_NO_CACHE; - flush_tlb_page(current->mm->mmap, mem_addr); + flush_tlb_page(init_mm.mmap, mem_addr); /* Set receive and transmit descriptor base. */ - fecp->fec_r_des_start = __pa(mem_addr); fep->rx_bd_base = cbd_base; - fecp->fec_x_des_start = __pa((unsigned long)(cbd_base + RX_RING_SIZE)); fep->tx_bd_base = cbd_base + RX_RING_SIZE; fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; @@ -937,9 +1528,9 @@ /* Make it uncached. */ - pte = find_pte(&init_mm, mem_addr); + pte = va_to_pte(mem_addr); pte_val(*pte) |= _PAGE_NO_CACHE; - flush_tlb_page(current->mm->mmap, mem_addr); + flush_tlb_page(init_mm.mmap, mem_addr); /* Initialize the BD for every fragment in the page. */ @@ -956,6 +1547,172 @@ bdp--; bdp->cbd_sc |= BD_SC_WRAP; +#ifdef CONFIG_FEC_PACKETHOOK + fep->ph_lock = 0; + fep->ph_rxhandler = fep->ph_txhandler = NULL; + fep->ph_proto = 0; + fep->ph_regaddr = NULL; + fep->ph_priv = NULL; +#endif + + /* Install our interrupt handler. + */ + if (request_8xxirq(FEC_INTERRUPT, fec_enet_interrupt, 0, "fec", dev) != 0) + panic("Could not allocate FEC IRQ!"); +#ifdef CONFIG_RPXCLASSIC + /* Make Port C, bit 15 an input that causes interrupts. + */ + immap->im_ioport.iop_pcpar &= ~0x0001; + immap->im_ioport.iop_pcdir &= ~0x0001; + immap->im_ioport.iop_pcso &= ~0x0001; + immap->im_ioport.iop_pcint |= 0x0001; + cpm_install_handler(CPMVEC_PIO_PC15, mii_link_interrupt, dev); + + /* Make LEDS reflect Link status. + */ + *((uint *) RPX_CSR_ADDR) &= ~BCSR2_FETHLEDMODE; +#endif +#ifdef CONFIG_FADS + if (request_8xxirq(SIU_IRQ2, mii_link_interrupt, 0, "mii", dev) != 0) + panic("Could not allocate MII IRQ!"); +#endif + + dev->base_addr = (unsigned long)fecp; + dev->priv = fep; + + /* The FEC Ethernet specific entries in the device structure. */ + dev->open = fec_enet_open; + dev->hard_start_xmit = fec_enet_start_xmit; + dev->tx_timeout = fec_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + dev->stop = fec_enet_close; + dev->get_stats = fec_enet_get_stats; + dev->set_multicast_list = set_multicast_list; + + for (i=0; iim_ioport.iop_pdpar = 0x1fff; + + /* Bits moved from Rev. D onward. + */ + if ((_get_IMMR() & 0xffff) < 0x0501) + immap->im_ioport.iop_pddir = 0x1c58; /* Pre rev. D */ + else + immap->im_ioport.iop_pddir = 0x1fff; /* Rev. D and later */ + + /* Set MII speed to 2.5 MHz + */ + fecp->fec_mii_speed = fep->phy_speed = + ((bd->bi_busfreq * 1000000) / 2500000) & 0x7e; + + printk("%s: FEC ENET Version 0.2, ", dev->name); + for (i=0; i<5; i++) + printk("%02x:", dev->dev_addr[i]); + printk("%02x\n", dev->dev_addr[5]); + + /* Queue up command to detect the PHY and initialize the + * remainder of the interface. + */ + fep->phy_id_done = 0; + fep->phy_addr = 0; + mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy); + + return 0; +} + +/* This function is called to start or restart the FEC during a link + * change. This only happens when switching between half and full + * duplex. + */ +static void +fec_restart(struct net_device *dev, int duplex) +{ + struct fec_enet_private *fep; + int i; + unsigned char *eap; + volatile cbd_t *bdp; + volatile immap_t *immap; + volatile fec_t *fecp; + + immap = (immap_t *)IMAP_ADDR; /* pointer to internal registers */ + + fecp = &(immap->im_cpm.cp_fec); + + fep = dev->priv; + + /* Whack a reset. We should wait for this. + */ + fecp->fec_ecntrl = 1; + udelay(10); + + /* Enable interrupts we wish to service. + */ + fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB | + FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII); + + /* Clear any outstanding interrupt. + */ + fecp->fec_ievent = 0xffc0; + + fecp->fec_ivec = (FEC_INTERRUPT/2) << 29; + + /* Set station address. + */ + fecp->fec_addr_low = (my_enet_addr[0] << 16) | my_enet_addr[1]; + fecp->fec_addr_high = my_enet_addr[2]; + + eap = (unsigned char *)&my_enet_addr[0]; + for (i=0; i<6; i++) + dev->dev_addr[i] = *eap++; + + /* Reset all multicast. + */ + fecp->fec_hash_table_high = 0; + fecp->fec_hash_table_low = 0; + + /* Set maximum receive buffer size. + */ + fecp->fec_r_buff_size = PKT_MAXBLR_SIZE; + fecp->fec_r_hash = PKT_MAXBUF_SIZE; + + /* Set receive and transmit descriptor base. + */ + fecp->fec_r_des_start = __pa((uint)(fep->rx_bd_base)); + fecp->fec_x_des_start = __pa((uint)(fep->tx_bd_base)); + + fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; + fep->cur_rx = fep->rx_bd_base; + + /* Reset SKB transmit buffers. + */ + fep->skb_cur = fep->skb_dirty = 0; + for (i=0; i<=TX_RING_MOD_MASK; i++) { + if (fep->tx_skbuff[i] != NULL) { + dev_kfree_skb(fep->tx_skbuff[i]); + fep->tx_skbuff[i] = NULL; + } + } + + /* Initialize the receive buffer descriptors. + */ + bdp = fep->rx_bd_base; + for (i=0; icbd_sc = BD_ENET_RX_EMPTY; + bdp++; + } + + /* Set the last buffer to wrap. + */ + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; + /* ...and the same for transmmit. */ bdp = fep->tx_bd_base; @@ -973,59 +1730,65 @@ bdp--; bdp->cbd_sc |= BD_SC_WRAP; - /* Enable MII mode, half-duplex until we know better.. + /* Enable MII mode. */ - fecp->fec_r_cntrl = 0x0c; - fecp->fec_x_cntrl = 0x00; + if (duplex) { + fecp->fec_r_cntrl = 0x04; /* MII enable */ + fecp->fec_x_cntrl = 0x04; /* FD enable */ + } + else { + fecp->fec_r_cntrl = 0x06; /* MII enable|No Rcv on Xmit */ + fecp->fec_x_cntrl = 0x00; + } + fep->full_duplex = duplex; /* Enable big endian and don't care about SDMA FC. */ fecp->fec_fun_code = 0x78000000; - /* Set MII speed (50 MHz core). + /* Set MII speed. */ - fecp->fec_mii_speed = 0x14; + fecp->fec_mii_speed = fep->phy_speed; - /* Configure all of port D for MII. + /* And last, enable the transmit and receive processing. */ - immap->im_ioport.iop_pdpar = 0x1fff; - immap->im_ioport.iop_pddir = 0x1c58; + fecp->fec_ecntrl = 6; + fecp->fec_r_des_active = 0x01000000; +} - /* Install our interrupt handlers. The 860T FADS board uses - * IRQ2 for the MII interrupt. - */ - if (request_8xxirq(FEC_INTERRUPT, fec_enet_interrupt, 0, "fec", dev) != 0) - panic("Could not allocate FEC IRQ!"); - if (request_8xxirq(SIU_IRQ2, mii_link_interrupt, 0, "mii", dev) != 0) - panic("Could not allocate MII IRQ!"); +static void +fec_stop(struct net_device *dev) +{ + volatile immap_t *immap; + volatile fec_t *fecp; + struct fec_enet_private *fep; - dev->base_addr = (unsigned long)fecp; - dev->priv = fep; - dev->name = "fec"; + immap = (immap_t *)IMAP_ADDR; /* pointer to internal registers */ + + fecp = &(immap->im_cpm.cp_fec); + + fep = dev->priv; - /* The FEC Ethernet specific entries in the device structure. */ - dev->open = fec_enet_open; - dev->hard_start_xmit = fec_enet_start_xmit; - dev->stop = fec_enet_close; - dev->get_stats = fec_enet_get_stats; - dev->set_multicast_list = set_multicast_list; - /* And last, enable the transmit and receive processing. - */ - fecp->fec_ecntrl = 2; - fecp->fec_r_des_active = 0x01000000; + fecp->fec_x_cntrl = 0x01; /* Graceful transmit stop */ - printk("FEC ENET Version 0.1, "); - for (i=0; i<5; i++) - printk("%02x:", dev->dev_addr[i]); - printk("%02x\n", dev->dev_addr[5]); + while(!(fecp->fec_ievent & 0x10000000)); - for (i=0; ifec_ecntrl = 1; + udelay(10); + + /* Clear outstanding MII command interrupts. + */ + fecp->fec_ievent = FEC_ENET_MII; - mii_startup_cmds(); + /* Enable MII command finihed interrupt + */ + fecp->fec_ivec = (FEC_INTERRUPT/2) << 29; + fecp->fec_imask = FEC_ENET_MII; - return 0; + /* Set MII speed. + */ + fecp->fec_mii_speed = fep->phy_speed; } - diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/8xx_io/uart.c linux/arch/ppc/8xx_io/uart.c --- v2.4.0-test1/linux/arch/ppc/8xx_io/uart.c Thu May 11 15:30:06 2000 +++ linux/arch/ppc/8xx_io/uart.c Mon Jun 19 13:25:06 2000 @@ -101,11 +101,15 @@ */ #define smc_scc_num hub6 +#ifdef CONFIG_8xxSMC2 /* SMC2 is sometimes used for low performance TDM interfaces. Define * this as 1 if you want SMC2 as a serial port UART managed by this driver. * Define this as 0 if you wish to use SMC2 for something else. */ #define USE_SMC2 1 +#else +#define USE_SMC2 0 +#endif /* Define SCC to ttySx mapping. */ @@ -130,7 +134,7 @@ #if USE_SMC2 { 0, 0, PROFF_SMC2, CPMVEC_SMC2, 0, 1 }, /* SMC2 ttyS1 */ #endif -#if defined(CONFIG_MPC860) || defined(CONFIG_MPC860T) +#ifdef CONFIG_8xxSCC { 0, 0, PROFF_SCC2, CPMVEC_SCC2, 0, SCC_NUM_BASE}, /* SCC2 ttyS2 */ { 0, 0, PROFF_SCC3, CPMVEC_SCC3, 0, SCC_NUM_BASE + 1}, /* SCC3 ttyS3 */ #endif @@ -2583,6 +2587,8 @@ if (info) { /*memset(info, 0, sizeof(ser_info_t));*/ __clear_user(info,sizeof(ser_info_t)); + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); info->magic = SERIAL_MAGIC; info->flags = state->flags; info->tqueue.routine = do_softint; diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/Makefile linux/arch/ppc/Makefile --- v2.4.0-test1/linux/arch/ppc/Makefile Thu May 11 15:30:06 2000 +++ linux/arch/ppc/Makefile Mon Jun 19 17:59:35 2000 @@ -34,8 +34,8 @@ CFLAGS := $(CFLAGS) -mcpu=860 -I../8xx_io endif -ifdef CONFIG_PPC64 -CFLAGS := $(CFLAGS) -Wa,-mppc64bridge #-mpowerpc64 +ifdef CONFIG_PPC64BRIDGE +CFLAGS := $(CFLAGS) -Wa,-mppc64bridge endif ifdef CONFIG_4xx @@ -128,7 +128,7 @@ endif endif -ifdef CONFIG_PPC64 +ifdef CONFIG_PPC64BRIDGE $(BOOT_TARGETS): $(CHECKS) vmlinux @$(MAKECOFFBOOT) $@ @$(MAKEBOOT) $@ @@ -171,6 +171,18 @@ walnut_config: clean_config cp -f arch/ppc/configs/walnut_defconfig arch/ppc/defconfig + +rpxlite_config: clean_config + cp -f arch/ppc/configs/rpxlite_defconfig arch/ppc/defconfig + +rpxcllf_config: clean_config + cp -f arch/ppc/configs/rpxcllf_defconfig arch/ppc/defconfig + +bseip_config: clean_config + cp -f arch/ppc/configs/bseip_defconfig arch/ppc/defconfig + +est8260_config: clean_config + cp -f arch/ppc/configs/est8260_defconfig arch/ppc/defconfig archclean: rm -f arch/ppc/kernel/{mk_defs,ppc_defs.h,find_name,checks} diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/boot/Makefile linux/arch/ppc/boot/Makefile --- v2.4.0-test1/linux/arch/ppc/boot/Makefile Tue Apr 11 15:09:13 2000 +++ linux/arch/ppc/boot/Makefile Mon Jun 19 17:59:35 2000 @@ -41,7 +41,7 @@ TFTPSIMAGE=/tftpboot/sImage endif -ifeq ($(CONFIG_PPC64),y) +ifeq ($(CONFIG_PPC64BRIDGE),y) MSIZE=.64 else MSIZE= diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/chrpboot/Makefile linux/arch/ppc/chrpboot/Makefile --- v2.4.0-test1/linux/arch/ppc/chrpboot/Makefile Tue Apr 11 15:09:13 2000 +++ linux/arch/ppc/chrpboot/Makefile Mon Jun 19 17:59:35 2000 @@ -5,29 +5,24 @@ # # Based on coffboot by Paul Mackerras -.c.s: - $(CC) $(CFLAGS) -S -o $*.s $< -.s.o: - $(AS) -o $*.o $< +ifeq ($(CONFIG_PPC64BRIDGE),y) +MSIZE=.64 +AFLAGS += -Wa,-mppc64bridge +else +MSIZE= +endif + .c.o: $(CC) $(CFLAGS) -DKERNELBASE=$(KERNELBASE) -c -o $*.o $< -.S.s: - $(CPP) $(AFLAGS) -traditional -o $*.o $< .S.o: $(CC) $(AFLAGS) -traditional -c -o $*.o $< CFLAGS = $(CPPFLAGS) -O -fno-builtin -DSTDC_HEADERS LD_ARGS = -Ttext 0x00400000 -OBJS = crt0.o start.o main.o misc.o ../coffboot/string.o ../coffboot/zlib.o image.o sysmap.o +OBJS = crt0.o start.o main.o misc.o ../coffboot/string.o ../coffboot/zlib.o image.o LIBS = $(TOPDIR)/lib/lib.a -ifeq ($(CONFIG_PPC64),y) -MSIZE=.64 -else -MSIZE= -endif - ifeq ($(CONFIG_ALL_PPC),y) # yes, we want to build chrp stuff CONFIG_CHRP = y @@ -58,8 +53,8 @@ piggyback: piggyback.c $(HOSTCC) $(HOSTCFLAGS) -DKERNELBASE=$(KERNELBASE) -o piggyback piggyback.c -mknote: mknote.c - $(HOSTCC) $(HOSTCFLAGS) -o mknote mknote.c +addnote: addnote.c + $(HOSTCC) $(HOSTCFLAGS) -o addnote addnote.c image.o: piggyback ../coffboot/vmlinux.gz ./piggyback image < ../coffboot/vmlinux.gz | $(AS) -o image.o @@ -70,13 +65,13 @@ initrd.o: ramdisk.image.gz piggyback ./piggyback initrd < ramdisk.image.gz | $(AS) -o initrd.o -zImage: $(OBJS) no_initrd.o mknote +zImage: $(OBJS) no_initrd.o addnote $(LD) $(LD_ARGS) -o $@ $(OBJS) no_initrd.o $(LIBS) - ./mknote > note - $(OBJCOPY) $@ $@ --add-section=.note=note -R .comment + ./addnote $@ -zImage.initrd: $(OBJS) initrd.o +zImage.initrd: $(OBJS) initrd.o addnote $(LD) $(LD_ARGS) -o $@ $(OBJS) initrd.o $(LIBS) + ./addnote $@ else znetboot: @@ -98,7 +93,7 @@ clean: - rm -f piggyback note mknote $(OBJS) zImage + rm -f piggyback note addnote $(OBJS) zImage fastdep: $(TOPDIR)/scripts/mkdep *.[Sch] > .depend diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/chrpboot/addnote.c linux/arch/ppc/chrpboot/addnote.c --- v2.4.0-test1/linux/arch/ppc/chrpboot/addnote.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/chrpboot/addnote.c Mon Jun 19 17:59:35 2000 @@ -0,0 +1,163 @@ +/* + * Program to hack in a PT_NOTE program header entry in an ELF file. + * This is needed for OF on RS/6000s to load an image correctly. + * Note that OF needs a program header entry for the note, not an + * ELF section. + * + * Copyright 2000 Paul Mackerras. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Usage: addnote zImage + */ +#include +#include +#include +#include + +char arch[] = "PowerPC"; + +#define N_DESCR 6 +unsigned int descr[N_DESCR] = { + 0xffffffff, /* real-mode = true */ + 0x00c00000, /* real-base, i.e. where we expect OF to be */ + 0xffffffff, /* real-size */ + 0xffffffff, /* virt-base */ + 0xffffffff, /* virt-size */ + 0x4000, /* load-base */ +}; + +unsigned char buf[512]; + +#define GET_16BE(off) ((buf[off] << 8) + (buf[(off)+1])) +#define GET_32BE(off) ((GET_16BE(off) << 16) + GET_16BE((off)+2)) + +#define PUT_16BE(off, v) (buf[off] = ((v) >> 8) & 0xff, \ + buf[(off) + 1] = (v) & 0xff) +#define PUT_32BE(off, v) (PUT_16BE((off), (v) >> 16), \ + PUT_16BE((off) + 2, (v))) + +/* Structure of an ELF file */ +#define E_IDENT 0 /* ELF header */ +#define E_PHOFF 28 +#define E_PHENTSIZE 42 +#define E_PHNUM 44 +#define E_HSIZE 52 /* size of ELF header */ + +#define EI_MAGIC 0 /* offsets in E_IDENT area */ +#define EI_CLASS 4 +#define EI_DATA 5 + +#define PH_TYPE 0 /* ELF program header */ +#define PH_OFFSET 4 +#define PH_FILESZ 16 +#define PH_HSIZE 32 /* size of program header */ + +#define PT_NOTE 4 /* Program header type = note */ + +#define ELFCLASS32 1 +#define ELFDATA2MSB 2 + +unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' }; + +main(int ac, char **av) +{ + int fd, n, i; + int ph, ps, np; + int nnote, ns; + + if (ac != 2) { + fprintf(stderr, "Usage: %s elf-file\n", av[0]); + exit(1); + } + fd = open(av[1], O_RDWR); + if (fd < 0) { + perror(av[1]); + exit(1); + } + + nnote = strlen(arch) + 1 + (N_DESCR + 3) * 4; + + n = read(fd, buf, sizeof(buf)); + if (n < 0) { + perror("read"); + exit(1); + } + + if (n < E_HSIZE || memcmp(&buf[E_IDENT+EI_MAGIC], elf_magic, 4) != 0) + goto notelf; + + if (buf[E_IDENT+EI_CLASS] != ELFCLASS32 + || buf[E_IDENT+EI_DATA] != ELFDATA2MSB) { + fprintf(stderr, "%s is not a big-endian 32-bit ELF image\n", + av[1]); + exit(1); + } + + ph = GET_32BE(E_PHOFF); + ps = GET_16BE(E_PHENTSIZE); + np = GET_16BE(E_PHNUM); + if (ph < E_HSIZE || ps < PH_HSIZE || np < 1) + goto notelf; + if (ph + (np + 1) * ps + nnote > n) + goto nospace; + + for (i = 0; i < np; ++i) { + if (GET_32BE(ph + PH_TYPE) == PT_NOTE) { + fprintf(stderr, "%s already has a note entry\n", + av[1]); + exit(0); + } + ph += ps; + } + + /* XXX check that the area we want to use is all zeroes */ + for (i = 0; i < ps + nnote; ++i) + if (buf[ph + i] != 0) + goto nospace; + + /* fill in the program header entry */ + ns = ph + ps; + PUT_32BE(ph + PH_TYPE, PT_NOTE); + PUT_32BE(ph + PH_OFFSET, ns); + PUT_32BE(ph + PH_FILESZ, nnote); + + /* fill in the note area we point to */ + /* XXX we should probably make this a proper section */ + PUT_32BE(ns, strlen(arch) + 1); + PUT_32BE(ns + 4, N_DESCR * 4); + PUT_32BE(ns + 8, 0x1275); + strcpy(&buf[ns + 12], arch); + ns += 12 + strlen(arch) + 1; + for (i = 0; i < N_DESCR; ++i) + PUT_32BE(ns + i * 4, descr[i]); + + /* Update the number of program headers */ + PUT_16BE(E_PHNUM, np + 1); + + /* write back */ + lseek(fd, (long) 0, SEEK_SET); + i = write(fd, buf, n); + if (i < 0) { + perror("write"); + exit(1); + } + if (i < n) { + fprintf(stderr, "%s: write truncated\n", av[1]); + exit(1); + } + + exit(0); + + notelf: + fprintf(stderr, "%s does not appear to be an ELF file\n", av[0]); + exit(1); + + nospace: + fprintf(stderr, "sorry, I can't find space in %s to put the note\n", + av[0]); + exit(1); +} diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/chrpboot/main.c linux/arch/ppc/chrpboot/main.c --- v2.4.0-test1/linux/arch/ppc/chrpboot/main.c Sat Feb 26 22:31:41 2000 +++ linux/arch/ppc/chrpboot/main.c Mon Jun 19 17:59:35 2000 @@ -16,11 +16,11 @@ extern int getprop(void *, const char *, void *, int); void gunzip(void *, int, unsigned char *, int *); -#define get_16be(x) (*(unsigned short *)(x)) -#define get_32be(x) (*(unsigned *)(x)) - #define RAM_START 0x00000000 -#define RAM_END (8<<20) +#define RAM_END (64<<20) + +#define BOOT_START ((unsigned long)_start) +#define BOOT_END ((unsigned long)(_end + 0xFFF) & ~0xFFF) #define RAM_FREE ((unsigned long)(_end+0x1000)&~0xFFF) #define PROG_START 0x00010000 @@ -36,6 +36,7 @@ extern char sysmap_data[]; extern int sysmap_len; +static char scratch[1024<<10]; /* 1MB of scratch space for gunzip */ chrpboot(int a1, int a2, void *prom) { @@ -48,13 +49,25 @@ printf("chrpboot starting: loaded at 0x%x\n\r", &_start); - end_avail = (char *) RAM_END; + if (initrd_len) { + initrd_size = initrd_len; + initrd_start = (RAM_END - initrd_size) & ~0xFFF; + a1 = initrd_start; + a2 = initrd_size; + claim(initrd_start, RAM_END - initrd_start, 0); + printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n\r", + initrd_start, initrd_data, initrd_size); + memcpy((char *)initrd_start, initrd_data, initrd_size); + } im = image_data; len = image_len; + /* claim 4MB starting at PROG_START */ + claim(PROG_START, (4<<20) - PROG_START, 0); dst = (void *) PROG_START; if (im[0] == 0x1f && im[1] == 0x8b) { - avail_ram = (char *)RAM_FREE; + avail_ram = scratch; + end_avail = scratch + sizeof(scratch); printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len); gunzip(dst, 0x400000, im, &len); printf("done %u bytes\n\r", len); @@ -86,17 +99,18 @@ rec->data[1] = 1; rec->size = sizeof(struct bi_record) + sizeof(unsigned long); rec = (struct bi_record *)((unsigned long)rec + rec->size); - +#if 0 rec->tag = BI_SYSMAP; rec->data[0] = (unsigned long)sysmap_data; rec->data[1] = sysmap_len; rec->size = sizeof(struct bi_record) + sizeof(unsigned long); rec = (struct bi_record *)((unsigned long)rec + rec->size); +#endif rec->tag = BI_LAST; rec->size = sizeof(struct bi_record); rec = (struct bi_record *)((unsigned long)rec + rec->size); } - (*(void (*)())sa)(0, 0, prom, a1, a2); + (*(void (*)())sa)(a1, a2, prom); printf("returned?\n\r"); diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/chrpboot/start.c linux/arch/ppc/chrpboot/start.c --- v2.4.0-test1/linux/arch/ppc/chrpboot/start.c Mon Jan 12 15:18:13 1998 +++ linux/arch/ppc/chrpboot/start.c Mon Jun 19 17:59:35 2000 @@ -131,6 +131,29 @@ return args.phandle; } +void * +claim(unsigned int virt, unsigned int size, unsigned int align) +{ + struct prom_args { + char *service; + int nargs; + int nret; + unsigned int virt; + unsigned int size; + unsigned int align; + void *ret; + } args; + + args.service = "claim"; + args.nargs = 3; + args.nret = 1; + args.virt = virt; + args.size = size; + args.align = align; + (*prom)(&args); + return args.ret; +} + int getprop(void *phandle, const char *name, void *buf, int buflen) { diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/coffboot/Makefile linux/arch/ppc/coffboot/Makefile --- v2.4.0-test1/linux/arch/ppc/coffboot/Makefile Fri Mar 10 16:40:40 2000 +++ linux/arch/ppc/coffboot/Makefile Mon Jun 19 17:59:35 2000 @@ -14,7 +14,7 @@ CHRPOBJS = crt0.o start.o chrpmain.o misc.o string.o zlib.o image.o LIBS = $(TOPDIR)/lib/lib.a -ifeq ($(CONFIG_PPC64),y) +ifeq ($(CONFIG_PPC64BRIDGE),y) MSIZE=.64 else MSIZE= @@ -54,7 +54,7 @@ miboot.image: dummy.o vmlinux.gz $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=vmlinux.gz dummy.o $@ -miboot.image.initrd: dummy.o vmlinux.gz +miboot.image.initrd: miboot.image ramdisk.image.gz $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=initrd=ramdisk.image.gz miboot.image $@ coffboot: $(COFFOBJS) no_initrd.o ld.script diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/config.in linux/arch/ppc/config.in --- v2.4.0-test1/linux/arch/ppc/config.in Thu May 11 15:30:06 2000 +++ linux/arch/ppc/config.in Mon Jun 19 17:59:35 2000 @@ -1,6 +1,6 @@ # $Id: config.in,v 1.106 1999/09/14 19:21:18 cort Exp $ # For a description of the syntax of this configuration file, -# see the Configure script. +# see Documentation/kbuild/config-language.txt. # define_bool CONFIG_UID16 n @@ -17,10 +17,14 @@ choice 'Processor Type' \ "6xx/7xx/7400 CONFIG_6xx \ 4xx CONFIG_4xx \ - 630/Power3(64-Bit) CONFIG_PPC64 \ + POWER3/POWER4(64-Bit) CONFIG_PPC64BRIDGE \ 8260 CONFIG_8260 \ 8xx CONFIG_8xx" 6xx +if [ "$CONFIG_PPC64BRIDGE" = "y" ]; then + bool 'Power 4 support' CONFIG_POWER4 +fi + if [ "$CONFIG_8260" = "y" ]; then define_bool CONFIG_6xx y define_bool CONFIG_SERIAL_CONSOLE y @@ -35,14 +39,6 @@ if [ "$CONFIG_8xx" = "y" ]; then define_bool CONFIG_SERIAL_CONSOLE y - choice 'Processor Model' \ - "821 CONFIG_MPC821 \ - 823 CONFIG_MPC823 \ - 850 CONFIG_MPC850 \ - 855 CONFIG_MPC855 \ - 860 CONFIG_MPC860 \ - 860T CONFIG_MPC860T" 860 - choice 'Machine Type' \ "RPX-Lite CONFIG_RPXLITE \ RPX-Classic CONFIG_RPXCLASSIC \ @@ -58,7 +54,7 @@ APUS CONFIG_APUS" PowerMac/PReP/MTX/CHRP fi -if [ "$CONFIG_PPC64" = "y" ]; then +if [ "$CONFIG_PPC64BRIDGE" = "y" ]; then define_bool CONFIG_ALL_PPC y fi @@ -99,7 +95,7 @@ "$CONFIG_8260" = "y" ]; then define_bool CONFIG_PCI n else - if [ "$CONFIG_6xx" = "y" -o "$CONFIG_PPC64" = "y" ]; then + if [ "$CONFIG_6xx" = "y" -o "$CONFIG_PPC64BRIDGE" = "y" ]; then define_bool CONFIG_PCI y else # CONFIG_8xx @@ -161,7 +157,7 @@ if [ "$CONFIG_PREP" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then bool 'PReP bootloader kernel arguments' CONFIG_CMDLINE_BOOL y if [ "$CONFIG_CMDLINE_BOOL" = "y" ] ; then - string 'Initial kernel command string' CONFIG_CMDLINE console=ttyS0,9600 console=tty0 root=/dev/sda2 + string 'Initial kernel command string' CONFIG_CMDLINE "console=ttyS0,9600 console=tty0 root=/dev/sda2" fi fi diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/configs/apus_defconfig linux/arch/ppc/configs/apus_defconfig --- v2.4.0-test1/linux/arch/ppc/configs/apus_defconfig Tue Dec 7 09:32:41 1999 +++ linux/arch/ppc/configs/apus_defconfig Mon Jun 19 17:59:36 2000 @@ -78,10 +78,6 @@ CONFIG_BLK_DEV_IDEDMA=y CONFIG_IDEDMA_PMAC_AUTO=y # CONFIG_IDE_CHIPSETS is not set - -# -# Additional Block Devices -# # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/configs/bseip_defconfig linux/arch/ppc/configs/bseip_defconfig --- v2.4.0-test1/linux/arch/ppc/configs/bseip_defconfig Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/configs/bseip_defconfig Mon Jun 19 17:59:36 2000 @@ -0,0 +1,397 @@ +# +# Automatically generated make config: don't edit +# +# CONFIG_UID16 is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Platform support +# +CONFIG_PPC=y +# CONFIG_6xx is not set +# CONFIG_4xx is not set +# CONFIG_PPC64BRIDGE is not set +# CONFIG_8260 is not set +CONFIG_8xx=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_RPXLITE is not set +# CONFIG_RPXCLASSIC is not set +CONFIG_BSEIP=y +# CONFIG_MBX is not set +# CONFIG_WINCEPT is not set +# CONFIG_ALL_PPC is not set +# CONFIG_SMP is not set +CONFIG_MACH_SPECIFIC=y +CONFIG_MATH_EMULATION=y + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# General setup +# +# CONFIG_ISA is not set +# CONFIG_SBUS is not set +# CONFIG_PCI is not set +CONFIG_NET=y +CONFIG_SYSCTL=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_KCORE_ELF=y +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_LVM is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_RAID15_DANGEROUS is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_INITRD=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK=y +# CONFIG_RTNETLINK is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +CONFIG_IP_ALIAS=y +CONFIG_SYN_COOKIES=y + +# +# (it is safe to leave these untouched) +# +CONFIG_SKB_LARGE=y +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_BRIDGE is not set +# CONFIG_LLC is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_ETHERTAP is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_MACE is not set +# CONFIG_BMAC is not set +# CONFIG_GMAC is not set +# CONFIG_NCR885E is not set +# CONFIG_OAKNET is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Console drivers +# + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK 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 + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV 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_DRM is not set +# CONFIG_DRM_TDFX is not set +# CONFIG_AGP is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS 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_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_CRAMFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# MPC8xx CPM Options +# +CONFIG_SCC_ENET=y +# CONFIG_SCC1_ENET is not set +CONFIG_SCC2_ENET=y +# CONFIG_FEC_ENET is not set +CONFIG_8xxSMC2=y +# CONFIG_8xxSCC is not set + +# +# Generic MPC8xx Options +# +CONFIG_8xx_COPYBACK=y +# CONFIG_8xx_CPU6 is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Kernel hacking +# +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_KGDB is not set +# CONFIG_XMON is not set diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/configs/common_defconfig linux/arch/ppc/configs/common_defconfig --- v2.4.0-test1/linux/arch/ppc/configs/common_defconfig Tue May 23 15:31:34 2000 +++ linux/arch/ppc/configs/common_defconfig Mon Jun 19 17:59:36 2000 @@ -14,7 +14,7 @@ CONFIG_PPC=y CONFIG_6xx=y # CONFIG_4xx is not set -# CONFIG_PPC64 is not set +# CONFIG_PPC64BRIDGE is not set # CONFIG_8260 is not set # CONFIG_8xx is not set CONFIG_ALL_PPC=y diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/configs/est8260_defconfig linux/arch/ppc/configs/est8260_defconfig --- v2.4.0-test1/linux/arch/ppc/configs/est8260_defconfig Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/configs/est8260_defconfig Mon Jun 19 17:59:36 2000 @@ -0,0 +1,397 @@ +# +# Automatically generated make config: don't edit +# +# CONFIG_UID16 is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Platform support +# +CONFIG_PPC=y +# CONFIG_6xx is not set +# CONFIG_4xx is not set +# CONFIG_PPC64BRIDGE is not set +CONFIG_8260=y +# CONFIG_8xx is not set +CONFIG_6xx=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_ALL_PPC is not set +# CONFIG_GEMINI is not set +CONFIG_EST8260=y +# CONFIG_APUS is not set +# CONFIG_ALL_PPC is not set +# CONFIG_SMP is not set +# CONFIG_ALTIVEC is not set +CONFIG_MACH_SPECIFIC=y + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# General setup +# +# CONFIG_ISA is not set +# CONFIG_SBUS is not set +# CONFIG_PCI is not set +CONFIG_NET=y +CONFIG_SYSCTL=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_KCORE_ELF=y +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set +# CONFIG_VGA_CONSOLE is not set +# CONFIG_FB is not set +# CONFIG_PMAC_PBOOK is not set +# CONFIG_MAC_FLOPPY is not set +# CONFIG_MAC_SERIAL is not set +# CONFIG_ADB is not set +# CONFIG_PROC_DEVICETREE is not set +# CONFIG_BOOTX_TEXT is not set +# CONFIG_MOTOROLA_HOTSWAP is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_LVM is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_RAID15_DANGEROUS is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_INITRD=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK=y +# CONFIG_RTNETLINK is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +CONFIG_IP_ALIAS=y +CONFIG_SYN_COOKIES=y + +# +# (it is safe to leave these untouched) +# +CONFIG_SKB_LARGE=y +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_BRIDGE is not set +# CONFIG_LLC is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_ETHERTAP is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_MACE is not set +# CONFIG_BMAC is not set +# CONFIG_GMAC is not set +# CONFIG_NCR885E is not set +# CONFIG_OAKNET is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Console drivers +# + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK 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 + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV 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_DRM is not set +# CONFIG_DRM_TDFX is not set +# CONFIG_AGP is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS 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_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_CRAMFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# MPC8260 Communication Options +# +CONFIG_SCC_ENET=y +CONFIG_SCC1_ENET=y +# CONFIG_FCC_ENET is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Kernel hacking +# +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_KGDB is not set +# CONFIG_XMON is not set diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/configs/gemini_defconfig linux/arch/ppc/configs/gemini_defconfig --- v2.4.0-test1/linux/arch/ppc/configs/gemini_defconfig Sun Feb 13 19:29:03 2000 +++ linux/arch/ppc/configs/gemini_defconfig Mon Jun 19 17:59:36 2000 @@ -14,7 +14,7 @@ CONFIG_PPC=y CONFIG_6xx=y # CONFIG_4xx is not set -# CONFIG_PPC64 is not set +# CONFIG_PPC64BRIDGE is not set # CONFIG_82xx is not set # CONFIG_8xx is not set # CONFIG_PMAC is not set @@ -77,10 +77,6 @@ # # CONFIG_BLK_DEV_HD_ONLY is not set # CONFIG_BLK_CPQ_DA is not set - -# -# Additional Block Devices -# # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/configs/oak_defconfig linux/arch/ppc/configs/oak_defconfig --- v2.4.0-test1/linux/arch/ppc/configs/oak_defconfig Thu Feb 10 17:11:04 2000 +++ linux/arch/ppc/configs/oak_defconfig Mon Jun 19 17:59:36 2000 @@ -13,7 +13,7 @@ CONFIG_PPC=y # CONFIG_6xx is not set CONFIG_4xx=y -# CONFIG_PPC64 is not set +# CONFIG_PPC64BRIDGE is not set # CONFIG_82xx is not set # CONFIG_8xx is not set CONFIG_OAK=y @@ -69,10 +69,6 @@ # Please see Documentation/ide.txt for help/info on IDE drives # # CONFIG_BLK_DEV_HD_ONLY is not set - -# -# Additional Block Devices -# CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/configs/rpxcllf_defconfig linux/arch/ppc/configs/rpxcllf_defconfig --- v2.4.0-test1/linux/arch/ppc/configs/rpxcllf_defconfig Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/configs/rpxcllf_defconfig Mon Jun 19 17:59:36 2000 @@ -0,0 +1,396 @@ +# +# Automatically generated make config: don't edit +# +# CONFIG_UID16 is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Platform support +# +CONFIG_PPC=y +# CONFIG_6xx is not set +# CONFIG_4xx is not set +# CONFIG_PPC64BRIDGE is not set +# CONFIG_8260 is not set +CONFIG_8xx=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_RPXLITE is not set +CONFIG_RPXCLASSIC=y +# CONFIG_BSEIP is not set +# CONFIG_MBX is not set +# CONFIG_WINCEPT is not set +# CONFIG_ALL_PPC is not set +# CONFIG_SMP is not set +CONFIG_MACH_SPECIFIC=y +CONFIG_MATH_EMULATION=y + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# General setup +# +# CONFIG_ISA is not set +# CONFIG_SBUS is not set +# CONFIG_PCI is not set +CONFIG_NET=y +CONFIG_SYSCTL=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_KCORE_ELF=y +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_LVM is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_RAID15_DANGEROUS is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_INITRD=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK=y +# CONFIG_RTNETLINK is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +CONFIG_IP_ALIAS=y +CONFIG_SYN_COOKIES=y + +# +# (it is safe to leave these untouched) +# +CONFIG_SKB_LARGE=y +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_BRIDGE is not set +# CONFIG_LLC is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_ETHERTAP is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_MACE is not set +# CONFIG_BMAC is not set +# CONFIG_GMAC is not set +# CONFIG_NCR885E is not set +# CONFIG_OAKNET is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Console drivers +# + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK 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 + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV 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_DRM is not set +# CONFIG_DRM_TDFX is not set +# CONFIG_AGP is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS 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_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_CRAMFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# MPC8xx CPM Options +# +CONFIG_SCC_ENET=y +CONFIG_SCC1_ENET=y +CONFIG_FEC_ENET=y +CONFIG_8xxSMC2=y +CONFIG_8xxSCC=y + +# +# Generic MPC8xx Options +# +CONFIG_8xx_COPYBACK=y +# CONFIG_8xx_CPU6 is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Kernel hacking +# +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_KGDB is not set +# CONFIG_XMON is not set diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/configs/rpxlite_defconfig linux/arch/ppc/configs/rpxlite_defconfig --- v2.4.0-test1/linux/arch/ppc/configs/rpxlite_defconfig Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/configs/rpxlite_defconfig Mon Jun 19 17:59:36 2000 @@ -0,0 +1,397 @@ +# +# Automatically generated make config: don't edit +# +# CONFIG_UID16 is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Platform support +# +CONFIG_PPC=y +# CONFIG_6xx is not set +# CONFIG_4xx is not set +# CONFIG_PPC64BRIDGE is not set +# CONFIG_8260 is not set +CONFIG_8xx=y +CONFIG_SERIAL_CONSOLE=y +CONFIG_RPXLITE=y +# CONFIG_RPXCLASSIC is not set +# CONFIG_BSEIP is not set +# CONFIG_MBX is not set +# CONFIG_WINCEPT is not set +# CONFIG_ALL_PPC is not set +# CONFIG_SMP is not set +CONFIG_MACH_SPECIFIC=y +CONFIG_MATH_EMULATION=y + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# General setup +# +# CONFIG_ISA is not set +# CONFIG_SBUS is not set +# CONFIG_PCI is not set +CONFIG_NET=y +CONFIG_SYSCTL=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_KCORE_ELF=y +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_LVM is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_RAID15_DANGEROUS is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_INITRD=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK=y +# CONFIG_RTNETLINK is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +CONFIG_IP_ALIAS=y +CONFIG_SYN_COOKIES=y + +# +# (it is safe to leave these untouched) +# +CONFIG_SKB_LARGE=y +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_BRIDGE is not set +# CONFIG_LLC is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_ETHERTAP is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_MACE is not set +# CONFIG_BMAC is not set +# CONFIG_GMAC is not set +# CONFIG_NCR885E is not set +# CONFIG_OAKNET is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Console drivers +# + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK 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 + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV 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_DRM is not set +# CONFIG_DRM_TDFX is not set +# CONFIG_AGP is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS 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_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_CRAMFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# MPC8xx CPM Options +# +CONFIG_SCC_ENET=y +# CONFIG_SCC1_ENET is not set +CONFIG_SCC2_ENET=y +# CONFIG_FEC_ENET is not set +# CONFIG_8xxSMC2 is not set +# CONFIG_8xxSCC is not set + +# +# Generic MPC8xx Options +# +CONFIG_8xx_COPYBACK=y +# CONFIG_8xx_CPU6 is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Kernel hacking +# +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_KGDB is not set +# CONFIG_XMON is not set diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/configs/walnut_defconfig linux/arch/ppc/configs/walnut_defconfig --- v2.4.0-test1/linux/arch/ppc/configs/walnut_defconfig Thu Feb 10 17:11:04 2000 +++ linux/arch/ppc/configs/walnut_defconfig Mon Jun 19 17:59:36 2000 @@ -13,7 +13,7 @@ CONFIG_PPC=y # CONFIG_6xx is not set CONFIG_4xx=y -# CONFIG_PPC64 is not set +# CONFIG_PPC64BRIDGE is not set # CONFIG_82xx is not set # CONFIG_8xx is not set # CONFIG_OAK is not set @@ -69,10 +69,6 @@ # Please see Documentation/ide.txt for help/info on IDE drives # # CONFIG_BLK_DEV_HD_ONLY is not set - -# -# Additional Block Devices -# CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/defconfig linux/arch/ppc/defconfig --- v2.4.0-test1/linux/arch/ppc/defconfig Tue May 23 15:31:34 2000 +++ linux/arch/ppc/defconfig Mon Jun 19 17:59:36 2000 @@ -14,7 +14,7 @@ CONFIG_PPC=y CONFIG_6xx=y # CONFIG_4xx is not set -# CONFIG_PPC64 is not set +# CONFIG_PPC64BRIDGE is not set # CONFIG_8260 is not set # CONFIG_8xx is not set CONFIG_ALL_PPC=y diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile --- v2.4.0-test1/linux/arch/ppc/kernel/Makefile Thu May 11 15:30:06 2000 +++ linux/arch/ppc/kernel/Makefile Mon Jun 19 17:59:36 2000 @@ -7,8 +7,13 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... +ifdef CONFIG_PPC64BRIDGE +.S.o: + $(CC) $(CFLAGS) -D__ASSEMBLY__ -mppc64bridge -c $< -o $*.o +else .S.o: $(CC) $(CFLAGS) -D__ASSEMBLY__ -c $< -o $*.o +endif O_TARGET := kernel.o OX_OBJS := ppc_ksyms.o setup.o @@ -32,6 +37,10 @@ O_OBJS := entry.o traps.o irq.o idle.o time.o process.o signal.o syscalls.o \ misc.o ptrace.o align.o ppc_htab.o semaphore.o bitops.o + +ifdef CONFIG_POWER4 +O_OBJS += xics.o +endif ifndef CONFIG_8xx O_OBJS += hashtable.o diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/align.c linux/arch/ppc/kernel/align.c --- v2.4.0-test1/linux/arch/ppc/kernel/align.c Thu May 11 15:30:06 2000 +++ linux/arch/ppc/kernel/align.c Mon Jun 19 17:59:36 2000 @@ -21,7 +21,7 @@ unsigned char flags; }; -#if defined(CONFIG_4xx) +#if defined(CONFIG_4xx) || defined(CONFIG_POWER4) #define OPCD(inst) (((inst) & 0xFC000000) >> 26) #define RS(inst) (((inst) & 0x03E00000) >> 21) #define RA(inst) (((inst) & 0x001F0000) >> 16) @@ -184,7 +184,7 @@ fix_alignment(struct pt_regs *regs) { int instr, nb, flags; -#if defined(CONFIG_4xx) +#if defined(CONFIG_4xx) || defined(CONFIG_POWER4) int opcode, f1, f2, f3; #endif int i, t; @@ -197,9 +197,11 @@ unsigned char v[8]; } data; -#if defined(CONFIG_4xx) +#if defined(CONFIG_4xx) || defined(CONFIG_POWER4) /* The 4xx-family processors have no DSISR register, * so we emulate it. + * The POWER4 has a DSISR register but doesn't set it on + * an alignment fault. -- paulus */ instr = *((unsigned int *)regs->nip); diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/chrp_pci.c linux/arch/ppc/kernel/chrp_pci.c --- v2.4.0-test1/linux/arch/ppc/kernel/chrp_pci.c Tue May 23 15:31:34 2000 +++ linux/arch/ppc/kernel/chrp_pci.c Mon Jun 19 17:59:36 2000 @@ -2,6 +2,7 @@ * CHRP pci routines. */ +#include #include #include #include @@ -21,6 +22,10 @@ #include "pci.h" +#ifdef CONFIG_POWER4 +static unsigned long pci_address_offset(int, unsigned int); +#endif /* CONFIG_POWER4 */ + /* LongTrail */ #define pci_config_addr(bus, dev, offset) \ (GG2_PCI_CONFIG_BASE | ((bus)<<16) | ((dev)<<8) | (offset)) @@ -172,8 +177,11 @@ unsigned char offset, unsigned char *val) { unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16); - if ( call_rtas( "read-pci-config", 2, 2, (ulong *)&val, addr, 1 ) != 0 ) + unsigned long ret; + + if (call_rtas( "read-pci-config", 2, 2, &ret, addr, 1) != 0) return PCIBIOS_DEVICE_NOT_FOUND; + *val = ret; return PCIBIOS_SUCCESSFUL; } @@ -181,8 +189,11 @@ unsigned char offset, unsigned short *val) { unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16); - if ( call_rtas( "read-pci-config", 2, 2, (ulong *)&val, addr, 2 ) != 0 ) + unsigned long ret; + + if (call_rtas("read-pci-config", 2, 2, &ret, addr, 2) != 0) return PCIBIOS_DEVICE_NOT_FOUND; + *val = ret; return PCIBIOS_SUCCESSFUL; } @@ -191,8 +202,11 @@ unsigned char offset, unsigned int *val) { unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16); - if ( call_rtas( "read-pci-config", 2, 2, (ulong *)&val, addr, 4 ) != 0 ) + unsigned long ret; + + if (call_rtas("read-pci-config", 2, 2, &ret, addr, 4) != 0) return PCIBIOS_DEVICE_NOT_FOUND; + *val = ret; return PCIBIOS_SUCCESSFUL; } @@ -275,14 +289,33 @@ { struct pci_dev *dev; int i; + int *brp; + struct device_node *np; extern struct pci_ops generic_pci_ops; - /* Some IBM's with the python have >1 bus, this finds them */ - for ( i = 0; i < python_busnr ; i++ ) - pci_scan_bus(i+1, &generic_pci_ops, NULL); +#ifndef CONFIG_POWER4 + np = find_devices("device-tree"); + if (np != 0) { + for (np = np->child; np != NULL; np = np->sibling) { + if (np->type == NULL || strcmp(np->type, "pci") != 0) + continue; + if ((brp = (int *) get_property(np, "bus-range", NULL)) == 0) + continue; + if (brp[0] != 0) /* bus 0 is already done */ + pci_scan_bus(brp[0], &generic_pci_ops, NULL); + } + } +#else + /* XXX kludge for now because we can't properly handle + physical addresses > 4GB. -- paulus */ + pci_scan_bus(0x1e, &generic_pci_ops, NULL); +#endif /* CONFIG_POWER4 */ /* PCI interrupts are controlled by the OpenPIC */ pci_for_each_dev(dev) { + np = find_pci_device_OFnode(dev->bus->number, dev->devfn); + if ( (np != 0) && (np->n_intrs > 0) && (np->intrs[0].line != 0)) + dev->irq = np->intrs[0].line; if ( dev->irq ) dev->irq = openpic_to_irq( dev->irq ); /* these need to be absolute addrs for OF and Matrox FB -- Cort */ @@ -301,10 +334,30 @@ pcibios_write_config_word(dev->bus->number, dev->devfn, PCI_VENDOR_ID, PCI_VENDOR_ID_AMD); } - if ( (dev->bus->number > 0) && - ((dev->vendor == PCI_VENDOR_ID_NCR) || - (dev->vendor == PCI_VENDOR_ID_AMD))) - dev->resource[0].start += (dev->bus->number*0x08000000); +#ifdef CONFIG_POWER4 + for (i = 0; i < 6; ++i) { + unsigned long offset; + if (dev->resource[i].start == 0) + continue; + offset = pci_address_offset(dev->bus->number, + dev->resource[i].flags); + if (offset) { + dev->resource[i].start += offset; + dev->resource[i].end += offset; + printk("device %x.%x[%d] now [%lx..%lx]\n", + dev->bus->number, dev->devfn, i, + dev->resource[i].start, + dev->resource[i].end); + } + /* zap the 2nd function of the winbond chip */ + if (dev->resource[i].flags & IORESOURCE_IO + && dev->bus->number == 0 && dev->devfn == 0x81) + dev->resource[i].flags &= ~IORESOURCE_IO; + } +#else + if (dev->bus->number > 0 && python_busnr > 0) + dev->resource[0].start += dev->bus->number*0x01000000; +#endif } } @@ -316,7 +369,11 @@ chrp_setup_pci_ptrs(void) { struct device_node *py; - + +#ifdef CONFIG_POWER4 + set_config_access_method(rtas); + pci_dram_offset = 0; +#else /* CONFIG_POWER4 */ if ( !strncmp("MOT", get_property(find_path_device("/"), "model", NULL),3) ) { @@ -327,23 +384,27 @@ } else { - if ( (py = find_compatible_devices( "pci", "IBM,python" )) ) + if ((py = find_compatible_devices("pci", "IBM,python")) != 0 + || (py = find_compatible_devices("pci", "IBM,python3.0")) != 0) { + char *name = get_property(find_path_device("/"), "name", NULL); + /* find out how many pythons */ while ( (py = py->next) ) python_busnr++; set_config_access_method(python); + /* * We base these values on the machine type but should * try to read them from the python controller itself. * -- Cort */ - if ( !strncmp("IBM,7025-F50", get_property(find_path_device("/"), "name", NULL),12) ) + if ( !strncmp("IBM,7025-F50", name, 12) ) { pci_dram_offset = 0x80000000; isa_mem_base = 0xa0000000; isa_io_base = 0x88000000; - } else if ( !strncmp("IBM,7043-260", - get_property(find_path_device("/"), "name", NULL),12) ) + } else if ( !strncmp("IBM,7043-260", name, 12) + || !strncmp("IBM,7044-270", name, 12)) { pci_dram_offset = 0x0; isa_mem_base = 0xc0000000; @@ -372,6 +433,66 @@ } } } +#endif /* CONFIG_POWER4 */ ppc_md.pcibios_fixup = chrp_pcibios_fixup; } + +#ifdef CONFIG_PPC64BRIDGE +/* + * Hack alert!!! + * 64-bit machines like POWER3 and POWER4 have > 32 bit + * physical addresses. For now we remap particular parts + * of the 32-bit physical address space that the Linux + * page table gives us into parts of the physical address + * space above 4GB so we can access the I/O devices. + */ + +#ifdef CONFIG_POWER4 +static unsigned long pci_address_offset(int busnr, unsigned int flags) +{ + unsigned long offset = 0; + + if (busnr >= 0x1e) { + if (flags & IORESOURCE_IO) + offset = -0x100000; + else if (flags & IORESOURCE_MEM) + offset = 0x38000000; + } else if (busnr <= 0xf) { + if (flags & IORESOURCE_MEM) + offset = -0x40000000; + else + } + return offset; +} + +unsigned long phys_to_bus(unsigned long pa) +{ + if (pa >= 0xf8000000) + pa -= 0x38000000; + else if (pa >= 0x80000000 && pa < 0xc0000000) + pa += 0x40000000; + return pa; +} + +unsigned long bus_to_phys(unsigned int ba, int busnr) +{ + return ba + pci_address_offset(busnr, IORESOURCE_MEM); +} + +#else /* CONFIG_POWER4 */ +/* + * For now assume I/O addresses are < 4GB and PCI bridges don't + * remap addresses on POWER3 machines. + */ +unsigned long phys_to_bus(unsigned long pa) +{ + return pa; +} + +unsigned long bus_to_phys(unsigned int ba, int busnr) +{ + return ba; +} +#endif /* CONFIG_POWER4 */ +#endif /* CONFIG_PPC64BRIDGE */ diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c --- v2.4.0-test1/linux/arch/ppc/kernel/chrp_setup.c Tue May 23 15:31:34 2000 +++ linux/arch/ppc/kernel/chrp_setup.c Mon Jun 19 17:59:36 2000 @@ -55,6 +55,7 @@ #include "local_irq.h" #include "i8259.h" #include "open_pic.h" +#include "xics.h" extern volatile unsigned char *chrp_int_ack_special; @@ -259,6 +260,7 @@ request_region(0x80,0x10,"dma page reg"); request_region(0xc0,0x20,"dma2"); +#ifndef CONFIG_PPC64BRIDGE /* PCI bridge config space access area - * appears to be not in devtree on longtrail. */ ioremap(GG2_PCI_CONFIG_BASE, 0x80000); @@ -267,14 +269,23 @@ * -- Geert */ hydra_init(); /* Mac I/O */ +#endif /* CONFIG_PPC64BRIDGE */ +#ifndef CONFIG_POWER4 /* Some IBM machines don't have the hydra -- Cort */ if ( !OpenPIC ) { - OpenPIC = (struct OpenPIC *)*(unsigned long *)get_property( - find_path_device("/"), "platform-open-pic", NULL); - OpenPIC = ioremap((unsigned long)OpenPIC, sizeof(struct OpenPIC)); + unsigned long *opprop; + + opprop = (unsigned long *)get_property(find_path_device("/"), + "platform-open-pic", NULL); + if (opprop != 0) { + printk("OpenPIC addrs: %lx %lx %lx\n", + opprop[0], opprop[1], opprop[2]); + OpenPIC = ioremap(opprop[0], sizeof(struct OpenPIC)); + } } +#endif /* * Fix the Super I/O configuration @@ -283,7 +294,10 @@ #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; #endif + +#ifndef CONFIG_PPC64BRIDGE pmac_find_bridges(); +#endif /* CONFIG_PPC64BRIDGE */ /* Get the event scan rate for the rtas so we know how * often it expects a heartbeat. -- Cort @@ -402,15 +416,15 @@ { struct device_node *np; int i; + unsigned long *addrp; - if ( !(np = find_devices("pci") ) ) + if (!(np = find_devices("pci")) + || !(addrp = (unsigned long *) + get_property(np, "8259-interrupt-acknowledge", NULL))) printk("Cannot find pci to get ack address\n"); else - { chrp_int_ack_special = (volatile unsigned char *) - (*(unsigned long *)get_property(np, - "8259-interrupt-acknowledge", NULL)); - } + ioremap(*addrp, 1); open_pic_irq_offset = 16; for ( i = 16 ; i < NR_IRQS ; i++ ) irq_desc[i].handler = &open_pic; @@ -435,6 +449,8 @@ #ifdef CONFIG_NVRAM pmac_nvram_init(); #endif + if (ppc_md.progress) + ppc_md.progress(" Have fun! ", 0x7777); } #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) @@ -560,10 +576,16 @@ ppc_md.setup_residual = NULL; ppc_md.get_cpuinfo = chrp_get_cpuinfo; ppc_md.irq_cannonicalize = chrp_irq_cannonicalize; +#ifndef CONFIG_POWER4 ppc_md.init_IRQ = chrp_init_IRQ; ppc_md.get_irq = chrp_get_irq; ppc_md.post_irq = chrp_post_irq; - +#else + ppc_md.init_IRQ = xics_init_IRQ; + ppc_md.get_irq = xics_get_irq; + ppc_md.post_irq = NULL; +#endif /* CONFIG_POWER4 */ + ppc_md.init = chrp_init2; ppc_md.restart = chrp_restart; @@ -652,6 +674,7 @@ if ( call_rtas( "display-character", 1, 1, NULL, '\r' ) ) { /* assume no display-character RTAS method - use hex display */ + call_rtas("set-indicator", 3, 1, NULL, 6, 0, hex); return; } diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/entry.S linux/arch/ppc/kernel/entry.S --- v2.4.0-test1/linux/arch/ppc/kernel/entry.S Tue May 23 15:31:34 2000 +++ linux/arch/ppc/kernel/entry.S Mon Jun 19 17:59:36 2000 @@ -31,8 +31,8 @@ #include #include -#define SHOW_SYSCALLS -#define SHOW_SYSCALLS_TASK +#undef SHOW_SYSCALLS +#undef SHOW_SYSCALLS_TASK #ifdef SHOW_SYSCALLS_TASK .data @@ -83,8 +83,8 @@ #endif /* SHOW_SYSCALLS */ cmpi 0,r0,0x7777 /* Special case for 'sys_sigreturn' */ beq- 10f - lwz r10,TASK_FLAGS(r2) - andi. r10,r10,PF_TRACESYS + lwz r10,TASK_PTRACE(r2) + andi. r10,r10,PT_TRACESYS bne- 50f cmpli 0,r0,NR_syscalls bge- 66f @@ -227,12 +227,15 @@ stw r1,KSP(r3) /* Set old stack pointer */ sync tophys(r0,r4) + CLR_TOP32(r0) mtspr SPRG3,r0 /* Update current THREAD phys addr */ #ifdef CONFIG_8xx /* XXX it would be nice to find a SPRGx for this on 6xx,7xx too */ lwz r9,PGDIR(r4) /* cache the page table root */ tophys(r9,r9) /* convert to phys addr */ mtspr M_TWB,r9 /* Update MMU base address */ + tlbia + SYNC #endif /* CONFIG_8xx */ lwz r1,KSP(r4) /* Load new stack pointer */ /* save the old current 'last' for return value */ @@ -244,6 +247,7 @@ 8: addi r4,r1,INT_FRAME_SIZE /* size of frame */ stw r4,THREAD+KSP(r2) /* save kernel stack pointer */ tophys(r9,r1) + CLR_TOP32(r9) mtspr SPRG2,r9 /* phys exception stack pointer */ 10: lwz r2,_CTR(r1) lwz r0,_LINK(r1) @@ -270,12 +274,13 @@ lwz r0,_MSR(r1) mtspr SRR0,r2 + FIX_SRR1(r0,r2) mtspr SRR1,r0 lwz r0,GPR0(r1) lwz r2,GPR2(r1) lwz r1,GPR1(r1) SYNC - rfi + RFI #ifdef CONFIG_SMP .globl ret_from_smpfork @@ -311,11 +316,7 @@ #ifdef CONFIG_SMP /* get processor # */ lwz r3,PROCESSOR(r2) -#ifndef CONFIG_PPC64 slwi r3,r3,5 -#else -#error not 64-bit ready -#endif add r4,r4,r3 #endif /* CONFIG_SMP */ lwz r5,0(r4) @@ -365,14 +366,17 @@ /* if returning to user mode, set new sprg2 and save kernel SP */ lwz r0,_MSR(r1) - mtspr SRR1,r0 andi. r0,r0,MSR_PR beq+ 1f addi r0,r1,INT_FRAME_SIZE /* size of frame */ stw r0,THREAD+KSP(r2) /* save kernel stack pointer */ tophys(r2,r1) + CLR_TOP32(r2) mtspr SPRG2,r2 /* phys exception stack pointer */ -1: +1: + lwz r0,_MSR(r1) + FIX_SRR1(r0,r2) + mtspr SRR1,r0 lwz r2,_CCR(r1) mtcrf 0xFF,r2 lwz r2,_NIP(r1) @@ -381,7 +385,7 @@ lwz r2,GPR2(r1) lwz r1,GPR1(r1) SYNC - rfi + RFI /* * Fake an interrupt from kernel mode. @@ -423,7 +427,6 @@ stw r0,20(r1) lis r4,rtas_data@ha lwz r4,rtas_data@l(r4) - addis r4,r4,-KERNELBASE@h lis r6,1f@ha /* physical return address for rtas */ addi r6,r6,1f@l addis r6,r6,-KERNELBASE@h @@ -436,20 +439,23 @@ li r0,0 ori r0,r0,MSR_EE|MSR_SE|MSR_BE andc r0,r9,r0 - andi. r9,r9,MSR_ME|MSR_RI + li r10,MSR_IR|MSR_DR|MSR_FE0|MSR_FE1|MSR_FP + andc r9,r0,r10 sync /* disable interrupts so SRR0/1 */ mtmsr r0 /* don't get trashed */ mtlr r6 + CLR_TOP32(r7) mtspr SPRG2,r7 mtspr SRR0,r8 mtspr SRR1,r9 - rfi + RFI 1: addis r9,r1,-KERNELBASE@h lwz r8,20(r9) /* get return address */ lwz r9,8(r9) /* original msr value */ + FIX_SRR1(r9,r0) li r0,0 mtspr SPRG2,r0 mtspr SRR0,r8 mtspr SRR1,r9 - rfi /* return to caller */ + RFI /* return to caller */ #endif /* CONFIG_ALL_PPC */ diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/hashtable.S linux/arch/ppc/kernel/hashtable.S --- v2.4.0-test1/linux/arch/ppc/kernel/hashtable.S Wed Apr 26 16:34:07 2000 +++ linux/arch/ppc/kernel/hashtable.S Mon Jun 19 17:59:36 2000 @@ -52,6 +52,13 @@ .globl hash_page hash_page: +#ifdef CONFIG_PPC64BRIDGE + mfmsr r0 + clrldi r0,r0,1 /* make sure it's in 32-bit mode */ + sync + MTMSRD(r0) + isync +#endif #ifdef CONFIG_SMP SAVE_2GPRS(7,r21) eieio @@ -120,28 +127,183 @@ ori r4,r4,0xe04 /* clear out reserved bits */ andc r6,r6,r4 /* PP=2 or 0, when _PAGE_HWWRITE */ +#ifdef CONFIG_POWER4 + /* + * XXX hack hack hack - translate 32-bit "physical" addresses + * in the linux page tables to 42-bit real addresses in such + * a fashion that we can get at the I/O we need to access. + * -- paulus + */ + cmpwi 0,r6,0 + rlwinm r4,r6,16,16,30 + bge 57f + cmplwi 0,r4,0xfe00 + li r5,0x3fd + bne 56f + li r5,0x3ff +56: sldi r5,r5,32 + or r6,r6,r5 +57: +#endif + +#ifdef CONFIG_PPC64BRIDGE /* Construct the high word of the PPC-style PTE */ mfsrin r5,r3 /* get segment reg for segment */ -#ifdef CONFIG_PPC64 + rlwinm r5,r5,0,5,31 sldi r5,r5,12 -#else /* CONFIG_PPC64 */ - rlwinm r5,r5,7,1,24 /* put VSID in 0x7fffff80 bits */ -#endif /* CONFIG_PPC64 */ #ifndef CONFIG_SMP /* do this later for SMP */ -#ifdef CONFIG_PPC64 ori r5,r5,1 /* set V (valid) bit */ -#else /* CONFIG_PPC64 */ +#endif + + rlwimi r5,r3,16,20,24 /* put in API (abbrev page index) */ + /* Get the address of the primary PTE group in the hash table */ + .globl hash_page_patch_A +hash_page_patch_A: + lis r4,Hash_base@h /* base address of hash table */ + rlwimi r4,r5,32-5,25-Hash_bits,24 /* (VSID & hash_mask) << 7 */ + rlwinm r0,r3,32-5,25-Hash_bits,24 /* (PI & hash_mask) << 7 */ + xor r4,r4,r0 /* make primary hash */ + + /* See whether it was a PTE not found exception or a + protection violation. */ + andis. r0,r20,0x4000 + li r2,8 /* PTEs/group */ + bne 10f /* no PTE: go look for an empty slot */ + tlbie r3 /* invalidate TLB entry */ + + /* Search the primary PTEG for a PTE whose 1st dword matches r5 */ + mtctr r2 + addi r3,r4,-16 +1: ldu r0,16(r3) /* get next PTE */ + cmpd 0,r0,r5 + bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ + beq+ found_slot + + /* Search the secondary PTEG for a matching PTE */ + ori r5,r5,0x2 /* set H (secondary hash) bit */ + .globl hash_page_patch_B +hash_page_patch_B: + xoris r3,r4,Hash_msk>>16 /* compute secondary hash */ + xori r3,r3,0xff80 + addi r3,r3,-16 + mtctr r2 +2: ldu r0,16(r3) + cmpd 0,r0,r5 + bdnzf 2,2b + beq+ found_slot + xori r5,r5,0x2 /* clear H bit again */ + + /* Search the primary PTEG for an empty slot */ +10: mtctr r2 + addi r3,r4,-16 /* search primary PTEG */ +1: ldu r0,16(r3) /* get next PTE */ + andi. r0,r0,1 + bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ + beq+ found_empty + + /* Search the secondary PTEG for an empty slot */ + ori r5,r5,0x2 /* set H (secondary hash) bit */ + .globl hash_page_patch_C +hash_page_patch_C: + xoris r3,r4,Hash_msk>>16 /* compute secondary hash */ + xori r3,r3,0xff80 + addi r3,r3,-16 + mtctr r2 +2: ldu r0,16(r3) + andi. r0,r0,1 + bdnzf 2,2b + beq+ found_empty + + /* + * Choose an arbitrary slot in the primary PTEG to overwrite. + * Since both the primary and secondary PTEGs are full, and we + * have no information that the PTEs in the primary PTEG are + * more important or useful than those in the secondary PTEG, + * and we know there is a definite (although small) speed + * advantage to putting the PTE in the primary PTEG, we always + * put the PTE in the primary PTEG. + */ + xori r5,r5,0x2 /* clear H bit again */ + lis r3,next_slot@ha + tophys(r3,r3) + lwz r2,next_slot@l(r3) + addi r2,r2,16 + andi. r2,r2,0x70 +#ifdef CONFIG_POWER4 + /* + * Since we don't have BATs on POWER4, we rely on always having + * PTEs in the hash table to map the hash table and the code + * that manipulates it in virtual mode, namely flush_hash_page and + * flush_hash_segments. Otherwise we can get a DSI inside those + * routines which leads to a deadlock on the hash_table_lock on + * SMP machines. We avoid this by never overwriting the first + * PTE of each PTEG if it is already valid. + * -- paulus. + */ + bne 102f + li r2,0x10 +102: +#endif /* CONFIG_POWER4 */ + stw r2,next_slot@l(r3) + add r3,r4,r2 +11: + /* update counter of evicted pages */ + lis r2,htab_evicts@ha + tophys(r2,r2) + lwz r4,htab_evicts@l(r2) + addi r4,r4,1 + stw r4,htab_evicts@l(r2) + +#ifndef CONFIG_SMP + /* Store PTE in PTEG */ +found_empty: + std r5,0(r3) +found_slot: + std r6,8(r3) + sync + +#else /* CONFIG_SMP */ +/* + * Between the tlbie above and updating the hash table entry below, + * another CPU could read the hash table entry and put it in its TLB. + * There are 3 cases: + * 1. using an empty slot + * 2. updating an earlier entry to change permissions (i.e. enable write) + * 3. taking over the PTE for an unrelated address + * + * In each case it doesn't really matter if the other CPUs have the old + * PTE in their TLB. So we don't need to bother with another tlbie here, + * which is convenient as we've overwritten the register that had the + * address. :-) The tlbie above is mainly to make sure that this CPU comes + * and gets the new PTE from the hash table. + * + * We do however have to make sure that the PTE is never in an invalid + * state with the V bit set. + */ +found_empty: +found_slot: + std r5,0(r3) /* clear V (valid) bit in PTE */ + sync + tlbsync + sync + std r6,8(r3) /* put in correct RPN, WIMG, PP bits */ + sync + ori r5,r5,1 + std r5,0(r3) /* finally set V bit in PTE */ +#endif /* CONFIG_SMP */ + +#else /* CONFIG_PPC64BRIDGE */ + + /* Construct the high word of the PPC-style PTE */ + mfsrin r5,r3 /* get segment reg for segment */ + rlwinm r5,r5,7,1,24 /* put VSID in 0x7fffff80 bits */ + +#ifndef CONFIG_SMP /* do this later for SMP */ oris r5,r5,0x8000 /* set V (valid) bit */ -#endif /* CONFIG_PPC64 */ #endif -#ifdef CONFIG_PPC64 -/* XXX: does this insert the api correctly? -- Cort */ - rlwimi r5,r3,17,21,25 /* put in API (abbrev page index) */ -#else /* CONFIG_PPC64 */ rlwimi r5,r3,10,26,31 /* put in API (abbrev page index) */ -#endif /* CONFIG_PPC64 */ /* Get the address of the primary PTE group in the hash table */ .globl hash_page_patch_A hash_page_patch_A: @@ -160,89 +322,44 @@ /* Search the primary PTEG for a PTE whose 1st word matches r5 */ mtctr r2 addi r3,r4,-8 -1: -#ifdef CONFIG_PPC64 - lwzu r0,16(r3) /* get next PTE */ -#else - lwzu r0,8(r3) /* get next PTE */ -#endif +1: lwzu r0,8(r3) /* get next PTE */ cmp 0,r0,r5 bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ beq+ found_slot /* Search the secondary PTEG for a matching PTE */ -#ifdef CONFIG_PPC64 - ori r5,r5,0x2 /* set H (secondary hash) bit */ -#else ori r5,r5,0x40 /* set H (secondary hash) bit */ -#endif .globl hash_page_patch_B hash_page_patch_B: xoris r3,r4,Hash_msk>>16 /* compute secondary hash */ xori r3,r3,0xffc0 -#ifdef CONFIG_PPC64 - addi r3,r3,-16 -#else addi r3,r3,-8 -#endif mtctr r2 -2: -#ifdef CONFIG_PPC64 - lwzu r0,16(r3) -#else - lwzu r0,8(r3) -#endif +2: lwzu r0,8(r3) cmp 0,r0,r5 bdnzf 2,2b beq+ found_slot -#ifdef CONFIG_PPC64 - xori r5,r5,0x2 /* clear H bit again */ -#else xori r5,r5,0x40 /* clear H bit again */ -#endif /* Search the primary PTEG for an empty slot */ 10: mtctr r2 -#ifdef CONFIG_PPC64 - addi r3,r4,-16 /* search primary PTEG */ -#else addi r3,r4,-8 /* search primary PTEG */ -#endif -1: -#ifdef CONFIG_PPC64 - lwzu r0,16(r3) /* get next PTE */ - andi. r0,r0,1 -#else - lwzu r0,8(r3) /* get next PTE */ +1: lwzu r0,8(r3) /* get next PTE */ rlwinm. r0,r0,0,0,0 /* only want to check valid bit */ -#endif bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ beq+ found_empty /* Search the secondary PTEG for an empty slot */ -#ifdef CONFIG_PPC64 - ori r5,r5,0x2 /* set H (secondary hash) bit */ -#else ori r5,r5,0x40 /* set H (secondary hash) bit */ -#endif .globl hash_page_patch_C hash_page_patch_C: xoris r3,r4,Hash_msk>>16 /* compute secondary hash */ xori r3,r3,0xffc0 -#ifdef CONFIG_PPC64 - addi r3,r3,-16 -#else addi r3,r3,-8 -#endif mtctr r2 2: -#ifdef CONFIG_PPC64 - lwzu r0,16(r3) - andi. r0,r0,1 -#else lwzu r0,8(r3) rlwinm. r0,r0,0,0,0 /* only want to check valid bit */ -#endif bdnzf 2,2b beq+ found_empty @@ -255,21 +372,12 @@ * advantage to putting the PTE in the primary PTEG, we always * put the PTE in the primary PTEG. */ -#ifdef CONFIG_PPC64 - xori r5,r5,0x2 /* clear H bit again */ -#else xori r5,r5,0x40 /* clear H bit again */ -#endif lis r3,next_slot@ha tophys(r3,r3) lwz r2,next_slot@l(r3) -#ifdef CONFIG_PPC64 - addi r2,r2,16 - andi. r2,r2,0x78 -#else addi r2,r2,8 andi. r2,r2,0x38 -#endif stw r2,next_slot@l(r3) add r3,r4,r2 11: @@ -283,17 +391,9 @@ #ifndef CONFIG_SMP /* Store PTE in PTEG */ found_empty: -#ifdef CONFIG_PPC64 - std r5,0(r3) -#else stw r5,0(r3) -#endif found_slot: -#ifdef CONFIG_PPC64 - std r6,8(r3) -#else stw r6,4(r3) -#endif sync #else /* CONFIG_SMP */ @@ -325,6 +425,7 @@ oris r5,r5,0x8000 stw r5,0(r3) /* finally set V bit in PTE */ #endif /* CONFIG_SMP */ +#endif /* CONFIG_PPC64BRIDGE */ /* * Update the hash table miss count. We only want misses here @@ -371,7 +472,7 @@ lwz r22,GPR22(r21) lwz r23,GPR23(r21) lwz r21,GPR21(r21) - rfi + RFI #ifdef CONFIG_SMP hash_page_out: @@ -410,7 +511,7 @@ #endif blr 99: -#ifdef CONFIG_SMP +#if defined(CONFIG_SMP) || defined(CONFIG_PPC64BRIDGE) /* Note - we had better not do anything which could generate a hash table miss while we have the hash table locked, or we'll get a deadlock. -paulus */ @@ -419,6 +520,8 @@ rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ mtmsr r0 SYNC +#endif +#ifdef CONFIG_SMP lis r9,hash_table_lock@h ori r9,r9,hash_table_lock@l lwz r8,PROCESSOR(r2) @@ -430,6 +533,7 @@ bne- 10b eieio #endif +#ifndef CONFIG_PPC64BRIDGE rlwinm r3,r3,7,1,24 /* put VSID lower limit in position */ oris r3,r3,0x8000 /* set V bit */ rlwinm r4,r4,7,1,24 /* put VSID upper limit in position */ @@ -448,6 +552,26 @@ blt 2f /* branch if out of range */ stw r0,0(r5) /* invalidate entry */ 2: bdnz 1b /* continue with loop */ +#else /* CONFIG_PPC64BRIDGE */ + rldic r3,r3,12,20 /* put VSID lower limit in position */ + ori r3,r3,1 /* set V bit */ + rldic r4,r4,12,20 /* put VSID upper limit in position */ + ori r4,r4,0xfff /* set V bit, API etc. */ + lis r6,Hash_size@ha + lwz r6,Hash_size@l(r6) /* size in bytes */ + srwi r6,r6,4 /* # PTEs */ + mtctr r6 + addi r5,r5,-16 + li r0,0 +1: ldu r6,16(r5) /* get next tag word */ + cmpld 0,r6,r3 + cmpld 1,r6,r4 + cror 0,0,5 /* set cr0.lt if out of range */ + blt 2f /* branch if out of range */ + std r0,0(r5) /* invalidate entry */ +2: bdnz 1b /* continue with loop */ +#endif /* CONFIG_PPC64BRIDGE */ + sync tlbia sync @@ -456,6 +580,8 @@ sync lis r3,hash_table_lock@ha stw r0,hash_table_lock@l(r3) +#endif +#if defined(CONFIG_SMP) || defined(CONFIG_PPC64BRIDGE) mtmsr r10 SYNC #endif @@ -479,7 +605,7 @@ #endif blr 99: -#ifdef CONFIG_SMP +#if defined(CONFIG_SMP) || defined(CONFIG_PPC64BRIDGE) /* Note - we had better not do anything which could generate a hash table miss while we have the hash table locked, or we'll get a deadlock. -paulus */ @@ -488,6 +614,8 @@ rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ mtmsr r0 SYNC +#endif +#ifdef CONFIG_SMP lis r9,hash_table_lock@h ori r9,r9,hash_table_lock@l lwz r8,PROCESSOR(r2) @@ -499,6 +627,7 @@ bne- 10b eieio #endif +#ifndef CONFIG_PPC64BRIDGE rlwinm r3,r3,11,1,20 /* put context into vsid */ rlwimi r3,r4,11,21,24 /* put top 4 bits of va into vsid */ oris r3,r3,0x8000 /* set V (valid) bit */ @@ -528,6 +657,37 @@ bne 4f /* if we didn't find it */ 3: li r0,0 stw r0,0(r7) /* invalidate entry */ +#else /* CONFIG_PPC64BRIDGE */ + rldic r3,r3,16,16 /* put context into vsid (<< 12) */ + rlwimi r3,r4,16,16,24 /* top 4 bits of va and API */ + ori r3,r3,1 /* set V (valid) bit */ + rlwinm r7,r4,32-5,9,24 /* get page index << 7 */ + srdi r5,r3,5 /* vsid << 7 */ + rlwinm r5,r5,0,1,24 /* vsid << 7 (limited to 24 bits) */ + xor r7,r7,r5 /* primary hash << 7 */ + lis r5,Hash_mask@ha + lwz r5,Hash_mask@l(r5) /* hash mask */ + slwi r5,r5,7 /* << 7 */ + and r7,r7,r5 + add r6,r6,r7 /* address of primary PTEG */ + li r8,8 + mtctr r8 + addi r7,r6,-16 +1: ldu r0,16(r7) /* get next PTE */ + cmpd 0,r0,r3 /* see if tag matches */ + bdnzf 2,1b /* while --ctr != 0 && !cr0.eq */ + beq 3f /* if we found it */ + ori r3,r3,2 /* set H (alt. hash) bit */ + xor r6,r6,r5 /* address of secondary PTEG */ + mtctr r8 + addi r7,r6,-16 +2: ldu r0,16(r7) /* get next PTE */ + cmpd 0,r0,r3 /* see if tag matches */ + bdnzf 2,2b /* while --ctr != 0 && !cr0.eq */ + bne 4f /* if we didn't find it */ +3: li r0,0 + std r0,0(r7) /* invalidate entry */ +#endif /* CONFIG_PPC64BRIDGE */ 4: sync tlbie r4 /* in hw tlb too */ sync @@ -536,6 +696,8 @@ sync li r0,0 stw r0,0(r9) /* clear hash_table_lock */ +#endif +#if defined(CONFIG_SMP) || defined(CONFIG_PPC64BRIDGE) mtmsr r10 SYNC #endif diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S --- v2.4.0-test1/linux/arch/ppc/kernel/head.S Tue May 23 15:31:34 2000 +++ linux/arch/ppc/kernel/head.S Mon Jun 19 17:59:36 2000 @@ -36,7 +36,19 @@ #include #endif -#ifdef CONFIG_PPC64 +#ifndef CONFIG_PPC64BRIDGE +CACHELINE_BYTES = 32 +LG_CACHELINE_BYTES = 5 +CACHELINE_MASK = 0x1f +CACHELINE_WORDS = 8 +#else +CACHELINE_BYTES = 128 +LG_CACHELINE_BYTES = 7 +CACHELINE_MASK = 0x7f +CACHELINE_WORDS = 32 +#endif /* CONFIG_PPC64BRIDGE */ + +#ifdef CONFIG_PPC64BRIDGE #define LOAD_BAT(n, reg, RA, RB) \ ld RA,(n*32)+0(reg); \ ld RB,(n*32)+8(reg); \ @@ -47,7 +59,7 @@ mtspr DBAT##n##U,RA; \ mtspr DBAT##n##L,RB; \ -#else /* CONFIG_PPC64 */ +#else /* CONFIG_PPC64BRIDGE */ /* 601 only have IBAT; cr0.eq is set on 601 when using this macro */ #define LOAD_BAT(n, reg, RA, RB) \ @@ -65,7 +77,7 @@ mtspr DBAT##n##U,RA; \ mtspr DBAT##n##L,RB; \ 1: -#endif /* CONFIG_PPC64 */ +#endif /* CONFIG_PPC64BRIDGE */ .text .globl _stext @@ -125,16 +137,6 @@ .globl __start __start: -#ifdef CONFIG_PPC64 -/* - * Go into 32-bit mode to boot. OF should do this for - * us already but just in case... - * -- Cort - */ - mfmsr r10 - clrldi r10,r10,3 - mtmsr r10 -#endif /* * We have to do any OF calls before we map ourselves to KERNELBASE, * because OF may have I/O devices mapped into that area @@ -166,67 +168,23 @@ bl flush_tlbs #endif +#ifndef CONFIG_POWER4 + /* POWER4 doesn't have BATs */ + bl initial_bats +#else /* CONFIG_POWER4 */ /* - * Use the first pair of BAT registers to map the 1st 16MB - * of RAM to KERNELBASE. From this point on we can't safely - * call OF any more. + * Load up the SDR1 and segment register values now + * since we don't have the BATs. */ - lis r11,KERNELBASE@h -#ifndef CONFIG_PPC64 - mfspr r9,PVR - rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ - cmpi 0,r9,1 - bne 4f - ori r11,r11,4 /* set up BAT registers for 601 */ - li r8,0x7f /* valid, block length = 8MB */ - oris r9,r11,0x800000@h /* set up BAT reg for 2nd 8M */ - oris r10,r8,0x800000@h /* set up BAT reg for 2nd 8M */ - mtspr IBAT0U,r11 /* N.B. 601 has valid bit in */ - mtspr IBAT0L,r8 /* lower BAT register */ - mtspr IBAT1U,r9 - mtspr IBAT1L,r10 - b 5f -#endif /* CONFIG_PPC64 */ - -4: tophys(r8,r11) -#ifdef CONFIG_SMP - ori r8,r8,0x12 /* R/W access, M=1 */ -#else - ori r8,r8,2 /* R/W access */ -#endif /* CONFIG_SMP */ -#ifdef CONFIG_APUS - ori r11,r11,BL_8M<<2|0x2 /* set up 8MB BAT registers for 604 */ -#else - ori r11,r11,BL_256M<<2|0x2 /* set up BAT registers for 604 */ -#endif /* CONFIG_APUS */ - -#ifdef CONFIG_PPC64 - /* clear out the high 32 bits in the BAT */ - clrldi r11,r11,32 - clrldi r8,r8,32 - /* turn off the pagetable mappings just in case */ - clrldi r16,r16,63 - mtsdr1 r16 -#else /* CONFIG_PPC64 */ - /* - * If the MMU is off clear the bats. See clear_bat() -- Cort - */ - mfmsr r20 - andi. r20,r20,MSR_DR - bne 100f - bl clear_bats -100: -#endif /* CONFIG_PPC64 */ - mtspr DBAT0L,r8 /* N.B. 6xx (not 601) have valid */ - mtspr DBAT0U,r11 /* bit in upper BAT register */ - mtspr IBAT0L,r8 - mtspr IBAT0U,r11 -#if 0 /* Useful debug code, please leave in for now so I don't have to - * look at docs when I need to setup a BAT ... - */ - bl setup_screen_bat -#endif -5: isync + bl reloc_offset + addis r4,r3,_SDR1@ha /* get the value from _SDR1 */ + lwz r4,_SDR1@l(r4) /* assume hash table below 4GB */ + mtspr SDR1,r4 + slbia + lis r5,0x2000 /* set pseudo-segment reg 12 */ + ori r5,r5,12 + mtsr 12,r5 +#endif /* CONFIG_POWER4 */ #ifndef CONFIG_APUS /* @@ -267,7 +225,21 @@ ori r0,r0,start_here@l mtspr SRR0,r0 SYNC - rfi /* enables MMU */ + RFI /* enables MMU */ + +#ifdef CONFIG_SMP + .globl __secondary_hold +__secondary_hold: + /* tell the master we're here */ + stw r3,4(0) +100: lwz r4,0(0) + /* wait until we're told to start */ + cmpw 0,r4,r3 + bne 100b + /* our cpu # was at addr 0 - go */ + mr r24,r3 /* cpu # */ + b __secondary_start +#endif /* * Exception entry code. This code runs with address translation @@ -284,7 +256,8 @@ bne 1f; \ tophys(r21,r1); /* use tophys(kernel sp) otherwise */ \ subi r21,r21,INT_FRAME_SIZE; /* alloc exc. frame */\ -1: stw r20,_CCR(r21); /* save registers */ \ +1: CLR_TOP32(r21); \ + stw r20,_CCR(r21); /* save registers */ \ stw r22,GPR22(r21); \ stw r23,GPR23(r21); \ mfspr r20,SPRG0; \ @@ -341,8 +314,13 @@ /* Data access exception. */ . = 0x300 +#ifdef CONFIG_PPC64BRIDGE + b DataAccess +DataAccessCont: +#else DataAccess: EXCEPTION_PROLOG +#endif /* CONFIG_PPC64BRIDGE */ mfspr r20,DSISR andis. r0,r20,0xa470 /* weird error? */ bne 1f /* if not, try to put a PTE */ @@ -361,10 +339,30 @@ .long do_page_fault .long ret_from_except +#ifdef CONFIG_PPC64BRIDGE +/* SLB fault on data access. */ + . = 0x380 + b DataSegment +DataSegmentCont: + mfspr r4,DAR + stw r4,_DAR(r21) + addi r3,r1,STACK_FRAME_OVERHEAD + li r20,MSR_KERNEL + rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ + bl transfer_to_handler + .long UnknownException + .long ret_from_except +#endif /* CONFIG_PPC64BRIDGE */ + /* Instruction access exception. */ . = 0x400 +#ifdef CONFIG_PPC64BRIDGE + b InstructionAccess +InstructionAccessCont: +#else InstructionAccess: EXCEPTION_PROLOG +#endif /* CONFIG_PPC64BRIDGE */ andis. r0,r23,0x4000 /* no pte found? */ beq 1f /* if so, try to put a PTE */ mr r3,r22 /* into the hash table */ @@ -380,6 +378,19 @@ .long do_page_fault .long ret_from_except +#ifdef CONFIG_PPC64BRIDGE +/* SLB fault on instruction access. */ + . = 0x480 + b InstructionSegment +InstructionSegmentCont: + addi r3,r1,STACK_FRAME_OVERHEAD + li r20,MSR_KERNEL + rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ + bl transfer_to_handler + .long UnknownException + .long ret_from_except +#endif /* CONFIG_PPC64BRIDGE */ + /* External interrupt */ . = 0x500; HardwareInterrupt: @@ -526,7 +537,7 @@ tlbli r3 mfspr r3,SRR1 /* Need to restore CR0 */ mtcrf 0x80,r3 - rfi + rfi InstructionAddressInvalid: mfspr r3,SRR1 rlwinm r1,r3,9,6,6 /* Get load/store bit */ @@ -593,7 +604,7 @@ tlbld r3 mfspr r3,SRR1 /* Need to restore CR0 */ mtcrf 0x80,r3 - rfi + rfi DataAddressInvalid: mfspr r3,SRR1 rlwinm r1,r3,9,6,6 /* Get load/store bit */ @@ -658,7 +669,7 @@ tlbld r3 mfspr r3,SRR1 /* Need to restore CR0 */ mtcrf 0x80,r3 - rfi + rfi STD_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint) STD_EXCEPTION(0x1400, SMI, SMIException) @@ -706,7 +717,22 @@ EXCEPTION_PROLOG b trap_0f_cont #endif /* CONFIG_ALTIVEC */ - + +#ifdef CONFIG_PPC64BRIDGE +DataAccess: + EXCEPTION_PROLOG + b DataAccessCont +InstructionAccess: + EXCEPTION_PROLOG + b InstructionAccessCont +DataSegment: + EXCEPTION_PROLOG + b DataSegmentCont +InstructionSegment: + EXCEPTION_PROLOG + b InstructionSegmentCont +#endif /* CONFIG_PPC64BRIDGE */ + /* * This code finishes saving the registers to the exception frame * and jumps to the appropriate handler for the exception, turning @@ -741,11 +767,12 @@ bgt- stack_ovf /* if r2 < r1 < r2+TASK_STRUCT_SIZE */ lwz r24,0(r23) /* virtual address of handler */ lwz r23,4(r23) /* where to go when done */ + FIX_SRR1(r20,r22) mtspr SRR0,r24 mtspr SRR1,r20 mtlr r23 SYNC - rfi /* jump to handler, enable MMU */ + RFI /* jump to handler, enable MMU */ /* * On kernel stack overflow, load up an initial stack pointer @@ -759,10 +786,11 @@ lis r24,StackOverflow@ha addi r24,r24,StackOverflow@l li r20,MSR_KERNEL + FIX_SRR1(r20,r22) mtspr SRR0,r24 mtspr SRR1,r20 SYNC - rfi + RFI /* * Disable FP for the task which had the FPU previously, @@ -774,8 +802,11 @@ load_up_fpu: mfmsr r5 ori r5,r5,MSR_FP +#ifdef CONFIG_PPC64BRIDGE + clrldi r5,r5,1 /* turn off 64-bit mode */ +#endif /* CONFIG_PPC64BRIDGE */ SYNC - mtmsr r5 /* enable use of fpu now */ + MTMSRD(r5) /* enable use of fpu now */ SYNC /* * For SMP, we don't do lazy FPU switching because it just gets too @@ -827,7 +858,7 @@ REST_2GPRS(22, r21) lwz r21,GPR21(r21) SYNC - rfi + RFI /* * FP unavailable trap from kernel - print a message, but let @@ -919,7 +950,7 @@ REST_2GPRS(22, r21) lwz r21,GPR21(r21) SYNC - rfi + RFI /* * AltiVec unavailable trap from kernel - print a message, but let @@ -1046,7 +1077,7 @@ copy_and_flush: addi r5,r5,-4 addi r6,r6,-4 -4: li r0,8 +4: li r0,CACHELINE_WORDS mtctr r0 3: addi r6,r6,4 /* copy a cache line */ lwzx r0,r6,r4 @@ -1195,27 +1226,6 @@ #endif /* CONFIG_APUS */ #ifdef CONFIG_SMP - .globl __secondary_hold -__secondary_hold: - /* tell the master we're here */ - lis r5,0x4@h - ori r5,r5,0x4@l - stw r3,0(r5) - dcbf 0,r5 -100: - lis r5,0 - dcbi 0,r5 - lwz r4,0(r5) - /* wait until we're told to start */ - cmp 0,r4,r3 - bne 100b - /* our cpu # was at addr 0 - go */ - lis r5,__secondary_start@h - ori r5,r5,__secondary_start@l - tophys(r5,r5) - mtlr r5 - mr r24,r3 /* cpu # */ - blr #ifdef CONFIG_GEMINI .globl __secondary_start_gemini __secondary_start_gemini: @@ -1243,7 +1253,15 @@ .globl __secondary_start __secondary_start: +#ifdef CONFIG_PPC64BRIDGE + mfmsr r0 + clrldi r0,r0,1 /* make sure it's in 32-bit mode */ + sync + MTMSRD(r0) + isync +#else bl enable_caches +#endif /* get current */ lis r2,current_set@h @@ -1264,6 +1282,7 @@ /* ptr to phys current thread */ tophys(r4,r2) addi r4,r4,THREAD /* phys address of our thread_struct */ + CLR_TOP32(r4) mtspr SPRG3,r4 li r3,0 mtspr SPRG2,r3 /* 0 => r1 has kernel sp */ @@ -1275,7 +1294,7 @@ mtspr SRR0,r3 mtspr SRR1,r4 SYNC - rfi + RFI #endif /* CONFIG_SMP */ /* @@ -1333,14 +1352,11 @@ tophys(r6,r6) lwz r6,_SDR1@l(r6) mtspr SDR1,r6 -#ifdef CONFIG_PPC64 - /* clear the v bit in the ASR so we can - * behave as if we have segment registers - * -- Cort - */ - clrldi r6,r6,63 +#ifdef CONFIG_PPC64BRIDGE + /* clear the ASR so we only use the pseudo-segment registers. */ + li r6,0 mtasr r6 -#endif /* CONFIG_PPC64 */ +#endif /* CONFIG_PPC64BRIDGE */ li r0,16 /* load up segment register values */ mtctr r0 /* for context 0 */ lis r3,0x2000 /* Ku = 1, VSID = 0 */ @@ -1349,6 +1365,7 @@ addi r3,r3,1 /* increment VSID */ addis r4,r4,0x1000 /* address of next segment */ bdnz 3b +#ifndef CONFIG_POWER4 /* Load the BAT registers with the values set up by MMU_init. MMU_init takes care of whether we're on a 601 or not. */ mfpvr r3 @@ -1361,17 +1378,29 @@ LOAD_BAT(1,r3,r4,r5) LOAD_BAT(2,r3,r4,r5) LOAD_BAT(3,r3,r4,r5) +#endif /* CONFIG_POWER4 */ blr /* * This is where the main kernel code starts. */ start_here: +#ifndef CONFIG_PPC64BRIDGE bl enable_caches +#endif /* ptr to current */ lis r2,init_task_union@h ori r2,r2,init_task_union@l + /* Set up for using our exception vectors */ + /* ptr to phys current thread */ + tophys(r4,r2) + addi r4,r4,THREAD /* init task's THREAD */ + CLR_TOP32(r4) + mtspr SPRG3,r4 + li r3,0 + mtspr SPRG2,r3 /* 0 => r1 has kernel sp */ + /* Clear out the BSS */ lis r11,_end@ha addi r11,r11,_end@l @@ -1424,10 +1453,11 @@ ori r4,r4,2f@l tophys(r4,r4) li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR) + FIX_SRR1(r3,r5) mtspr SRR0,r4 mtspr SRR1,r3 SYNC - rfi + RFI /* Load up the kernel context */ 2: SYNC /* Force all PTE updates to finish */ @@ -1439,34 +1469,30 @@ #endif bl load_up_mmu - -/* Set up for using our exception vectors */ - /* ptr to phys current thread */ - tophys(r4,r2) - addi r4,r4,THREAD /* init task's THREAD */ - mtspr SPRG3,r4 - li r3,0 - mtspr SPRG2,r3 /* 0 => r1 has kernel sp */ /* Now turn on the MMU for real! */ li r4,MSR_KERNEL + FIX_SRR1(r4,r5) lis r3,start_kernel@h ori r3,r3,start_kernel@l mtspr SRR0,r3 mtspr SRR1,r4 SYNC - rfi /* enable MMU and jump to start_kernel */ + RFI /* * Set up the segment registers for a new context. */ - .globl set_context -set_context: +_GLOBAL(set_context) rlwinm r3,r3,4,8,27 /* VSID = context << 4 */ addis r3,r3,0x6000 /* Set Ks, Ku bits */ li r0,12 /* TASK_SIZE / SEGMENT_SIZE */ mtctr r0 li r4,0 -3: mtsrin r3,r4 +3: +#ifdef CONFIG_PPC64BRIDGE + slbie r4 +#endif /* CONFIG_PPC64BRIDGE */ + mtsrin r3,r4 addi r3,r3,1 /* next VSID */ addis r4,r4,0x1000 /* address of next segment */ bdnz 3b @@ -1511,7 +1537,7 @@ #ifndef CONFIG_GEMINI flush_tlbs: - lis r20, 0x1000 + lis r20, 0x40 1: addic. r20, r20, -0x1000 tlbie r20 blt 1b @@ -1522,30 +1548,79 @@ addi r4, r3, __after_prom_start - _start mfmsr r3 andi. r0,r3,MSR_DR|MSR_IR /* MMU enabled? */ - beq 1f + beqlr ori r3,r3,MSR_DR|MSR_IR xori r3,r3,MSR_DR|MSR_IR mtspr SRR0,r4 mtspr SRR1,r3 sync - rfi -1: blr + RFI #endif -#if 0 /* That's useful debug stuff */ +#ifndef CONFIG_POWER4 +/* + * Use the first pair of BAT registers to map the 1st 16MB + * of RAM to KERNELBASE. From this point on we can't safely + * call OF any more. + */ +initial_bats: + lis r11,KERNELBASE@h +#ifndef CONFIG_PPC64BRIDGE + mfspr r9,PVR + rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ + cmpi 0,r9,1 + bne 4f + ori r11,r11,4 /* set up BAT registers for 601 */ + li r8,0x7f /* valid, block length = 8MB */ + oris r9,r11,0x800000@h /* set up BAT reg for 2nd 8M */ + oris r10,r8,0x800000@h /* set up BAT reg for 2nd 8M */ + mtspr IBAT0U,r11 /* N.B. 601 has valid bit in */ + mtspr IBAT0L,r8 /* lower BAT register */ + mtspr IBAT1U,r9 + mtspr IBAT1L,r10 + isync + blr +#endif /* CONFIG_PPC64BRIDGE */ + +4: tophys(r8,r11) +#ifdef CONFIG_SMP + ori r8,r8,0x12 /* R/W access, M=1 */ +#else + ori r8,r8,2 /* R/W access */ +#endif /* CONFIG_SMP */ +#ifdef CONFIG_APUS + ori r11,r11,BL_8M<<2|0x2 /* set up 8MB BAT registers for 604 */ +#else + ori r11,r11,BL_256M<<2|0x2 /* set up BAT registers for 604 */ +#endif /* CONFIG_APUS */ + +#ifdef CONFIG_PPC64BRIDGE + /* clear out the high 32 bits in the BAT */ + clrldi r11,r11,32 + clrldi r8,r8,32 +#endif /* CONFIG_PPC64BRIDGE */ + mtspr DBAT0L,r8 /* N.B. 6xx (not 601) have valid */ + mtspr DBAT0U,r11 /* bit in upper BAT register */ + mtspr IBAT0L,r8 + mtspr IBAT0U,r11 +#if 0 /* Useful debug code, please leave in for now so I don't have to + * look at docs when I need to setup a BAT ... + */ setup_screen_bat: li r3,0 mtspr DBAT1U,r3 - mtspr IBAT1U,r3 - lis r3, 0x8200 - ori r4,r3,0x2a + lis r3,0xfa00 + CLR_TOP32(r3) + lis r4,0xfa00 + CLR_TOP32(r4) + ori r4,r4,0x2a mtspr DBAT1L,r4 - mtspr IBAT1L,r4 ori r3,r3,(BL_16M<<2)|0x2 /* set up BAT registers for 604 */ mtspr DBAT1U,r3 - mtspr IBAT1U,r3 - blr #endif + isync + blr +#endif /* CONFIG_POWER4 */ #ifdef CONFIG_8260 /* Jump into the system reset for the rom. @@ -1568,7 +1643,7 @@ mtlr r4 blr #endif - + /* * We put a few things here that have to be page-aligned. * This stuff goes at the beginning of the data segment, diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/head_8xx.S linux/arch/ppc/kernel/head_8xx.S --- v2.4.0-test1/linux/arch/ppc/kernel/head_8xx.S Thu May 11 15:30:06 2000 +++ linux/arch/ppc/kernel/head_8xx.S Mon Jun 19 17:59:36 2000 @@ -31,6 +31,13 @@ #include #include +/* XXX need definitions here for 16 byte cachelines on some/all 8xx + -- paulus */ +CACHELINE_BYTES = 32 +LG_CACHELINE_BYTES = 5 +CACHELINE_MASK = 0x1f +CACHELINE_WORDS = 8 + .text .globl _stext _stext: @@ -90,6 +97,9 @@ li r8, 0 mtspr MI_CTR, r8 /* Set instruction control to zero */ lis r8, MD_RESETVAL@h +#ifndef CONFIG_8xx_COPYBACK + oris r8, r8, MD_WTDEF@h +#endif mtspr MD_CTR, r8 /* Set data TLB control */ /* Now map the lower 8 Meg into the TLBs. For this quick hack, @@ -374,6 +384,16 @@ #endif mtspr MD_EPN, r20 /* Have to use MD_EPN for walk, MI_EPN can't */ mfspr r20, M_TWB /* Get level 1 table entry address */ + + /* If we are faulting a kernel address, we have to use the + * kernel page tables. + */ + andi. r21, r20, 0x0800 /* Address >= 0x80000000 */ + beq 3f + lis r21, swapper_pg_dir@h + ori r21, r21, swapper_pg_dir@l + rlwimi r20, r21, 0, 2, 19 +3: lwz r21, 0(r20) /* Get the level 1 entry */ rlwinm. r20, r21,0,0,19 /* Extract page descriptor page address */ beq 2f /* If zero, don't try to find a pte */ @@ -445,6 +465,16 @@ stw r20, 0(r0) stw r21, 4(r0) mfspr r20, M_TWB /* Get level 1 table entry address */ + + /* If we are faulting a kernel address, we have to use the + * kernel page tables. + */ + andi. r21, r20, 0x0800 + beq 3f + lis r21, swapper_pg_dir@h + ori r21, r21, swapper_pg_dir@l + rlwimi r20, r21, 0, 2, 19 +3: lwz r21, 0(r20) /* Get the level 1 entry */ rlwinm. r20, r21,0,0,19 /* Extract page descriptor page address */ beq 2f /* If zero, don't try to find a pte */ @@ -546,6 +576,16 @@ beq 2f mfspr r20, M_TWB /* Get level 1 table entry address */ + + /* If we are faulting a kernel address, we have to use the + * kernel page tables. + */ + andi. r21, r20, 0x0800 + beq 3f + lis r21, swapper_pg_dir@h + ori r21, r21, swapper_pg_dir@l + rlwimi r20, r21, 0, 2, 19 +3: lwz r21, 0(r20) /* Get the level 1 entry */ rlwinm. r20, r21,0,0,19 /* Extract page descriptor page address */ beq 2f /* If zero, bail */ @@ -717,7 +757,7 @@ copy_and_flush: addi r5,r5,-4 addi r6,r6,-4 -4: li r0,8 +4: li r0,CACHELINE_WORDS mtctr r0 3: addi r6,r6,4 /* copy a cache line */ lwzx r0,r6,r4 @@ -901,6 +941,8 @@ */ _GLOBAL(set_context) mtspr M_CASID,r3 /* Update context */ + tophys (r4, r4) + mtspr M_TWB, r4 /* and pgd */ tlbia SYNC blr @@ -948,3 +990,4 @@ .globl cmd_line cmd_line: .space 512 + diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/i8259.c linux/arch/ppc/kernel/i8259.c --- v2.4.0-test1/linux/arch/ppc/kernel/i8259.c Fri Jan 28 15:09:07 2000 +++ linux/arch/ppc/kernel/i8259.c Mon Jun 19 17:59:36 2000 @@ -104,11 +104,6 @@ 0 }; -static void -no_action(int cpl, void *dev_id, struct pt_regs *regs) -{ -} - void __init i8259_init(void) { /* init master interrupt controller */ diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c --- v2.4.0-test1/linux/arch/ppc/kernel/irq.c Thu May 11 15:30:06 2000 +++ linux/arch/ppc/kernel/irq.c Mon Jun 19 17:59:36 2000 @@ -286,10 +286,18 @@ action = action->next; } while ( action ); __cli(); - unmask_irq(irq); + if (irq_desc[irq].handler) { + if (irq_desc[irq].handler->end) + irq_desc[irq].handler->end(irq); + else if (irq_desc[irq].handler->enable) + irq_desc[irq].handler->enable(irq); + } } else { ppc_spurious_interrupts++; - disable_irq( irq ); + printk(KERN_DEBUG "Unhandled interrupt %x, disabled\n", irq); + disable_irq(irq); + if (irq_desc[irq].handler->end) + irq_desc[irq].handler->end(irq); } } @@ -301,6 +309,7 @@ /* every arch is required to have a get_irq -- Cort */ irq = ppc_md.get_irq( regs ); + if ( irq < 0 ) { /* -2 means ignore, already handled */ @@ -313,7 +322,7 @@ goto out; } ppc_irq_dispatch_handler( regs, irq ); - if ( ppc_md.post_irq ) + if (ppc_md.post_irq) ppc_md.post_irq( regs, irq ); out: @@ -769,4 +778,8 @@ continue; register_irq_proc(i); } +} + +void no_action(int irq, void *dev, struct pt_regs *regs) +{ } diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/m8260_setup.c linux/arch/ppc/kernel/m8260_setup.c --- v2.4.0-test1/linux/arch/ppc/kernel/m8260_setup.c Thu May 11 15:30:06 2000 +++ linux/arch/ppc/kernel/m8260_setup.c Mon Jun 19 17:59:36 2000 @@ -167,9 +167,11 @@ bp = (bd_t *)__res; - len += sprintf(len+buffer,"clock\t\t: %dMHz\n" - "bus clock\t: %dMHz\n", + len += sprintf(len+buffer,"core clock\t: %d MHz\n" + "CPM clock\t: %d MHz\n" + "bus clock\t: %d MHz\n", bp->bi_intfreq /*/ 1000000*/, + bp->bi_cpmfreq /*/ 1000000*/, bp->bi_busfreq /*/ 1000000*/); return len; diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S --- v2.4.0-test1/linux/arch/ppc/kernel/misc.S Thu May 11 15:30:06 2000 +++ linux/arch/ppc/kernel/misc.S Mon Jun 19 17:59:36 2000 @@ -22,11 +22,14 @@ #include "ppc_asm.h" #if defined(CONFIG_4xx) || defined(CONFIG_8xx) -CACHE_LINE_SIZE = 16 -LG_CACHE_LINE_SIZE = 4 +#define CACHE_LINE_SIZE 16 +#define LG_CACHE_LINE_SIZE 4 +#elif !defined(CONFIG_PPC64BRIDGE) +#define CACHE_LINE_SIZE 32 +#define LG_CACHE_LINE_SIZE 5 #else -CACHE_LINE_SIZE = 32 -LG_CACHE_LINE_SIZE = 5 +#define CACHE_LINE_SIZE 128 +#define LG_CACHE_LINE_SIZE 7 #endif /* CONFIG_4xx || CONFIG_8xx */ .text @@ -140,12 +143,33 @@ * Flush MMU TLB */ _GLOBAL(_tlbia) +#if defined(CONFIG_SMP) + mfmsr r10 + sync + rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ + mtmsr r0 + SYNC + lis r9,hash_table_lock@h + ori r9,r9,hash_table_lock@l + lwz r8,PROCESSOR(r2) + oris r8,r8,10 +10: lwarx r7,0,r9 + cmpi 0,r7,0 + bne- 10b + stwcx. r8,0,r9 + bne- 10b + eieio +#endif /* CONFIG_SMP */ sync tlbia sync #ifdef CONFIG_SMP tlbsync sync + li r0,0 + stw r0,0(r9) /* clear hash_table_lock */ + mtmsr r10 + SYNC #endif blr @@ -153,11 +177,32 @@ * Flush MMU TLB for a particular address */ _GLOBAL(_tlbie) +#if defined(CONFIG_SMP) + mfmsr r10 + sync + rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ + mtmsr r0 + SYNC + lis r9,hash_table_lock@h + ori r9,r9,hash_table_lock@l + lwz r8,PROCESSOR(r2) + oris r8,r8,11 +10: lwarx r7,0,r9 + cmpi 0,r7,0 + bne- 10b + stwcx. r8,0,r9 + bne- 10b + eieio +#endif /* CONFIG_SMP */ tlbie r3 sync #ifdef CONFIG_SMP tlbsync sync + li r0,0 + stw r0,0(r9) /* clear hash_table_lock */ + mtmsr r10 + SYNC #endif blr @@ -305,6 +350,16 @@ * the destination into cache). This requires that the destination * is cacheable. */ +#define COPY_16_BYTES \ + lwz r6,4(r4); \ + lwz r7,8(r4); \ + lwz r8,12(r4); \ + lwzu r9,16(r4); \ + stw r6,4(r3); \ + stw r7,8(r3); \ + stw r8,12(r3); \ + stwu r9,16(r3) + _GLOBAL(copy_page) li r0,4096/CACHE_LINE_SIZE mtctr r0 @@ -312,22 +367,20 @@ addi r4,r4,-4 li r5,4 1: dcbz r5,r3 - lwz r6,4(r4) - lwz r7,8(r4) - lwz r8,12(r4) - lwzu r9,16(r4) - stw r6,4(r3) - stw r7,8(r3) - stw r8,12(r3) - stwu r9,16(r3) - lwz r6,4(r4) - lwz r7,8(r4) - lwz r8,12(r4) - lwzu r9,16(r4) - stw r6,4(r3) - stw r7,8(r3) - stw r8,12(r3) - stwu r9,16(r3) + COPY_16_BYTES +#if CACHE_LINE_SIZE >= 32 + COPY_16_BYTES +#if CACHE_LINE_SIZE >= 64 + COPY_16_BYTES + COPY_16_BYTES +#if CACHE_LINE_SIZE >= 128 + COPY_16_BYTES + COPY_16_BYTES + COPY_16_BYTES + COPY_16_BYTES +#endif +#endif +#endif bdnz 1b blr @@ -464,7 +517,7 @@ * The *_ns versions don't do byte-swapping. */ _GLOBAL(_insb) - cmpw 0,r5,0 + cmpwi 0,r5,0 mtctr r5 subi r4,r4,1 blelr- @@ -475,7 +528,7 @@ blr _GLOBAL(_outsb) - cmpw 0,r5,0 + cmpwi 0,r5,0 mtctr r5 subi r4,r4,1 blelr- @@ -486,7 +539,7 @@ blr _GLOBAL(_insw) - cmpw 0,r5,0 + cmpwi 0,r5,0 mtctr r5 subi r4,r4,2 blelr- @@ -497,7 +550,7 @@ blr _GLOBAL(_outsw) - cmpw 0,r5,0 + cmpwi 0,r5,0 mtctr r5 subi r4,r4,2 blelr- @@ -508,7 +561,7 @@ blr _GLOBAL(_insl) - cmpw 0,r5,0 + cmpwi 0,r5,0 mtctr r5 subi r4,r4,4 blelr- @@ -519,7 +572,7 @@ blr _GLOBAL(_outsl) - cmpw 0,r5,0 + cmpwi 0,r5,0 mtctr r5 subi r4,r4,4 blelr- @@ -531,7 +584,7 @@ _GLOBAL(ide_insw) _GLOBAL(_insw_ns) - cmpw 0,r5,0 + cmpwi 0,r5,0 mtctr r5 subi r4,r4,2 blelr- @@ -543,7 +596,7 @@ _GLOBAL(ide_outsw) _GLOBAL(_outsw_ns) - cmpw 0,r5,0 + cmpwi 0,r5,0 mtctr r5 subi r4,r4,2 blelr- @@ -554,7 +607,7 @@ blr _GLOBAL(_insl_ns) - cmpw 0,r5,0 + cmpwi 0,r5,0 mtctr r5 subi r4,r4,4 blelr- @@ -565,7 +618,7 @@ blr _GLOBAL(_outsl_ns) - cmpw 0,r5,0 + cmpwi 0,r5,0 mtctr r5 subi r4,r4,4 blelr- @@ -650,6 +703,12 @@ _GLOBAL(_get_PVR) mfspr r3,PVR blr + +#ifdef CONFIG_8xx +_GLOBAL(_get_IMMR) + mfspr r3, 638 + blr +#endif _GLOBAL(_get_HID0) mfspr r3,HID0 diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/mk_defs.c linux/arch/ppc/kernel/mk_defs.c --- v2.4.0-test1/linux/arch/ppc/kernel/mk_defs.c Sat Feb 26 22:31:42 2000 +++ linux/arch/ppc/kernel/mk_defs.c Mon Jun 19 17:59:36 2000 @@ -44,8 +44,9 @@ DEFINE(PGDIR, offsetof(struct thread_struct, pgdir)); DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall)); DEFINE(PT_REGS, offsetof(struct thread_struct, regs)); - DEFINE(PF_TRACESYS, PF_TRACESYS); + DEFINE(PT_TRACESYS, PT_TRACESYS); DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags)); + DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace)); DEFINE(NEED_RESCHED, offsetof(struct task_struct, need_resched)); DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0])); DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr)); diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/open_pic.c linux/arch/ppc/kernel/open_pic.c --- v2.4.0-test1/linux/arch/ppc/kernel/open_pic.c Wed Apr 26 16:34:07 2000 +++ linux/arch/ppc/kernel/open_pic.c Mon Jun 19 17:59:36 2000 @@ -97,10 +97,6 @@ #define check_arg_cpu(cpu) do {} while (0) #endif -void no_action(int ir1, void *dev, struct pt_regs *regs) -{ -} - #ifdef CONFIG_SMP void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs) { @@ -293,7 +289,7 @@ void find_ISUs(void) { -#ifdef CONFIG_PPC64 +#ifdef CONFIG_PPC64BRIDGE /* hardcode this for now since the IBM 260 is the only thing with * a distributed openpic right now. -- Cort */ diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/pmac_time.c linux/arch/ppc/kernel/pmac_time.c --- v2.4.0-test1/linux/arch/ppc/kernel/pmac_time.c Sun Feb 13 19:29:03 2000 +++ linux/arch/ppc/kernel/pmac_time.c Mon Jun 19 17:59:36 2000 @@ -28,6 +28,8 @@ #include "time.h" +extern rwlock_t xtime_lock; + /* Apparently the RTC stores seconds since 1 Jan 1904 */ #define RTC_OFFSET 2082844800 @@ -151,16 +153,21 @@ static int time_sleep_notify(struct pmu_sleep_notifier *self, int when) { static unsigned long time_diff; + unsigned long flags; switch (when) { case PBOOK_SLEEP_NOW: + read_lock_irqsave(&xtime_lock, flags); time_diff = xtime.tv_sec - pmac_get_rtc_time(); + read_unlock_irqrestore(&xtime_lock, flags); break; case PBOOK_WAKE: + write_lock_irqsave(&xtime_lock, flags); xtime.tv_sec = pmac_get_rtc_time() + time_diff; xtime.tv_usec = 0; set_dec(decrementer_count); last_rtc_update = xtime.tv_sec; + write_unlock_irqrestore(&xtime_lock, flags); break; } return PBOOK_SLEEP_OK; diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/ppc_asm.h linux/arch/ppc/kernel/ppc_asm.h --- v2.4.0-test1/linux/arch/ppc/kernel/ppc_asm.h Sun Feb 13 19:29:03 2000 +++ linux/arch/ppc/kernel/ppc_asm.h Mon Jun 19 17:59:36 2000 @@ -73,11 +73,13 @@ /* * This instruction is not implemented on the PPC 603 or 601; however, on * the 403GCX and 405GP tlbia IS defined and tlbie is not. + * All of these instructions exist in the 8xx, they have magical powers, + * and they must be used. */ -#if !defined(CONFIG_4xx) +#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) #define tlbia \ - li r4,128; \ + li r4,1024; \ mtctr r4; \ lis r4,KERNELBASE@h; \ 0: tlbie r4; \ @@ -102,3 +104,25 @@ .align 1; \ .long 0b; \ .previous + +/* + * On 64-bit cpus, we use the rfid instruction instead of rfi, but + * we then have to make sure we preserve the top 32 bits except for + * the 64-bit mode bit, which we clear. + */ +#ifdef CONFIG_PPC64BRIDGE +#define FIX_SRR1(ra, rb) \ + mr rb,ra; \ + mfmsr ra; \ + clrldi ra,ra,1; /* turn off 64-bit mode */ \ + rldimi ra,rb,0,32 +#define RFI .long 0x4c000024 /* rfid instruction */ +#define MTMSRD(r) .long (0x7c000164 + ((r) << 21)) /* mtmsrd */ +#define CLR_TOP32(r) rlwinm (r),(r),0,0,31 /* clear top 32 bits */ + +#else +#define FIX_SRR1(ra, rb) +#define RFI rfi +#define MTMSRD(r) mtmsr r +#define CLR_TOP32(r) +#endif /* CONFIG_PPC64BRIDGE */ diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/ppc_htab.c linux/arch/ppc/kernel/ppc_htab.c --- v2.4.0-test1/linux/arch/ppc/kernel/ppc_htab.c Thu May 11 15:30:06 2000 +++ linux/arch/ppc/kernel/ppc_htab.c Mon Jun 19 17:59:36 2000 @@ -165,7 +165,7 @@ valid = 0; for_each_task(p) { - if ( (ptr->vsid >> 4) == p->mm->context ) + if (p->mm && (ptr->vsid >> 4) == p->mm->context) { valid = 1; break; @@ -565,17 +565,22 @@ if (!first) *p++ = '\t'; val = _get_L2CR(); - p += sprintf(p, "%08x: ", val); - p += sprintf(p, " %s", - (val&0x80000000)?"enabled":"disabled"); - p += sprintf(p,",%sparity",(val&0x40000000)?"":"no "); - p += sprintf(p, ",%s", sizestrings[(val >> 28) & 3]); - p += sprintf(p, ",%s", clockstrings[(val >> 25) & 7]); - p += sprintf(p, ",%s", typestrings[(val >> 23) & 0x2]); - p += sprintf(p,"%s",(val>>22)&1?"":",data only"); - p += sprintf(p,"%s",(val>>20)&1?",ZZ enabled":""); - p += sprintf(p,",%s",(val>>19)&1?"write-through":"copy-back"); - p += sprintf(p,",%sns hold", holdstrings[(val>>16)&3]); + p += sprintf(p, "0x%08x: ", val); + p += sprintf(p, " %s", (val >> 31) & 1 ? "enabled" : + "disabled"); + p += sprintf(p, ", %sparity", (val>>30)&1 ? "" : "no "); + p += sprintf(p, ", %s", sizestrings[(val >> 28) & 3]); + p += sprintf(p, ", %s", clockstrings[(val >> 25) & 7]); + p += sprintf(p, ", %s", typestrings[(val >> 23) & 2]); + p += sprintf(p, "%s", (val>>22)&1 ? ", data only" : ""); + p += sprintf(p, "%s", (val>>20)&1 ? ", ZZ enabled": ""); + p += sprintf(p, ", %s", (val>>19)&1 ? "write-through" : + "copy-back"); + p += sprintf(p, "%s", (val>>18)&1 ? ", testing" : ""); + p += sprintf(p, ", %sns hold",holdstrings[(val>>16)&3]); + p += sprintf(p, "%s", (val>>15)&1 ? ", DLL slow" : ""); + p += sprintf(p, "%s", (val>>14)&1 ? ", diff clock" :""); + p += sprintf(p, "%s", (val>>13)&1 ? ", DLL bypass" :""); p += sprintf(p,"\n"); diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c --- v2.4.0-test1/linux/arch/ppc/kernel/ppc_ksyms.c Tue May 23 15:31:34 2000 +++ linux/arch/ppc/kernel/ppc_ksyms.c Mon Jun 19 17:59:36 2000 @@ -97,12 +97,14 @@ #endif #endif +#if !__INLINE_BITOPS EXPORT_SYMBOL(set_bit); EXPORT_SYMBOL(clear_bit); EXPORT_SYMBOL(change_bit); EXPORT_SYMBOL(test_and_set_bit); EXPORT_SYMBOL(test_and_clear_bit); EXPORT_SYMBOL(test_and_change_bit); +#endif /* __INLINE_BITOPS */ EXPORT_SYMBOL(strcpy); EXPORT_SYMBOL(strncpy); @@ -267,11 +269,13 @@ EXPORT_SYMBOL(decrementer_count); EXPORT_SYMBOL(get_wchan); EXPORT_SYMBOL(console_drivers); +EXPORT_SYMBOL(console_lock); #ifdef CONFIG_XMON EXPORT_SYMBOL(xmon); #endif EXPORT_SYMBOL(down_read_failed); +#if defined(CONFIG_KGDB) || defined(CONFIG_XMON) extern void (*debugger)(struct pt_regs *regs); extern int (*debugger_bpt)(struct pt_regs *regs); extern int (*debugger_sstep)(struct pt_regs *regs); @@ -285,5 +289,7 @@ EXPORT_SYMBOL(debugger_iabr_match); EXPORT_SYMBOL(debugger_dabr_match); EXPORT_SYMBOL(debugger_fault_handler); +#endif EXPORT_SYMBOL(ret_to_user_hook); +EXPORT_SYMBOL(do_softirq); diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c --- v2.4.0-test1/linux/arch/ppc/kernel/process.c Thu May 11 15:30:06 2000 +++ linux/arch/ppc/kernel/process.c Mon Jun 19 17:59:36 2000 @@ -501,6 +501,8 @@ giveup_altivec(current); #endif /* CONFIG_ALTIVEC */ error = do_execve(filename, (char **) a1, (char **) a2, regs); + if (error == 0) + current->ptrace &= ~PT_DTRACE; putname(filename); out: return error; diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c --- v2.4.0-test1/linux/arch/ppc/kernel/prom.c Thu May 11 15:30:06 2000 +++ linux/arch/ppc/kernel/prom.c Mon Jun 19 17:59:36 2000 @@ -29,6 +29,9 @@ #include #include #include +#include +#include +#include #ifdef CONFIG_FB #include @@ -80,7 +83,8 @@ unsigned intr; }; -typedef unsigned long interpret_func(struct device_node *, unsigned long); +typedef unsigned long interpret_func(struct device_node *, unsigned long, + int, int); static interpret_func interpret_pci_props; static interpret_func interpret_dbdma_props; static interpret_func interpret_isa_props; @@ -101,7 +105,7 @@ char *bootpath = 0; char *bootdevice = 0; -unsigned int rtas_data = 0; /* virtual pointer */ +unsigned int rtas_data = 0; /* physical pointer */ unsigned int rtas_entry = 0; /* physical pointer */ unsigned int rtas_size = 0; unsigned int old_rtas = 0; @@ -145,7 +149,7 @@ static unsigned long inspect_node(phandle, struct device_node *, unsigned long, unsigned long, struct device_node ***); static unsigned long finish_node(struct device_node *, unsigned long, - interpret_func *); + interpret_func *, int, int); static unsigned long finish_node_interrupts(struct device_node *, unsigned long); static unsigned long check_display(unsigned long); static int prom_next_node(phandle *); @@ -158,6 +162,7 @@ extern void enter_rtas(void *); extern unsigned long reloc_offset(void); +void phys_call_rtas(int, int, int, ...); extern char cmd_line[512]; /* XXX */ boot_infos_t *boot_infos = 0; /* init it so it's in data segment not bss */ @@ -279,7 +284,267 @@ } } -unsigned long smp_chrp_cpu_nr __initdata = 1; +void +prom_print_hex(unsigned int v) +{ + char buf[16]; + int i, c; + + for (i = 0; i < 8; ++i) { + c = (v >> ((7-i)*4)) & 0xf; + c += (c >= 10)? ('a' - 10): '0'; + buf[i] = c; + } + buf[i] = ' '; + buf[i+1] = 0; + prom_print(buf); +} + +void +prom_print_nl(void) +{ + unsigned long offset = reloc_offset(); + prom_print(RELOC("\n")); +} + +unsigned long smp_chrp_cpu_nr __initdata = 0; + +#ifdef CONFIG_SMP +/* + * With CHRP SMP we need to use the OF to start the other + * processors so we can't wait until smp_boot_cpus (the OF is + * trashed by then) so we have to put the processors into + * a holding pattern controlled by the kernel (not OF) before + * we destroy the OF. + * + * This uses a chunk of high memory, puts some holding pattern + * code there and sends the other processors off to there until + * smp_boot_cpus tells them to do something. We do that by using + * physical address 0x0. The holding pattern checks that address + * until its cpu # is there, when it is that cpu jumps to + * __secondary_start(). smp_boot_cpus() takes care of setting those + * values. + * + * We also use physical address 0x4 here to tell when a cpu + * is in its holding pattern code. + * + * -- Cort + */ +static void +prom_hold_cpus(unsigned long mem) +{ + extern void __secondary_hold(void); + unsigned long i; + int cpu; + phandle node; + unsigned long offset = reloc_offset(); + char type[16], *path; + unsigned int reg; + + /* + * XXX: hack to make sure we're chrp, assume that if we're + * chrp we have a device_type property -- Cort + */ + node = call_prom(RELOC("finddevice"), 1, 1, RELOC("/")); + if ( (int)call_prom(RELOC("getprop"), 4, 1, node, + RELOC("device_type"),type, sizeof(type)) <= 0) + return; + + /* copy the holding pattern code to someplace safe (0) */ + /* the holding pattern is now within the first 0x100 + bytes of the kernel image -- paulus */ + memcpy((void *)0, KERNELBASE + offset, 0x100); + flush_icache_range(0, 0x100); + + /* look for cpus */ + *(unsigned long *)(0x0) = 0; + asm volatile("dcbf 0,%0": : "r" (0) : "memory"); + for (node = 0; prom_next_node(&node); ) { + type[0] = 0; + call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"), + type, sizeof(type)); + if (strcmp(type, RELOC("cpu")) != 0) + continue; + path = (char *) mem; + memset(path, 0, 256); + if ((int) call_prom(RELOC("package-to-path"), 3, 1, + node, path, 255) < 0) + continue; + reg = -1; + call_prom(RELOC("getprop"), 4, 1, node, RELOC("reg"), + ®, sizeof(reg)); + cpu = RELOC(smp_chrp_cpu_nr)++; + RELOC(smp_hw_index)[cpu] = reg; + /* XXX: hack - don't start cpu 0, this cpu -- Cort */ + if (cpu == 0) + continue; + prom_print(RELOC("starting cpu ")); + prom_print(path); + *(ulong *)(0x4) = 0; + call_prom(RELOC("start-cpu"), 3, 0, node, + __pa(__secondary_hold), cpu); + prom_print(RELOC("...")); + for ( i = 0 ; (i < 10000) && (*(ulong *)(0x4) == 0); i++ ) + ; + if (*(ulong *)(0x4) == cpu) + prom_print(RELOC("ok\n")); + else { + prom_print(RELOC("failed: ")); + prom_print_hex(*(ulong *)0x4); + prom_print_nl(); + } + } +} +#endif /* CONFIG_SMP */ + +void +bootx_init(unsigned long r4, unsigned long phys) +{ + boot_infos_t *bi = (boot_infos_t *) r4; + unsigned long space; + unsigned long ptr, x; + char *model; + unsigned long offset = reloc_offset(); + + RELOC(boot_infos) = PTRUNRELOC(bi); + if (!BOOT_INFO_IS_V2_COMPATIBLE(bi)) + bi->logicalDisplayBase = 0; + +#ifdef CONFIG_BOOTX_TEXT + RELOC(g_loc_X) = 0; + RELOC(g_loc_Y) = 0; + RELOC(g_max_loc_X) = (bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) / 8; + RELOC(g_max_loc_Y) = (bi->dispDeviceRect[3] - bi->dispDeviceRect[1]) / 16; + RELOC(disp_bi) = PTRUNRELOC(bi); + + clearscreen(); + + /* Test if boot-info is compatible. Done only in config CONFIG_BOOTX_TEXT since + there is nothing much we can do with an incompatible version, except display + a message and eventually hang the processor... + + I'll try to keep enough of boot-info compatible in the future to always allow + display of this message; + */ + if (!BOOT_INFO_IS_COMPATIBLE(bi)) + prom_print(RELOC(" !!! WARNING - Incompatible version of BootX !!!\n\n\n")); + + prom_welcome(bi, phys); + flushscreen(); +#endif /* CONFIG_BOOTX_TEXT */ + + /* New BootX enters kernel with MMU off, i/os are not allowed + here. This hack will have been done by the boostrap anyway. + */ + if (bi->version < 4) { + /* + * XXX If this is an iMac, turn off the USB controller. + */ + model = (char *) early_get_property + (r4 + bi->deviceTreeOffset, 4, RELOC("model")); + if (model + && (strcmp(model, RELOC("iMac,1")) == 0 + || strcmp(model, RELOC("PowerMac1,1")) == 0)) { + out_le32((unsigned *)0x80880008, 1); /* XXX */ + } + } + + /* Move klimit to enclose device tree, args, ramdisk, etc... */ + if (bi->version < 5) { + space = bi->deviceTreeOffset + bi->deviceTreeSize; + if (bi->ramDisk) + space = bi->ramDisk + bi->ramDiskSize; + } else + space = bi->totalParamsSize; + RELOC(klimit) = PTRUNRELOC((char *) bi + space); + + /* New BootX will have flushed all TLBs and enters kernel with + MMU switched OFF, so this should not be useful anymore. + */ + if (bi->version < 4) { + /* + * Touch each page to make sure the PTEs for them + * are in the hash table - the aim is to try to avoid + * getting DSI exceptions while copying the kernel image. + */ + for (ptr = (KERNELBASE + offset) & PAGE_MASK; + ptr < (unsigned long)bi + space; ptr += PAGE_SIZE) + x = *(volatile unsigned long *)ptr; + } + +#ifdef CONFIG_BOOTX_TEXT + prom_drawstring(RELOC("booting...\n")); + flushscreen(); + RELOC(bootx_text_mapped) = 0; +#endif +} + +#ifdef CONFIG_PPC64BRIDGE +/* + * Set up a hash table with a set of entries in it to map the + * first 64MB of RAM. This is used on 64-bit machines since + * some of them don't have BATs. + * We assume the PTE will fit in the primary PTEG. + */ + +static inline void make_pte(unsigned long htab, unsigned int hsize, + unsigned int va, unsigned int pa, int mode) +{ + unsigned int *pteg; + unsigned int hash, i; + + hash = ((va >> 5) ^ (va >> 21)) & 0x7fff80; + pteg = (unsigned int *)(htab + (hash & (hsize - 1))); + for (i = 0; i < 8; ++i, pteg += 4) { + if ((pteg[1] & 1) == 0) { + pteg[1] = ((va >> 16) & 0xff80) | 1; + pteg[3] = pa | mode; + break; + } + } +} + +extern unsigned long _SDR1; +extern PTE *Hash; +extern unsigned long Hash_size; + +void +prom_alloc_htab(void) +{ + unsigned int hsize; + unsigned long htab; + unsigned int addr; + unsigned long offset = reloc_offset(); + + /* + * Because of OF bugs we can't use the "claim" client + * interface to allocate memory for the hash table. + * This code is only used on 64-bit PPCs, and the only + * 64-bit PPCs at the moment are RS/6000s, and their + * OF is based at 0xc00000 (the 12M point), so we just + * arbitrarily use the 0x800000 - 0xc00000 region for the + * hash table. + * -- paulus. + */ +#ifdef CONFIG_POWER4 + hsize = 4 << 20; /* POWER4 has no BATs */ +#else + hsize = 2 << 20; +#endif /* CONFIG_POWER4 */ + htab = (8 << 20); + RELOC(Hash) = (void *)(htab + KERNELBASE); + RELOC(Hash_size) = hsize; + RELOC(_SDR1) = htab + __ilog2(hsize) - 18; + + /* + * Put in PTEs for the first 64MB of RAM + */ + cacheable_memzero((void *)htab, hsize); + for (addr = 0; addr < 0x4000000; addr += 0x1000) + make_pte(htab, hsize, addr + KERNELBASE, addr, + _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX); +} +#endif /* CONFIG_PPC64BRIDGE */ /* * We enter here early on, when the Open Firmware prom is still @@ -289,11 +554,6 @@ unsigned long prom_init(int r3, int r4, prom_entry pp) { -#ifdef CONFIG_SMP - int i; - phandle node; - char type[16], *path; -#endif int chrp = 0; unsigned long mem; ihandle prom_rtas, prom_mmu, prom_op; @@ -313,82 +573,7 @@ /* If we came here from BootX, clear the screen, * set up some pointers and return. */ if (r3 == 0x426f6f58 && pp == NULL) { - boot_infos_t *bi = (boot_infos_t *) r4; - unsigned long space; - unsigned long ptr, x; - char *model; - - RELOC(boot_infos) = PTRUNRELOC(bi); - if (!BOOT_INFO_IS_V2_COMPATIBLE(bi)) - bi->logicalDisplayBase = 0; - -#ifdef CONFIG_BOOTX_TEXT - RELOC(g_loc_X) = 0; - RELOC(g_loc_Y) = 0; - RELOC(g_max_loc_X) = (bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) / 8; - RELOC(g_max_loc_Y) = (bi->dispDeviceRect[3] - bi->dispDeviceRect[1]) / 16; - RELOC(disp_bi) = PTRUNRELOC(bi); - - clearscreen(); - - /* Test if boot-info is compatible. Done only in config CONFIG_BOOTX_TEXT since - there is nothing much we can do with an incompatible version, except display - a message and eventually hang the processor... - - I'll try to keep enough of boot-info compatible in the future to always allow - display of this message; - */ - if (!BOOT_INFO_IS_COMPATIBLE(bi)) - prom_print(RELOC(" !!! WARNING - Incompatible version of BootX !!!\n\n\n")); - - prom_welcome(bi, phys); - flushscreen(); -#endif /* CONFIG_BOOTX_TEXT */ - - /* New BootX enters kernel with MMU off, i/os are not allowed - here. This hack will have been done by the boostrap anyway. - */ - if (bi->version < 4) { - /* - * XXX If this is an iMac, turn off the USB controller. - */ - model = (char *) early_get_property - (r4 + bi->deviceTreeOffset, 4, RELOC("model")); - if (model - && (strcmp(model, RELOC("iMac,1")) == 0 - || strcmp(model, RELOC("PowerMac1,1")) == 0)) { - out_le32((unsigned *)0x80880008, 1); /* XXX */ - } - } - - /* Move klimit to enclose device tree, args, ramdisk, etc... */ - if (bi->version < 5) { - space = bi->deviceTreeOffset + bi->deviceTreeSize; - if (bi->ramDisk) - space = bi->ramDisk + bi->ramDiskSize; - } else - space = bi->totalParamsSize; - RELOC(klimit) = PTRUNRELOC((char *) bi + space); - - /* New BootX will have flushed all TLBs and enters kernel with - MMU switched OFF, so this should not be useful anymore. - */ - if (bi->version < 4) { - /* - * Touch each page to make sure the PTEs for them - * are in the hash table - the aim is to try to avoid - * getting DSI exceptions while copying the kernel image. - */ - for (ptr = (KERNELBASE + offset) & PAGE_MASK; - ptr < (unsigned long)bi + space; ptr += PAGE_SIZE) - x = *(volatile unsigned long *)ptr; - } - -#ifdef CONFIG_BOOTX_TEXT - prom_print(RELOC("booting...\n")); - flushscreen(); - RELOC(bootx_text_mapped) = 0; -#endif + bootx_init(r4, phys); return phys; } @@ -421,7 +606,8 @@ if (prom_op != (void*)-1) { char model[64]; int sz; - sz = (int)call_prom(RELOC("getprop"), 4, 1, prom_op, RELOC("model"), model, 64); + sz = (int)call_prom(RELOC("getprop"), 4, 1, prom_op, + RELOC("model"), model, 64); if (sz > 0) { char *c; /* hack to skip the ibm chrp firmware # */ @@ -454,62 +640,68 @@ mem = ALIGN(mem + strlen(d) + 1); } - mem = check_display(mem); - - prom_print(RELOC("copying OF device tree...")); - mem = copy_device_tree(mem, mem + (1<<20)); - prom_print(RELOC("done\n")); - - - RELOC(klimit) = (char *) (mem - offset); - prom_rtas = call_prom(RELOC("finddevice"), 1, 1, RELOC("/rtas")); if (prom_rtas != (void *) -1) { + int i, nargs; + struct prom_args prom_args; + RELOC(rtas_size) = 0; call_prom(RELOC("getprop"), 4, 1, prom_rtas, RELOC("rtas-size"), &RELOC(rtas_size), sizeof(rtas_size)); - prom_print(RELOC("instantiating rtas...")); + prom_print(RELOC("instantiating rtas")); if (RELOC(rtas_size) == 0) { RELOC(rtas_data) = 0; } else { /* - * We do _not_ want the rtas_data inside the klimit - * boundry since it'll be squashed when we do the - * relocate of the kernel on chrp right after prom_init() - * in head.S. So, we just pick a spot in memory. - * -- Cort + * Ask OF for some space for RTAS. + * Actually OF has bugs so we just arbitrarily + * use memory at the 6MB point. */ -#if 0 - mem = (mem + 4095) & -4096; - RELOC(rtas_data) = mem + KERNELBASE; - mem += RELOC(rtas_size); -#endif - RELOC(rtas_data) = (6<<20) + KERNELBASE; + RELOC(rtas_data) = 6 << 20; + prom_print(RELOC(" at ")); + prom_print_hex(RELOC(rtas_data)); } prom_rtas = call_prom(RELOC("open"), 1, 1, RELOC("/rtas")); - { - int i, nargs; - struct prom_args prom_args; - nargs = 3; - prom_args.service = RELOC("call-method"); - prom_args.nargs = nargs; - prom_args.nret = 2; - prom_args.args[0] = RELOC("instantiate-rtas"); - prom_args.args[1] = prom_rtas; - prom_args.args[2] = ((void *)(RELOC(rtas_data)-KERNELBASE)); - RELOC(prom)(&prom_args); - if (prom_args.args[nargs] != 0) - i = 0; - else - i = (int)prom_args.args[nargs+1]; - RELOC(rtas_entry) = i; - } + prom_print(RELOC("...")); + nargs = 3; + prom_args.service = RELOC("call-method"); + prom_args.nargs = nargs; + prom_args.nret = 2; + prom_args.args[0] = RELOC("instantiate-rtas"); + prom_args.args[1] = prom_rtas; + prom_args.args[2] = (void *) RELOC(rtas_data); + RELOC(prom)(&prom_args); + if (prom_args.args[nargs] != 0) + i = 0; + else + i = (int)prom_args.args[nargs+1]; + RELOC(rtas_entry) = i; if ((RELOC(rtas_entry) == -1) || (RELOC(rtas_entry) == 0)) prom_print(RELOC(" failed\n")); else prom_print(RELOC(" done\n")); } +#ifdef CONFIG_PPC64BRIDGE + /* + * Find out how much memory we have and allocate a + * suitably-sized hash table. + */ + prom_alloc_htab(); +#endif + +#ifdef CONFIG_SMP + prom_hold_cpus(mem); +#endif + + mem = check_display(mem); + + prom_print(RELOC("copying OF device tree...")); + mem = copy_device_tree(mem, mem + (1<<20)); + prom_print(RELOC("done\n")); + + RELOC(klimit) = (char *) (mem - offset); + /* If we are already running at 0xc0000000, we assume we were loaded by * an OF bootloader which did set a BAT for us. This breaks OF translate * so we force phys to be 0 @@ -542,85 +734,10 @@ } #ifdef CONFIG_BOOTX_TEXT - if (!chrp && RELOC(prom_disp_node) != 0) + if (RELOC(prom_disp_node) != 0) setup_disp_fake_bi(RELOC(prom_disp_node)); #endif -#ifdef CONFIG_SMP - /* - * With CHRP SMP we need to use the OF to start the other - * processors so we can't wait until smp_boot_cpus (the OF is - * trashed by then) so we have to put the processors into - * a holding pattern controlled by the kernel (not OF) before - * we destroy the OF. - * - * This uses a chunk of high memory, puts some holding pattern - * code there and sends the other processors off to there until - * smp_boot_cpus tells them to do something. We do that by using - * physical address 0x0. The holding pattern checks that address - * until its cpu # is there, when it is that cpu jumps to - * __secondary_start(). smp_boot_cpus() takes care of setting those - * values. - * - * We also use physical address 0x4 here to tell when a cpu - * is in its holding pattern code. - * - * -- Cort - */ - { - extern void __secondary_hold(void); - unsigned long i; - char type[16]; - - - /* - * XXX: hack to make sure we're chrp, assume that if we're - * chrp we have a device_type property -- Cort - */ - node = call_prom(RELOC("finddevice"), 1, 1, RELOC("/")); - if ( (int)call_prom(RELOC("getprop"), 4, 1, node, - RELOC("device_type"),type, sizeof(type)) <= 0) - return phys; - - /* copy the holding pattern code to someplace safe (8M) */ - memcpy( (void *)(8<<20), RELOC(__secondary_hold), 0x100 ); - for (i = 8<<20; i < ((8<<20)+0x100); i += 32) - { - asm volatile("dcbf 0,%0" : : "r" (i) : "memory"); - asm volatile("icbi 0,%0" : : "r" (i) : "memory"); - } - } - - /* look for cpus */ - for (node = 0; prom_next_node(&node);) - { - type[0] = 0; - call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"), - type, sizeof(type)); - if (strcmp(type, RELOC("cpu")) != 0) - continue; - path = (char *) mem; - memset(path, 0, 256); - if ((int) call_prom(RELOC("package-to-path"), 3, 1, - node, path, 255) < 0) - continue; - /* XXX: hack - don't start cpu 0, this cpu -- Cort */ - if ( smp_chrp_cpu_nr++ == 0 ) - continue; - prom_print(RELOC("starting cpu ")); - prom_print(path); - *(unsigned long *)(0x4) = 0; - asm volatile("dcbf 0,%0": : "r" (0x4) : "memory"); - call_prom(RELOC("start-cpu"), 3, 0, node, 8<<20, smp_chrp_cpu_nr-1); - for ( i = 0 ; (i < 10000) && - (*(ulong *)(0x4) == (ulong)0); i++ ) - ; - if (*(ulong *)(0x4) == (ulong)smp_chrp_cpu_nr-1 ) - prom_print(RELOC("...ok\n")); - else - prom_print(RELOC("...failed\n")); - } -#endif /* If OpenFirmware version >= 3, then use quiesce call */ if (prom_version >= 3) { prom_print(RELOC("Calling quiesce ...\n")); @@ -631,17 +748,41 @@ #ifdef CONFIG_BOOTX_TEXT if (!chrp && RELOC(disp_bi)) { - RELOC(prom_stdout) = 0; clearscreen(); prom_welcome(PTRRELOC(RELOC(disp_bi)), phys); - prom_print(RELOC("booting...\n")); + prom_drawstring(RELOC("booting...\n")); } RELOC(bootx_text_mapped) = 0; #endif + prom_print(RELOC("returning from prom_init\n")); + RELOC(prom_stdout) = 0; return phys; } +void phys_call_rtas(int service, int nargs, int nret, ...) +{ + va_list list; + union { + unsigned long words[16]; + double align; + } u; + unsigned long offset = reloc_offset(); + void (*rtas)(void *, unsigned long); + int i; + + u.words[0] = service; + u.words[1] = nargs; + u.words[2] = nret; + va_start(list, nret); + for (i = 0; i < nargs; ++i) + u.words[i+3] = va_arg(list, unsigned long); + va_end(list); + + rtas = (void (*)(void *, unsigned long)) RELOC(rtas_entry); + rtas(&u, RELOC(rtas_data)); +} + #ifdef CONFIG_BOOTX_TEXT __init static void prom_welcome(boot_infos_t* bi, unsigned long phys) @@ -650,34 +791,34 @@ unsigned long flags; unsigned long pvr; - prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n")); - prom_print(RELOC("\nstarted at : 0x")); + prom_drawstring(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n")); + prom_drawstring(RELOC("\nstarted at : 0x")); prom_drawhex(phys); - prom_print(RELOC("\nlinked at : 0x")); + prom_drawstring(RELOC("\nlinked at : 0x")); prom_drawhex(KERNELBASE); - prom_print(RELOC("\nframe buffer at : 0x")); + prom_drawstring(RELOC("\nframe buffer at : 0x")); prom_drawhex((unsigned long)bi->dispDeviceBase); - prom_print(RELOC(" (phys), 0x")); + prom_drawstring(RELOC(" (phys), 0x")); prom_drawhex((unsigned long)bi->logicalDisplayBase); - prom_print(RELOC(" (log)")); - prom_print(RELOC("\nklimit : 0x")); - prom_drawhex(RELOC(klimit)); - prom_print(RELOC("\nMSR : 0x")); + prom_drawstring(RELOC(" (log)")); + prom_drawstring(RELOC("\nklimit : 0x")); + prom_drawhex((unsigned long)RELOC(klimit)); + prom_drawstring(RELOC("\nMSR : 0x")); __asm__ __volatile__ ("mfmsr %0" : "=r" (flags)); prom_drawhex(flags); __asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr)); pvr >>= 16; if (pvr > 1) { - prom_print(RELOC("\nHID0 : 0x")); + prom_drawstring(RELOC("\nHID0 : 0x")); __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags)); prom_drawhex(flags); } if (pvr == 8 || pvr == 12) { - prom_print(RELOC("\nICTC : 0x")); + prom_drawstring(RELOC("\nICTC : 0x")); __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags)); prom_drawhex(flags); } - prom_print(RELOC("\n\n")); + prom_drawstring(RELOC("\n\n")); } #endif @@ -822,6 +963,10 @@ call_prom(RELOC("getprop"), 4, 1, dp, RELOC("linebytes"), &pitch, sizeof(pitch)); address = 0; + if (pitch == 1) { + address = 0xfa000000; + pitch = 0x1000; /* for strange IBM display */ + } call_prom(RELOC("getprop"), 4, 1, dp, RELOC("address"), &address, sizeof(address)); if (address == 0) { @@ -987,6 +1132,7 @@ /* All newworld machines now use the interrupt tree */ struct device_node *np = allnodes; + while(np) { if (get_property(np, "interrupt-parent", 0)) { pmac_newworld = 1; @@ -997,7 +1143,7 @@ if (boot_infos == 0 && pmac_newworld) use_of_interrupt_tree = 1; - mem = finish_node(allnodes, mem, NULL); + mem = finish_node(allnodes, mem, NULL, 0, 0); dev_tree_size = mem - (unsigned long) allnodes; klimit = (char *) mem; } @@ -1025,21 +1171,30 @@ __init static unsigned long finish_node(struct device_node *np, unsigned long mem_start, - interpret_func *ifunc) + interpret_func *ifunc, int naddrc, int nsizec) { struct device_node *child; + int *ip; np->name = get_property(np, "name", 0); np->type = get_property(np, "device_type", 0); /* get the device addresses and interrupts */ if (ifunc != NULL) { - mem_start = ifunc(np, mem_start); + mem_start = ifunc(np, mem_start, naddrc, nsizec); } if (use_of_interrupt_tree) { mem_start = finish_node_interrupts(np, mem_start); } + /* Look for #address-cells and #size-cells properties. */ + ip = (int *) get_property(np, "#address-cells", 0); + if (ip != NULL) + naddrc = *ip; + ip = (int *) get_property(np, "#size-cells", 0); + if (ip != NULL) + nsizec = *ip; + /* the f50 sets the name to 'display' and 'compatible' to what we * expect for the name -- Cort */ @@ -1080,7 +1235,8 @@ } for (child = np->child; child != NULL; child = child->sibling) - mem_start = finish_node(child, mem_start, ifunc); + mem_start = finish_node(child, mem_start, ifunc, + naddrc, nsizec); return mem_start; } @@ -1246,7 +1402,8 @@ __init static unsigned long -interpret_pci_props(struct device_node *np, unsigned long mem_start) +interpret_pci_props(struct device_node *np, unsigned long mem_start, + int naddrc, int nsizec) { struct address_range *adr; struct pci_reg_property *pci_addrs; @@ -1329,7 +1486,8 @@ __init static unsigned long -interpret_dbdma_props(struct device_node *np, unsigned long mem_start) +interpret_dbdma_props(struct device_node *np, unsigned long mem_start, + int naddrc, int nsizec) { struct reg_property *rp; struct address_range *adr; @@ -1381,7 +1539,8 @@ __init static unsigned long -interpret_macio_props(struct device_node *np, unsigned long mem_start) +interpret_macio_props(struct device_node *np, unsigned long mem_start, + int naddrc, int nsizec) { struct reg_property *rp; struct address_range *adr; @@ -1450,7 +1609,8 @@ __init static unsigned long -interpret_isa_props(struct device_node *np, unsigned long mem_start) +interpret_isa_props(struct device_node *np, unsigned long mem_start, + int naddrc, int nsizec) { struct isa_reg_property *rp; struct address_range *adr; @@ -1491,21 +1651,24 @@ __init static unsigned long -interpret_root_props(struct device_node *np, unsigned long mem_start) +interpret_root_props(struct device_node *np, unsigned long mem_start, + int naddrc, int nsizec) { - struct reg_property *rp; struct address_range *adr; int i, l, *ip; + unsigned int *rp; + int rpsize = (naddrc + nsizec) * sizeof(unsigned int); - rp = (struct reg_property *) get_property(np, "reg", &l); - if (rp != 0 && l >= sizeof(struct reg_property)) { + rp = (unsigned int *) get_property(np, "reg", &l); + if (rp != 0 && l >= rpsize) { i = 0; adr = (struct address_range *) mem_start; - while ((l -= sizeof(struct reg_property)) >= 0) { + while ((l -= rpsize) >= 0) { adr[i].space = 0; - adr[i].address = rp[i].address; - adr[i].size = rp[i].size; + adr[i].address = rp[naddrc - 1]; + adr[i].size = rp[naddrc + nsizec - 1]; ++i; + rp += naddrc + nsizec; } np->addrs = adr; np->n_addrs = i; @@ -1583,9 +1746,8 @@ int l; for (np = allnodes; np != 0; np = np->allnext) { - char *pname = np->parent ? - (char *)get_property(np->parent, "name", &l) : 0; - if (pname && strcmp(pname, "mac-io") == 0) + if (np->parent == NULL || np->parent->type == NULL + || strcmp(np->parent->type, "pci") != 0) continue; reg = (unsigned int *) get_property(np, "reg", &l); if (reg == 0 || l < sizeof(struct reg_property)) @@ -1781,6 +1943,8 @@ } #endif +spinlock_t rtas_lock = SPIN_LOCK_UNLOCKED; + /* this can be called after setup -- Cort */ __openfirmware int @@ -1813,11 +1977,10 @@ u.words[i+3] = va_arg(list, unsigned long); va_end(list); - save_flags(s); - cli(); - + spin_lock_irqsave(&rtas_lock, s); enter_rtas((void *)__pa(&u)); - restore_flags(s); + spin_unlock_irqrestore(&rtas_lock, s); + if (nret > 1 && outputs != NULL) for (i = 0; i < nret-1; ++i) outputs[i] = u.words[i+nargs+4]; diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/ptrace.c linux/arch/ppc/kernel/ptrace.c --- v2.4.0-test1/linux/arch/ppc/kernel/ptrace.c Tue May 23 15:31:34 2000 +++ linux/arch/ppc/kernel/ptrace.c Mon Jun 19 17:59:36 2000 @@ -89,10 +89,10 @@ lock_kernel(); if (request == PTRACE_TRACEME) { /* are we already being traced? */ - if (current->flags & PF_PTRACED) + if (current->ptrace & PT_PTRACED) goto out; /* set the ptrace bit in the process flags. */ - current->flags |= PF_PTRACED; + current->ptrace |= PT_PTRACED; ret = 0; goto out; } @@ -123,9 +123,9 @@ && !capable(CAP_SYS_PTRACE)) goto out_tsk; /* the same process cannot be attached many times */ - if (child->flags & PF_PTRACED) + if (child->ptrace & PT_PTRACED) goto out_tsk; - child->flags |= PF_PTRACED; + child->ptrace |= PT_PTRACED; write_lock_irq(&tasklist_lock); if (child->p_pptr != current) { @@ -140,7 +140,7 @@ goto out_tsk; } ret = -ESRCH; - if (!(child->flags & PF_PTRACED)) + if (!(child->ptrace & PT_PTRACED)) goto out_tsk; if (child->state != TASK_STOPPED) { if (request != PTRACE_KILL) @@ -175,7 +175,7 @@ if ((addr & 3) || index > PT_FPSCR) break; - if (addr < PT_FPR0) { + if (index < PT_FPR0) { tmp = get_reg(child, (int) index); } else { if (child->thread.regs->msr & MSR_FP) @@ -206,10 +206,10 @@ if ((addr & 3) || index > PT_FPSCR) break; - if (addr == PT_ORIG_R3) + if (index == PT_ORIG_R3) break; - if (addr < PT_FPR0) { - ret = put_reg(child, addr, data); + if (index < PT_FPR0) { + ret = put_reg(child, index, data); } else { if (child->thread.regs->msr & MSR_FP) giveup_fpu(child); @@ -225,9 +225,9 @@ if ((unsigned long) data > _NSIG) break; if (request == PTRACE_SYSCALL) - child->flags |= PF_TRACESYS; + child->ptrace |= PT_TRACESYS; else - child->flags &= ~PF_TRACESYS; + child->ptrace &= ~PT_TRACESYS; child->exit_code = data; /* make sure the single step bit is not set. */ clear_single_step(child); @@ -256,7 +256,7 @@ ret = -EIO; if ((unsigned long) data > _NSIG) break; - child->flags &= ~PF_TRACESYS; + child->ptrace &= ~PT_TRACESYS; set_single_step(child); child->exit_code = data; /* give it a chance to run. */ @@ -269,7 +269,7 @@ ret = -EIO; if ((unsigned long) data > _NSIG) break; - child->flags &= ~(PF_PTRACED|PF_TRACESYS); + child->ptrace &= ~(PT_PTRACED|PT_TRACESYS); child->exit_code = data; write_lock_irq(&tasklist_lock); REMOVE_LINKS(child); @@ -296,8 +296,8 @@ void syscall_trace(void) { - if ((current->flags & (PF_PTRACED|PF_TRACESYS)) - != (PF_PTRACED|PF_TRACESYS)) + if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) + != (PT_PTRACED|PT_TRACESYS)) return; current->exit_code = SIGTRAP; current->state = TASK_STOPPED; diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c --- v2.4.0-test1/linux/arch/ppc/kernel/setup.c Tue May 23 15:31:34 2000 +++ linux/arch/ppc/kernel/setup.c Mon Jun 19 17:59:36 2000 @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef CONFIG_8xx #include #include @@ -130,6 +131,14 @@ }; /* + * These are used in binfmt_elf.c to put aux entries on the stack + * for each elf executable being started. + */ +int dcache_bsize; +int icache_bsize; +int ucache_bsize; + +/* * I really need to add multiple-console support... -- Cort */ int __init pmac_display_supported(char *name) @@ -275,7 +284,11 @@ } break; case 0x000C: - len += sprintf(len+buffer, "7400 (G4)\n"); + len += sprintf(len+buffer, "7400 (G4"); +#ifdef CONFIG_ALTIVEC + len += sprintf(len+buffer, ", altivec enabled"); +#endif /* CONFIG_ALTIVEC */ + len += sprintf(len+buffer, ")\n"); break; case 0x0020: len += sprintf(len+buffer, "403G"); @@ -288,6 +301,15 @@ break; } break; + case 0x0035: + len += sprintf(len+buffer, "POWER4\n"); + break; + case 0x0040: + len += sprintf(len+buffer, "POWER3 (630)\n"); + break; + case 0x0041: + len += sprintf(len+buffer, "POWER3 (630+)\n"); + break; case 0x0050: len += sprintf(len+buffer, "8xx\n"); break; @@ -458,7 +480,6 @@ intuit_machine_type(); #endif /* CONFIG_MACH_SPECIFIC */ finish_device_tree(); - /* * If we were booted via quik, r3 points to the physical * address of the command-line parameters. @@ -494,6 +515,8 @@ #ifdef CONFIG_BLK_DEV_INITRD if (r3 && r4 && r4 != 0xdeadbeef) { + if (r3 < KERNELBASE) + r3 += KERNELBASE; initrd_start = r3; initrd_end = r3 + r4; ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); @@ -574,7 +597,7 @@ } __max_memory = maxmem; } - + /* this is for modules since _machine can be a define -- Cort */ ppc_md.ppc_machine = _machine; @@ -684,6 +707,24 @@ breakpoint(); #endif + /* + * Set cache line size based on type of cpu as a default. + * Systems with OF can look in the properties on the cpu node(s) + * for a possibly more accurate value. + */ + dcache_bsize = icache_bsize = 32; /* most common value */ + switch (_get_PVR() >> 16) { + case 1: /* 601, with unified cache */ + ucache_bsize = 32; + break; + /* XXX need definitions in here for 8xx etc. */ + case 0x40: + case 0x41: + case 0x35: /* 64-bit POWER3, POWER3+, POWER4 */ + dcache_bsize = icache_bsize = 128; + break; + } + /* reboot on panic */ panic_timeout = 180; @@ -779,7 +820,7 @@ for (i = 0; i < 26; i++) id->words130_155[i] = __le16_to_cpu(id->words130_155[i]); id->word156 = __le16_to_cpu(id->word156); - for (i = 0; i < 4; i++) + for (i = 0; i < 3; i++) id->words157_159[i] = __le16_to_cpu(id->words157_159[i]); for (i = 0; i < 96; i++) id->words160_255[i] = __le16_to_cpu(id->words160_255[i]); diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/signal.c linux/arch/ppc/kernel/signal.c --- v2.4.0-test1/linux/arch/ppc/kernel/signal.c Mon Jun 19 16:31:57 2000 +++ linux/arch/ppc/kernel/signal.c Mon Jun 19 17:59:36 2000 @@ -411,7 +411,7 @@ if (!signr) break; - if ((current->flags & PF_PTRACED) && signr != SIGKILL) { + if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { /* Let the debugger run. */ current->exit_code = signr; current->state = TASK_STOPPED; diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c --- v2.4.0-test1/linux/arch/ppc/kernel/smp.c Sat Feb 26 22:31:42 2000 +++ linux/arch/ppc/kernel/smp.c Mon Jun 19 17:59:36 2000 @@ -53,6 +53,9 @@ unsigned int prof_counter[NR_CPUS]; cycles_t cacheflush_time; +/* this has to go in the data section because it is accessed from prom_init */ +int smp_hw_index[NR_CPUS] = {0}; + /* all cpu mappings are 1-1 -- Cort */ volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; @@ -238,6 +241,7 @@ case _MACH_chrp: case _MACH_prep: case _MACH_gemini: +#ifndef CONFIG_POWER4 /* make sure we're sending something that translates to an IPI */ if ( msg > 0x3 ) break; @@ -254,6 +258,18 @@ openpic_cause_IPI(smp_processor_id(), msg, 1<mm->mmap->vm_page_prot = PAGE_SHARED; - current->mm->mmap->vm_start = PAGE_OFFSET; - current->mm->mmap->vm_end = init_mm.mmap->vm_end; -#endif cpu_callin_map[current->processor] = 1; + +#ifndef CONFIG_POWER4 /* * Each processor has to do this and this is the best * place to stick it for now. * -- Cort */ - if ( _machine & (_MACH_gemini|_MACH_chrp|_MACH_prep) ) + if (OpenPIC && _machine & (_MACH_gemini|_MACH_chrp|_MACH_prep)) do_openpic_setup_cpu(); +#else + xics_setup_cpu(); +#endif /* CONFIG_POWER4 */ #ifdef CONFIG_GEMINI if ( _machine == _MACH_gemini ) gemini_init_l2(); diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c --- v2.4.0-test1/linux/arch/ppc/kernel/time.c Tue May 23 15:31:34 2000 +++ linux/arch/ppc/kernel/time.c Mon Jun 19 17:59:36 2000 @@ -50,6 +50,7 @@ /* keep track of when we need to update the rtc */ time_t last_rtc_update = 0; +extern rwlock_t xtime_lock; /* The decrementer counts down by 128 every 128ns on a 601. */ #define DECREMENTER_COUNT_601 (1000000000 / HZ) @@ -69,6 +70,7 @@ int timer_interrupt(struct pt_regs * regs) { int dval, d; + unsigned long flags; unsigned long cpu = smp_processor_id(); hardirq_enter(cpu); @@ -102,7 +104,6 @@ while ((d = get_dec()) == dval) ; asm volatile("mftb %0" : "=r" (last_tb) ); - /* * Don't play catchup between the call to time_init() * and sti() in init/main.c. @@ -122,6 +123,7 @@ /* * update the rtc when needed */ + read_lock_irqsave(&xtime_lock, flags); if ( (time_status & STA_UNSYNC) && ((xtime.tv_sec > last_rtc_update + 60) || (xtime.tv_sec < last_rtc_update)) ) @@ -132,6 +134,7 @@ /* do it again in 60 s */ last_rtc_update = xtime.tv_sec; } + read_unlock_irqrestore(&xtime_lock, flags); } #ifdef CONFIG_SMP smp_local_timer_interrupt(regs); @@ -153,17 +156,18 @@ save_flags(flags); cli(); + read_lock_irqsave(&xtime_lock, flags); *tv = xtime; + read_unlock_irqrestore(&xtime_lock, flags); /* XXX we don't seem to have the decrementers synced properly yet */ #ifndef CONFIG_SMP asm volatile("mftb %0" : "=r" (diff) ); diff -= last_tb; - tv->tv_usec += diff * count_period_num / count_period_den; tv->tv_sec += tv->tv_usec / 1000000; tv->tv_usec = tv->tv_usec % 1000000; #endif - + restore_flags(flags); } @@ -177,8 +181,10 @@ frac_tick = tv->tv_usec % (1000000 / HZ); save_flags(flags); cli(); + write_lock_irqsave(&xtime_lock, flags); xtime.tv_sec = tv->tv_sec; xtime.tv_usec = tv->tv_usec - frac_tick; + write_unlock_irqrestore(&xtime_lock, flags); set_dec(frac_tick * count_period_den / count_period_num); time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; @@ -191,6 +197,7 @@ void __init time_init(void) { + unsigned long flags; if (ppc_md.time_init != NULL) { ppc_md.time_init(); @@ -205,8 +212,10 @@ ppc_md.calibrate_decr(); } - xtime.tv_sec = ppc_md.get_rtc_time(); - xtime.tv_usec = 0; + write_lock_irqsave(&xtime_lock, flags); + xtime.tv_sec = ppc_md.get_rtc_time(); + xtime.tv_usec = 0; + write_unlock_irqrestore(&xtime_lock, flags); set_dec(decrementer_count); /* allow setting the time right away */ diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/xics.c linux/arch/ppc/kernel/xics.c --- v2.4.0-test1/linux/arch/ppc/kernel/xics.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/kernel/xics.c Mon Jun 19 17:59:36 2000 @@ -0,0 +1,214 @@ +/* + * arch/ppc/kernel/xics.c + * + * Copyright 2000 IBM Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include "i8259.h" +#include "xics.h" + +void xics_enable_irq(u_int irq); +void xics_disable_irq(u_int irq); +void xics_mask_and_ack_irq(u_int irq); +void xics_end_irq(u_int irq); + +struct hw_interrupt_type xics_pic = { + " XICS ", + NULL, + NULL, + xics_enable_irq, + xics_disable_irq, + xics_mask_and_ack_irq, + xics_end_irq +}; + +struct hw_interrupt_type xics_8259_pic = { + " XICS/8259", + NULL, + NULL, + NULL, + NULL, + xics_mask_and_ack_irq, + NULL +}; + +#define XICS_IPI 2 +#define XICS_IRQ_8259_CASCADE 0x2c +#define XICS_IRQ_OFFSET 16 +#define XICS_IRQ_SPURIOUS 0 + +#define DEFAULT_SERVER 0 +#define DEFAULT_PRIORITY 0 + +struct xics_ipl { + union { + u32 word; + u8 bytes[4]; + } xirr_poll; + union { + u32 word; + u8 bytes[4]; + } xirr; + u32 dummy; + union { + u32 word; + u8 bytes[4]; + } qirr; +}; + +struct xics_info { + volatile struct xics_ipl * per_cpu[NR_CPUS]; +}; + +struct xics_info xics_info; + +#define xirr_info(n_cpu) (xics_info.per_cpu[n_cpu]->xirr.word) +#define cppr_info(n_cpu) (xics_info.per_cpu[n_cpu]->xirr.bytes[0]) +#define poll_info(n_cpu) (xics_info.per_cpu[n_cpu]->xirr_poll.word) +#define qirr_info(n_cpu) (xics_info.per_cpu[n_cpu]->qirr.bytes[0]) + +void +xics_enable_irq( + u_int irq + ) +{ + int status; + int call_status; + + irq -= XICS_IRQ_OFFSET; + if (irq == XICS_IPI) + return; + call_status = call_rtas("ibm,set-xive", 3, 1, (ulong*)&status, + irq, DEFAULT_SERVER, DEFAULT_PRIORITY); + if( call_status != 0 ) { + printk("xics_enable_irq: irq=%x: call_rtas failed; retn=%x, status=%x\n", + irq, call_status, status); + return; + } +} + +void +xics_disable_irq( + u_int irq + ) +{ + int status; + int call_status; + + irq -= XICS_IRQ_OFFSET; + call_status = call_rtas("ibm,int-off", 1, 1, (ulong*)&status, irq); + if( call_status != 0 ) { + printk("xics_disable_irq: irq=%x: call_rtas failed, retn=%x\n", + irq, call_status); + return; + } +} + +void +xics_end_irq( + u_int irq + ) +{ + int cpu = smp_processor_id(); + + cppr_info(cpu) = 0; /* actually the value overwritten by ack */ + xirr_info(cpu) = (0xff<<24) | (irq-XICS_IRQ_OFFSET); +} + +void +xics_mask_and_ack_irq( + u_int irq + ) +{ + int cpu = smp_processor_id(); + + if( irq < XICS_IRQ_OFFSET ) { + i8259_pic.ack(irq); + xirr_info(cpu) = (0xff<<24) | XICS_IRQ_8259_CASCADE; + } + else { + cppr_info(cpu) = 0xff; + } +} + +int +xics_get_irq(struct pt_regs *regs) +{ + u_int cpu = smp_processor_id(); + u_int vec; + int irq; + + vec = xirr_info(cpu); + /* (vec >> 24) == old priority */ + vec &= 0x00ffffff; + /* for sanity, this had better be < NR_IRQS - 16 */ + if( vec == XICS_IRQ_8259_CASCADE ) + irq = i8259_irq(cpu); + else if( vec == XICS_IRQ_SPURIOUS ) + irq = -1; + else + irq = vec + XICS_IRQ_OFFSET; + return irq; +} + +#ifdef CONFIG_SMP +void xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs) +{ + qirr_info(smp_processor_id()) = 0xff; + smp_message_recv(MSG_RESCHEDULE); +} + +void xics_cause_IPI(int cpu) +{ + qirr_info(cpu) = 0; +} + +void xics_setup_cpu(void) +{ + int cpu = smp_processor_id(); + + cppr_info(cpu) = 0xff; +} +#endif /* CONFIG_SMP */ + +void +xics_init_IRQ( void ) +{ + int i; + extern unsigned long smp_chrp_cpu_nr; + +#ifdef CONFIG_SMP + for (i = 0; i < smp_chrp_cpu_nr; ++i) + xics_info.per_cpu[i] = + ioremap(0xfe000000 + smp_hw_index[i] * 0x1000, 0x20); +#else + xics_info.per_cpu[0] = ioremap(0xfe000000, 0x20); +#endif /* CONFIG_SMP */ + xics_8259_pic.enable = i8259_pic.enable; + xics_8259_pic.disable = i8259_pic.disable; + for (i = 0; i < 16; ++i) + irq_desc[i].handler = &xics_8259_pic; + for (; i < NR_IRQS; ++i) + irq_desc[i].handler = &xics_pic; + + cppr_info(0) = 0xff; + if (request_irq(XICS_IRQ_8259_CASCADE + XICS_IRQ_OFFSET, no_action, + 0, "8259 cascade", 0)) + printk(KERN_ERR "xics_init_IRQ: couldn't get 8259 cascade\n"); + i8259_init(); + +#ifdef CONFIG_SMP + request_irq(XICS_IPI + XICS_IRQ_OFFSET, xics_ipi_action, 0, "IPI", 0); +#endif +} diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/xics.h linux/arch/ppc/kernel/xics.h --- v2.4.0-test1/linux/arch/ppc/kernel/xics.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/kernel/xics.h Mon Jun 19 17:59:36 2000 @@ -0,0 +1,23 @@ +/* + * arch/ppc/kernel/xics.h + * + * Copyright 2000 IBM Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _PPC_KERNEL_XICS_H +#define _PPC_KERNEL_XICS_H + +#include "local_irq.h" + +extern struct hw_interrupt_type xics_pic; +extern struct hw_interrupt_type xics_8259_pic; + +void xics_init_IRQ(void); +int xics_get_irq(struct pt_regs *); + +#endif /* _PPC_KERNEL_XICS_H */ diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/mbxboot/Makefile linux/arch/ppc/mbxboot/Makefile --- v2.4.0-test1/linux/arch/ppc/mbxboot/Makefile Tue May 23 15:31:34 2000 +++ linux/arch/ppc/mbxboot/Makefile Mon Jun 19 17:59:36 2000 @@ -28,14 +28,14 @@ TFTPIMAGE=/tftpboot/zImage.embedded ifdef CONFIG_8xx -ZLINKFLAGS = -T vmlinux.lds -Ttext 0x00180000 -OBJECTS := head.o misc.o ../coffboot/zlib.o m8xx_tty.o gzimage.o rdimage.o +ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00180000 +OBJECTS := head.o misc.o ../coffboot/zlib.o m8xx_tty.o CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin -DCONFIG_8xx endif ifdef CONFIG_8260 -ZLINKFLAGS = -T vmlinux.lds -Ttext 0x00400000 -OBJECTS := head_8260.o misc.o ../coffboot/zlib.o m8260_tty.o embed_config.o gzimage.o rdimage.o +ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00400000 +OBJECTS := head_8260.o misc.o ../coffboot/zlib.o m8260_tty.o embed_config.o CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin -DCONFIG_8260 endif @@ -61,32 +61,21 @@ all: zImage zvmlinux.initrd: zvmlinux -# -# Build the boot loader images -# - $(OBJCOPY) $(OBJCOPY_ARGS) -R .gzimage gzimage.o - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ - --add-section=.gzimage=../coffboot/vmlinux.gz \ - --set-section-flags=.gzimage=alloc,load,readonly,data \ - gzimage.o - $(OBJCOPY) $(OBJCOPY_ARGS) -R .rdimage rdimage.o + $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp1 $(OBJECTS) $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ - --add-section=.rdimage=ramdisk.image.gz \ - --set-section-flags=.rdimage=alloc,load,readonly,data \ - rdimage.o - $(LD) $(ZLINKFLAGS) -o $@ $(OBJECTS) -# -# Compute the sizes/offsets for the final image, and rebuild with these values. -# - $(CC) $(CFLAGS) \ - -DINITRD_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd .rdimage` \ - -DINITRD_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd .rdimage` \ - -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd .gzimage` \ - -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd .gzimage` \ + --add-section=initrd=ramdisk.image.gz \ + --add-section=image=../coffboot/vmlinux.gz \ + zvmlinux.initrd.tmp1 zvmlinux.initrd1 + $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd1 initrd` \ + -DINITRD_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd1 initrd` \ + -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd1 image` \ + -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd1 image` \ -c -o misc.o misc.c - $(LD) $(ZLINKFLAGS) -o $@ $(OBJECTS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment $@ - $(OBJDUMP) -h $@ + $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=initrd=ramdisk.image.gz \ + --add-section=image=../coffboot/vmlinux.gz \ + zvmlinux.initrd.tmp $@ zImage: zvmlinux ln -sf zvmlinux zImage @@ -96,27 +85,23 @@ zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz # -# Build the boot loader images -# -# - $(OBJCOPY) $(OBJCOPY_ARGS) -R .gzimage gzimage.o - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ - --add-section=.gzimage=../coffboot/vmlinux.gz \ - --set-section-flags=.gzimage=alloc,load,readonly,data \ - gzimage.o - $(LD) $(ZLINKFLAGS) -o $@ $(OBJECTS) -# -# Compute the sizes/offsets for the final image, and rebuild with these values. +# build the boot loader image and then compute the offset into it +# for the kernel image # - $(CC) $(CFLAGS) \ - -DINITRD_OFFSET=0 \ - -DINITRD_SIZE=0 \ - -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux .gzimage` \ - -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux .gzimage` \ + $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \ + zvmlinux.tmp $@ +# +# then with the offset rebuild the bootloader so we know where the kernel is +# + $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \ + -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux image` \ + -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux image` \ -c -o misc.o misc.c - $(LD) $(ZLINKFLAGS) -o $@ $(OBJECTS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment $@ - $(OBJDUMP) -h $@ + $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \ + zvmlinux.tmp $@ + rm zvmlinux.tmp znetboot : zImage cp zImage $(TFTPIMAGE) diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/mbxboot/embed_config.c linux/arch/ppc/mbxboot/embed_config.c --- v2.4.0-test1/linux/arch/ppc/mbxboot/embed_config.c Tue May 23 15:31:34 2000 +++ linux/arch/ppc/mbxboot/embed_config.c Mon Jun 19 17:59:36 2000 @@ -231,17 +231,17 @@ u_char *cp; int i; -#if 1 +#if 0 /* This is actually provided by my boot rom. I have it * here for those people that may load the kernel with * a JTAG/COP tool and not the rom monitor. */ - bd->bi_baudrate = 19200; - bd->bi_intfreq = 165; - bd->bi_busfreq = 33; - bd->bi_cpmfreq = 132; - bd->bi_brgfreq = bd->bi_cpmfreq / 2; /* BRGCLK = (CPM*2/4) */ - bd->bi_memsize = 16 * 1024 * 1024; + bd->bi_baudrate = 115200; + bd->bi_intfreq = 200; + bd->bi_busfreq = 66; + bd->bi_cpmfreq = 66; + bd->bi_brgfreq = 33; + bd->bi_memsize = 16 * 1024 * 1024; #endif cp = (u_char *)def_enet_addr; diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/mbxboot/head_8260.S linux/arch/ppc/mbxboot/head_8260.S --- v2.4.0-test1/linux/arch/ppc/mbxboot/head_8260.S Tue May 23 15:31:34 2000 +++ linux/arch/ppc/mbxboot/head_8260.S Mon Jun 19 17:59:36 2000 @@ -101,6 +101,11 @@ subi r1,r1,256 li r2,0x000F /* Mask pointer to 16-byte boundary */ andc r1,r1,r2 + + /* Speed us up a little. + */ + bl flush_instruction_cache + /* Run loader */ mr r3,r8 /* Load point */ mr r4,r7 /* Program length */ diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/mbxboot/m8260_tty.c linux/arch/ppc/mbxboot/m8260_tty.c --- v2.4.0-test1/linux/arch/ppc/mbxboot/m8260_tty.c Thu May 11 15:30:06 2000 +++ linux/arch/ppc/mbxboot/m8260_tty.c Mon Jun 19 17:59:36 2000 @@ -72,8 +72,8 @@ */ up->smc_rbase = dpaddr; up->smc_tbase = dpaddr+sizeof(cbd_t); - up->smc_rfcr = SMC_EB; - up->smc_tfcr = SMC_EB; + up->smc_rfcr = CPMFCR_EB; + up->smc_tfcr = CPMFCR_EB; up->smc_brklen = 0; up->smc_brkec = 0; up->smc_brkcr = 0; diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/mbxboot/mbxtty.c linux/arch/ppc/mbxboot/mbxtty.c --- v2.4.0-test1/linux/arch/ppc/mbxboot/mbxtty.c Fri Mar 19 10:50:03 1999 +++ linux/arch/ppc/mbxboot/mbxtty.c Wed Dec 31 16:00:00 1969 @@ -1,201 +0,0 @@ - - -/* Minimal serial functions needed to send messages out the serial - * port on the MBX console. - * - * The MBX uxes SMC1 for the serial port. We reset the port and use - * only the first BD that EPPC-Bug set up as a character FIFO. - * - * Later versions (at least 1.4, maybe earlier) of the MBX EPPC-Bug - * use COM1 instead of SMC1 as the console port. This kinda sucks - * for the rest of the kernel, so here we force the use of SMC1 again. - * I f**ked around for a day trying to figure out how to make EPPC-Bug - * use SMC1, but gave up and decided to fix it here. - */ -#include -#include -#ifdef CONFIG_MBX -#include -#endif -#ifdef CONFIG_FADS -#include -#endif -#include "../8xx_io/commproc.h" - -#ifdef CONFIG_MBX -#define MBX_CSR1 ((volatile u_char *)0xfa100000) -#define CSR1_COMEN (u_char)0x02 -#endif - -static cpm8xx_t *cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm); - -void -serial_init(bd_t *bd) -{ - volatile smc_t *sp; - volatile smc_uart_t *up; - volatile cbd_t *tbdf, *rbdf; - volatile cpm8xx_t *cp; - uint dpaddr, memaddr; - - cp = cpmp; - sp = (smc_t*)&(cp->cp_smc[0]); - up = (smc_uart_t *)&cp->cp_dparam[PROFF_SMC1]; - - /* Disable transmitter/receiver. - */ - sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); - -#ifdef CONFIG_MBX - if (*MBX_CSR1 & CSR1_COMEN) { - /* COM1 is enabled. Initialize SMC1 and use it for - * the console port. - */ - - /* Enable SDMA. - */ - ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sdcr = 1; - - /* Use Port B for SMCs instead of other functions. - */ - cp->cp_pbpar |= 0x00000cc0; - cp->cp_pbdir &= ~0x00000cc0; - cp->cp_pbodr &= ~0x00000cc0; - - /* Allocate space for two buffer descriptors in the DP ram. - * For now, this address seems OK, but it may have to - * change with newer versions of the firmware. - */ - dpaddr = 0x0800; - - /* Grab a few bytes from the top of memory. EPPC-Bug isn't - * running any more, so we can do this. - */ - memaddr = (bd->bi_memsize - 32) & ~15; - - /* Set the physical address of the host memory buffers in - * the buffer descriptors. - */ - rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr]; - rbdf->cbd_bufaddr = memaddr; - rbdf->cbd_sc = 0; - tbdf = rbdf + 1; - tbdf->cbd_bufaddr = memaddr+4; - tbdf->cbd_sc = 0; - - /* Set up the uart parameters in the parameter ram. - */ - up->smc_rbase = dpaddr; - up->smc_tbase = dpaddr+sizeof(cbd_t); - up->smc_rfcr = SMC_EB; - up->smc_tfcr = SMC_EB; - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; - - /* Mask all interrupts and remove anything pending. - */ - sp->smc_smcm = 0; - sp->smc_smce = 0xff; - - /* Set up the baud rate generator. - * See 8xx_io/commproc.c for details. - */ - cp->cp_simode = 0x10000000; - cp->cp_brgc1 = - ((((bd->bi_intfreq * 1000000)/16) / 9600) << 1) | CPM_BRG_EN; - - /* Enable SMC1 for console output. - */ - *MBX_CSR1 &= ~CSR1_COMEN; - } - else { -#endif - /* SMC1 is used as console port. - */ - tbdf = (cbd_t *)&cp->cp_dpmem[up->smc_tbase]; - rbdf = (cbd_t *)&cp->cp_dpmem[up->smc_rbase]; - - /* Issue a stop transmit, and wait for it. - */ - cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC1, - CPM_CR_STOP_TX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); -#ifdef CONFIG_MBX - } -#endif - - /* Make the first buffer the only buffer. - */ - tbdf->cbd_sc |= BD_SC_WRAP; - rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; - - /* Single character receive. - */ - up->smc_mrblr = 1; - up->smc_maxidl = 0; - - /* Initialize Tx/Rx parameters. - */ - cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC1, CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); - - /* Enable transmitter/receiver. - */ - sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; -} - -void -serial_putchar(const char c) -{ - volatile cbd_t *tbdf; - volatile char *buf; - volatile smc_uart_t *up; - - up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC1]; - tbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase]; - - /* Wait for last character to go. - */ - buf = (char *)tbdf->cbd_bufaddr; - while (tbdf->cbd_sc & BD_SC_READY); - - *buf = c; - tbdf->cbd_datlen = 1; - tbdf->cbd_sc |= BD_SC_READY; -} - -char -serial_getc() -{ - volatile cbd_t *rbdf; - volatile char *buf; - volatile smc_uart_t *up; - char c; - - up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC1]; - rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase]; - - /* Wait for character to show up. - */ - buf = (char *)rbdf->cbd_bufaddr; - while (rbdf->cbd_sc & BD_SC_EMPTY); - c = *buf; - rbdf->cbd_sc |= BD_SC_EMPTY; - - return(c); -} - -int -serial_tstc() -{ - volatile cbd_t *rbdf; - volatile smc_uart_t *up; - - up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC1]; - rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase]; - - return(!(rbdf->cbd_sc & BD_SC_EMPTY)); -} diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c --- v2.4.0-test1/linux/arch/ppc/mm/fault.c Tue May 23 15:31:34 2000 +++ linux/arch/ppc/mm/fault.c Mon Jun 19 17:59:37 2000 @@ -238,11 +238,17 @@ /* The pgtable.h claims some functions generically exist, but I * can't find them...... */ -pte_t *find_pte(struct mm_struct *mm, unsigned long address) +pte_t *va_to_pte(unsigned long address) { pgd_t *dir; pmd_t *pmd; pte_t *pte; + struct mm_struct *mm; + + if (address < TASK_SIZE) + mm = current->mm; + else + mm = &init_mm; dir = pgd_offset(mm, address & PAGE_MASK); if (dir) { @@ -267,7 +273,7 @@ { pte_t *pte; - pte = find_pte(current->mm, address); + pte = va_to_pte(address); if (pte) return(((unsigned long)(pte_val(*pte)) & PAGE_MASK) | (address & ~(PAGE_MASK-1))); return (0); diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c --- v2.4.0-test1/linux/arch/ppc/mm/init.c Tue May 23 15:31:34 2000 +++ linux/arch/ppc/mm/init.c Mon Jun 19 17:59:37 2000 @@ -94,6 +94,7 @@ extern int num_memory; extern struct mem_info memory[]; extern boot_infos_t *boot_infos; +extern unsigned int rtas_data, rtas_size; #ifndef CONFIG_SMP struct pgtable_cache_struct quicklists; #endif @@ -116,21 +117,26 @@ #endif /* CONFIG_8260 */ static void mapin_ram(void); void map_page(unsigned long va, unsigned long pa, int flags); +void set_phys_avail(struct mem_pieces *mp); extern void die_if_kernel(char *,struct pt_regs *,long); -struct mem_pieces phys_mem; - +extern char _start[], _end[]; +extern char _stext[], etext[]; extern struct task_struct *current_set[NR_CPUS]; -PTE *Hash, *Hash_end; -unsigned long Hash_size, Hash_mask; +struct mem_pieces phys_mem; +char *klimit = _end; +struct mem_pieces phys_avail; + +PTE *Hash=0, *Hash_end; +unsigned long Hash_size=0, Hash_mask; #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) -unsigned long _SDR1; +unsigned long _SDR1=0; static void hash_init(void); union ubat { /* BAT register values to be loaded */ BAT bat; -#ifdef CONFIG_PPC64 +#ifdef CONFIG_PPC64BRIDGE u64 word[2]; #else u32 word[2]; @@ -479,7 +485,8 @@ if (pmd_none(oldpd) && mem_init_done) set_pgdir(va, *(pgd_t *)pd); set_pte(pg, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags))); - flush_hash_page(0, va); + if (mem_init_done) + flush_hash_page(0, va); } #ifndef CONFIG_8xx @@ -503,11 +510,16 @@ void local_flush_tlb_all(void) { +#ifdef CONFIG_PPC64BRIDGE + /* XXX this assumes that the vmalloc arena starts no lower than + * 0xd0000000 on 64-bit machines. */ + flush_hash_segments(0xd, 0xffffff); +#else __clear_user(Hash, Hash_size); - _tlbia(); #ifdef CONFIG_SMP smp_send_tlb_invalidate(0); -#endif +#endif /* CONFIG_SMP */ +#endif /* CONFIG_PPC64BRIDGE */ } /* @@ -591,7 +603,10 @@ atomic_set(&next_mmu_context, 0); /* make sure current always has a context */ current->mm->context = MUNGE_CONTEXT(atomic_inc_return(&next_mmu_context)); - set_context(current->mm->context); + /* The PGD is only a placeholder. It is only used on + * 8xx processors. + */ + set_context(current->mm->context, current->mm->pgd); } #endif /* CONFIG_8xx */ @@ -690,7 +705,7 @@ int i; unsigned long v, p, s, f; -#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) +#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) && !defined(CONFIG_POWER4) if (!__map_without_bats) { unsigned long tot, mem_base, bl, done; unsigned long max_size = (256<<20); @@ -725,7 +740,7 @@ RAM_PAGE); } } -#endif /* !CONFIG_4xx && !CONFIG_8xx */ +#endif /* !CONFIG_4xx && !CONFIG_8xx && !CONFIG_POWER4 */ for (i = 0; i < phys_mem.n_regions; ++i) { v = (ulong)__va(phys_mem.regions[i].address); @@ -940,9 +955,7 @@ if ( ppc_md.progress ) ppc_md.progress("MMU:hash init", 0x300); hash_init(); -#ifdef CONFIG_PPC64 - _SDR1 = __pa(Hash) | (ffz(~Hash_size) - 7)-11; -#else +#ifndef CONFIG_PPC64BRIDGE _SDR1 = __pa(Hash) | (Hash_mask >> 10); #endif @@ -952,6 +965,11 @@ /* Map in all of RAM starting at KERNELBASE */ mapin_ram(); +#ifdef CONFIG_POWER4 + ioremap_base = ioremap_bot = 0xfffff000; + isa_io_base = (unsigned long) ioremap(0xffd00000, 0x200000) + 0x100000; + +#else /* CONFIG_POWER4 */ /* * Setup the bat mappings we're going to load that cover * the io areas. RAM was mapped by mapin_ram(). @@ -966,26 +984,15 @@ break; case _MACH_chrp: setbat(0, 0xf8000000, 0xf8000000, 0x08000000, IO_PAGE); -#ifdef CONFIG_PPC64 - /* temporary hack to get working until page tables are stable -- Cort*/ -/* setbat(1, 0x80000000, 0xc0000000, 0x10000000, IO_PAGE);*/ - setbat(3, 0xd0000000, 0xd0000000, 0x10000000, IO_PAGE); +#ifdef CONFIG_PPC64BRIDGE + setbat(1, 0x80000000, 0xc0000000, 0x10000000, IO_PAGE); #else setbat(1, 0x80000000, 0x80000000, 0x10000000, IO_PAGE); setbat(3, 0x90000000, 0x90000000, 0x10000000, IO_PAGE); -#endif +#endif break; case _MACH_Pmac: -#if 0 - { - unsigned long base = 0xf3000000; - struct device_node *macio = find_devices("mac-io"); - if (macio && macio->n_addrs) - base = macio->addrs[0].address; - setbat(0, base, base, 0x100000, IO_PAGE); - } -#endif - ioremap_base = 0xf0000000; + ioremap_base = 0xf8000000; break; case _MACH_apus: /* Map PPC exception vectors. */ @@ -1009,6 +1016,7 @@ break; } ioremap_bot = ioremap_base; +#endif /* CONFIG_POWER4 */ #else /* CONFIG_8xx */ end_of_DRAM = m8xx_find_end_of_memory(); @@ -1080,6 +1088,7 @@ /* remove the bootmem bitmap from the available memory */ mem_pieces_remove(&phys_avail, start, boot_mapsize, 1); + /* add everything in phys_avail into the bootmem map */ for (i = 0; i < phys_avail.n_regions; ++i) free_bootmem(phys_avail.regions[i].address, @@ -1159,9 +1168,6 @@ int codepages = 0; int datapages = 0; int initpages = 0; -#if defined(CONFIG_ALL_PPC) - extern unsigned int rtas_data, rtas_size; -#endif /* defined(CONFIG_ALL_PPC) */ max_mapnr = max_low_pfn; high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); num_physpages = max_mapnr; /* RAM is assumed contiguous */ @@ -1223,13 +1229,7 @@ unsigned long __init *pmac_find_end_of_memory(void) { unsigned long a, total; - unsigned long ram_limit = 0xf0000000 - KERNELBASE; - /* allow 0x08000000 for IO space */ - if ( _machine & (_MACH_prep|_MACH_Pmac) ) - ram_limit = 0xd8000000 - KERNELBASE; -#ifdef CONFIG_PPC64 - ram_limit = 64<<20; -#endif + unsigned long ram_limit = 0xe0000000 - KERNELBASE; memory_node = find_devices("memory"); if (memory_node == NULL) { @@ -1422,27 +1422,42 @@ */ static void __init hash_init(void) { - int Hash_bits; - unsigned long h, ramsize; + int Hash_bits, mb, mb2; + unsigned int hmask, ramsize, h; extern unsigned int hash_page_patch_A[], hash_page_patch_B[], hash_page_patch_C[], hash_page[]; + ramsize = (ulong)end_of_DRAM - KERNELBASE; +#ifdef CONFIG_PPC64BRIDGE + /* The hash table has already been allocated and initialized + in prom.c */ + Hash_mask = (Hash_size >> 7) - 1; + hmask = Hash_mask >> 9; + Hash_bits = __ilog2(Hash_size) - 7; + mb = 25 - Hash_bits; + if (Hash_bits > 16) + Hash_bits = 16; + mb2 = 25 - Hash_bits; + +#else /* CONFIG_PPC64BRIDGE */ + if ( ppc_md.progress ) ppc_md.progress("hash:enter", 0x105); /* * Allow 64k of hash table for every 16MB of memory, * up to a maximum of 2MB. */ - ramsize = (ulong)end_of_DRAM - KERNELBASE; - for (h = 64<<10; h < ramsize / 256 && h < 2<<20; h *= 2) + for (h = 64<<10; h < ramsize / 256 && h < (2<<20); h *= 2) ; Hash_size = h; -#ifdef CONFIG_PPC64 - Hash_mask = (h >> 7) - 1; -#else Hash_mask = (h >> 6) - 1; -#endif - + hmask = Hash_mask >> 10; + Hash_bits = __ilog2(h) - 6; + mb = 26 - Hash_bits; + if (Hash_bits > 16) + Hash_bits = 16; + mb2 = 26 - Hash_bits; + /* shrink the htab since we don't use it on 603's -- Cort */ switch (_get_PVR()>>16) { case 3: /* 603 */ @@ -1459,50 +1474,36 @@ if ( ppc_md.progress ) ppc_md.progress("hash:find piece", 0x322); /* Find some memory for the hash table. */ - if ( Hash_size ) + if ( Hash_size ) { Hash = mem_pieces_find(Hash_size, Hash_size); - else + /*__clear_user(Hash, Hash_size);*/ + } else Hash = 0; +#endif /* CONFIG_PPC64BRIDGE */ - printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n", + printk("Total memory = %dMB; using %ldkB for hash table (at %p)\n", ramsize >> 20, Hash_size >> 10, Hash); if ( Hash_size ) { if ( ppc_md.progress ) ppc_md.progress("hash:patch", 0x345); Hash_end = (PTE *) ((unsigned long)Hash + Hash_size); - /*__clear_user(Hash, Hash_size);*/ /* * Patch up the instructions in head.S:hash_page */ -#ifdef CONFIG_PPC64 - Hash_bits = ffz(~Hash_size) - 7; -#else - Hash_bits = ffz(~Hash_size) - 6; -#endif hash_page_patch_A[0] = (hash_page_patch_A[0] & ~0xffff) | (__pa(Hash) >> 16); hash_page_patch_A[1] = (hash_page_patch_A[1] & ~0x7c0) - | ((26 - Hash_bits) << 6); - if (Hash_bits > 16) - Hash_bits = 16; + | (mb << 6); hash_page_patch_A[2] = (hash_page_patch_A[2] & ~0x7c0) - | ((26 - Hash_bits) << 6); + | (mb2 << 6); hash_page_patch_B[0] = (hash_page_patch_B[0] & ~0xffff) -#ifdef CONFIG_PPC64 - | (Hash_mask >> 11); -#else - | (Hash_mask >> 10); -#endif + | hmask; hash_page_patch_C[0] = (hash_page_patch_C[0] & ~0xffff) -#ifdef CONFIG_PPC64 - | (Hash_mask >> 11); -#else - | (Hash_mask >> 10); -#endif + | hmask; #if 0 /* see hash_page in head.S, note also patch_C ref below */ hash_page_patch_D[0] = (hash_page_patch_D[0] & ~0xffff) - | (Hash_mask >> 10); + | hmask; #endif /* * Ensure that the locations we've patched have been written @@ -1579,3 +1580,48 @@ return (ret); } #endif + +/* + * Set phys_avail to phys_mem less the kernel text/data/bss. + */ +void __init +set_phys_avail(struct mem_pieces *mp) +{ + unsigned long kstart, ksize; + + /* + * Initially, available phyiscal memory is equivalent to all + * physical memory. + */ + + phys_avail = *mp; + + /* + * Map out the kernel text/data/bss from the available physical + * memory. + */ + + kstart = __pa(_stext); /* should be 0 */ + ksize = PAGE_ALIGN(klimit - _stext); + + mem_pieces_remove(&phys_avail, kstart, ksize, 0); + mem_pieces_remove(&phys_avail, 0, 0x4000, 0); + +#if defined(CONFIG_BLK_DEV_INITRD) + /* Remove the init RAM disk from the available memory. */ + if (initrd_start) { + mem_pieces_remove(&phys_avail, __pa(initrd_start), + initrd_end - initrd_start, 1); + } +#endif /* CONFIG_BLK_DEV_INITRD */ +#ifdef CONFIG_ALL_PPC + /* remove the RTAS pages from the available memory */ + if (rtas_data) + mem_pieces_remove(&phys_avail, rtas_data, rtas_size, 1); +#endif /* CONFIG_ALL_PPC */ +#ifdef CONFIG_PPC64BRIDGE + /* Remove the hash table from the available memory */ + if (Hash) + mem_pieces_remove(&phys_avail, __pa(Hash), Hash_size, 1); +#endif /* CONFIG_PPC64BRIDGE */ +} diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/mm/mem_pieces.c linux/arch/ppc/mm/mem_pieces.c --- v2.4.0-test1/linux/arch/ppc/mm/mem_pieces.c Sat Feb 26 22:31:42 2000 +++ linux/arch/ppc/mm/mem_pieces.c Mon Jun 19 17:59:37 2000 @@ -18,18 +18,11 @@ #include #include #include - -#include -#include +#include #include "mem_pieces.h" -extern char _start[], _end[]; -extern char _stext[], etext[]; - -char *klimit = _end; - -struct mem_pieces phys_avail; +extern struct mem_pieces phys_avail; static void mem_pieces_print(struct mem_pieces *); @@ -142,7 +135,7 @@ rp->address = start; rp->size = size; } -#endif +#endif /* CONFIG_APUS || CONFIG_ALL_PPC */ void __init mem_pieces_sort(struct mem_pieces *mp) @@ -184,39 +177,4 @@ ++d; } mp->n_regions = d; -} - -/* - * Set phys_avail to phys_mem less the kernel text/data/bss. - */ -void __init -set_phys_avail(struct mem_pieces *mp) -{ - unsigned long kstart, ksize; - - /* - * Initially, available phyiscal memory is equivalent to all - * physical memory. - */ - - phys_avail = *mp; - - /* - * Map out the kernel text/data/bss from the available physical - * memory. - */ - - kstart = __pa(_stext); /* should be 0 */ - ksize = PAGE_ALIGN(klimit - _stext); - - mem_pieces_remove(&phys_avail, kstart, ksize, 0); - mem_pieces_remove(&phys_avail, 0, 0x4000, 0); - -#if defined(CONFIG_BLK_DEV_INITRD) - /* Remove the init RAM disk from the available memory. */ - if (initrd_start) { - mem_pieces_remove(&phys_avail, __pa(initrd_start), - initrd_end - initrd_start, 1); - } -#endif /* CONFIG_BLK_DEV_INITRD */ } diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/mm/mem_pieces.h linux/arch/ppc/mm/mem_pieces.h --- v2.4.0-test1/linux/arch/ppc/mm/mem_pieces.h Tue Dec 7 09:32:42 1999 +++ linux/arch/ppc/mm/mem_pieces.h Mon Jun 19 17:59:37 2000 @@ -17,8 +17,7 @@ #ifndef __MEM_PIECES_H__ #define __MEM_PIECES_H__ -#include - +#include #ifdef __cplusplus extern "C" { @@ -34,13 +33,6 @@ struct reg_property regions[MEM_PIECES_MAX]; }; - -/* Global Variables */ - -extern char *klimit; -extern struct mem_pieces phys_avail; - - /* Function Prototypes */ extern void *mem_pieces_find(unsigned int size, unsigned int align); @@ -50,9 +42,6 @@ unsigned int size); extern void mem_pieces_coalesce(struct mem_pieces *mp); extern void mem_pieces_sort(struct mem_pieces *mp); - -extern void set_phys_avail(struct mem_pieces *mp); - #ifdef __cplusplus } diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/xmon/start.c linux/arch/ppc/xmon/start.c --- v2.4.0-test1/linux/arch/ppc/xmon/start.c Thu May 11 15:30:06 2000 +++ linux/arch/ppc/xmon/start.c Mon Jun 19 17:59:37 2000 @@ -272,7 +272,7 @@ if ( _machine == _MACH_chrp ) { sccd[3] = 0x83; eieio(); /* LCR = 8N1 + DLAB */ - sccd[0] = 3; eieio(); /* DLL = 38400 baud */ + sccd[0] = 12; eieio(); /* DLL = 9600 baud */ sccd[1] = 0; eieio(); sccd[2] = 0; eieio(); /* FCR = 0 */ sccd[3] = 3; eieio(); /* LCR = 8N1 */ diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/xmon/xmon.c linux/arch/ppc/xmon/xmon.c --- v2.4.0-test1/linux/arch/ppc/xmon/xmon.c Thu May 11 15:30:06 2000 +++ linux/arch/ppc/xmon/xmon.c Mon Jun 19 17:59:37 2000 @@ -19,6 +19,7 @@ static int size = 1; static unsigned ndump = 64; static unsigned nidump = 16; +static unsigned ncsum = 4096; static int termch; static u_int bus_error_jmp[100]; @@ -85,6 +86,7 @@ static void cacheflush(void); static char *pretty_print_addr(unsigned long addr); static char *lookup_name(unsigned long addr); +static void csum(void); extern int print_insn_big_powerpc(FILE *, unsigned long, unsigned); extern void printf(const char *fmt, ...); @@ -261,7 +263,7 @@ bp->enabled = 0; } } -#ifndef CONFIG_8xx +#if !defined(CONFIG_8xx) && !defined(CONFIG_POWER4) if (dabr.enabled) set_dabr(dabr.address); if (iabr.enabled) @@ -276,7 +278,7 @@ struct bpt *bp; unsigned instr; -#ifndef CONFIG_8xx +#if !defined(CONFIG_8xx) && !defined(CONFIG_POWER4) set_dabr(0); set_iabr(0); #endif @@ -379,10 +381,70 @@ case 'b': bpt_cmds(); break; + case 'c': + csum(); + break; } } } +static unsigned short fcstab[256] = { + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + +#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff]) + +static void +csum(void) +{ + unsigned int i; + unsigned short fcs; + unsigned char v; + + scanhex(&adrs); + scanhex(&ncsum); + fcs = 0xffff; + for (i = 0; i < ncsum; ++i) { + if (mread(adrs+i, &v, 1) == 0) { + printf("csum stopped at %x\n", adrs+i); + break; + } + fcs = FCS(fcs, v); + } + printf("%x\n", fcs); +} + static void bpt_cmds(void) { @@ -393,7 +455,7 @@ cmd = inchar(); switch (cmd) { -#ifndef CONFIG_8xx +#if !defined(CONFIG_8xx) && !defined(CONFIG_POWER4) case 'd': mode = 7; cmd = inchar(); @@ -695,6 +757,7 @@ } #endif +#ifndef CONFIG_PPC64BRIDGE static void dump_hash_table_seg(unsigned seg, unsigned start, unsigned end) { @@ -752,6 +815,67 @@ if (last_found) printf(" ... %x\n", last_va); } + +#else /* CONFIG_PPC64BRIDGE */ +static void +dump_hash_table_seg(unsigned seg, unsigned start, unsigned end) +{ + extern void *Hash; + extern unsigned long Hash_size; + unsigned *htab = Hash; + unsigned hsize = Hash_size; + unsigned v, hmask, va, last_va; + int found, last_found, i; + unsigned *hg, w1, last_w2, last_va0; + + last_found = 0; + hmask = hsize / 128 - 1; + va = start; + start = (start >> 12) & 0xffff; + end = (end >> 12) & 0xffff; + for (v = start; v < end; ++v) { + found = 0; + hg = htab + (((v ^ seg) & hmask) * 32); + w1 = 1 | (seg << 12) | ((v & 0xf800) >> 4); + for (i = 0; i < 8; ++i, hg += 4) { + if (hg[1] == w1) { + found = 1; + break; + } + } + if (!found) { + w1 ^= 2; + hg = htab + ((~(v ^ seg) & hmask) * 32); + for (i = 0; i < 8; ++i, hg += 4) { + if (hg[1] == w1) { + found = 1; + break; + } + } + } + if (!(last_found && found && (hg[3] & ~0x180) == last_w2 + 4096)) { + if (last_found) { + if (last_va != last_va0) + printf(" ... %x", last_va); + printf("\n"); + } + if (found) { + printf("%x to %x", va, hg[3]); + last_va0 = va; + } + last_found = found; + } + if (found) { + last_w2 = hg[3] & ~0x180; + last_va = va; + } + va += 4096; + } + if (last_found) + printf(" ... %x\n", last_va); +} +#endif /* CONFIG_PPC64BRIDGE */ + static unsigned hash_ctx; static unsigned hash_start; static unsigned hash_end; diff -u --recursive --new-file v2.4.0-test1/linux/arch/s390/config.in linux/arch/s390/config.in --- v2.4.0-test1/linux/arch/s390/config.in Fri May 12 14:18:55 2000 +++ linux/arch/s390/config.in Mon Jun 19 13:25:06 2000 @@ -1,6 +1,6 @@ - +# # For a description of the syntax of this configuration file, -# see the Configure script. +# see Documentation/kbuild/config-language.txt. # define_bool CONFIG_UID16 y @@ -63,10 +63,6 @@ comment 'Kernel hacking' #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC -bool 'Kernel profiling support' CONFIG_PROFILE -if [ "$CONFIG_PROFILE" = "y" ]; then - int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 -fi if [ "$CONFIG_CTC" = "y" ]; then bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG fi diff -u --recursive --new-file v2.4.0-test1/linux/arch/s390/defconfig linux/arch/s390/defconfig --- v2.4.0-test1/linux/arch/s390/defconfig Fri May 12 14:18:55 2000 +++ linux/arch/s390/defconfig Mon Jun 19 13:25:06 2000 @@ -174,5 +174,4 @@ # # Kernel hacking # -# CONFIG_PROFILE is not set # CONFIG_REMOTE_DEBUG is not set diff -u --recursive --new-file v2.4.0-test1/linux/arch/s390/kernel/traps.c linux/arch/s390/kernel/traps.c --- v2.4.0-test1/linux/arch/s390/kernel/traps.c Fri May 12 14:18:55 2000 +++ linux/arch/s390/kernel/traps.c Mon Jun 19 13:25:06 2000 @@ -62,9 +62,6 @@ force_sig(signr, tsk); \ } - -void page_exception(void); - /* TODO: define these as 'pgm_check_handler_t xxx;' asmlinkage void divide_error(void); asmlinkage void debug(void); diff -u --recursive --new-file v2.4.0-test1/linux/arch/sh/Makefile linux/arch/sh/Makefile --- v2.4.0-test1/linux/arch/sh/Makefile Tue Apr 11 15:09:14 2000 +++ linux/arch/sh/Makefile Mon Jun 19 17:59:37 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.4 2000/03/08 15:14:14 gniibe Exp $ +# $Id: Makefile,v 1.6 2000/06/10 03:03:52 gniibe Exp $ # # This file is subject to the terms and conditions of the GNU General Public # License. See the file "COPYING" in the main directory of this archive @@ -22,6 +22,11 @@ AFLAGS += -ml # LINKFLAGS += -EL LDFLAGS := -EL +else +CFLAGS += -mb +AFLAGS += -mb +# LINKFLAGS += -EB +LDFLAGS := -EB endif # ifdef CONFIG_CROSSCOMPILE @@ -29,7 +34,7 @@ # endif LD =$(CROSS_COMPILE)ld $(LDFLAGS) -OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S +OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -R .stab -R .stabstr -S MODFLAGS += diff -u --recursive --new-file v2.4.0-test1/linux/arch/sh/boot/Makefile linux/arch/sh/boot/Makefile --- v2.4.0-test1/linux/arch/sh/boot/Makefile Tue Mar 7 14:32:25 2000 +++ linux/arch/sh/boot/Makefile Mon Jun 19 17:59:37 2000 @@ -5,37 +5,30 @@ # License. See the file "COPYING" in the main directory of this archive # for more details. # +# Copyright (C) 1999 Stuart Menefy +# -.S.s: - $(CPP) $(CFLAGS) $< -o $*.s -.S.o: - $(CC) $(CFLAGS) -c $< -o $*.o +SYSTEM =$(TOPDIR)/vmlinux -OBJS = +Image: $(CONFIGURE) $(SYSTEM) + $(OBJCOPY) $(SYSTEM) Image -# -# Drop some uninteresting sections in the kernel. -# -drop-sections = .reginfo .mdebug -strip-flags = $(addprefix --remove-section=,$(drop-sections)) +zImage: $(CONFIGURE) compressed/vmlinux + $(OBJCOPY) compressed/vmlinux zImage -# -# Fake compressed boot -# -zImage: $(CONFIGURE) mkboot $(TOPDIR)/vmlinux - $(OBJCOPY) $(strip-flags) $(TOPDIR)/vmlinux zImage.tmp - ./mkboot zImage.tmp zImage - rm -f zImage.tmp +compressed/vmlinux: $(TOPDIR)/vmlinux + $(MAKE) -C compressed vmlinux + +install: $(CONFIGURE) Image + sh -x ./install.sh $(KERNELRELEASE) Image $(TOPDIR)/System.map "$(INSTALL_PATH)" -mkboot: mkboot.c - $(HOSTCC) -o $@ $^ +zinstall: $(CONFIGURE) zImage + sh -x ./install.sh $(KERNELRELEASE) zImage $(TOPDIR)/System.map "$(INSTALL_PATH)" -# Don't build dependencies, this may die if $(CC) isn't gcc dep: clean: - rm -f zImage zImage.tmp mkboot - -dummy: - -include $(TOPDIR)/Rules.make + rm -f tools/build + rm -f setup bootsect zImage compressed/vmlinux.out + rm -f bsetup bbootsect bzImage compressed/bvmlinux.out + @$(MAKE) -C compressed clean diff -u --recursive --new-file v2.4.0-test1/linux/arch/sh/boot/compressed/Makefile linux/arch/sh/boot/compressed/Makefile --- v2.4.0-test1/linux/arch/sh/boot/compressed/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/boot/compressed/Makefile Mon Jun 19 17:59:37 2000 @@ -0,0 +1,39 @@ +# +# linux/arch/sh/boot/compressed/Makefile +# +# create a compressed vmlinux image from the original vmlinux +# + +HEAD = head.o +SYSTEM = $(TOPDIR)/vmlinux + +OBJECTS = $(HEAD) misc.o + +ZLDFLAGS = -e startup -T $(TOPDIR)/arch/sh/vmlinux.lds + +# +# ZIMAGE_OFFSET is the load offset of the compression loader +# +ZIMAGE_OFFSET = $(shell printf "0x%8x" $$[0x80000000+0x$(CONFIG_MEMORY_START)+0x200000]) + +ZLINKFLAGS = -Ttext $(ZIMAGE_OFFSET) $(ZLDFLAGS) + +all: vmlinux + +vmlinux: piggy.o $(OBJECTS) + $(LD) $(ZLINKFLAGS) -o vmlinux $(OBJECTS) piggy.o + +head.o: head.S + $(CC) $(AFLAGS) -traditional -c head.S + +piggy.o: $(SYSTEM) + tmppiggy=_tmp_$$$$piggy; \ + rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \ + $(OBJCOPY) -R .empty_zero_page $(SYSTEM) $$tmppiggy; \ + gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \ + echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \ + $(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-shl -T $$tmppiggy.lnk; \ + rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk + +clean: + rm -f vmlinux _tmp_* diff -u --recursive --new-file v2.4.0-test1/linux/arch/sh/boot/compressed/head.S linux/arch/sh/boot/compressed/head.S --- v2.4.0-test1/linux/arch/sh/boot/compressed/head.S Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/boot/compressed/head.S Mon Jun 19 17:59:37 2000 @@ -0,0 +1,53 @@ +/* + * linux/arch/sh/boot/compressed/head.S + * + * Copyright (C) 1999 Stuart Menefy + */ + +.text + +#include + + .global startup +startup: + + /* First clear BSS */ + mov.l end_addr, r1 + mov.l bss_start_addr, r2 + mov #0, r0 +l1: + mov.l r0, @-r1 + cmp/eq r1,r2 + bf l1 + + /* Load initial status register */ + mov.l init_sr, r1 + ldc r1, sr + + /* Set the initial pointer. */ + mov.l init_stack_addr, r0 + mov.l @r0, r15 + + /* Decompress the kernel */ + mov.l decompress_kernel_addr, r0 + jsr @r0 + nop + + /* Jump to the start of the decompressed kernel */ + mov.l kernel_start_addr, r0 + jmp @r0 + nop + + .align 2 +bss_start_addr: + .long __bss_start +end_addr: + .long _end +init_sr: + .long 0x50000000 /* Privileged mode, Bank=0, Block=1, I3-I0=0 */ +init_stack_addr: + .long stack_start +decompress_kernel_addr: + .long decompress_kernel +kernel_start_addr: + .long _text+0x1000 diff -u --recursive --new-file v2.4.0-test1/linux/arch/sh/boot/compressed/install.sh linux/arch/sh/boot/compressed/install.sh --- v2.4.0-test1/linux/arch/sh/boot/compressed/install.sh Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/boot/compressed/install.sh Mon Jun 19 17:59:37 2000 @@ -0,0 +1,56 @@ +#!/bin/sh +# +# arch/sh/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 +# Adapted from code in arch/arm/boot/install.sh by Stuart Menefy +# +# "make install" script for sh 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 diff -u --recursive --new-file v2.4.0-test1/linux/arch/sh/boot/compressed/misc.c linux/arch/sh/boot/compressed/misc.c --- v2.4.0-test1/linux/arch/sh/boot/compressed/misc.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/boot/compressed/misc.c Mon Jun 19 17:59:37 2000 @@ -0,0 +1,232 @@ +/* + * arch/sh/boot/compressed/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 + * + * Adapted for SH by Stuart Menefy, Aug 1999 + */ + +#include +#include + +/* + * gzip declarations + */ + +#define OF(args) args +#define STATIC static + +#undef memset +#undef memcpy +#define memzero(s, n) memset ((s), 0, (n)) + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +#define WSIZE 0x8000 /* Window size must be at least 32k, */ + /* and a power of two */ + +static uch *inbuf; /* input buffer */ +static uch window[WSIZE]; /* Sliding window buffer */ + +static unsigned insize = 0; /* valid bytes in inbuf */ +static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ +static unsigned outcnt = 0; /* bytes in output buffer */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +#define get_byte() (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 int input_len; + +static long bytes_out = 0; +static uch *output_data; +static unsigned long output_ptr = 0; + + +static void *malloc(int size); +static void free(void *where); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +static void puts(const char *); + +extern int _text; /* Defined in vmlinux.lds.S */ +extern int _end; +static unsigned long free_mem_ptr; +static unsigned long free_mem_end_ptr; + +#define HEAP_SIZE 0x10000 + +#include "../../../../lib/inflate.c" + +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_end_ptr) + error("\nOut of memory\n"); + + return p; +} + +static void free(void *where) +{ /* Don't care */ +} + +static void gzip_mark(void **ptr) +{ + *ptr = (void *) free_mem_ptr; +} + +static void gzip_release(void **ptr) +{ + free_mem_ptr = (long) *ptr; +} + +#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB +#define IN_GDB 1 +#endif +#include +#include "../../../../drivers/char/sh-sci.h" + +static int strlen(const char *s) +{ + int i = 0; + + while (*s++) + i++; + return i; +} + +void puts(const char *s) +{ + put_string(s, strlen(s)); +} + +void* memset(void* s, int c, size_t n) +{ + int i; + char *ss = (char*)s; + + for (i=0;i> 8); + } + crc = c; + bytes_out += (ulg)outcnt; + output_ptr += (ulg)outcnt; + outcnt = 0; +} + +static void error(char *x) +{ + puts("\n\n"); + puts(x); + puts("\n\n -- System halted"); + + while(1); /* Halt */ +} + +#define STACK_SIZE (4096) +long user_stack [STACK_SIZE]; +long* stack_start = &user_stack[STACK_SIZE]; + +void decompress_kernel(void) +{ + output_data = 0; + output_ptr = (unsigned long)&_text+0x20001000; + free_mem_ptr = (unsigned long)&_end; + free_mem_end_ptr = free_mem_ptr + HEAP_SIZE; + + makecrc(); + puts("Uncompressing Linux... "); + gunzip(); + puts("Ok, booting the kernel.\n"); +} diff -u --recursive --new-file v2.4.0-test1/linux/arch/sh/config.in linux/arch/sh/config.in --- v2.4.0-test1/linux/arch/sh/config.in Tue May 23 15:31:34 2000 +++ linux/arch/sh/config.in Mon Jun 19 17:59:37 2000 @@ -1,6 +1,6 @@ # # For a description of the syntax of this configuration file, -# see the Configure script. +# see Documentation/kbuild/config-language.txt. # mainmenu_name "Linux/SuperH Kernel Configuration" @@ -17,7 +17,9 @@ comment 'Processor type and features' choice 'SuperH system type' \ "Generic CONFIG_SH_GENERIC \ - SolutionEngine CONFIG_SH_SOLUTION_ENGINE" Generic + SolutionEngine CONFIG_SH_SOLUTION_ENGINE \ + Overdrive CONFIG_SH_OVERDRIVE \ + HP600 CONFIG_SH_HP600" Generic choice 'Processor type' \ "SH7708 CONFIG_CPU_SUBTYPE_SH7708 \ @@ -36,7 +38,8 @@ define_bool CONFIG_CPU_SH4 y fi bool 'Little Endian' CONFIG_LITTLE_ENDIAN -if [ "$CONFIG_SH_SOLUTION_ENGINE" = "y" ]; then +if [ "$CONFIG_SH_SOLUTION_ENGINE" = "y" -o "$CONFIG_SH_HP600" = "y" -o \ + "$CONFIG_SH_OVERDRIVE" = "y" ]; then define_hex CONFIG_MEMORY_START 0c000000 else hex 'Physical memory start address' CONFIG_MEMORY_START 08000000 @@ -61,8 +64,14 @@ bool 'Networking support' CONFIG_NET -if [ "$CONFIG_SH_SOLUTION_ENGINE" != "y" ]; then - bool 'Directly Connected Compact Flash support' CONFIG_CF_ENABLER +if [ "$CONFIG_SH_GENERIC" = "y" -o "$CONFIG_SH_SOLUTION_ENGINE" = "y" ]; then + bool 'Compact Flash Enabler support' CONFIG_CF_ENABLER +fi + +bool 'Hitachi HD64461 companion chip support' CONFIG_HD64461 +if [ "$CONFIG_HD64461" = "y" ]; then + int 'HD64461 IRQ' CONFIG_HD64461_IRQ 36 + bool 'HD64461 PCMCIA enabler' CONFIG_HD64461_ENABLER fi bool 'PCI support' CONFIG_PCI @@ -158,11 +167,6 @@ fi tristate 'Serial support' CONFIG_SERIAL -if [ "$CONFIG_SERIAL" = "y" -o "$CONFIG_SERIAL" = "m" ]; then - choice 'Serial interface type' \ - "SCI CONFIG_SH_SCI_SERIAL \ - SCIF CONFIG_SH_SCIF_SERIAL" -fi if [ "$CONFIG_SERIAL" = "y" ]; then bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE fi diff -u --recursive --new-file v2.4.0-test1/linux/arch/sh/defconfig linux/arch/sh/defconfig --- v2.4.0-test1/linux/arch/sh/defconfig Tue May 23 15:31:34 2000 +++ linux/arch/sh/defconfig Mon Jun 19 17:59:37 2000 @@ -14,6 +14,8 @@ # CONFIG_SH_GENERIC=y # CONFIG_SH_SOLUTION_ENGINE is not set +# CONFIG_SH_OVERDRIVE is not set +# CONFIG_SH_HP600 is not set CONFIG_CPU_SUBTYPE_SH7708=y # CONFIG_CPU_SUBTYPE_SH7709 is not set # CONFIG_CPU_SUBTYPE_SH7750 is not set @@ -35,6 +37,7 @@ # CONFIG_SBUS is not set # CONFIG_NET is not set CONFIG_CF_ENABLER=y +# CONFIG_HD64461 is not set # CONFIG_PCI is not set # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set @@ -59,17 +62,16 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_DEV_DAC960 is not set - -# -# Additional Block Devices -# # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_LVM 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_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y # @@ -96,6 +98,8 @@ # CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set # CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set # CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set # CONFIG_BLK_DEV_IDECS is not set # CONFIG_BLK_DEV_IDECD is not set # CONFIG_BLK_DEV_IDETAPE is not set @@ -110,6 +114,7 @@ # CONFIG_BLK_DEV_ISAPNP is not set # CONFIG_IDE_CHIPSETS is not set # CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set # CONFIG_BLK_DEV_IDE_MODES is not set # @@ -122,8 +127,6 @@ # # CONFIG_VT is not set CONFIG_SERIAL=y -CONFIG_SH_SCI_SERIAL=y -# CONFIG_SH_SCIF_SERIAL is not set CONFIG_SERIAL_CONSOLE=y # diff -u --recursive --new-file v2.4.0-test1/linux/arch/sh/kernel/Makefile linux/arch/sh/kernel/Makefile --- v2.4.0-test1/linux/arch/sh/kernel/Makefile Tue May 23 15:31:34 2000 +++ linux/arch/sh/kernel/Makefile Mon Jun 19 17:59:37 2000 @@ -28,8 +28,20 @@ O_OBJS += setup_se.o io_se.o endif +ifdef CONFIG_SH_OVERDRIVE +O_OBJS += setup_od.o io_generic.o +endif + +ifdef CONFIG_SH_HP600 +O_OBJS += io_hd64461.o +endif + ifdef CONFIG_CPU_SH4 O_OBJS += fpu.o +endif + +ifdef CONFIG_HD64461 +O_OBJS += setup_hd64461.o endif all: kernel.o head.o init_task.o diff -u --recursive --new-file v2.4.0-test1/linux/arch/sh/kernel/cf-enabler.c linux/arch/sh/kernel/cf-enabler.c --- v2.4.0-test1/linux/arch/sh/kernel/cf-enabler.c Tue Mar 7 14:32:25 2000 +++ linux/arch/sh/kernel/cf-enabler.c Mon Jun 19 17:59:37 2000 @@ -1,19 +1,81 @@ -/* $Id: cf-enabler.c,v 1.2 1999/12/20 10:14:40 gniibe Exp $ +/* $Id: cf-enabler.c,v 1.2 2000/06/08 05:50:10 gniibe Exp $ * * linux/drivers/block/cf-enabler.c * * Copyright (C) 1999 Niibe Yutaka + * Copyright (C) 2000 Toshiharu Nozawa * * Enable the CF configuration. */ +#include #include #include #include +#ifdef CONFIG_SH_SOLUTION_ENGINE +#include +/* + * 0xB8400000 : Common Memory + * 0xB8500000 : Attribute + * 0xB8600000 : I/O + */ + +int __init cf_init(void) +{ + if ((ctrl_inw(MRSHPC_CSR) & 0x000c) != 0) + return 0; /* Not detected */ + + if ((ctrl_inw(MRSHPC_CSR) & 0x0080) == 0) { + ctrl_outw(0x0674, MRSHPC_CPWCR); /* Card Vcc is 3.3v? */ + } else { + ctrl_outw(0x0678, MRSHPC_CPWCR); /* Card Vcc is 5V */ + } + + /* + * PC-Card window open + * flag == COMMON/ATTRIBUTE/IO + */ + /* common window open */ + ctrl_outw(0x8a84, MRSHPC_MW0CR1);/* window 0xb8400000 */ + if((ctrl_inw(MRSHPC_CSR) & 0x4000) != 0) + /* common mode & bus width 16bit SWAP = 1*/ + ctrl_outw(0x0b00, MRSHPC_MW0CR2); + else + /* common mode & bus width 16bit SWAP = 0*/ + ctrl_outw(0x0300, MRSHPC_MW0CR2); + + /* attribute window open */ + ctrl_outw(0x8a85, MRSHPC_MW1CR1);/* window 0xb8500000 */ + if ((ctrl_inw(MRSHPC_CSR) & 0x4000) != 0) + /* attribute mode & bus width 16bit SWAP = 1*/ + ctrl_outw(0x0a00, MRSHPC_MW1CR2); + else + /* attribute mode & bus width 16bit SWAP = 0*/ + ctrl_outw(0x0200, MRSHPC_MW1CR2); + + /* I/O window open */ + ctrl_outw(0x8a86, MRSHPC_IOWCR1);/* I/O window 0xb8600000 */ + ctrl_outw(0x0008, MRSHPC_CDCR); /* I/O card mode */ + if ((ctrl_inw(MRSHPC_CSR) & 0x4000) != 0) + ctrl_outw(0x0a00, MRSHPC_IOWCR2); /* bus width 16bit SWAP = 1*/ + else + ctrl_outw(0x0200, MRSHPC_IOWCR2); /* bus width 16bit SWAP = 0*/ + + ctrl_outw(0x2000, MRSHPC_ICR); + ctrl_outb(0x00, PA_MRSHPC_MW2 + 0x206); + ctrl_outb(0x42, PA_MRSHPC_MW2 + 0x200); + return 0; +} +#else /* then generic system type */ #define CF_CIS_BASE 0xb8000000 /* + * You can connect Compact Flash directly to the bus of SuperH. + * This is the enabler for that. + */ + +/* * 0xB8000000 : Attribute * 0xB8001000 : Common Memory * 0xBA000000 : I/O @@ -21,10 +83,12 @@ int __init cf_init(void) { + /* Enable the card, and set the level interrupt */ outw(0x0042, CF_CIS_BASE+0x0200); make_imask_irq(14); disable_irq(14); return 0; } +#endif __initcall (cf_init); diff -u --recursive --new-file v2.4.0-test1/linux/arch/sh/kernel/entry.S linux/arch/sh/kernel/entry.S --- v2.4.0-test1/linux/arch/sh/kernel/entry.S Tue May 23 15:31:34 2000 +++ linux/arch/sh/kernel/entry.S Mon Jun 19 17:59:37 2000 @@ -52,8 +52,9 @@ flags = 4 sigpending = 8 need_resched = 20 +tsk_ptrace = 60 -PF_TRACESYS = 0x00000020 +PT_TRACESYS = 0x00000002 PF_USEDFPU = 0x00100000 ENOSYS = 38 @@ -127,7 +128,7 @@ or $r11, $r10; \ ldc $r10, $sr - .balign 4 + .align 2 tlb_miss_load: mov.l 2f, $r0 mov.l @$r0, $r6 @@ -137,7 +138,7 @@ jmp @$r0 mov #0, $r5 - .balign 4 + .align 2 tlb_miss_store: mov.l 2f, $r0 mov.l @$r0, $r6 @@ -147,7 +148,7 @@ jmp @$r0 mov #1, $r5 - .balign 4 + .align 2 initial_page_write: mov.l 2f, $r0 mov.l @$r0, $r6 @@ -157,7 +158,7 @@ jmp @$r0 mov #1, $r5 - .balign 4 + .align 2 tlb_protection_violation_load: mov.l 2f, $r0 mov.l @$r0, $r6 @@ -167,7 +168,7 @@ jmp @$r0 mov #0, $r5 - .balign 4 + .align 2 tlb_protection_violation_store: mov.l 2f, $r0 mov.l @$r0, $r6 @@ -177,14 +178,14 @@ jmp @$r0 mov #1, $r5 - .balign 4 + .align 2 1: .long SYMBOL_NAME(do_page_fault) 2: .long MMU_TEA #ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB - .balign 4 + .align 2 /* Unwind the stack and jmp to the debug entry */ -debug: +debug_kernel: mov.l @$r15+, $r0 mov.l @$r15+, $r1 mov.l @$r15+, $r2 @@ -216,19 +217,36 @@ mov.l 2f, $k0 jmp @$k0 ldc $k1, $ssr - .balign 4 + .align 2 1: .long 0x300000f0 2: .long 0xa0000100 #endif - .balign 4 + .align 2 +debug_trap: +#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB + mov #SR, $r0 + mov.l @($r0,$r15), $r0 ! get status register + shll $r0 + shll $r0 ! kernel space? + bt/s debug_kernel +#endif + mov.l @$r15, $r0 + mov.l 1f, $r8 + jmp @$r8 + nop + + .align 2 +1: .long SYMBOL_NAME(break_point_trap_software) + + .align 2 error: ! STI() mov.l 1f, $r0 jmp @$r0 nop - .balign 4 + .align 2 1: .long SYMBOL_NAME(do_exception_error) badsys: mov #-ENOSYS, $r0 @@ -263,13 +281,11 @@ mov.l 1f, $r9 mov.l @$r9, $r8 ! -#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB mov #0x20, $r9 extu.b $r9, $r9 shll2 $r9 cmp/hs $r9, $r8 - bt debug -#endif + bt debug_trap ! mov #SYSCALL_NR, $r14 add $r15, $r14 @@ -311,16 +327,34 @@ bt 7b #endif 0: stc $k_current, $r11 - mov.l @(flags,$r11), $r10 ! Is it trace? - mov #PF_TRACESYS, $r11 + mov.l @(tsk_ptrace,$r11), $r10 ! Is it trace? + mov #PT_TRACESYS, $r11 tst $r11, $r10 bt 5f ! Trace system call mov #-ENOSYS, $r11 mov.l $r11, @(R0,$r15) + ! Push up $R0--$R2, and $R4--$R7 + mov.l $r0, @-$r15 + mov.l $r1, @-$r15 + mov.l $r2, @-$r15 + mov.l $r4, @-$r15 + mov.l $r5, @-$r15 + mov.l $r6, @-$r15 + mov.l $r7, @-$r15 + ! mov.l 2f, $r11 jsr @$r11 nop + ! Pop down $R0--$R2, and $R4--$R7 + mov.l @$r15+, $r7 + mov.l @$r15+, $r6 + mov.l @$r15+, $r5 + mov.l @$r15+, $r4 + mov.l @$r15+, $r2 + mov.l @$r15+, $r1 + mov.l @$r15+, $r0 + ! mov.l __syscall_ret_trace, $r10 bra 6f lds $r10, $pr @@ -337,7 +371,7 @@ nop ! In case of trace - .balign 4 + .align 2 3: #ifdef COMPAT_OLD_SYSCALL_ABI add $r8, $r15 ! pop off the arguments @@ -347,7 +381,7 @@ mova SYMBOL_NAME(ret_from_syscall), $r0 jmp @$r1 lds $r0, $pr - .balign 4 + .align 2 1: .long TRA 2: .long SYMBOL_NAME(syscall_trace) __n_sys: .long NR_syscalls @@ -366,18 +400,18 @@ .previous .section __ex_table, "a" - .balign 4 + .align 2 .long 4b,fixup_syscall_argerr .previous #endif - .balign 4 + .align 2 reschedule: mova SYMBOL_NAME(ret_from_syscall), $r0 mov.l 1f, $r1 jmp @$r1 lds $r0, $pr - .balign 4 + .align 2 1: .long SYMBOL_NAME(schedule) ENTRY(ret_from_irq) @@ -401,11 +435,11 @@ STI() bra ret_from_syscall nop - .balign 4 + .align 2 __INV_IMASK: .long 0xffffff0f ! ~(IMASK) - .balign 4 + .align 2 syscall_ret: #ifdef COMPAT_OLD_SYSCALL_ABI add $r8, $r15 ! pop off the arguments @@ -438,7 +472,7 @@ mova restore_all, $r0 jmp @$r1 lds $r0, $pr - .balign 4 + .align 2 __do_signal: .long SYMBOL_NAME(do_signal) __softirq_state: @@ -446,7 +480,7 @@ __do_softirq: .long SYMBOL_NAME(do_softirq) - .balign 4 + .align 2 restore_all: #if defined(__SH4__) mov.l __fpu_prepare_fd, $r0 @@ -554,7 +588,7 @@ rte nop - .balign 4 + .align 2 __blrb_flags: .long 0x30000000 #if defined(__SH4__) __fpu_prepare_fd: @@ -582,7 +616,7 @@ mov.l 2f, $k3 bra handle_exception mov.l @$k2, $k2 - .balign 4 + .align 2 2: .long SYMBOL_NAME(ret_from_exception) 1: .long EXPEVT ! @@ -601,7 +635,7 @@ bra handle_exception mov.l @$k2, $k2 - .balign 4 + .align 2 1: .long EXPEVT 2: .long INTEVT 3: .long SYMBOL_NAME(ret_from_irq) @@ -707,7 +741,7 @@ mov.l @$r9, $r9 jmp @$r9 nop - .balign 4 + .align 2 1: .long SYMBOL_NAME(exception_handling_table) 2: .long 0x00008000 ! FD=1 3: .long 0x000000f0 ! FD=0, IMASK=15 diff -u --recursive --new-file v2.4.0-test1/linux/arch/sh/kernel/io_hd64461.c linux/arch/sh/kernel/io_hd64461.c --- v2.4.0-test1/linux/arch/sh/kernel/io_hd64461.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/io_hd64461.c Mon Jun 19 17:59:37 2000 @@ -0,0 +1,109 @@ +/* + * $Id: io_hd64461.c,v 1.1 2000/06/10 21:45:18 yaegashi Exp $ + * Copyright (C) 2000 YAEGASHI Takeshi + * Typical I/O routines for HD64461 system. + */ + +#include +#include +#include + +static __inline__ unsigned long PORT2ADDR(unsigned long port) +{ + /* HD64461 internal devices (0xb0000000) */ + if (port < 0x10000) return CONFIG_HD64461_IOBASE + port; + + /* PCMCIA channel 0, I/O (0xba000000) */ + if (port < 0x20000) return 0xba000000 + port - 0x10000; + + /* PCMCIA channel 1, memory (0xb5000000) + SH7709 cannot support I/O card attached to Area 5 */ + if (port < 0x30000) return 0xb5000000 + port - 0x20000; + + /* Whole physical address space (0xa0000000) */ + return 0xa0000000 + (port & 0x1fffffff); +} + +static inline void delay(void) +{ + ctrl_inw(0xa0000000); +} + +unsigned long inb(unsigned int port) +{ + return *(volatile unsigned char*)PORT2ADDR(port); +} + +unsigned long inb_p(unsigned int port) +{ + unsigned long v = *(volatile unsigned char*)PORT2ADDR(port); + delay(); + return v; +} + +unsigned long inw(unsigned int port) +{ + return *(volatile unsigned short*)PORT2ADDR(port); +} + +unsigned long inl(unsigned int port) +{ + return *(volatile unsigned long*)PORT2ADDR(port); +} + +void insb(unsigned int port, void *buffer, unsigned long count) +{ + unsigned char *buf=buffer; + while(count--) *buf++=inb(port); +} + +void insw(unsigned int port, void *buffer, unsigned long count) +{ + unsigned short *buf=buffer; + while(count--) *buf++=inw(port); +} + +void insl(unsigned int port, void *buffer, unsigned long count) +{ + unsigned long *buf=buffer; + while(count--) *buf++=inl(port); +} + +void outb(unsigned long b, unsigned int port) +{ + *(volatile unsigned char*)PORT2ADDR(port) = b; +} + +void outb_p(unsigned long b, unsigned int port) +{ + *(volatile unsigned char*)PORT2ADDR(port) = b; + delay(); +} + +void outw(unsigned long b, unsigned int port) +{ + *(volatile unsigned short*)PORT2ADDR(port) = b; +} + +void outl(unsigned long b, unsigned int port) +{ + *(volatile unsigned long*)PORT2ADDR(port) = b; +} + +void outsb(unsigned int port, const void *buffer, unsigned long count) +{ + const unsigned char *buf=buffer; + while(count--) outb(*buf++, port); +} + +void outsw(unsigned int port, const void *buffer, unsigned long count) +{ + const unsigned short *buf=buffer; + while(count--) outw(*buf++, port); +} + +void outsl(unsigned int port, const void *buffer, unsigned long count) +{ + const unsigned long *buf=buffer; + while(count--) outl(*buf++, port); +} diff -u --recursive --new-file v2.4.0-test1/linux/arch/sh/kernel/io_se.c linux/arch/sh/kernel/io_se.c --- v2.4.0-test1/linux/arch/sh/kernel/io_se.c Tue May 23 15:31:34 2000 +++ linux/arch/sh/kernel/io_se.c Mon Jun 19 17:59:37 2000 @@ -1,4 +1,4 @@ -/* $Id: io_se.c,v 1.4 2000/05/07 23:31:58 gniibe Exp $ +/* $Id: io_se.c,v 1.5 2000/06/08 05:50:10 gniibe Exp $ * * linux/arch/sh/kernel/io_se.c * @@ -7,6 +7,7 @@ * I/O routine for Hitachi SolutionEngine. * */ + #include #include #include diff -u --recursive --new-file v2.4.0-test1/linux/arch/sh/kernel/irq.c linux/arch/sh/kernel/irq.c --- v2.4.0-test1/linux/arch/sh/kernel/irq.c Tue May 23 15:31:34 2000 +++ linux/arch/sh/kernel/irq.c Mon Jun 19 17:59:37 2000 @@ -37,6 +37,9 @@ #include #include +#ifdef CONFIG_HD64461 +#include +#endif unsigned int local_bh_count[NR_CPUS]; unsigned int local_irq_count[NR_CPUS]; @@ -243,6 +246,18 @@ "shlr %0\n\t" "add #-16, %0\n\t" :"=z" (irq)); +#if defined(CONFIG_HD64461) + if (irq == CONFIG_HD64461_IRQ) { + unsigned short bit; + unsigned short nirr = inw(HD64461_NIRR); + unsigned short nimr = inw(HD64461_NIMR); + nirr &= ~nimr; + for (bit = 1, irq = 0; irq < 16; bit <<= 1, irq++) + if (nirr & bit) break; + if (irq == 16) irq = CONFIG_HD64461_IRQ; + else irq += HD64461_IRQBASE; + } +#endif kstat.irqs[cpu][irq]++; desc = irq_desc + irq; diff -u --recursive --new-file v2.4.0-test1/linux/arch/sh/kernel/process.c linux/arch/sh/kernel/process.c --- v2.4.0-test1/linux/arch/sh/kernel/process.c Wed Apr 26 16:34:07 2000 +++ linux/arch/sh/kernel/process.c Mon Jun 19 17:59:37 2000 @@ -339,7 +339,7 @@ error = do_execve(filename, uargv, uenvp, ®s); if (error == 0) - current->flags &= ~PF_DTRACE; + current->ptrace &= ~PT_DTRACE; putname(filename); out: unlock_kernel(); @@ -384,11 +384,21 @@ restore_flags(flags); } -asmlinkage void break_point_trap(void) +asmlinkage void break_point_trap(unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, + struct pt_regs regs) { - /* Clear traicng. */ + /* Clear tracing. */ ctrl_outw(0, UBC_BBRA); ctrl_outw(0, UBC_BBRB); + force_sig(SIGTRAP, current); +} + +asmlinkage void break_point_trap_software(unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, + struct pt_regs regs) +{ + regs.pc -= 2; force_sig(SIGTRAP, current); } diff -u --recursive --new-file v2.4.0-test1/linux/arch/sh/kernel/ptrace.c linux/arch/sh/kernel/ptrace.c --- v2.4.0-test1/linux/arch/sh/kernel/ptrace.c Tue May 23 15:31:34 2000 +++ linux/arch/sh/kernel/ptrace.c Mon Jun 19 17:59:37 2000 @@ -1,4 +1,4 @@ -/* $Id: ptrace.c,v 1.5 2000/05/09 01:42:21 gniibe Exp $ +/* $Id: ptrace.c,v 1.6 2000/06/08 23:44:50 gniibe Exp $ * * linux/arch/sh/kernel/ptrace.c * @@ -10,6 +10,7 @@ * */ +#include #include #include #include @@ -121,13 +122,21 @@ { ctrl_outl(nextpc1, UBC_BARA); ctrl_outb(asid, UBC_BASRA); +#if defined(CONFIG_CPU_SUBTYPE_SH7709) + ctrl_outl(0x0fff, UBC_BAMRA); +#else ctrl_outb(BAMR_12, UBC_BAMRA); +#endif ctrl_outw(BBR_INST | BBR_READ, UBC_BBRA); if (nextpc2 != (unsigned long) -1) { ctrl_outl(nextpc2, UBC_BARB); ctrl_outb(asid, UBC_BASRB); +#if defined(CONFIG_CPU_SUBTYPE_SH7709) + ctrl_outl(0x0fff, UBC_BAMRA); +#else ctrl_outb(BAMR_12, UBC_BAMRB); +#endif ctrl_outw(BBR_INST | BBR_READ, UBC_BBRB); } ctrl_outw(BRCR_PCBA | BRCR_PCBB, UBC_BRCR); @@ -143,10 +152,10 @@ ret = -EPERM; if (request == PTRACE_TRACEME) { /* are we already being traced? */ - if (current->flags & PF_PTRACED) + if (current->ptrace & PT_PTRACED) goto out; /* set the ptrace bit in the process flags. */ - current->flags |= PF_PTRACED; + current->ptrace |= PT_PTRACED; ret = 0; goto out; } @@ -176,9 +185,9 @@ (tsk->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) goto out_tsk; /* the same process cannot be attached many times */ - if (child->flags & PF_PTRACED) + if (child->ptrace & PT_PTRACED) goto out_tsk; - child->flags |= PF_PTRACED; + child->ptrace |= PT_PTRACED; write_lock_irq(&tasklist_lock); if (child->p_pptr != tsk) { @@ -193,7 +202,7 @@ goto out_tsk; } ret = -ESRCH; - if (!(child->flags & PF_PTRACED)) + if (!(child->ptrace & PT_PTRACED)) goto out_tsk; if (child->state != TASK_STOPPED) { if (request != PTRACE_KILL) @@ -280,9 +289,9 @@ if ((unsigned long) data > _NSIG) break; if (request == PTRACE_SYSCALL) - child->flags |= PF_TRACESYS; + child->ptrace |= PT_TRACESYS; else - child->flags &= ~PF_TRACESYS; + child->ptrace &= ~PT_TRACESYS; child->exit_code = data; wake_up_process(child); ret = 0; @@ -313,16 +322,16 @@ ret = -EIO; if ((unsigned long) data > _NSIG) break; - child->flags &= ~PF_TRACESYS; - if ((child->flags & PF_DTRACE) == 0) { + child->ptrace &= ~PT_TRACESYS; + if ((child->ptrace & PT_DTRACE) == 0) { /* Spurious delayed TF traps may occur */ - child->flags |= PF_DTRACE; + child->ptrace |= PT_DTRACE; } /* Compute next pc. */ pc = get_stack_long(child, (long)&dummy->pc); regs = (struct pt_regs *)((unsigned long)child + THREAD_SIZE - sizeof(struct pt_regs)); - if (access_process_vm(child, pc&~3, &tmp, sizeof(tmp), 1) != sizeof(data)) + if (access_process_vm(child, pc&~3, &tmp, sizeof(tmp), 0) != sizeof(tmp)) break; #ifdef __LITTLE_ENDIAN__ @@ -357,7 +366,7 @@ ret = -EIO; if ((unsigned long) data > _NSIG) break; - child->flags &= ~(PF_PTRACED|PF_TRACESYS); + child->ptrace &= ~(PT_PTRACED|PT_TRACESYS); child->exit_code = data; write_lock_irq(&tasklist_lock); REMOVE_LINKS(child); @@ -384,8 +393,8 @@ { struct task_struct *tsk = current; - if ((tsk->flags & (PF_PTRACED|PF_TRACESYS)) - != (PF_PTRACED|PF_TRACESYS)) + if ((tsk->ptrace & (PT_PTRACED|PT_TRACESYS)) + != (PT_PTRACED|PT_TRACESYS)) return; tsk->exit_code = SIGTRAP; tsk->state = TASK_STOPPED; diff -u --recursive --new-file v2.4.0-test1/linux/arch/sh/kernel/setup.c linux/arch/sh/kernel/setup.c --- v2.4.0-test1/linux/arch/sh/kernel/setup.c Wed Apr 26 16:34:07 2000 +++ linux/arch/sh/kernel/setup.c Mon Jun 19 17:59:37 2000 @@ -110,23 +110,6 @@ static unsigned long memory_start, memory_end; -unsigned long __init memparse(char *ptr, char **retptr) -{ - unsigned long ret; - - ret = simple_strtoul(ptr, retptr, 0); - - if (**retptr == 'K' || **retptr == 'k') { - ret <<= 10; - (*retptr)++; - } - else if (**retptr == 'M' || **retptr == 'm') { - ret <<= 20; - (*retptr)++; - } - return ret; -} /* memparse */ - static inline void parse_mem_cmdline (char ** cmdline_p) { char c = ' ', *to = command_line, *from = COMMAND_LINE; @@ -326,6 +309,14 @@ p += sprintf(p, "bogomips\t: %lu.%02lu\n\n", (loops_per_sec+2500)/500000, ((loops_per_sec+2500)/5000) % 100); + +#define PRINT_CLOCK(name, value) \ + p += sprintf(p, name " clock: %d.%02dMHz\n", \ + ((value) / 1000000), ((value) % 1000000)/10000) + + PRINT_CLOCK("CPU", boot_cpu_data.cpu_clock); + PRINT_CLOCK("Bus", boot_cpu_data.bus_clock); + PRINT_CLOCK("Peripheral module", boot_cpu_data.module_clock); return p - buffer; } diff -u --recursive --new-file v2.4.0-test1/linux/arch/sh/kernel/setup_hd64461.c linux/arch/sh/kernel/setup_hd64461.c --- v2.4.0-test1/linux/arch/sh/kernel/setup_hd64461.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/setup_hd64461.c Mon Jun 19 17:59:37 2000 @@ -0,0 +1,128 @@ +/* + * $Id: setup_hd64461.c,v 1.1 2000/06/10 21:45:18 yaegashi Exp $ + * Copyright (C) 2000 YAEGASHI Takeshi + * Hitachi HD64461 companion chip support + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +static void disable_hd64461_irq(unsigned int irq) +{ + unsigned long flags; + unsigned short nimr; + unsigned short mask = 1 << (irq - HD64461_IRQBASE); + + save_and_cli(flags); + nimr = inw(HD64461_NIMR); + nimr |= mask; + outw(nimr, HD64461_NIMR); + restore_flags(flags); +} + + +static void enable_hd64461_irq(unsigned int irq) +{ + unsigned long flags; + unsigned short nimr; + unsigned short mask = 1 << (irq - HD64461_IRQBASE); + + save_and_cli(flags); + nimr = inw(HD64461_NIMR); + nimr &= ~mask; + outw(nimr, HD64461_NIMR); + restore_flags(flags); +} + + +static void mask_and_ack_hd64461(unsigned int irq) +{ + disable_hd64461_irq(irq); +#ifdef CONFIG_HD64461_ENABLER + if (irq == HD64461_IRQBASE + 13) + outb(0x00, HD64461_PCC1CSCR); +#endif +} + + +static void end_hd64461_irq(unsigned int irq) +{ + enable_hd64461_irq(irq); +} + + +static unsigned int startup_hd64461_irq(unsigned int irq) +{ + enable_hd64461_irq(irq); + return 0; +} + + +static void shutdown_hd64461_irq(unsigned int irq) +{ + disable_hd64461_irq(irq); +} + + +static struct hw_interrupt_type hd64461_irq_type = { + "HD64461-IRQ", + startup_hd64461_irq, + shutdown_hd64461_irq, + enable_hd64461_irq, + disable_hd64461_irq, + mask_and_ack_hd64461, + end_hd64461_irq +}; + + +static void hd64461_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + printk(KERN_INFO + "HD64461: spurious interrupt, nirr: 0x%lx nimr: 0x%lx\n", + inw(HD64461_NIRR), inw(HD64461_NIMR)); +} + + +static struct irqaction irq0 = { hd64461_interrupt, SA_INTERRUPT, 0, "HD64461", NULL, NULL}; + + +int __init setup_hd64461(void) +{ + int i; + + printk(KERN_INFO "HD64461 configured at 0x%x on irq %d(mapped into %d to %d)\n", + CONFIG_HD64461_IOBASE, CONFIG_HD64461_IRQ, + HD64461_IRQBASE, HD64461_IRQBASE+15); +#if 1 + /* IRQ line for HD64461 should be set level trigger mode("10"). */ + /* And this should be done earlier than the kernel starts. */ + ctrl_outw(0x0200, INTC_ICR1); /* when connected to IRQ4. */ +#endif + outw(0xffff, HD64461_NIMR); + + for (i = HD64461_IRQBASE; i < HD64461_IRQBASE + 16; i++) { + irq_desc[i].handler = &hd64461_irq_type; + } + + setup_irq(CONFIG_HD64461_IRQ, &irq0); + +#ifdef CONFIG_HD64461_ENABLER + printk(KERN_INFO "HD64461: enabling PCMCIA devices\n"); + outb(0x04, HD64461_PCC1CSCIER); + outb(0x00, HD64461_PCC1CSCR); +#endif + + return 0; +} + +module_init(setup_hd64461); diff -u --recursive --new-file v2.4.0-test1/linux/arch/sh/kernel/setup_od.c linux/arch/sh/kernel/setup_od.c --- v2.4.0-test1/linux/arch/sh/kernel/setup_od.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/setup_od.c Mon Jun 19 17:59:37 2000 @@ -0,0 +1,35 @@ +/* $Id: setup_od.c,v 1.1 2000/06/14 09:35:59 stuart_menefy Exp $ + * + * arch/sh/kernel/setup_od.c + * + * Copyright (C) 2000 Stuart Menefy + * + * STMicroelectronics Overdrive Support. + * + */ + +#include +#include +#include + +/* + * Initialize the board + */ +int __init setup_od(void) +{ + /* Enable RS232 receive buffers */ + volatile int* p = (volatile int*)0xa3000000; + +#if defined(CONFIG_SH_ORION) + *p=1; +#elif defined(CONFIG_SH_OVERDRIVE) + *p=0x1e; +#else +#error Illegal configuration +#endif + + printk(KERN_INFO "STMicroelectronics Overdrive Setup...done\n"); + return 0; +} + +module_init(setup_od); diff -u --recursive --new-file v2.4.0-test1/linux/arch/sh/kernel/signal.c linux/arch/sh/kernel/signal.c --- v2.4.0-test1/linux/arch/sh/kernel/signal.c Mon Jun 19 16:31:58 2000 +++ linux/arch/sh/kernel/signal.c Mon Jun 19 17:59:37 2000 @@ -595,7 +595,7 @@ if (!signr) break; - if ((current->flags & PF_PTRACED) && signr != SIGKILL) { + if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { /* Let the debugger run. */ current->exit_code = signr; current->state = TASK_STOPPED; diff -u --recursive --new-file v2.4.0-test1/linux/arch/sh/kernel/time.c linux/arch/sh/kernel/time.c --- v2.4.0-test1/linux/arch/sh/kernel/time.c Tue May 23 15:31:34 2000 +++ linux/arch/sh/kernel/time.c Mon Jun 19 17:59:37 2000 @@ -8,6 +8,7 @@ * Copyright (C) 1991, 1992, 1995 Linus Torvalds */ +#include #include #include #include @@ -421,7 +422,11 @@ tmp = (frqcr & 0x2000) >> 11; tmp |= frqcr & 0x0003; pfc = pfc_table[tmp]; +#ifdef CONFIG_SH_HP600 + master_clock = cpu_clock/6; +#else master_clock = cpu_clock; +#endif bus_clock = master_clock/pfc; } #elif defined(__SH4__) @@ -443,6 +448,11 @@ interval = (module_clock/(HZ*4)); printk("Interval = %ld\n", interval); + + current_cpu_data.cpu_clock = cpu_clock; + current_cpu_data.master_clock = master_clock; + current_cpu_data.bus_clock = bus_clock; + current_cpu_data.module_clock = module_clock; /* Start TMU0 */ ctrl_outb(TMU_TOCR_INIT, TMU_TOCR); diff -u --recursive --new-file v2.4.0-test1/linux/arch/sh/mm/fault.c linux/arch/sh/mm/fault.c --- v2.4.0-test1/linux/arch/sh/mm/fault.c Tue May 23 15:31:34 2000 +++ linux/arch/sh/mm/fault.c Mon Jun 19 17:59:37 2000 @@ -82,7 +82,7 @@ return 0; } -static void handle_vmalloc_fault(struct task_struct *tsk, unsigned long address) +static void handle_vmalloc_fault(struct mm_struct *mm, unsigned long address) { pgd_t *dir; pmd_t *pmd; @@ -107,6 +107,13 @@ return; } +#if defined(__SH4__) + /* + * ITLB is not affected by "ldtlb" instruction. + * So, we need to flush the entry by ourselves. + */ + __flush_tlb_page(mm, address&PAGE_MASK); +#endif update_mmu_cache(NULL, address, entry); } @@ -128,7 +135,7 @@ mm = tsk->mm; if (address >= VMALLOC_START && address < VMALLOC_END) { - handle_vmalloc_fault(tsk, address); + handle_vmalloc_fault(mm, address); return; } @@ -269,18 +276,13 @@ unsigned long pteaddr; save_and_cli(flags); -#if defined(__SH4__) - /* - * ITLB is not affected by "ldtlb" instruction. - * So, we need to flush the entry by ourselves. - */ - __flush_tlb_page(vma->vm_mm, address&PAGE_MASK); -#endif /* Set PTEH register */ - pteaddr = (address & MMU_VPN_MASK) | - (vma->vm_mm->context & MMU_CONTEXT_ASID_MASK); - ctrl_outl(pteaddr, MMU_PTEH); + if (vma) { + pteaddr = (address & MMU_VPN_MASK) | + (vma->vm_mm->context & MMU_CONTEXT_ASID_MASK); + ctrl_outl(pteaddr, MMU_PTEH); + } /* Set PTEL register */ pteval = pte_val(pte); diff -u --recursive --new-file v2.4.0-test1/linux/arch/sh/vmlinux.lds.S linux/arch/sh/vmlinux.lds.S --- v2.4.0-test1/linux/arch/sh/vmlinux.lds.S Tue Mar 7 14:32:25 2000 +++ linux/arch/sh/vmlinux.lds.S Mon Jun 19 17:59:37 2000 @@ -15,12 +15,14 @@ . = 0x80000000 + CONFIG_MEMORY_START + 0x1000; _text = .; /* Text and read-only data */ text = .; /* Text and read-only data */ - .text : { + .empty_zero_page : { *(.empty_zero_page) + } = 0 + .text : { *(.text) *(.fixup) *(.gnu.warning) - } = 0 + } = 0x0009 .text.lock : { *(.text.lock) } /* out-of-line lock text */ .rodata : { *(.rodata) } .kstrtab : { *(.kstrtab) } diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc/config.in linux/arch/sparc/config.in --- v2.4.0-test1/linux/arch/sparc/config.in Tue May 23 15:31:34 2000 +++ linux/arch/sparc/config.in Thu Jun 22 07:21:12 2000 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.93 2000/05/22 08:12:19 davem Exp $ +# $Id: config.in,v 1.96 2000/06/20 01:10:00 anton Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -12,6 +12,15 @@ endmenu mainmenu_option next_comment +comment 'Loadable module support' +bool 'Enable loadable module support' CONFIG_MODULES +if [ "$CONFIG_MODULES" = "y" ]; then + bool ' Set version information on all symbols for modules' CONFIG_MODVERSIONS + bool ' Kernel module loader' CONFIG_KMOD +fi +endmenu + +mainmenu_option next_comment comment 'General setup' define_bool CONFIG_VT y @@ -59,15 +68,6 @@ endmenu mainmenu_option next_comment -comment 'Loadable module support' -bool 'Enable loadable module support' CONFIG_MODULES -if [ "$CONFIG_MODULES" = "y" ]; then - bool ' Set version information on all symbols for modules' CONFIG_MODVERSIONS - bool ' Kernel module loader' CONFIG_KMOD -fi -endmenu - -mainmenu_option next_comment comment 'Console drivers' bool 'PROM console' CONFIG_PROM_CONSOLE source drivers/video/Config.in @@ -92,9 +92,10 @@ fi tristate 'RAM disk support' CONFIG_BLK_DEV_RAM -if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then - bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD +if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then + int ' Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096 fi +dep_bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP tristate 'Network block device support' CONFIG_BLK_DEV_NBD @@ -105,22 +106,27 @@ source net/Config.in fi -define_bool CONFIG_IDE n -define_bool CONFIG_BLK_DEV_IDE_MODES n -define_bool CONFIG_BLK_DEV_HD n +# Don't frighten a common SBus user +if [ "$CONFIG_PCI" = "y" ]; then -# mainmenu_option next_comment -# comment 'ATA/IDE/MFM/RLL support' -# -# tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE -# -# if [ "$CONFIG_IDE" != "n" ]; then -# source drivers/ide/Config.in -# else -# define_bool CONFIG_BLK_DEV_IDE_MODES n -# define_bool CONFIG_BLK_DEV_HD n -# fi -# endmenu + mainmenu_option next_comment + comment 'ATA/IDE/MFM/RLL support' + + tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE + + if [ "$CONFIG_IDE" != "n" ]; then + source drivers/ide/Config.in + else + define_bool CONFIG_BLK_DEV_IDE_MODES n + define_bool CONFIG_BLK_DEV_HD n + fi + endmenu +else + + define_bool CONFIG_IDE n + define_bool CONFIG_BLK_DEV_IDE_MODES n + define_bool CONFIG_BLK_DEV_HD n +fi mainmenu_option next_comment comment 'ISDN subsystem' @@ -211,6 +217,9 @@ fi tristate ' Sun QuadEthernet support' CONFIG_SUNQE tristate ' MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS + if [ "$CONFIG_PCI" = "y" ]; then + tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX + fi # bool ' FDDI driver support' CONFIG_FDDI # if [ "$CONFIG_FDDI" = "y" ]; then diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc/defconfig linux/arch/sparc/defconfig --- v2.4.0-test1/linux/arch/sparc/defconfig Thu May 11 15:30:06 2000 +++ linux/arch/sparc/defconfig Mon Jun 19 17:59:38 2000 @@ -9,6 +9,13 @@ CONFIG_EXPERIMENTAL=y # +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y + +# # General setup # CONFIG_VT=y @@ -47,13 +54,6 @@ # CONFIG_PRINTER is not set # -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_MODVERSIONS=y -CONFIG_KMOD=y - -# # Console drivers # CONFIG_PROM_CONSOLE=y @@ -149,9 +149,9 @@ CONFIG_DECNET=m CONFIG_DECNET_SIOCGIFCONF=y # CONFIG_DECNET_ROUTER is not set +# CONFIG_BRIDGE is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set # CONFIG_LLC is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set @@ -252,6 +252,7 @@ CONFIG_AUTOFS_FS=m CONFIG_AUTOFS4_FS=m # CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set CONFIG_AFFS_FS=m # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set @@ -261,10 +262,12 @@ CONFIG_VFAT_FS=m CONFIG_EFS_FS=m # CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set CONFIG_ISO9660_FS=m # CONFIG_JOLIET is not set CONFIG_MINIX_FS=m # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set CONFIG_HPFS_FS=m CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set @@ -272,11 +275,13 @@ # CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set CONFIG_ROMFS_FS=m CONFIG_EXT2_FS=y CONFIG_SYSV_FS=m # CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set CONFIG_UFS_FS=m # CONFIG_UFS_FS_WRITE is not set @@ -285,9 +290,11 @@ # CONFIG_CODA_FS=m CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set # CONFIG_ROOT_NFS is not set CONFIG_NFSD=m # CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_TCP is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y CONFIG_SMB_FS=m diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc/kernel/ebus.c linux/arch/sparc/kernel/ebus.c --- v2.4.0-test1/linux/arch/sparc/kernel/ebus.c Fri Jan 28 15:09:07 2000 +++ linux/arch/sparc/kernel/ebus.c Thu Jun 22 07:21:12 2000 @@ -1,4 +1,4 @@ -/* $Id: ebus.c,v 1.9 2000/01/22 07:35:25 zaitcev Exp $ +/* $Id: ebus.c,v 1.10 2000/06/20 01:10:00 anton Exp $ * ebus.c: PCI to EBus bridge device. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -127,13 +127,13 @@ if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_name)) != 0) { dev->num_irqs = 1; } else if ((len = prom_getproperty(node, "interrupts", - (char *)&irqs, sizeof(irqs)) == -1) || (len == 0)) { + (char *)&irqs, sizeof(irqs))) == -1 || len == 0) { dev->num_irqs = 0; dev->irqs[0] = 0; if (dev->parent->num_irqs != 0) { dev->num_irqs = 1; dev->irqs[0] = dev->parent->irqs[0]; -/* P3 remove */ printk("EBUS: dev %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); +/* P3 */ /* printk("EBUS: dev %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); */ } } else { dev->num_irqs = len / sizeof(irqs[0]); @@ -219,11 +219,11 @@ if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_name)) != 0) { dev->num_irqs = 1; } else if ((len = prom_getproperty(node, "interrupts", - (char *)&irqs, sizeof(irqs)) == -1) || (len == 0)) { + (char *)&irqs, sizeof(irqs))) == -1 || len == 0) { dev->num_irqs = 0; if ((dev->irqs[0] = dev->bus->self->irq) != 0) { dev->num_irqs = 1; -/* P3 remove */ printk("EBUS: child %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); +/* P3 */ /* printk("EBUS: child %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); */ } } else { dev->num_irqs = 1; /* dev->num_irqs = len / sizeof(irqs[0]); */ diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc/kernel/entry.S linux/arch/sparc/kernel/entry.S --- v2.4.0-test1/linux/arch/sparc/kernel/entry.S Tue May 23 15:31:34 2000 +++ linux/arch/sparc/kernel/entry.S Mon Jun 19 17:59:38 2000 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.164 2000/05/09 17:40:13 davem Exp $ +/* $Id: entry.S,v 1.166 2000/06/19 06:24:36 davem Exp $ * arch/sparc/kernel/entry.S: Sparc trap low-level entry points. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -945,7 +945,7 @@ and %l5, %l4, %l5 /* Test for NULL pte_t * in vmalloc area. */ - sethi %hi(SUN4C_VMALLOC_START), %l4 + sethi %hi(VMALLOC_START), %l4 cmp %l5, %l4 blu,a C_LABEL(invalid_segment_patch1) lduXa [%l5] ASI_SEGMAP, %l4 @@ -1072,7 +1072,7 @@ andn %l4, 0x1ff, %l5 1: - sethi %hi(SUN4C_VMALLOC_START), %l4 + sethi %hi(VMALLOC_START), %l4 cmp %l5, %l4 bgeu 1f @@ -1233,8 +1233,8 @@ call C_LABEL(do_ptrace) add %sp, REGWIN_SZ, %o0 - ld [%curptr + AOFF_task_flags], %l5 - andcc %l5, 0x20, %g0 + ld [%curptr + AOFF_task_ptrace], %l5 + andcc %l5, 0x02, %g0 be 1f nop @@ -1283,8 +1283,8 @@ call C_LABEL(do_sigpause) add %sp, REGWIN_SZ, %o1 - ld [%curptr + AOFF_task_flags], %l5 - andcc %l5, 0x20, %g0 + ld [%curptr + AOFF_task_ptrace], %l5 + andcc %l5, 0x02, %g0 be 1f nop @@ -1301,8 +1301,8 @@ call C_LABEL(do_sigsuspend) add %sp, REGWIN_SZ, %o0 - ld [%curptr + AOFF_task_flags], %l5 - andcc %l5, 0x20, %g0 + ld [%curptr + AOFF_task_ptrace], %l5 + andcc %l5, 0x02, %g0 be 1f nop @@ -1320,8 +1320,8 @@ call C_LABEL(do_rt_sigsuspend) add %sp, REGWIN_SZ, %o2 - ld [%curptr + AOFF_task_flags], %l5 - andcc %l5, 0x20, %g0 + ld [%curptr + AOFF_task_ptrace], %l5 + andcc %l5, 0x02, %g0 be 1f nop @@ -1338,8 +1338,8 @@ call C_LABEL(do_sigreturn) add %sp, REGWIN_SZ, %o0 - ld [%curptr + AOFF_task_flags], %l5 - andcc %l5, 0x20, %g0 + ld [%curptr + AOFF_task_ptrace], %l5 + andcc %l5, 0x02, %g0 be 1f nop @@ -1358,8 +1358,8 @@ call C_LABEL(do_rt_sigreturn) add %sp, REGWIN_SZ, %o0 - ld [%curptr + AOFF_task_flags], %l5 - andcc %l5, 0x20, %g0 + ld [%curptr + AOFF_task_ptrace], %l5 + andcc %l5, 0x02, %g0 be 1f nop @@ -1496,9 +1496,9 @@ mov %i1, %o1 mov %i2, %o2 - ld [%curptr + AOFF_task_flags], %l5 + ld [%curptr + AOFF_task_ptrace], %l5 mov %i3, %o3 - andcc %l5, 0x20, %g0 + andcc %l5, 0x02, %g0 mov %i4, %o4 bne linux_syscall_trace mov %i0, %l5 @@ -1510,12 +1510,12 @@ .globl C_LABEL(ret_sys_call) C_LABEL(ret_sys_call): - ld [%curptr + AOFF_task_flags], %l6 + ld [%curptr + AOFF_task_ptrace], %l6 cmp %o0, -ENOIOCTLCMD ld [%sp + REGWIN_SZ + PT_PSR], %g3 set PSR_C, %g2 bgeu 1f - andcc %l6, 0x20, %l6 + andcc %l6, 0x02, %l6 /* System call success, clear Carry condition code. */ andn %g3, %g2, %g3 diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc/kernel/ioport.c linux/arch/sparc/kernel/ioport.c --- v2.4.0-test1/linux/arch/sparc/kernel/ioport.c Tue Apr 11 15:09:14 2000 +++ linux/arch/sparc/kernel/ioport.c Thu Jun 22 07:21:12 2000 @@ -1,4 +1,4 @@ -/* $Id: ioport.c,v 1.37 2000/03/28 06:38:19 davem Exp $ +/* $Id: ioport.c,v 1.39 2000/06/20 01:10:00 anton Exp $ * ioport.c: Simple io mapping allocator. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -43,6 +43,8 @@ #include #include +#define mmu_inval_dma_area(p, l) /* Anton pulled it out for 2.4.0-xx */ + struct resource *_sparc_find_resource(struct resource *r, unsigned long); static void *_sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz); @@ -52,11 +54,11 @@ /* This points to the next to use virtual memory for DVMA mappings */ static struct resource _sparc_dvma = { - "sparc_dvma", DVMA_VADDR, DVMA_VADDR + DVMA_LEN - 1 + "sparc_dvma", DVMA_VADDR, DVMA_END - 1 }; /* This points to the start of I/O mappings, cluable from outside. */ /*ext*/ struct resource sparc_iomap = { - "sparc_iomap", IOBASE_VADDR, IOBASE_END-1 + "sparc_iomap", IOBASE_VADDR, IOBASE_END - 1 }; /* @@ -453,7 +455,11 @@ panic("sbus_dma_sync_single: 0x%x\n", ba); va = (unsigned long) phys_to_virt(mmu_translate_dvma(ba)); - mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); + /* + * XXX This bogosity will be fixed with the iommu rewrite coming soon + * to a kernel near you. - Anton + */ + /* mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); */ } void sbus_dma_sync_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction) diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc/kernel/pcic.c linux/arch/sparc/kernel/pcic.c --- v2.4.0-test1/linux/arch/sparc/kernel/pcic.c Thu Mar 2 14:36:22 2000 +++ linux/arch/sparc/kernel/pcic.c Thu Jun 22 07:21:12 2000 @@ -1,4 +1,4 @@ -/* $Id: pcic.c,v 1.14 2000/03/01 02:53:28 davem Exp $ +/* $Id: pcic.c,v 1.15 2000/06/20 01:10:00 anton Exp $ * pcic.c: Sparc/PCI controller support * * Copyright (C) 1998 V. Roganov and G. Raiko @@ -155,8 +155,15 @@ /* * Krups (courtesy of Varol Kaptan) - * No documentation available, so we guess it, based on Espresso layout. - * Since we always run PROLL on Krups we may put map in there. + * No documentation available, but it was easy to guess + * because it was very similar to Espresso. + * + * pin 0 - kbd, mouse, serial; + * pin 1 - Ethernet; + * pin 2 - igs (we do not use it); + * pin 3 - audio; + * pin 4,5,6 - unused; + * pin 7 - RTC (from P2 onwards as David B. says). */ static struct pcic_ca2irq pcic_i_jk[] = { { 0, 0x00, 0, 13, 0 }, /* Ebus - serial and keyboard */ @@ -600,10 +607,10 @@ } else { /* Corrupted map */ printk("PCIC: BAD PIN %d\n", i); for (;;) {} } -/* P3 remove later */ printk("PCIC: device %s pin %d ivec 0x%x irq %x\n", namebuf, i, ivec, dev->irq); +/* P3 */ /* printk("PCIC: device %s pin %d ivec 0x%x irq %x\n", namebuf, i, ivec, dev->irq); */ /* - * dev->irq=0 means PROM did not bothered to program the upper + * dev->irq=0 means PROM did not bother to program the upper * half of PCIC. This happens on JS-E with PROM 3.11, for instance. */ if (dev->irq == 0 || p->force) { @@ -730,7 +737,7 @@ printk("PCIC: BAD PIN %d FOR %s\n", pin, name); for (;;) {} /* XXX Cannot panic properly in case of PROLL */ } -/* P3 remove later */ printk("PCIC: dev %s pin %d ivec 0x%x irq %x\n", name, pin, ivec, irq); +/* P3 */ /* printk("PCIC: dev %s pin %d ivec 0x%x irq %x\n", name, pin, ivec, irq); */ return irq; } diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc/kernel/ptrace.c linux/arch/sparc/kernel/ptrace.c --- v2.4.0-test1/linux/arch/sparc/kernel/ptrace.c Wed Apr 26 16:34:07 2000 +++ linux/arch/sparc/kernel/ptrace.c Mon Jun 19 17:59:38 2000 @@ -289,12 +289,12 @@ #endif if(request == PTRACE_TRACEME) { /* are we already being traced? */ - if (current->flags & PF_PTRACED) { + if (current->ptrace & PT_PTRACED) { pt_error_return(regs, EPERM); goto out; } /* set the ptrace bit in the process flags. */ - current->flags |= PF_PTRACED; + current->ptrace |= PT_PTRACED; pt_succ_return(regs, 0); goto out; } @@ -333,11 +333,11 @@ goto out; } /* the same process cannot be attached many times */ - if (child->flags & PF_PTRACED) { + if (child->ptrace & PT_PTRACED) { pt_error_return(regs, EPERM); goto out; } - child->flags |= PF_PTRACED; + child->ptrace |= PT_PTRACED; write_lock_irqsave(&tasklist_lock, flags); if(child->p_pptr != current) { REMOVE_LINKS(child); @@ -349,7 +349,7 @@ pt_succ_return(regs, 0); goto out; } - if (!(child->flags & PF_PTRACED)) { + if (!(child->ptrace & PT_PTRACED)) { pt_error_return(regs, ESRCH); goto out; } @@ -566,9 +566,9 @@ } if (request == PTRACE_SYSCALL) - child->flags |= PF_TRACESYS; + child->ptrace |= PT_TRACESYS; else - child->flags &= ~PF_TRACESYS; + child->ptrace &= ~PT_TRACESYS; child->exit_code = data; #ifdef DEBUG_PTRACE @@ -605,7 +605,7 @@ pt_error_return(regs, EIO); goto out; } - child->flags &= ~(PF_PTRACED|PF_TRACESYS); + child->ptrace &= ~(PT_PTRACED|PT_TRACESYS); wake_up_process(child); child->exit_code = data; write_lock_irqsave(&tasklist_lock, flags); @@ -632,8 +632,8 @@ #ifdef DEBUG_PTRACE printk("%s [%d]: syscall_trace\n", current->comm, current->pid); #endif - if ((current->flags & (PF_PTRACED|PF_TRACESYS)) - != (PF_PTRACED|PF_TRACESYS)) + if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) + != (PT_PTRACED|PT_TRACESYS)) return; current->exit_code = SIGTRAP; current->state = TASK_STOPPED; diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc/kernel/signal.c linux/arch/sparc/kernel/signal.c --- v2.4.0-test1/linux/arch/sparc/kernel/signal.c Mon Jun 19 16:31:58 2000 +++ linux/arch/sparc/kernel/signal.c Mon Jun 19 17:59:38 2000 @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.103 2000/05/09 17:40:13 davem Exp $ +/* $Id: signal.c,v 1.105 2000/06/19 06:24:37 davem Exp $ * linux/arch/sparc/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -1177,7 +1177,7 @@ if (!signr) break; - if ((current->flags & PF_PTRACED) && signr != SIGKILL) { + if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { current->exit_code = signr; current->state = TASK_STOPPED; @@ -1241,7 +1241,7 @@ continue; case SIGSTOP: - if (current->flags & PF_PTRACED) + if (current->ptrace & PT_PTRACED) continue; current->state = TASK_STOPPED; current->exit_code = signr; diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc/kernel/sys_sparc.c linux/arch/sparc/kernel/sys_sparc.c --- v2.4.0-test1/linux/arch/sparc/kernel/sys_sparc.c Sun Feb 20 21:12:38 2000 +++ linux/arch/sparc/kernel/sys_sparc.c Thu Jun 22 07:21:12 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.61 2000/02/16 07:31:29 davem Exp $ +/* $Id: sys_sparc.c,v 1.63 2000/06/22 11:42:25 davem Exp $ * linux/arch/sparc/kernel/sys_sparc.c * * This file contains various random system calls that diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c --- v2.4.0-test1/linux/arch/sparc/kernel/sys_sunos.c Tue May 23 15:31:34 2000 +++ linux/arch/sparc/kernel/sys_sunos.c Thu Jun 22 07:21:12 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.123 2000/05/22 07:29:39 davem Exp $ +/* $Id: sys_sunos.c,v 1.125 2000/06/22 11:42:25 davem Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc/kernel/time.c linux/arch/sparc/kernel/time.c --- v2.4.0-test1/linux/arch/sparc/kernel/time.c Tue May 23 15:31:34 2000 +++ linux/arch/sparc/kernel/time.c Mon Jun 19 17:59:38 2000 @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.55 2000/05/09 17:40:13 davem Exp $ +/* $Id: time.c,v 1.56 2000/06/13 22:51:28 anton Exp $ * linux/arch/sparc/kernel/time.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -79,12 +79,15 @@ extern int _stext; extern int __copy_user_begin, __copy_user_end; extern int __atomic_begin, __atomic_end; + extern int __bzero_begin, __bzero_end; extern int __bitops_begin, __bitops_end; if ((pc >= (unsigned long) &__copy_user_begin && pc < (unsigned long) &__copy_user_end) || (pc >= (unsigned long) &__atomic_begin && pc < (unsigned long) &__atomic_end) || + (pc >= (unsigned long) &__bzero_begin && + pc < (unsigned long) &__bzero_end) || (pc >= (unsigned long) &__bitops_begin && pc < (unsigned long) &__bitops_end)) pc = o7; diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc/kernel/traps.c linux/arch/sparc/kernel/traps.c --- v2.4.0-test1/linux/arch/sparc/kernel/traps.c Tue May 23 15:31:34 2000 +++ linux/arch/sparc/kernel/traps.c Mon Jun 19 17:59:38 2000 @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.62 2000/05/09 17:40:13 davem Exp $ +/* $Id: traps.c,v 1.63 2000/06/04 06:23:52 anton Exp $ * arch/sparc/kernel/traps.c * * Copyright 1995 David S. Miller (davem@caip.rutgers.edu) @@ -498,8 +498,6 @@ */ extern void sparc_cpu_startup(void); - -extern ctxd_t *srmmu_ctx_table_phys; int linux_smp_still_initting; unsigned int thiscpus_tbr; diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc/lib/memset.S linux/arch/sparc/lib/memset.S --- v2.4.0-test1/linux/arch/sparc/lib/memset.S Mon Mar 17 14:54:22 1997 +++ linux/arch/sparc/lib/memset.S Mon Jun 19 17:59:38 2000 @@ -55,6 +55,9 @@ .text .align 4 + .globl __bzero_begin +__bzero_begin: + .globl C_LABEL(__bzero), C_LABEL(__memset), .globl C_LABEL(memset) .globl C_LABEL(__memset_start), C_LABEL(__memset_end) @@ -193,3 +196,6 @@ mov %i4, %o2 ret restore + + .globl __bzero_end +__bzero_end: diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc/mm/hypersparc.S linux/arch/sparc/mm/hypersparc.S --- v2.4.0-test1/linux/arch/sparc/mm/hypersparc.S Tue May 23 15:31:34 2000 +++ linux/arch/sparc/mm/hypersparc.S Mon Jun 19 17:59:38 2000 @@ -1,4 +1,4 @@ -/* $Id: hypersparc.S,v 1.15 2000/05/09 17:40:13 davem Exp $ +/* $Id: hypersparc.S,v 1.16 2000/06/04 06:23:52 anton Exp $ * hypersparc.S: High speed Hypersparc mmu/cache operations. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -28,7 +28,7 @@ .globl hypersparc_flush_cache_all, hypersparc_flush_cache_mm .globl hypersparc_flush_cache_range, hypersparc_flush_cache_page - .globl hypersparc_flush_page_to_ram, hypersparc_flush_chunk + .globl hypersparc_flush_page_to_ram .globl hypersparc_flush_page_for_dma, hypersparc_flush_sig_insns .globl hypersparc_flush_tlb_all, hypersparc_flush_tlb_mm .globl hypersparc_flush_tlb_range, hypersparc_flush_tlb_page @@ -229,7 +229,6 @@ /* HyperSparc is copy-back. */ hypersparc_flush_page_to_ram: -hypersparc_flush_chunk: sethi %hi(vac_line_size), %g1 ld [%g1 + %lo(vac_line_size)], %o4 andn %o0, (PAGE_SIZE - 1), %o0 diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c --- v2.4.0-test1/linux/arch/sparc/mm/init.c Tue May 23 15:31:34 2000 +++ linux/arch/sparc/mm/init.c Mon Jun 19 17:59:38 2000 @@ -1,10 +1,10 @@ -/* $Id: init.c,v 1.85 2000/05/09 17:40:13 davem Exp $ +/* $Id: init.c,v 1.86 2000/06/04 06:23:52 anton Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1995 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - * Copyright (C) 2000 Anton Blanchard (anton@progsoc.uts.edu.au) + * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com) */ #include @@ -125,9 +125,13 @@ unsigned long bootmap_pfn; int i; - /* Limit maximum memory until we implement highmem for sparc */ - if (!cmdline_memory_size || cmdline_memory_size > 0x0d000000) - cmdline_memory_size = 0x0d000000; + /* + * XXX Limit maximum memory until we implement highmem for sparc. + * The nocache region has taken up some room but I'll rearrange + * the virtual address regions soon - Anton + */ + if (!cmdline_memory_size || cmdline_memory_size > 0x0c000000) + cmdline_memory_size = 0x0c000000; /* XXX It is a bit ambiguous here, whether we should * XXX treat the user specified mem=xxx as total wanted diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c --- v2.4.0-test1/linux/arch/sparc/mm/srmmu.c Tue May 23 15:31:34 2000 +++ linux/arch/sparc/mm/srmmu.c Thu Jun 22 07:21:12 2000 @@ -1,11 +1,11 @@ -/* $Id: srmmu.c,v 1.209 2000/05/09 17:40:13 davem Exp $ +/* $Id: srmmu.c,v 1.214 2000/06/22 01:28:44 anton Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1995 Pete Zaitcev * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - * Copyright (C) 1999 Anton Blanchard (anton@progsoc.uts.edu.au) + * Copyright (C) 1999,2000 Anton Blanchard (anton@linuxcare.com) */ #include @@ -57,6 +57,8 @@ extern unsigned long last_valid_pfn; +pgd_t *srmmu_swapper_pg_dir; + #ifdef CONFIG_SMP #define FLUSH_BEGIN(mm) #define FLUSH_END @@ -65,40 +67,31 @@ #define FLUSH_END } #endif -BTFIXUPDEF_CALL(void, ctxd_set, ctxd_t *, pgd_t *) BTFIXUPDEF_CALL(void, pmd_set, pmd_t *, pte_t *) - -#define ctxd_set(ctxp,pgdp) BTFIXUP_CALL(ctxd_set)(ctxp,pgdp) #define pmd_set(pmdp,ptep) BTFIXUP_CALL(pmd_set)(pmdp,ptep) BTFIXUPDEF_CALL(void, flush_page_for_dma, unsigned long) -BTFIXUPDEF_CALL(void, flush_chunk, unsigned long) - #define flush_page_for_dma(page) BTFIXUP_CALL(flush_page_for_dma)(page) + int flush_page_for_dma_global = 1; -#define flush_chunk(chunk) BTFIXUP_CALL(flush_chunk)(chunk) + #ifdef CONFIG_SMP BTFIXUPDEF_CALL(void, local_flush_page_for_dma, unsigned long) - #define local_flush_page_for_dma(page) BTFIXUP_CALL(local_flush_page_for_dma)(page) #endif -static struct srmmu_stats { - int invall; - int invpg; - int invrnge; - int invmm; -} module_stats; - char *srmmu_name; ctxd_t *srmmu_ctx_table_phys; ctxd_t *srmmu_context_table; int viking_mxcc_present = 0; -static spinlock_t srmmu_context_spinlock = SPIN_LOCK_UNLOCKED; +spinlock_t srmmu_context_spinlock = SPIN_LOCK_UNLOCKED; + +int is_hypersparc; -/* In general all page table modifications should use the V8 atomic +/* + * In general all page table modifications should use the V8 atomic * swap instruction. This insures the mmu and the cpu are in sync * with respect to ref/mod bits in the page tables. */ @@ -108,8 +101,10 @@ return value; } -/* Functions really use this, not srmmu_swap directly. */ -#define srmmu_set_entry(ptr, newentry) srmmu_swap((unsigned long *) (ptr), (newentry)) +static inline void srmmu_set_pte(pte_t *ptep, pte_t pteval) +{ + srmmu_swap((unsigned long *)ptep, pte_val(pteval)); +} /* The very generic SRMMU page table operations. */ static inline int srmmu_device_memory(unsigned long x) @@ -117,31 +112,56 @@ return ((x & 0xF0000000) != 0); } -static unsigned long srmmu_pgd_page(pgd_t pgd) -{ return srmmu_device_memory(pgd_val(pgd))?~0:(unsigned long)__va((pgd_val(pgd) & SRMMU_PTD_PMASK) << 4); } +int srmmu_cache_pagetables; + +/* XXX Make this dynamic based on ram size - Anton */ +#define SRMMU_NOCACHE_NPAGES 256 +#define SRMMU_NOCACHE_VADDR 0xfc000000 +#define SRMMU_NOCACHE_SIZE (SRMMU_NOCACHE_NPAGES*PAGE_SIZE) +#define SRMMU_NOCACHE_END (SRMMU_NOCACHE_VADDR + SRMMU_NOCACHE_SIZE) +#define SRMMU_NOCACHE_BITMAP_SIZE (SRMMU_NOCACHE_NPAGES * 16) +#define SRMMU_NOCACHE_BITMAP_SHIFT (PAGE_SHIFT - 4) + +void *srmmu_nocache_pool; +void *srmmu_nocache_bitmap; +int srmmu_nocache_low; +int srmmu_nocache_used; +spinlock_t srmmu_nocache_spinlock; + +/* This makes sense. Honest it does - Anton */ +#define __nocache_pa(VADDR) (((unsigned long)VADDR) - SRMMU_NOCACHE_VADDR + __pa((unsigned long)srmmu_nocache_pool)) +#define __nocache_va(PADDR) (__va((unsigned long)PADDR) - (unsigned long)srmmu_nocache_pool + SRMMU_NOCACHE_VADDR) +#define __nocache_fix(VADDR) __va(__nocache_pa(VADDR)) + +static inline unsigned long srmmu_pgd_page(pgd_t pgd) +{ return srmmu_device_memory(pgd_val(pgd))?~0:(unsigned long)__nocache_va((pgd_val(pgd) & SRMMU_PTD_PMASK) << 4); } -static unsigned long srmmu_pmd_page(pmd_t pmd) -{ return srmmu_device_memory(pmd_val(pmd))?~0:(unsigned long)__va((pmd_val(pmd) & SRMMU_PTD_PMASK) << 4); } +static inline unsigned long srmmu_pmd_page(pmd_t pmd) +{ return srmmu_device_memory(pmd_val(pmd))?~0:(unsigned long)__nocache_va((pmd_val(pmd) & SRMMU_PTD_PMASK) << 4); } -static unsigned long srmmu_pte_pagenr(pte_t pte) +static inline unsigned long srmmu_pte_pagenr(pte_t pte) { return srmmu_device_memory(pte_val(pte))?~0:(((pte_val(pte) & SRMMU_PTE_PMASK) << 4) >> PAGE_SHIFT); } static inline int srmmu_pte_none(pte_t pte) { return !(pte_val(pte) & 0xFFFFFFF); } + static inline int srmmu_pte_present(pte_t pte) { return ((pte_val(pte) & SRMMU_ET_MASK) == SRMMU_ET_PTE); } -static inline void srmmu_pte_clear(pte_t *ptep) { set_pte(ptep, __pte(0)); } +static inline void srmmu_pte_clear(pte_t *ptep) +{ srmmu_set_pte(ptep, __pte(0)); } static inline int srmmu_pmd_none(pmd_t pmd) { return !(pmd_val(pmd) & 0xFFFFFFF); } + static inline int srmmu_pmd_bad(pmd_t pmd) { return (pmd_val(pmd) & SRMMU_ET_MASK) != SRMMU_ET_PTD; } static inline int srmmu_pmd_present(pmd_t pmd) { return ((pmd_val(pmd) & SRMMU_ET_MASK) == SRMMU_ET_PTD); } -static inline void srmmu_pmd_clear(pmd_t *pmdp) { set_pte((pte_t *)pmdp, __pte(0)); } +static inline void srmmu_pmd_clear(pmd_t *pmdp) +{ srmmu_set_pte((pte_t *)pmdp, __pte(0)); } static inline int srmmu_pgd_none(pgd_t pgd) { return !(pgd_val(pgd) & 0xFFFFFFF); } @@ -152,18 +172,35 @@ static inline int srmmu_pgd_present(pgd_t pgd) { return ((pgd_val(pgd) & SRMMU_ET_MASK) == SRMMU_ET_PTD); } -static inline void srmmu_pgd_clear(pgd_t * pgdp) { set_pte((pte_t *)pgdp, __pte(0)); } +static inline void srmmu_pgd_clear(pgd_t * pgdp) +{ srmmu_set_pte((pte_t *)pgdp, __pte(0)); } + +static inline int srmmu_pte_write(pte_t pte) +{ return pte_val(pte) & SRMMU_WRITE; } + +static inline int srmmu_pte_dirty(pte_t pte) +{ return pte_val(pte) & SRMMU_DIRTY; } + +static inline int srmmu_pte_young(pte_t pte) +{ return pte_val(pte) & SRMMU_REF; } + +static inline pte_t srmmu_pte_wrprotect(pte_t pte) +{ return __pte(pte_val(pte) & ~SRMMU_WRITE);} -static inline int srmmu_pte_write(pte_t pte) { return pte_val(pte) & SRMMU_WRITE; } -static inline int srmmu_pte_dirty(pte_t pte) { return pte_val(pte) & SRMMU_DIRTY; } -static inline int srmmu_pte_young(pte_t pte) { return pte_val(pte) & SRMMU_REF; } - -static inline pte_t srmmu_pte_wrprotect(pte_t pte) { return __pte(pte_val(pte) & ~SRMMU_WRITE);} -static inline pte_t srmmu_pte_mkclean(pte_t pte) { return __pte(pte_val(pte) & ~SRMMU_DIRTY);} -static inline pte_t srmmu_pte_mkold(pte_t pte) { return __pte(pte_val(pte) & ~SRMMU_REF);} -static inline pte_t srmmu_pte_mkwrite(pte_t pte) { return __pte(pte_val(pte) | SRMMU_WRITE);} -static inline pte_t srmmu_pte_mkdirty(pte_t pte) { return __pte(pte_val(pte) | SRMMU_DIRTY);} -static inline pte_t srmmu_pte_mkyoung(pte_t pte) { return __pte(pte_val(pte) | SRMMU_REF);} +static inline pte_t srmmu_pte_mkclean(pte_t pte) +{ return __pte(pte_val(pte) & ~SRMMU_DIRTY);} + +static inline pte_t srmmu_pte_mkold(pte_t pte) +{ return __pte(pte_val(pte) & ~SRMMU_REF);} + +static inline pte_t srmmu_pte_mkwrite(pte_t pte) +{ return __pte(pte_val(pte) | SRMMU_WRITE);} + +static inline pte_t srmmu_pte_mkdirty(pte_t pte) +{ return __pte(pte_val(pte) | SRMMU_DIRTY);} + +static inline pte_t srmmu_pte_mkyoung(pte_t pte) +{ return __pte(pte_val(pte) | SRMMU_REF);} /* * Conversion functions: convert a page and protection to a page entry, @@ -176,352 +213,290 @@ { return __pte(((page) >> 4) | pgprot_val(pgprot)); } static pte_t srmmu_mk_pte_io(unsigned long page, pgprot_t pgprot, int space) -{ - return __pte(((page) >> 4) | (space << 28) | pgprot_val(pgprot)); -} +{ return __pte(((page) >> 4) | (space << 28) | pgprot_val(pgprot)); } -static void srmmu_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp) -{ - set_pte((pte_t *)ctxp, (SRMMU_ET_PTD | (__pa((unsigned long) pgdp) >> 4))); -} +/* XXX should we hyper_flush_whole_icache here - Anton */ +static inline void srmmu_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp) +{ srmmu_set_pte((pte_t *)ctxp, (SRMMU_ET_PTD | (__nocache_pa((unsigned long) pgdp) >> 4))); } -static void srmmu_pgd_set(pgd_t * pgdp, pmd_t * pmdp) -{ - set_pte((pte_t *)pgdp, (SRMMU_ET_PTD | (__pa((unsigned long) pmdp) >> 4))); -} +static inline void srmmu_pgd_set(pgd_t * pgdp, pmd_t * pmdp) +{ srmmu_set_pte((pte_t *)pgdp, (SRMMU_ET_PTD | (__nocache_pa((unsigned long) pmdp) >> 4))); } -static void srmmu_pmd_set(pmd_t * pmdp, pte_t * ptep) -{ - set_pte((pte_t *)pmdp, (SRMMU_ET_PTD | (__pa((unsigned long) ptep) >> 4))); -} +static inline void srmmu_pmd_set(pmd_t * pmdp, pte_t * ptep) +{ srmmu_set_pte((pte_t *)pmdp, (SRMMU_ET_PTD | (__nocache_pa((unsigned long) ptep) >> 4))); } static inline pte_t srmmu_pte_modify(pte_t pte, pgprot_t newprot) -{ - return __pte((pte_val(pte) & SRMMU_CHG_MASK) | pgprot_val(newprot)); -} +{ return __pte((pte_val(pte) & SRMMU_CHG_MASK) | pgprot_val(newprot)); } /* to find an entry in a top-level page table... */ extern inline pgd_t *srmmu_pgd_offset(struct mm_struct * mm, unsigned long address) -{ - return mm->pgd + (address >> SRMMU_PGDIR_SHIFT); -} +{ return mm->pgd + (address >> SRMMU_PGDIR_SHIFT); } /* Find an entry in the second-level page table.. */ static inline pmd_t *srmmu_pmd_offset(pgd_t * dir, unsigned long address) -{ - return (pmd_t *) srmmu_pgd_page(*dir) + ((address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1)); -} +{ return (pmd_t *) srmmu_pgd_page(*dir) + ((address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1)); } /* Find an entry in the third-level page table.. */ static inline pte_t *srmmu_pte_offset(pmd_t * dir, unsigned long address) +{ return (pte_t *) srmmu_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1)); } + +unsigned long __srmmu_get_nocache(int size, int align) +{ + int offset = srmmu_nocache_low; + int i; + unsigned long va_tmp, phys_tmp; + int lowest_failed = 0; + + size = size >> SRMMU_NOCACHE_BITMAP_SHIFT; + + spin_lock(&srmmu_nocache_spinlock); + +repeat: + offset = find_next_zero_bit(srmmu_nocache_bitmap, SRMMU_NOCACHE_BITMAP_SIZE, offset); + + /* we align on physical address */ + if (align) { + va_tmp = (SRMMU_NOCACHE_VADDR + (offset << SRMMU_NOCACHE_BITMAP_SHIFT)); + phys_tmp = (__nocache_pa(va_tmp) + align - 1) & ~(align - 1); + va_tmp = (unsigned long)__nocache_va(phys_tmp); + offset = (va_tmp - SRMMU_NOCACHE_VADDR) >> SRMMU_NOCACHE_BITMAP_SHIFT; + } + + if ((SRMMU_NOCACHE_BITMAP_SIZE - offset) < size) { + printk("Run out of nocached RAM!\n"); + spin_unlock(&srmmu_nocache_spinlock); + return 0; + } + + i = 0; + while(i < size) { + if (test_bit(offset + i, srmmu_nocache_bitmap)) { + lowest_failed = 1; + offset = offset + i + 1; + goto repeat; + } + i++; + } + + i = 0; + while(i < size) { + set_bit(offset + i, srmmu_nocache_bitmap); + i++; + srmmu_nocache_used++; + } + + if (!lowest_failed && ((align >> SRMMU_NOCACHE_BITMAP_SHIFT) <= 1) && (offset > srmmu_nocache_low)) + srmmu_nocache_low = offset; + + spin_unlock(&srmmu_nocache_spinlock); + + return (SRMMU_NOCACHE_VADDR + (offset << SRMMU_NOCACHE_BITMAP_SHIFT)); +} + +unsigned inline long srmmu_get_nocache(int size, int align) { - return (pte_t *) srmmu_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1)); + unsigned long tmp; + + tmp = __srmmu_get_nocache(size, align); + + if (tmp) + memset((void *)tmp, 0, size); + + return tmp; } -static inline pte_t *srmmu_get_pte_fast(void) +void srmmu_free_nocache(unsigned long vaddr, int size) { - struct page *ret; - - spin_lock(&pte_spinlock); - if ((ret = (struct page *)pte_quicklist) != NULL) { - unsigned int mask = (unsigned int)ret->pprev_hash; - unsigned int tmp, off; - - if (mask & 0xff) - for (tmp = 0x001, off = 0; (mask & tmp) == 0; tmp <<= 1, off += 256); - else - for (tmp = 0x100, off = 2048; (mask & tmp) == 0; tmp <<= 1, off += 256); - (unsigned int)ret->pprev_hash = mask & ~tmp; - if (!(mask & ~tmp)) - pte_quicklist = (unsigned long *)ret->next_hash; - ret = (struct page *)(page_address(ret) + off); - pgtable_cache_size--; + int offset = (vaddr - SRMMU_NOCACHE_VADDR) >> SRMMU_NOCACHE_BITMAP_SHIFT; + + size = size >> SRMMU_NOCACHE_BITMAP_SHIFT; + + spin_lock(&srmmu_nocache_spinlock); + + while(size--) { + clear_bit(offset + size, srmmu_nocache_bitmap); + srmmu_nocache_used--; } - spin_unlock(&pte_spinlock); - return (pte_t *)ret; + + if (offset < srmmu_nocache_low) + srmmu_nocache_low = offset; + + spin_unlock(&srmmu_nocache_spinlock); } -static inline pte_t *srmmu_get_pte_slow(void) +void srmmu_early_allocate_ptable_skeleton(unsigned long start, unsigned long end); + +void srmmu_nocache_init(void) { - pte_t *ret; - struct page *page; - - ret = (pte_t *)get_free_page(GFP_KERNEL); - if (ret) { - page = mem_map + MAP_NR(ret); - flush_chunk((unsigned long)ret); - (unsigned int)page->pprev_hash = 0xfffe; - spin_lock(&pte_spinlock); - (unsigned long *)page->next_hash = pte_quicklist; - pte_quicklist = (unsigned long *)page; - pgtable_cache_size += 15; - } - return ret; -} - -static inline pgd_t *srmmu_get_pgd_fast(void) -{ - struct page *ret; - - spin_lock(&pgd_spinlock); - if ((ret = (struct page *)pgd_quicklist) != NULL) { - unsigned int mask = (unsigned int)ret->pprev_hash; - unsigned int tmp, off; - - for (tmp = 0x001, off = 0; (mask & tmp) == 0; tmp <<= 1, off += 1024); - (unsigned int)ret->pprev_hash = mask & ~tmp; - if (!(mask & ~tmp)) - pgd_quicklist = (unsigned long *)ret->next_hash; - ret = (struct page *)(page_address(ret) + off); - pgd_cache_size--; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned long paddr, vaddr; + unsigned long pteval; + + srmmu_nocache_pool = __alloc_bootmem(SRMMU_NOCACHE_SIZE, PAGE_SIZE, 0UL); + memset(srmmu_nocache_pool, 0, SRMMU_NOCACHE_SIZE); + + srmmu_nocache_bitmap = __alloc_bootmem(SRMMU_NOCACHE_BITMAP_SIZE, SMP_CACHE_BYTES, 0UL); + memset(srmmu_nocache_bitmap, 0, SRMMU_NOCACHE_BITMAP_SIZE); + + srmmu_swapper_pg_dir = (pgd_t *)__srmmu_get_nocache(SRMMU_PGD_TABLE_SIZE, SRMMU_PGD_TABLE_SIZE); + memset(__nocache_fix(srmmu_swapper_pg_dir), 0, SRMMU_PGD_TABLE_SIZE); + init_mm.pgd = srmmu_swapper_pg_dir; + + srmmu_early_allocate_ptable_skeleton(SRMMU_NOCACHE_VADDR, SRMMU_NOCACHE_END); + + spin_lock_init(&srmmu_nocache_spinlock); + + paddr = __pa((unsigned long)srmmu_nocache_pool); + vaddr = SRMMU_NOCACHE_VADDR; + + while (vaddr < SRMMU_NOCACHE_END) { + pgd = pgd_offset_k(vaddr); + pmd = srmmu_pmd_offset(__nocache_fix(pgd), vaddr); + pte = srmmu_pte_offset(__nocache_fix(pmd), vaddr); + + pteval = ((paddr >> 4) | SRMMU_ET_PTE | SRMMU_PRIV); + + if (srmmu_cache_pagetables) + pteval |= SRMMU_CACHE; + + srmmu_set_pte(__nocache_fix(pte), pteval); + + vaddr += PAGE_SIZE; + paddr += PAGE_SIZE; } - spin_unlock(&pgd_spinlock); - return (pgd_t *)ret; + + flush_cache_all(); + flush_tlb_all(); } -static inline pgd_t *srmmu_get_pgd_slow(void) +static inline pgd_t *srmmu_pgd_alloc(void) { - pgd_t *ret; - struct page *page; - - ret = (pgd_t *)__get_free_page(GFP_KERNEL); - if (ret) { - pgd_t *init = pgd_offset(&init_mm, 0); - memset(ret + (0 * PTRS_PER_PGD), 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); - memcpy(ret + (0 * PTRS_PER_PGD) + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, - (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); - memset(ret + (1 * PTRS_PER_PGD), 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); - memcpy(ret + (1 * PTRS_PER_PGD) + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, - (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); - memset(ret + (2 * PTRS_PER_PGD), 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); - memcpy(ret + (2 * PTRS_PER_PGD) + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, - (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); - memset(ret + (3 * PTRS_PER_PGD), 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); - memcpy(ret + (3 * PTRS_PER_PGD) + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, + pgd_t *pgd = NULL; + + pgd = (pgd_t *)__srmmu_get_nocache(SRMMU_PGD_TABLE_SIZE, SRMMU_PGD_TABLE_SIZE); + if (pgd) { + pgd_t *init = pgd_offset_k(0); + memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); + memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); - page = mem_map + MAP_NR(ret); - flush_chunk((unsigned long)ret); - (unsigned int)page->pprev_hash = 0xe; - spin_lock(&pgd_spinlock); - (unsigned long *)page->next_hash = pgd_quicklist; - pgd_quicklist = (unsigned long *)page; - pgd_cache_size += 3; - spin_unlock(&pgd_spinlock); } - return ret; + + return pgd; +} + +static void srmmu_pgd_free(pgd_t *pgd) +{ + srmmu_free_nocache((unsigned long)pgd, SRMMU_PGD_TABLE_SIZE); } -static void srmmu_free_pte_slow(pte_t *pte) +pmd_t *empty_bad_pmd_table; +pte_t *empty_bad_pte_table; + +/* + * We init them before every return and make them writable-shared. + * This guarantees we get out of the kernel in some more or less sane + * way. + */ +static pmd_t * get_bad_pmd_table(void) { + int i; + + for (i = 0; i < PAGE_SIZE/sizeof(pmd_t); i++) + srmmu_pmd_set(&(empty_bad_pmd_table[i]), empty_bad_pte_table); + + return empty_bad_pmd_table; } -static void srmmu_free_pgd_slow(pgd_t *pgd) +static pte_t * get_bad_pte_table(void) { + pte_t v; + int i; + + memset((void *)&empty_bad_page, 0, PAGE_SIZE); + + v = srmmu_pte_mkdirty(srmmu_mk_pte_phys(__pa(&empty_bad_page) + phys_base, PAGE_SHARED)); + + for (i = 0; i < PAGE_SIZE/sizeof(pte_t); i++) + srmmu_set_pte(&(empty_bad_pte_table[i]), v); + + return empty_bad_pte_table; } -static inline void srmmu_pte_free(pte_t *pte) +void __handle_bad_pgd(pgd_t *pgd) { - struct page *page = mem_map + MAP_NR(pte); + pgd_ERROR(*pgd); + srmmu_pgd_set(pgd, get_bad_pmd_table()); +} - spin_lock(&pte_spinlock); - if (!page->pprev_hash) { - (unsigned long *)page->next_hash = pte_quicklist; - pte_quicklist = (unsigned long *)page; - } - (unsigned int)page->pprev_hash |= (1 << ((((unsigned long)pte) >> 8) & 15)); - pgtable_cache_size++; - spin_unlock(&pte_spinlock); +void __handle_bad_pmd(pmd_t *pmd) +{ + pmd_ERROR(*pmd); + srmmu_pmd_set(pmd, get_bad_pte_table()); } static pte_t *srmmu_pte_alloc(pmd_t * pmd, unsigned long address) { address = (address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1); if(srmmu_pmd_none(*pmd)) { - pte_t *page = srmmu_get_pte_fast(); - - if (page) { - pmd_set(pmd, page); - return page + address; - } - page = srmmu_get_pte_slow(); - if(srmmu_pmd_none(*pmd)) { - if(page) { - spin_unlock(&pte_spinlock); - pmd_set(pmd, page); - return page + address; - } - pmd_set(pmd, BAD_PAGETABLE); - return NULL; - } - if (page) { - (unsigned int)(((struct page *)pte_quicklist)->pprev_hash) = 0xffff; - pgtable_cache_size++; + pte_t *page = (pte_t *)srmmu_get_nocache(SRMMU_PTE_TABLE_SIZE, SRMMU_PTE_TABLE_SIZE); + if(page) { spin_unlock(&pte_spinlock); + srmmu_pmd_set(pmd, page); + return page + address; } + srmmu_pmd_set(pmd, get_bad_pte_table()); + return NULL; } if(srmmu_pmd_bad(*pmd)) { - printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); - pmd_set(pmd, BAD_PAGETABLE); + __handle_bad_pmd(pmd); return NULL; } return ((pte_t *) pmd_page(*pmd)) + address; } -/* Real three-level page tables on SRMMU. */ -static void srmmu_pmd_free(pmd_t * pmd) +static inline void srmmu_pte_free(pte_t *pte) { - return srmmu_pte_free((pte_t *)pmd); + srmmu_free_nocache((unsigned long)pte, SRMMU_PTE_TABLE_SIZE); } static pmd_t *srmmu_pmd_alloc(pgd_t * pgd, unsigned long address) { address = (address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1); if(srmmu_pgd_none(*pgd)) { - pmd_t *page = (pmd_t *)srmmu_get_pte_fast(); - - if (page) { - pgd_set(pgd, page); - return page + address; - } - page = (pmd_t *)srmmu_get_pte_slow(); - if(srmmu_pgd_none(*pgd)) { - if(page) { - spin_unlock(&pte_spinlock); - pgd_set(pgd, page); - return page + address; - } - pgd_set(pgd, (pmd_t *) BAD_PAGETABLE); - return NULL; - } - if (page) { - (unsigned int)(((struct page *)pte_quicklist)->pprev_hash) = 0xffff; - pgtable_cache_size++; + pmd_t *page = (pmd_t *)srmmu_get_nocache(SRMMU_PMD_TABLE_SIZE, SRMMU_PMD_TABLE_SIZE); + if(page) { spin_unlock(&pte_spinlock); + srmmu_pgd_set(pgd, page); + return page + address; } + srmmu_pgd_set(pgd, get_bad_pmd_table()); + return NULL; } if(srmmu_pgd_bad(*pgd)) { - printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd)); - pgd_set(pgd, (pmd_t *) BAD_PAGETABLE); + __handle_bad_pgd(pgd); return NULL; } - return (pmd_t *) pgd_page(*pgd) + address; + return (pmd_t *) srmmu_pgd_page(*pgd) + address; } -static void srmmu_pgd_free(pgd_t *pgd) -{ - struct page *page = mem_map + MAP_NR(pgd); - - spin_lock(&pgd_spinlock); - if (!page->pprev_hash) { - (unsigned long *)page->next_hash = pgd_quicklist; - pgd_quicklist = (unsigned long *)page; - } - (unsigned int)page->pprev_hash |= (1 << ((((unsigned long)pgd) >> 10) & 3)); - pgd_cache_size++; - spin_unlock(&pgd_spinlock); -} - -static pgd_t *srmmu_pgd_alloc(void) +static void srmmu_pmd_free(pmd_t * pmd) { - pgd_t *ret; - - ret = srmmu_get_pgd_fast(); - if (ret) return ret; - return srmmu_get_pgd_slow(); + srmmu_free_nocache((unsigned long)pmd, SRMMU_PMD_TABLE_SIZE); } - static void srmmu_set_pgdir(unsigned long address, pgd_t entry) { struct task_struct * p; - struct page *page; read_lock(&tasklist_lock); for_each_task(p) { if (!p->mm) continue; - *pgd_offset(p->mm,address) = entry; + *srmmu_pgd_offset(p->mm,address) = entry; } read_unlock(&tasklist_lock); - spin_lock(&pgd_spinlock); - address >>= SRMMU_PGDIR_SHIFT; - for (page = (struct page *)pgd_quicklist; page; page = page->next_hash) { - pgd_t *pgd = (pgd_t *)page_address(page); - unsigned int mask = (unsigned int)page->pprev_hash; - - if (mask & 1) - pgd[address + 0 * SRMMU_PTRS_PER_PGD] = entry; - if (mask & 2) - pgd[address + 1 * SRMMU_PTRS_PER_PGD] = entry; - if (mask & 4) - pgd[address + 2 * SRMMU_PTRS_PER_PGD] = entry; - if (mask & 8) - pgd[address + 3 * SRMMU_PTRS_PER_PGD] = entry; - if (mask) - flush_chunk((unsigned long)pgd); - } - spin_unlock(&pgd_spinlock); -} - -static void srmmu_set_pte_cacheable(pte_t *ptep, pte_t pteval) -{ - srmmu_set_entry(ptep, pte_val(pteval)); -} - -static void srmmu_set_pte_nocache_cypress(pte_t *ptep, pte_t pteval) -{ - register unsigned long a, b, c, d, e, f, g; - unsigned long line, page; - - srmmu_set_entry(ptep, pte_val(pteval)); - page = ((unsigned long)ptep) & PAGE_MASK; - line = (page + PAGE_SIZE) - 0x100; - a = 0x20; b = 0x40; c = 0x60; d = 0x80; e = 0xa0; f = 0xc0; g = 0xe0; - goto inside; - do { - line -= 0x100; - inside: - __asm__ __volatile__("sta %%g0, [%0] %1\n\t" - "sta %%g0, [%0 + %2] %1\n\t" - "sta %%g0, [%0 + %3] %1\n\t" - "sta %%g0, [%0 + %4] %1\n\t" - "sta %%g0, [%0 + %5] %1\n\t" - "sta %%g0, [%0 + %6] %1\n\t" - "sta %%g0, [%0 + %7] %1\n\t" - "sta %%g0, [%0 + %8] %1\n\t" : : - "r" (line), - "i" (ASI_M_FLUSH_PAGE), - "r" (a), "r" (b), "r" (c), "r" (d), - "r" (e), "r" (f), "r" (g)); - } while(line != page); -} - -static void srmmu_set_pte_nocache_viking(pte_t *ptep, pte_t pteval) -{ - unsigned long vaddr; - int set; - int i; - - set = ((unsigned long)ptep >> 5) & 0x7f; - vaddr = (KERNBASE + PAGE_SIZE) | (set << 5); - srmmu_set_entry(ptep, pte_val(pteval)); - for (i = 0; i < 8; i++) { - __asm__ __volatile__ ("ld [%0], %%g0" : : "r" (vaddr)); - vaddr += PAGE_SIZE; - } -} - -static void srmmu_quick_kernel_fault(unsigned long address) -{ -#ifdef CONFIG_SMP - printk("CPU[%d]: Kernel faults at addr=0x%08lx\n", - smp_processor_id(), address); - while (1) ; -#else - printk("Kernel faults at addr=0x%08lx\n", address); - printk("PTE=%08lx\n", srmmu_hwprobe((address & PAGE_MASK))); - die_if_kernel("SRMMU bolixed...", current->thread.kregs); -#endif } static inline void alloc_context(struct mm_struct *old_mm, struct mm_struct *mm) @@ -567,8 +542,12 @@ spin_lock(&srmmu_context_spinlock); alloc_context(old_mm, mm); spin_unlock(&srmmu_context_spinlock); - ctxd_set(&srmmu_context_table[mm->context], mm->pgd); + srmmu_ctxd_set(&srmmu_context_table[mm->context], mm->pgd); } + + if (is_hypersparc) + hyper_flush_whole_icache(); + srmmu_set_context(mm->context); } @@ -581,12 +560,13 @@ unsigned long tmp; physaddr &= PAGE_MASK; - pgdp = srmmu_pgd_offset(&init_mm, virt_addr); - pmdp = pmd_offset(pgdp, virt_addr); - ptep = pte_offset(pmdp, virt_addr); + pgdp = pgd_offset_k(virt_addr); + pmdp = srmmu_pmd_offset(pgdp, virt_addr); + ptep = srmmu_pte_offset(pmdp, virt_addr); tmp = (physaddr >> 4) | SRMMU_ET_PTE; - /* I need to test whether this is consistent over all + /* + * I need to test whether this is consistent over all * sun4m's. The bus_type represents the upper 4 bits of * 36-bit physical address on the I/O space lines... */ @@ -596,7 +576,7 @@ else tmp |= SRMMU_PRIV; __flush_page_to_ram(virt_addr); - set_pte(ptep, __pte(tmp)); + srmmu_set_pte(ptep, __pte(tmp)); flush_tlb_all(); } @@ -606,16 +586,17 @@ pmd_t *pmdp; pte_t *ptep; - pgdp = srmmu_pgd_offset(&init_mm, virt_addr); - pmdp = pmd_offset(pgdp, virt_addr); - ptep = pte_offset(pmdp, virt_addr); + pgdp = pgd_offset_k(virt_addr); + pmdp = srmmu_pmd_offset(pgdp, virt_addr); + ptep = srmmu_pte_offset(pmdp, virt_addr); /* No need to flush uncacheable page. */ - pte_clear(ptep); + srmmu_pte_clear(ptep); flush_tlb_all(); } -/* On the SRMMU we do not have the problems with limited tlb entries +/* + * On the SRMMU we do not have the problems with limited tlb entries * for mapping kernel pages, so we just take things from the free page * pool. As a side effect we are putting a little too much pressure * on the gfp() subsystem. This setup also makes the logic of the @@ -646,14 +627,14 @@ extern void tsunami_flush_page_to_ram(unsigned long page); extern void tsunami_flush_page_for_dma(unsigned long page); extern void tsunami_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr); -extern void tsunami_flush_chunk(unsigned long chunk); extern void tsunami_flush_tlb_all(void); extern void tsunami_flush_tlb_mm(struct mm_struct *mm); extern void tsunami_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end); extern void tsunami_flush_tlb_page(struct vm_area_struct *vma, unsigned long page); extern void tsunami_setup_blockops(void); -/* Workaround, until we find what's going on with Swift. When low on memory, +/* + * Workaround, until we find what's going on with Swift. When low on memory, * it sometimes loops in fault/handle_mm_fault incl. flush_tlb_page to find * out it is already in page tables/ fault again on the same instruction. * I really don't understand it, have checked it and contexts @@ -693,7 +674,6 @@ extern void swift_flush_page_to_ram(unsigned long page); extern void swift_flush_page_for_dma(unsigned long page); extern void swift_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr); -extern void swift_flush_chunk(unsigned long chunk); extern void swift_flush_tlb_all(void); extern void swift_flush_tlb_mm(struct mm_struct *mm); extern void swift_flush_tlb_range(struct mm_struct *mm, @@ -727,11 +707,11 @@ /* same as above: srmmu_flush_tlb_page() */ } } - module_stats.invpg++; } #endif -/* The following are all MBUS based SRMMU modules, and therefore could +/* + * The following are all MBUS based SRMMU modules, and therefore could * be found in a multiprocessor configuration. On the whole, these * chips seems to be much more touchy about DVMA and page tables * with respect to cache coherency. @@ -900,11 +880,6 @@ } while(line != page); } -static void cypress_flush_chunk(unsigned long chunk) -{ - cypress_flush_page_to_ram(chunk); -} - /* Cypress is also IO cache coherent. */ static void cypress_flush_page_for_dma(unsigned long page) { @@ -921,7 +896,6 @@ static void cypress_flush_tlb_all(void) { srmmu_flush_whole_tlb(); - module_stats.invall++; } static void cypress_flush_tlb_mm(struct mm_struct *mm) @@ -936,7 +910,6 @@ : "r" (SRMMU_CTX_REG), "r" (0x300), "r" (mm->context), "i" (ASI_M_MMUREGS), "i" (ASI_M_FLUSH_PROBE) : "g5"); - module_stats.invmm++; FLUSH_END } @@ -959,7 +932,6 @@ "r" (size), "r" (SRMMU_PGDIR_SIZE), "i" (ASI_M_MMUREGS), "i" (ASI_M_FLUSH_PROBE) : "g5", "cc"); - module_stats.invrnge++; FLUSH_END } @@ -977,7 +949,6 @@ : "r" (SRMMU_CTX_REG), "r" (mm->context), "r" (page & PAGE_MASK), "i" (ASI_M_MMUREGS), "i" (ASI_M_FLUSH_PROBE) : "g5"); - module_stats.invpg++; FLUSH_END } @@ -993,8 +964,6 @@ extern void viking_flush_sig_insns(struct mm_struct *mm, unsigned long addr); extern void viking_flush_page(unsigned long page); extern void viking_mxcc_flush_page(unsigned long page); -extern void viking_flush_chunk(unsigned long chunk); -extern void viking_mxcc_flush_chunk(unsigned long chunk); extern void viking_flush_tlb_all(void); extern void viking_flush_tlb_mm(struct mm_struct *mm); extern void viking_flush_tlb_range(struct mm_struct *mm, unsigned long start, @@ -1014,7 +983,6 @@ extern void hypersparc_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end); extern void hypersparc_flush_cache_page(struct vm_area_struct *vma, unsigned long page); extern void hypersparc_flush_page_to_ram(unsigned long page); -extern void hypersparc_flush_chunk(unsigned long chunk); extern void hypersparc_flush_page_for_dma(unsigned long page); extern void hypersparc_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr); extern void hypersparc_flush_tlb_all(void); @@ -1023,39 +991,8 @@ extern void hypersparc_flush_tlb_page(struct vm_area_struct *vma, unsigned long page); extern void hypersparc_setup_blockops(void); -static void srmmu_set_pte_nocache_hyper(pte_t *ptep, pte_t pteval) -{ - unsigned long page = ((unsigned long)ptep) & PAGE_MASK; - - srmmu_set_entry(ptep, pte_val(pteval)); - hypersparc_flush_page_to_ram(page); -} - -static void hypersparc_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp) -{ - srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (__pa((unsigned long) pgdp) >> 4)))); - hypersparc_flush_page_to_ram((unsigned long)ctxp); - hyper_flush_whole_icache(); -} - -static void hypersparc_switch_mm(struct mm_struct *old_mm, - struct mm_struct *mm, struct task_struct *tsk, int cpu) -{ - if(mm->context == NO_CONTEXT) { - ctxd_t *ctxp; - - spin_lock(&srmmu_context_spinlock); - alloc_context(old_mm, mm); - spin_unlock(&srmmu_context_spinlock); - ctxp = &srmmu_context_table[mm->context]; - srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (__pa((unsigned long) mm->pgd) >> 4)))); - hypersparc_flush_page_to_ram((unsigned long)ctxp); - } - hyper_flush_whole_icache(); - srmmu_set_context(mm->context); -} - -/* NOTE: All of this startup code assumes the low 16mb (approx.) of +/* + * NOTE: All of this startup code assumes the low 16mb (approx.) of * kernel mappings are done with one single contiguous chunk of * ram. On small ram machines (classics mainly) we only get * around 8mb mapped for us. @@ -1067,17 +1004,43 @@ prom_halt(); } -static inline void srmmu_allocate_ptable_skeleton(unsigned long start, unsigned long end) +void __init srmmu_early_allocate_ptable_skeleton(unsigned long start, unsigned long end) +{ + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + while(start < end) { + pgdp = pgd_offset_k(start); + if(srmmu_pgd_none(*(pgd_t *)__nocache_fix(pgdp))) { + pmdp = (pmd_t *)__srmmu_get_nocache(SRMMU_PMD_TABLE_SIZE, SRMMU_PMD_TABLE_SIZE); + if (pmdp == NULL) + early_pgtable_allocfail("pmd"); + memset(__nocache_fix(pmdp), 0, SRMMU_PMD_TABLE_SIZE); + srmmu_pgd_set(__nocache_fix(pgdp), pmdp); + } + pmdp = srmmu_pmd_offset(__nocache_fix(pgdp), start); + if(srmmu_pmd_none(*(pmd_t *)__nocache_fix(pmdp))) { + ptep = (pte_t *)__srmmu_get_nocache(SRMMU_PTE_TABLE_SIZE, SRMMU_PTE_TABLE_SIZE); + if (ptep == NULL) + early_pgtable_allocfail("pte"); + memset(__nocache_fix(ptep), 0, SRMMU_PTE_TABLE_SIZE); + srmmu_pmd_set(__nocache_fix(pmdp), ptep); + } + start = (start + SRMMU_PMD_SIZE) & SRMMU_PMD_MASK; + } +} + +void __init srmmu_allocate_ptable_skeleton(unsigned long start, unsigned long end) { pgd_t *pgdp; pmd_t *pmdp; pte_t *ptep; while(start < end) { - pgdp = srmmu_pgd_offset(&init_mm, start); + pgdp = pgd_offset_k(start); if(srmmu_pgd_none(*pgdp)) { - pmdp = __alloc_bootmem(SRMMU_PMD_TABLE_SIZE, - SRMMU_PMD_TABLE_SIZE, 0UL); + pmdp = (pmd_t *)__srmmu_get_nocache(SRMMU_PMD_TABLE_SIZE, SRMMU_PMD_TABLE_SIZE); if (pmdp == NULL) early_pgtable_allocfail("pmd"); memset(pmdp, 0, SRMMU_PMD_TABLE_SIZE); @@ -1085,7 +1048,7 @@ } pmdp = srmmu_pmd_offset(pgdp, start); if(srmmu_pmd_none(*pmdp)) { - ptep = __alloc_bootmem(SRMMU_PTE_TABLE_SIZE, SRMMU_PTE_TABLE_SIZE, 0UL); + ptep = (pte_t *)__srmmu_get_nocache(SRMMU_PTE_TABLE_SIZE, SRMMU_PTE_TABLE_SIZE); if (ptep == NULL) early_pgtable_allocfail("pte"); memset(ptep, 0, SRMMU_PTE_TABLE_SIZE); @@ -1095,7 +1058,8 @@ } } -/* This is much cleaner than poking around physical address space +/* + * This is much cleaner than poking around physical address space * looking at the prom's page table directly which is what most * other OS's do. Yuck... this is much better. */ @@ -1131,35 +1095,34 @@ what = 2; } - pgdp = srmmu_pgd_offset(&init_mm, start); + pgdp = pgd_offset_k(start); if(what == 2) { - *pgdp = __pgd(prompte); + *(pgd_t *)__nocache_fix(pgdp) = __pgd(prompte); start += SRMMU_PGDIR_SIZE; continue; } - if(srmmu_pgd_none(*pgdp)) { - pmdp = __alloc_bootmem(SRMMU_PMD_TABLE_SIZE, - SRMMU_PMD_TABLE_SIZE, 0UL); + if(srmmu_pgd_none(*(pgd_t *)__nocache_fix(pgdp))) { + pmdp = (pmd_t *)__srmmu_get_nocache(SRMMU_PMD_TABLE_SIZE, SRMMU_PMD_TABLE_SIZE); if (pmdp == NULL) early_pgtable_allocfail("pmd"); - memset(pmdp, 0, SRMMU_PMD_TABLE_SIZE); - srmmu_pgd_set(pgdp, pmdp); + memset(__nocache_fix(pmdp), 0, SRMMU_PMD_TABLE_SIZE); + srmmu_pgd_set(__nocache_fix(pgdp), pmdp); } - pmdp = srmmu_pmd_offset(pgdp, start); + pmdp = srmmu_pmd_offset(__nocache_fix(pgdp), start); if(what == 1) { - *pmdp = __pmd(prompte); + *(pmd_t *)__nocache_fix(pmdp) = __pmd(prompte); start += SRMMU_PMD_SIZE; continue; } - if(srmmu_pmd_none(*pmdp)) { - ptep = __alloc_bootmem(SRMMU_PTE_TABLE_SIZE, SRMMU_PTE_TABLE_SIZE, 0UL); + if(srmmu_pmd_none(*(pmd_t *)__nocache_fix(pmdp))) { + ptep = (pte_t *)__srmmu_get_nocache(SRMMU_PTE_TABLE_SIZE, SRMMU_PTE_TABLE_SIZE); if (ptep == NULL) early_pgtable_allocfail("pte"); - memset(ptep, 0, SRMMU_PTE_TABLE_SIZE); - srmmu_pmd_set(pmdp, ptep); + memset(__nocache_fix(ptep), 0, SRMMU_PTE_TABLE_SIZE); + srmmu_pmd_set(__nocache_fix(pmdp), ptep); } - ptep = srmmu_pte_offset(pmdp, start); - *ptep = __pte(prompte); + ptep = srmmu_pte_offset(__nocache_fix(pmdp), start); + *(pte_t *)__nocache_fix(ptep) = __pte(prompte); start += PAGE_SIZE; } } @@ -1171,15 +1134,14 @@ /* Create a third-level SRMMU 16MB page mapping. */ static void __init do_large_mapping(unsigned long vaddr, unsigned long phys_base) { - pgd_t *pgdp = srmmu_pgd_offset(&init_mm, vaddr); + pgd_t *pgdp = pgd_offset_k(vaddr); unsigned long big_pte; big_pte = KERNEL_PTE(phys_base >> 4); - *pgdp = __pgd(big_pte); + *(pgd_t *)__nocache_fix(pgdp) = __pgd(big_pte); } -/* Map sp_bank entry SP_ENTRY, starting at virtual address VBASE. - */ +/* Map sp_bank entry SP_ENTRY, starting at virtual address VBASE. */ static unsigned long __init map_spbank(unsigned long vbase, int sp_entry) { unsigned long pstart = (sp_banks[sp_entry].base_addr & SRMMU_PGDIR_MASK); @@ -1254,53 +1216,43 @@ prom_printf("Something wrong, can't find cpu node in paging_init.\n"); prom_halt(); } - - memset(swapper_pg_dir, 0, PAGE_SIZE); last_valid_pfn = end_pfn = bootmem_init(); - srmmu_allocate_ptable_skeleton(KERNBASE, (unsigned long)__va(end_of_phys_memory)); -#if CONFIG_SUN_IO - srmmu_allocate_ptable_skeleton(sparc_iomap.start, IOBASE_END); - srmmu_allocate_ptable_skeleton(DVMA_VADDR, DVMA_END); -#endif - - /* This does not logically belong here, but we need to - * call it at the moment we are able to use the bootmem - * allocator. - */ - sun_serial_setup(); - + srmmu_nocache_init(); srmmu_inherit_prom_mappings(0xfe400000,(LINUX_OPPROM_ENDVM-PAGE_SIZE)); map_kernel(); -#define BOOTMEM_BROKEN -#ifdef BOOTMEM_BROKEN - srmmu_context_table = __alloc_bootmem(num_contexts*sizeof(ctxd_t)*2, SMP_CACHE_BYTES, 0UL); - (unsigned long)srmmu_context_table += num_contexts*sizeof(ctxd_t); - (unsigned long)srmmu_context_table &= ~(num_contexts*sizeof(ctxd_t)-1); -#else - srmmu_context_table = __alloc_bootmem(num_contexts*sizeof(ctxd_t), num_contexts*sizeof(ctxd_t), 0UL); -#endif + /* ctx table has to be physically aligned to its size */ + srmmu_context_table = (ctxd_t *)__srmmu_get_nocache(num_contexts*sizeof(ctxd_t), num_contexts*sizeof(ctxd_t)); + srmmu_ctx_table_phys = (ctxd_t *)__nocache_pa((unsigned long)srmmu_context_table); - srmmu_ctx_table_phys = (ctxd_t *) __pa((unsigned long) srmmu_context_table); for(i = 0; i < num_contexts; i++) - ctxd_set(&srmmu_context_table[i], swapper_pg_dir); + srmmu_ctxd_set((ctxd_t *)__nocache_fix(&srmmu_context_table[i]), srmmu_swapper_pg_dir); flush_cache_all(); - if(BTFIXUPVAL_CALL(flush_page_for_dma) == (unsigned long)viking_flush_page) { - unsigned long start = (unsigned long)srmmu_context_table; - unsigned long end = PAGE_ALIGN((unsigned long)srmmu_context_table + num_contexts*sizeof(ctxd_t)); - - while(start < end) { - viking_flush_page(start); - start += PAGE_SIZE; - } - } - srmmu_set_ctable_ptr((unsigned long) srmmu_ctx_table_phys); + srmmu_set_ctable_ptr((unsigned long)srmmu_ctx_table_phys); flush_tlb_all(); poke_srmmu(); +#if CONFIG_SUN_IO + srmmu_allocate_ptable_skeleton(sparc_iomap.start, IOBASE_END); + srmmu_allocate_ptable_skeleton(DVMA_VADDR, DVMA_END); +#endif + + flush_cache_all(); + flush_tlb_all(); + + empty_bad_pmd_table = (pte_t *)srmmu_get_nocache(SRMMU_PMD_TABLE_SIZE, SRMMU_PMD_TABLE_SIZE); + empty_bad_pte_table = (pte_t *)srmmu_get_nocache(SRMMU_PTE_TABLE_SIZE, SRMMU_PTE_TABLE_SIZE); + + /* + * This does not logically belong here, but we need to + * call it at the moment we are able to use the bootmem + * allocator. + */ + sun_serial_setup(); + sparc_context_init(num_contexts); { @@ -1309,36 +1261,19 @@ zones_size[ZONE_DMA] = end_pfn; free_area_init(zones_size); } - -#ifdef CONFIG_BLK_DEV_INITRD - /* If initial ramdisk was specified with physical address, - translate it here, as the p2v translation in srmmu - is not straightforward. */ - if (initrd_start && initrd_start < KERNBASE) { - initrd_start = __va(initrd_start); - initrd_end = __va(initrd_end); - if (initrd_end <= initrd_start) - initrd_start = 0; - } -#endif - } static int srmmu_mmu_info(char *buf) { return sprintf(buf, "MMU type\t: %s\n" - "invall\t\t: %d\n" - "invmm\t\t: %d\n" - "invrnge\t\t: %d\n" - "invpg\t\t: %d\n" "contexts\t: %d\n" + "nocache total\t: %d\n" + "nocache used\t: %d\n" , srmmu_name, - module_stats.invall, - module_stats.invmm, - module_stats.invrnge, - module_stats.invpg, - num_contexts + num_contexts, + SRMMU_NOCACHE_SIZE, + (srmmu_nocache_used << SRMMU_NOCACHE_BITMAP_SHIFT) ); } @@ -1351,7 +1286,7 @@ if(mm->context != NO_CONTEXT) { flush_cache_mm(mm); - ctxd_set(&srmmu_context_table[mm->context], swapper_pg_dir); + srmmu_ctxd_set(&srmmu_context_table[mm->context], srmmu_swapper_pg_dir); flush_tlb_mm(mm); spin_lock(&srmmu_context_spinlock); free_context(mm->context); @@ -1405,7 +1340,7 @@ vmaring->vm_mm->context, start); #endif flush_cache_page(vmaring, start); - set_pte(ptep, __pte((pte_val(*ptep) & + srmmu_set_pte(ptep, __pte((pte_val(*ptep) & ~SRMMU_CACHE))); flush_tlb_page(vmaring, start); } @@ -1421,7 +1356,7 @@ pmdp = srmmu_pmd_offset(pgdp, address); ptep = srmmu_pte_offset(pmdp, address); flush_cache_page(vma, address); - set_pte(ptep, __pte((pte_val(*ptep) & ~SRMMU_CACHE))); + srmmu_set_pte(ptep, __pte((pte_val(*ptep) & ~SRMMU_CACHE))); flush_tlb_page(vma, address); } done: @@ -1429,30 +1364,6 @@ } } -static void hypersparc_destroy_context(struct mm_struct *mm) -{ - if(mm->context != NO_CONTEXT) { - ctxd_t *ctxp; - - /* HyperSparc is copy-back, any data for this - * process in a modified cache line is stale - * and must be written back to main memory now - * else we eat shit later big time. - */ - flush_cache_mm(mm); - - ctxp = &srmmu_context_table[mm->context]; - srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (__pa((unsigned long) swapper_pg_dir) >> 4)))); - hypersparc_flush_page_to_ram((unsigned long)ctxp); - - flush_tlb_mm(mm); - spin_lock(&srmmu_context_spinlock); - free_context(mm->context); - spin_unlock(&srmmu_context_spinlock); - mm->context = NO_CONTEXT; - } -} - /* Init various srmmu chip types. */ static void __init srmmu_is_bad(void) { @@ -1527,7 +1438,7 @@ srmmu_set_mmureg(mreg); -#if 0 /* I think this is bad news... -DaveM */ +#if 0 /* XXX I think this is bad news... -DaveM */ hyper_clear_all_tags(); #endif @@ -1543,7 +1454,8 @@ init_vac_layout(); - BTFIXUPSET_CALL(set_pte, srmmu_set_pte_nocache_hyper, BTFIXUPCALL_NORM); + is_hypersparc = 1; + BTFIXUPSET_CALL(pte_clear, srmmu_pte_clear, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pmd_clear, srmmu_pmd_clear, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pgd_clear, srmmu_pgd_clear, BTFIXUPCALL_NORM); @@ -1561,11 +1473,7 @@ BTFIXUPSET_CALL(flush_sig_insns, hypersparc_flush_sig_insns, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_page_for_dma, hypersparc_flush_page_for_dma, BTFIXUPCALL_NOP); - BTFIXUPSET_CALL(flush_chunk, hypersparc_flush_chunk, BTFIXUPCALL_NORM); /* local flush _only_ */ - BTFIXUPSET_CALL(ctxd_set, hypersparc_ctxd_set, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(switch_mm, hypersparc_switch_mm, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(destroy_context, hypersparc_destroy_context, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(update_mmu_cache, srmmu_vac_update_mmu_cache, BTFIXUPCALL_NORM); poke_srmmu = poke_hypersparc; @@ -1615,7 +1523,6 @@ { init_vac_layout(); - BTFIXUPSET_CALL(set_pte, srmmu_set_pte_nocache_cypress, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pte_clear, srmmu_pte_clear, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pmd_clear, srmmu_pmd_clear, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pgd_clear, srmmu_pgd_clear, BTFIXUPCALL_NORM); @@ -1629,7 +1536,6 @@ BTFIXUPSET_CALL(flush_tlb_page, cypress_flush_tlb_page, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_tlb_range, cypress_flush_tlb_range, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_chunk, cypress_flush_chunk, BTFIXUPCALL_NORM); /* local flush _only_ */ BTFIXUPSET_CALL(__flush_page_to_ram, cypress_flush_page_to_ram, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_sig_insns, cypress_flush_sig_insns, BTFIXUPCALL_NOP); @@ -1673,7 +1579,8 @@ /* Enable I & D caches */ mreg = srmmu_get_mmureg(); mreg |= (SWIFT_IE | SWIFT_DE); - /* The Swift branch folding logic is completely broken. At + /* + * The Swift branch folding logic is completely broken. At * trap time, if things are just right, if can mistakenly * think that a trap is coming from kernel mode when in fact * it is coming from user mode (it mis-executes the branch in @@ -1702,7 +1609,8 @@ case 0x30: srmmu_modtype = Swift_lots_o_bugs; hwbug_bitmask |= (HWBUG_KERN_ACCBROKEN | HWBUG_KERN_CBITBROKEN); - /* Gee george, I wonder why Sun is so hush hush about + /* + * Gee george, I wonder why Sun is so hush hush about * this hardware bug... really braindamage stuff going * on here. However I think we can find a way to avoid * all of the workaround overhead under Linux. Basically, @@ -1723,7 +1631,8 @@ case 0x31: srmmu_modtype = Swift_bad_c; hwbug_bitmask |= HWBUG_KERN_CBITBROKEN; - /* You see Sun allude to this hardware bug but never + /* + * You see Sun allude to this hardware bug but never * admit things directly, they'll say things like, * "the Swift chip cache problems" or similar. */ @@ -1738,7 +1647,6 @@ BTFIXUPSET_CALL(flush_cache_page, swift_flush_cache_page, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_cache_range, swift_flush_cache_range, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_chunk, swift_flush_chunk, BTFIXUPCALL_NORM); /* local flush _only_ */ BTFIXUPSET_CALL(flush_tlb_all, swift_flush_tlb_all, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_tlb_mm, swift_flush_tlb_mm, BTFIXUPCALL_NORM); @@ -1753,7 +1661,8 @@ flush_page_for_dma_global = 0; - /* Are you now convinced that the Swift is one of the + /* + * Are you now convinced that the Swift is one of the * biggest VLSI abortions of all time? Bravo Fujitsu! * Fujitsu, the !#?!%$'d up processor people. I bet if * you examined the microcode of the Swift you'd find @@ -1815,21 +1724,15 @@ turbosparc_flush_dcache(); } -static void turbosparc_flush_chunk(unsigned long chunk) -{ -} - static void turbosparc_flush_tlb_all(void) { srmmu_flush_whole_tlb(); - module_stats.invall++; } static void turbosparc_flush_tlb_mm(struct mm_struct *mm) { FLUSH_BEGIN(mm) srmmu_flush_whole_tlb(); - module_stats.invmm++; FLUSH_END } @@ -1837,7 +1740,6 @@ { FLUSH_BEGIN(mm) srmmu_flush_whole_tlb(); - module_stats.invrnge++; FLUSH_END } @@ -1845,7 +1747,6 @@ { FLUSH_BEGIN(vma->vm_mm) srmmu_flush_whole_tlb(); - module_stats.invpg++; FLUSH_END } @@ -1906,7 +1807,6 @@ BTFIXUPSET_CALL(flush_tlb_range, turbosparc_flush_tlb_range, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(__flush_page_to_ram, turbosparc_flush_page_to_ram, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_chunk, turbosparc_flush_chunk, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_sig_insns, turbosparc_flush_sig_insns, BTFIXUPCALL_NOP); BTFIXUPSET_CALL(flush_page_for_dma, turbosparc_flush_page_for_dma, BTFIXUPCALL_NORM); @@ -1927,7 +1827,8 @@ static void __init init_tsunami(void) { - /* Tsunami's pretty sane, Sun and TI actually got it + /* + * Tsunami's pretty sane, Sun and TI actually got it * somewhat right this time. Fujitsu should have * taken some lessons from them. */ @@ -1940,7 +1841,6 @@ BTFIXUPSET_CALL(flush_cache_page, tsunami_flush_cache_page, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_cache_range, tsunami_flush_cache_range, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_chunk, tsunami_flush_chunk, BTFIXUPCALL_NORM); /* local flush _only_ */ BTFIXUPSET_CALL(flush_tlb_all, tsunami_flush_tlb_all, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_tlb_mm, tsunami_flush_tlb_mm, BTFIXUPCALL_NORM); @@ -1968,7 +1868,8 @@ mxcc_control &= ~(MXCC_CTL_RRC); mxcc_set_creg(mxcc_control); - /* We don't need memory parity checks. + /* + * We don't need memory parity checks. * XXX This is a mess, have to dig out later. ecd. viking_mxcc_turn_off_parity(&mreg, &mxcc_control); */ @@ -1980,9 +1881,7 @@ mreg &= ~(VIKING_TCENABLE); if(smp_catch++) { - /* Must disable mixed-cmd mode here for - * other cpu's. - */ + /* Must disable mixed-cmd mode here for other cpu's. */ bpreg = viking_get_bpreg(); bpreg &= ~(VIKING_ACTION_MIX); viking_set_bpreg(bpreg); @@ -2021,14 +1920,12 @@ viking_mxcc_present = 0; msi_set_sync(); - BTFIXUPSET_CALL(set_pte, srmmu_set_pte_nocache_viking, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pte_clear, srmmu_pte_clear, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pmd_clear, srmmu_pmd_clear, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pgd_clear, srmmu_pgd_clear, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_chunk, viking_flush_chunk, BTFIXUPCALL_NORM); /* local flush _only_ */ - - /* We need this to make sure old viking takes no hits + /* + * We need this to make sure old viking takes no hits * on it's cache for dma snoops to workaround the * "load from non-cacheable memory" interrupt bug. * This is only necessary because of the new way in @@ -2041,7 +1938,7 @@ srmmu_name = "TI Viking/MXCC"; viking_mxcc_present = 1; - BTFIXUPSET_CALL(flush_chunk, viking_mxcc_flush_chunk, BTFIXUPCALL_NOP); /* local flush _only_ */ + srmmu_cache_pagetables = 1; /* MXCC vikings lack the DMA snooping bug. */ BTFIXUPSET_CALL(flush_page_for_dma, viking_flush_page_for_dma, BTFIXUPCALL_NOP); @@ -2118,8 +2015,10 @@ return; } - /* Now Fujitsu TurboSparc. It might happen that it is - in Swift emulation mode, so we will check later... */ + /* + * Now Fujitsu TurboSparc. It might happen that it is + * in Swift emulation mode, so we will check later... + */ if (psr_typ == 0 && psr_vers == 5) { init_turbosparc(); return; @@ -2166,74 +2065,10 @@ srmmu_is_bad(); } +/* dont laugh, static pagetables */ static int srmmu_check_pgt_cache(int low, int high) { - struct page *page, *page2; - int freed = 0; - - if (pgtable_cache_size > high) { - spin_lock(&pte_spinlock); - for (page2 = NULL, page = (struct page *)pte_quicklist; page;) { - if ((unsigned int)page->pprev_hash == 0xffff) { - if (page2) - page2->next_hash = page->next_hash; - else - (struct page *)pte_quicklist = page->next_hash; - page->next_hash = NULL; - page->pprev_hash = NULL; - pgtable_cache_size -= 16; - __free_page(page); - freed++; - if (page2) - page = page2->next_hash; - else - page = (struct page *)pte_quicklist; - if (pgtable_cache_size <= low) - break; - continue; - } - page2 = page; - page = page->next_hash; - } - spin_unlock(&pte_spinlock); - } - if (pgd_cache_size > high / 4) { - spin_lock(&pgd_spinlock); - for (page2 = NULL, page = (struct page *)pgd_quicklist; page;) { - if ((unsigned int)page->pprev_hash == 0xf) { - if (page2) - page2->next_hash = page->next_hash; - else - (struct page *)pgd_quicklist = page->next_hash; - page->next_hash = NULL; - page->pprev_hash = NULL; - pgd_cache_size -= 4; - __free_page(page); - freed++; - if (page2) - page = page2->next_hash; - else - page = (struct page *)pgd_quicklist; - if (pgd_cache_size <= low / 4) - break; - continue; - } - page2 = page; - page = page->next_hash; - } - spin_unlock(&pgd_spinlock); - } - return freed; -} - -static void srmmu_flush_dma_area(unsigned long addr, int len) -{ - /* XXX Later */ -} - -static void srmmu_inval_dma_area(unsigned long addr, int len) -{ - /* XXX Later */ + return 0; } extern unsigned long spwin_mmu_patchme, fwin_mmu_patchme, @@ -2302,22 +2137,18 @@ #ifndef CONFIG_SMP BTFIXUPSET_CALL(___xchg32, ___xchg32_sun4md, BTFIXUPCALL_SWAPG1G2); #endif - BTFIXUPSET_CALL(get_pte_fast, srmmu_get_pte_fast, BTFIXUPCALL_RETINT(0)); - BTFIXUPSET_CALL(get_pgd_fast, srmmu_get_pgd_fast, BTFIXUPCALL_RETINT(0)); - BTFIXUPSET_CALL(free_pte_slow, srmmu_free_pte_slow, BTFIXUPCALL_NOP); - BTFIXUPSET_CALL(free_pgd_slow, srmmu_free_pgd_slow, BTFIXUPCALL_NOP); BTFIXUPSET_CALL(do_check_pgt_cache, srmmu_check_pgt_cache, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(set_pgdir, srmmu_set_pgdir, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(set_pte, srmmu_set_pte_cacheable, BTFIXUPCALL_SWAPO0O1); + BTFIXUPSET_CALL(set_pte, srmmu_set_pte, BTFIXUPCALL_SWAPO0O1); BTFIXUPSET_CALL(switch_mm, srmmu_switch_mm, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pte_pagenr, srmmu_pte_pagenr, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pmd_page, srmmu_pmd_page, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pgd_page, srmmu_pgd_page, BTFIXUPCALL_NORM); - BTFIXUPSET_SETHI(none_mask, 0xF0000000); /* P3: is it used? */ + BTFIXUPSET_SETHI(none_mask, 0xF0000000); /* XXX P3: is it used? */ BTFIXUPSET_CALL(pte_present, srmmu_pte_present, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pte_clear, srmmu_pte_clear, BTFIXUPCALL_SWAPO0G0); @@ -2369,16 +2200,8 @@ BTFIXUPSET_CALL(free_task_struct, srmmu_free_task_struct, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(get_task_struct, srmmu_get_task_struct, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(quick_kernel_fault, srmmu_quick_kernel_fault, BTFIXUPCALL_NORM); - /* SRMMU specific. */ - BTFIXUPSET_CALL(ctxd_set, srmmu_ctxd_set, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pmd_set, srmmu_pmd_set, BTFIXUPCALL_NORM); - -/* hmm isn't flush_dma_area the same thing as flush_page_for_dma? */ -/* It is, except flush_page_for_dma was local to srmmu.c */ - BTFIXUPSET_CALL(mmu_flush_dma_area, srmmu_flush_dma_area, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(mmu_inval_dma_area, srmmu_inval_dma_area, BTFIXUPCALL_NORM); get_srmmu_type(); patch_window_trap_handlers(); diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c --- v2.4.0-test1/linux/arch/sparc/mm/sun4c.c Tue May 23 15:31:34 2000 +++ linux/arch/sparc/mm/sun4c.c Mon Jun 19 17:59:38 2000 @@ -1,10 +1,10 @@ -/* $Id: sun4c.c,v 1.192 2000/05/09 17:40:13 davem Exp $ +/* $Id: sun4c.c,v 1.194 2000/06/05 06:08:45 anton Exp $ * sun4c.c: Doing in software what should be done in hardware. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1996 Andrew Tridgell (Andrew.Tridgell@anu.edu.au) - * Copyright (C) 1997,99 Anton Blanchard (anton@progsoc.uts.edu.au) + * Copyright (C) 1997-2000 Anton Blanchard (anton@linuxcare.com) * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ @@ -597,14 +597,6 @@ /* XXX Implement this */ } -static void sun4c_inval_dma_area(unsigned long virt, int len) -{ -} - -static void sun4c_flush_dma_area(unsigned long virt, int len) -{ -} - /* TLB management. */ /* Don't change this struct without changing entry.S. This is used @@ -1011,13 +1003,6 @@ } } -/* This is now a fast in-window trap handler to avoid any and all races. */ -static void sun4c_quick_kernel_fault(unsigned long address) -{ - printk("Kernel faults at addr 0x%08lx\n", address); - panic("sun4c kernel fault handler bolixed..."); -} - /* 2 page buckets for task struct and kernel stack allocation. * * TASK_STACK_BEGIN @@ -2280,22 +2265,6 @@ return (pgd_t *)ret; } -static int sun4c_check_pgt_cache(int low, int high) -{ - int freed = 0; - if (pgtable_cache_size > high) { - do { - if (pgd_quicklist) - free_pgd_slow(get_pgd_fast()), freed++; - if (pmd_quicklist) - free_pmd_slow(get_pmd_fast()), freed++; - if (pte_quicklist) - free_pte_slow(get_pte_fast()), freed++; - } while (pgtable_cache_size > low); - } - return freed; -} - static void sun4c_set_pgdir(unsigned long address, pgd_t entry) { /* Nothing to do */ @@ -2361,11 +2330,6 @@ return (pte_t *) sun4c_pmd_page(*pmd) + address; } -static pte_t *sun4c_pte_get(void) -{ - return sun4c_get_pte_fast(); -} - /* * allocating and freeing a pmd is trivial: the 1-entry pmd is * inside the pgd, so has no extra memory associated with it. @@ -2389,6 +2353,22 @@ return sun4c_get_pgd_fast(); } +static int sun4c_check_pgt_cache(int low, int high) +{ + int freed = 0; + if (pgtable_cache_size > high) { + do { + if (pgd_quicklist) + sun4c_free_pgd_slow(sun4c_get_pgd_fast()), freed++; + if (pmd_quicklist) + sun4c_free_pmd_slow(sun4c_get_pmd_fast()), freed++; + if (pte_quicklist) + sun4c_free_pte_slow(sun4c_get_pte_fast()), freed++; + } while (pgtable_cache_size > low); + } + return freed; +} + /* There are really two cases of aliases to watch out for, and these * are: * @@ -2568,7 +2548,7 @@ memset(pg3, 0, PAGE_SIZE); /* Save work later. */ - vaddr = SUN4C_VMALLOC_START; + vaddr = VMALLOC_START; swapper_pg_dir[vaddr>>SUN4C_PGDIR_SHIFT] = __pgd(PGD_TABLE | (unsigned long) pg0); vaddr += SUN4C_PGDIR_SIZE; swapper_pg_dir[vaddr>>SUN4C_PGDIR_SHIFT] = __pgd(PGD_TABLE | (unsigned long) pg1); @@ -2628,10 +2608,6 @@ #ifndef CONFIG_SMP BTFIXUPSET_CALL(___xchg32, ___xchg32_sun4c, BTFIXUPCALL_NORM); #endif - BTFIXUPSET_CALL(get_pte_fast, sun4c_pte_get, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(get_pgd_fast, sun4c_pgd_alloc, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(free_pte_slow, sun4c_free_pte_slow, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(free_pgd_slow, sun4c_free_pgd_slow, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(do_check_pgt_cache, sun4c_check_pgt_cache, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(set_pgdir, sun4c_set_pgdir, BTFIXUPCALL_NOP); @@ -2727,14 +2703,11 @@ BTFIXUPSET_CALL(mmu_map_dma_area, sun4c_map_dma_area, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(mmu_unmap_dma_area, sun4c_unmap_dma_area, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(mmu_translate_dvma, sun4c_translate_dvma, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(mmu_flush_dma_area, sun4c_flush_dma_area, BTFIXUPCALL_NOP); - BTFIXUPSET_CALL(mmu_inval_dma_area, sun4c_inval_dma_area, BTFIXUPCALL_NORM); /* Task struct and kernel stack allocating/freeing. */ BTFIXUPSET_CALL(alloc_task_struct, sun4c_alloc_task_struct, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(get_task_struct, sun4c_get_task_struct, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(quick_kernel_fault, sun4c_quick_kernel_fault, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(mmu_info, sun4c_mmu_info, BTFIXUPCALL_NORM); /* These should _never_ get called with two level tables. */ diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc/mm/swift.S linux/arch/sparc/mm/swift.S --- v2.4.0-test1/linux/arch/sparc/mm/swift.S Tue May 23 15:31:34 2000 +++ linux/arch/sparc/mm/swift.S Mon Jun 19 17:59:38 2000 @@ -1,4 +1,4 @@ -/* $Id: swift.S,v 1.5 2000/05/09 17:40:13 davem Exp $ +/* $Id: swift.S,v 1.6 2000/06/04 06:23:53 anton Exp $ * swift.S: MicroSparc-II mmu/cache operations. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -30,7 +30,7 @@ */ .globl swift_flush_cache_all, swift_flush_cache_mm .globl swift_flush_cache_range, swift_flush_cache_page - .globl swift_flush_page_for_dma, swift_flush_chunk + .globl swift_flush_page_for_dma .globl swift_flush_page_to_ram swift_flush_cache_all: @@ -38,7 +38,6 @@ swift_flush_cache_range: swift_flush_cache_page: swift_flush_page_for_dma: -swift_flush_chunk: swift_flush_page_to_ram: sethi %hi(0x2000), %o0 1: subcc %o0, 0x10, %o0 @@ -190,10 +189,8 @@ * caches which are virtually indexed and tagged. */ .globl swift_flush_page_for_dma - .globl swift_flush_chunk .globl swift_flush_page_to_ram swift_flush_page_for_dma: -swift_flush_chunk: swift_flush_page_to_ram: andn %o0, (PAGE_SIZE - 1), %o1 #if 1 diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc/mm/tsunami.S linux/arch/sparc/mm/tsunami.S --- v2.4.0-test1/linux/arch/sparc/mm/tsunami.S Tue May 23 15:31:34 2000 +++ linux/arch/sparc/mm/tsunami.S Mon Jun 19 17:59:38 2000 @@ -1,4 +1,4 @@ -/* $Id: tsunami.S,v 1.4 2000/05/09 17:40:13 davem Exp $ +/* $Id: tsunami.S,v 1.5 2000/06/04 06:23:53 anton Exp $ * tsunami.S: High speed MicroSparc-I mmu/cache operations. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -28,7 +28,7 @@ .globl tsunami_flush_cache_all, tsunami_flush_cache_mm .globl tsunami_flush_cache_range, tsunami_flush_cache_page .globl tsunami_flush_page_to_ram, tsunami_flush_page_for_dma - .globl tsunami_flush_sig_insns, tsunami_flush_chunk + .globl tsunami_flush_sig_insns .globl tsunami_flush_tlb_all, tsunami_flush_tlb_mm .globl tsunami_flush_tlb_range, tsunami_flush_tlb_page @@ -46,7 +46,6 @@ WINDOW_FLUSH(%g4, %g5) tsunami_flush_page_for_dma: sta %g0, [%g0] ASI_M_IC_FLCLEAR -tsunami_flush_chunk: sta %g0, [%g0] ASI_M_DC_FLCLEAR tsunami_flush_cache_out: tsunami_flush_page_to_ram: diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc/mm/viking.S linux/arch/sparc/mm/viking.S --- v2.4.0-test1/linux/arch/sparc/mm/viking.S Tue May 23 15:31:34 2000 +++ linux/arch/sparc/mm/viking.S Mon Jun 19 17:59:38 2000 @@ -1,4 +1,4 @@ -/* $Id: viking.S,v 1.16 2000/05/09 17:40:13 davem Exp $ +/* $Id: viking.S,v 1.17 2000/06/04 06:23:53 anton Exp $ * viking.S: High speed Viking cache/mmu operations * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -31,12 +31,10 @@ .globl viking_flush_cache_range, viking_flush_cache_page .globl viking_flush_page, viking_mxcc_flush_page .globl viking_flush_page_for_dma, viking_flush_page_to_ram - .globl viking_flush_chunk, viking_mxcc_flush_chunk .globl viking_flush_sig_insns .globl viking_flush_tlb_all, viking_flush_tlb_mm .globl viking_flush_tlb_range, viking_flush_tlb_page -viking_flush_chunk: viking_flush_page: sethi %hi(PAGE_OFFSET), %g2 sub %o0, %g2, %g3 @@ -107,10 +105,6 @@ sub %g3, MXCC_STREAM_SIZE, %g3 9: retl - nop - -viking_mxcc_flush_chunk: - retl nop #define WINDOW_FLUSH(tmp1, tmp2) \ diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc64/config.in linux/arch/sparc64/config.in --- v2.4.0-test1/linux/arch/sparc64/config.in Tue May 23 15:31:34 2000 +++ linux/arch/sparc64/config.in Thu Jun 22 07:21:12 2000 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.112 2000/05/22 08:12:19 davem Exp $ +# $Id: config.in,v 1.115 2000/06/20 04:36:22 ecd Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -10,6 +10,15 @@ endmenu mainmenu_option next_comment +comment 'Loadable module support' +bool 'Enable loadable module support' CONFIG_MODULES +if [ "$CONFIG_MODULES" = "y" ]; then + bool ' Set version information on all symbols for modules' CONFIG_MODVERSIONS + bool ' Kernel module loader' CONFIG_KMOD +fi +endmenu + +mainmenu_option next_comment comment 'General setup' define_bool CONFIG_VT y @@ -61,15 +70,6 @@ endmenu mainmenu_option next_comment -comment 'Loadable module support' -bool 'Enable loadable module support' CONFIG_MODULES -if [ "$CONFIG_MODULES" = "y" ]; then - bool ' Set version information on all symbols for modules' CONFIG_MODVERSIONS - bool ' Kernel module loader' CONFIG_KMOD -fi -endmenu - -mainmenu_option next_comment comment 'Console drivers' bool 'PROM console' CONFIG_PROM_CONSOLE bool 'Support Frame buffer devices' CONFIG_FB @@ -93,6 +93,9 @@ fi tristate 'RAM disk support' CONFIG_BLK_DEV_RAM +if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then + int ' Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096 +fi if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD fi @@ -294,7 +297,7 @@ mainmenu_option next_comment comment 'XFree86 DRI support' bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM -# dep_tristate ' Creator/Creator3D/Elite3D' CONFIG_DRM_FFB $CONFIG_DRM +dep_tristate ' Creator/Creator3D' CONFIG_DRM_FFB $CONFIG_DRM endmenu source fs/Config.in diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig --- v2.4.0-test1/linux/arch/sparc64/defconfig Mon Jun 19 16:31:58 2000 +++ linux/arch/sparc64/defconfig Mon Jun 19 17:59:38 2000 @@ -8,6 +8,13 @@ CONFIG_EXPERIMENTAL=y # +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y + +# # General setup # CONFIG_VT=y @@ -59,13 +66,6 @@ CONFIG_ENVCTRL=m # -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_MODVERSIONS=y -CONFIG_KMOD=y - -# # Console drivers # CONFIG_PROM_CONSOLE=y @@ -170,9 +170,9 @@ CONFIG_DECNET=m CONFIG_DECNET_SIOCGIFCONF=y # CONFIG_DECNET_ROUTER is not set +# CONFIG_BRIDGE is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set # CONFIG_LLC is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set @@ -208,6 +208,8 @@ # CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set # CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set # CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set # CONFIG_BLK_DEV_IDECS is not set CONFIG_BLK_DEV_IDECD=y CONFIG_BLK_DEV_IDETAPE=m @@ -227,7 +229,6 @@ # CONFIG_BLK_DEV_OFFBOARD is not set CONFIG_IDEDMA_PCI_AUTO=y CONFIG_BLK_DEV_IDEDMA=y -CONFIG_IDEDMA_PCI_EXPERIMENTAL=y # CONFIG_IDEDMA_PCI_WIP is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set # CONFIG_BLK_DEV_AEC62XX is not set @@ -237,25 +238,23 @@ # CONFIG_BLK_DEV_AMD7409 is not set # CONFIG_AMD7409_OVERRIDE is not set CONFIG_BLK_DEV_CMD64X=y -# CONFIG_CMD64X_RAID is not set # CONFIG_BLK_DEV_CY82C693 is not set # CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_HPT34X is not set # CONFIG_HPT34X_AUTODMA is not set # CONFIG_BLK_DEV_HPT366 is not set -# CONFIG_HPT366_FIP is not set -# CONFIG_HPT366_MODE3 is not set CONFIG_BLK_DEV_NS87415=y # CONFIG_BLK_DEV_OPTI621 is not set # CONFIG_BLK_DEV_PDC202XX is not set # CONFIG_PDC202XX_BURST is not set -# CONFIG_PDC202XX_MASTER is not set # CONFIG_BLK_DEV_SIS5513 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set # CONFIG_VIA82CXXX_TUNING is not set # CONFIG_IDE_CHIPSETS is not set CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set CONFIG_BLK_DEV_IDE_MODES=y # @@ -287,20 +286,20 @@ # CONFIG_SCSI_SUNESP=y CONFIG_SCSI_QLOGICPTI=m -CONFIG_SCSI_AIC7XXX=y +CONFIG_SCSI_AIC7XXX=m CONFIG_AIC7XXX_TAGGED_QUEUEING=y CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 CONFIG_AIC7XXX_PROC_STATS=y CONFIG_AIC7XXX_RESET_DELAY=5 -CONFIG_SCSI_NCR53C8XX=y +CONFIG_SCSI_NCR53C8XX=m CONFIG_SCSI_SYM53C8XX=y CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 -CONFIG_SCSI_NCR53C8XX_SYNC=10 +CONFIG_SCSI_NCR53C8XX_SYNC=40 # CONFIG_SCSI_NCR53C8XX_PROFILE is not set # CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set # CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set -CONFIG_SCSI_QLOGIC_ISP=y +CONFIG_SCSI_QLOGIC_ISP=m CONFIG_SCSI_QLOGIC_FC=m # @@ -379,6 +378,7 @@ # XFree86 DRI support # CONFIG_DRM=y +CONFIG_DRM_FFB=m # # File systems @@ -429,6 +429,7 @@ # CONFIG_ROOT_NFS is not set CONFIG_NFSD=m CONFIG_NFSD_V3=y +# CONFIG_NFSD_TCP is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile --- v2.4.0-test1/linux/arch/sparc64/kernel/Makefile Mon Jun 19 16:31:58 2000 +++ linux/arch/sparc64/kernel/Makefile Mon Jun 19 17:59:38 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.54 2000/05/12 23:51:24 davem Exp $ +# $Id: Makefile,v 1.55 2000/05/27 00:49:35 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc64/kernel/binfmt_aout32.c linux/arch/sparc64/kernel/binfmt_aout32.c --- v2.4.0-test1/linux/arch/sparc64/kernel/binfmt_aout32.c Wed Apr 26 16:34:07 2000 +++ linux/arch/sparc64/kernel/binfmt_aout32.c Fri Jun 23 21:09:14 2000 @@ -277,20 +277,24 @@ goto beyond_if; } + down(¤t->mm->mmap_sem); error = do_mmap(bprm->file, N_TXTADDR(ex), ex.a_text, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset); + up(¤t->mm->mmap_sem); if (error != N_TXTADDR(ex)) { send_sig(SIGKILL, current, 0); return error; } + down(¤t->mm->mmap_sem); error = do_mmap(bprm->file, N_DATADDR(ex), ex.a_data, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset + ex.a_text); + up(¤t->mm->mmap_sem); if (error != N_DATADDR(ex)) { send_sig(SIGKILL, current, 0); return error; diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S --- v2.4.0-test1/linux/arch/sparc64/kernel/entry.S Tue Apr 11 15:09:15 2000 +++ linux/arch/sparc64/kernel/entry.S Mon Jun 19 17:59:38 2000 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.115 2000/03/29 09:55:30 davem Exp $ +/* $Id: entry.S,v 1.116 2000/06/19 06:24:37 davem Exp $ * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points. * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -867,8 +867,8 @@ add %o7, 1f-.-4, %o7 nop .align 32 -1: ldx [%curptr + AOFF_task_flags], %l5 - andcc %l5, 0x20, %g0 +1: ldx [%curptr + AOFF_task_ptrace], %l5 + andcc %l5, 0x02, %g0 be,pt %icc, rtrap clr %l6 call syscall_trace @@ -994,11 +994,11 @@ mov %i4, %o4 ! IEU1 lduw [%l7 + %l4], %l7 ! Load srl %i1, 0, %o1 ! IEU0 Group - ldx [%curptr + AOFF_task_flags], %l0 ! Load + ldx [%curptr + AOFF_task_ptrace], %l0 ! Load mov %i5, %o5 ! IEU1 srl %i2, 0, %o2 ! IEU0 Group - andcc %l0, 0x20, %g0 ! IEU0 Group + andcc %l0, 0x02, %g0 ! IEU0 Group bne,pn %icc, linux_syscall_trace32 ! CTI mov %i0, %l5 ! IEU1 call %l7 ! CTI Group brk forced @@ -1023,11 +1023,11 @@ mov %i1, %o1 ! IEU1 lduw [%l7 + %l4], %l7 ! Load 4: mov %i2, %o2 ! IEU0 Group - ldx [%curptr + AOFF_task_flags], %l0 ! Load + ldx [%curptr + AOFF_task_ptrace], %l0 ! Load mov %i3, %o3 ! IEU1 mov %i4, %o4 ! IEU0 Group - andcc %l0, 0x20, %g0 ! IEU1 Group+1 bubble + andcc %l0, 0x02, %g0 ! IEU1 Group+1 bubble bne,pn %icc, linux_syscall_trace ! CTI Group mov %i0, %l5 ! IEU0 2: call %l7 ! CTI Group brk forced @@ -1048,7 +1048,7 @@ sllx %g2, 32, %g2 bgeu,pn %xcc, 1f - andcc %l0, 0x20, %l6 + andcc %l0, 0x02, %l6 andn %g3, %g2, %g3 /* System call success, clear Carry condition code. */ stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE] bne,pn %icc, linux_syscall_trace2 diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c --- v2.4.0-test1/linux/arch/sparc64/kernel/ioctl32.c Mon Jun 19 16:31:58 2000 +++ linux/arch/sparc64/kernel/ioctl32.c Mon Jun 19 17:59:38 2000 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.91 2000/05/23 05:25:44 davem Exp $ +/* $Id: ioctl32.c,v 1.92 2000/05/26 22:44:11 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) @@ -2442,8 +2442,8 @@ } typedef struct drm32_unique { - size_t unique_len; /* Length of unique */ - u32 unique; /* Unique name for driver instantiation */ + int unique_len; /* Length of unique */ + u32 unique; /* Unique name for driver instantiation */ } drm32_unique_t; #define DRM32_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm32_unique_t) #define DRM32_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm32_unique_t) @@ -2487,13 +2487,15 @@ if (!ret) { if (cmd == DRM32_IOCTL_GET_UNIQUE && + uptr != NULL && copy_to_user(uptr, karg.unique, karg.unique_len)) ret = -EFAULT; if (put_user(karg.unique_len, &uarg->unique_len)) ret = -EFAULT; } - kfree(karg.unique); + if (karg.unique != NULL) + kfree(karg.unique); return ret; } @@ -2836,7 +2838,7 @@ int count; u32 contexts; /* (drm_ctx_t *) */ } drm32_ctx_res_t; -#define DRM32_IOCTL_RES_CTX DRM_IOWR(0x26, drm_ctx_res_t) +#define DRM32_IOCTL_RES_CTX DRM_IOWR(0x26, drm32_ctx_res_t) static int drm32_res_ctx(unsigned int fd, unsigned int cmd, unsigned long arg) { diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc64/kernel/iommu_common.c linux/arch/sparc64/kernel/iommu_common.c --- v2.4.0-test1/linux/arch/sparc64/kernel/iommu_common.c Tue Feb 1 01:35:43 2000 +++ linux/arch/sparc64/kernel/iommu_common.c Mon Jun 19 17:59:38 2000 @@ -1,4 +1,4 @@ -/* $Id: iommu_common.c,v 1.3 2000/01/28 13:41:59 jj Exp $ +/* $Id: iommu_common.c,v 1.4 2000/06/04 21:50:23 anton Exp $ * iommu_common.c: UltraSparc SBUS/PCI common iommu code. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -45,7 +45,7 @@ } if (pgcount != npages) { - printk("verify_langths: Error, page count wrong, " + printk("verify_lengths: Error, page count wrong, " "npages[%d] pgcount[%d]\n", npages, pgcount); return -1; diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc64/kernel/ptrace.c linux/arch/sparc64/kernel/ptrace.c --- v2.4.0-test1/linux/arch/sparc64/kernel/ptrace.c Wed Apr 26 16:34:07 2000 +++ linux/arch/sparc64/kernel/ptrace.c Mon Jun 19 17:59:38 2000 @@ -139,12 +139,12 @@ #endif if(request == PTRACE_TRACEME) { /* are we already being traced? */ - if (current->flags & PF_PTRACED) { + if (current->ptrace & PT_PTRACED) { pt_error_return(regs, EPERM); goto out; } /* set the ptrace bit in the process flags. */ - current->flags |= PF_PTRACED; + current->ptrace |= PT_PTRACED; pt_succ_return(regs, 0); goto out; } @@ -187,11 +187,11 @@ goto out; } /* the same process cannot be attached many times */ - if (child->flags & PF_PTRACED) { + if (child->ptrace & PT_PTRACED) { pt_error_return(regs, EPERM); goto out; } - child->flags |= PF_PTRACED; + child->ptrace |= PT_PTRACED; write_lock_irqsave(&tasklist_lock, flags); if(child->p_pptr != current) { REMOVE_LINKS(child); @@ -203,7 +203,7 @@ pt_succ_return(regs, 0); goto out; } - if (!(child->flags & PF_PTRACED)) { + if (!(child->ptrace & PT_PTRACED)) { pt_error_return(regs, ESRCH); goto out; } @@ -544,9 +544,9 @@ } if (request == PTRACE_SYSCALL) - child->flags |= PF_TRACESYS; + child->ptrace |= PT_TRACESYS; else - child->flags &= ~PF_TRACESYS; + child->ptrace &= ~PT_TRACESYS; child->exit_code = data; #ifdef DEBUG_PTRACE @@ -584,7 +584,7 @@ pt_error_return(regs, EIO); goto out; } - child->flags &= ~(PF_PTRACED|PF_TRACESYS); + child->ptrace &= ~(PT_PTRACED|PT_TRACESYS); child->exit_code = data; write_lock_irqsave(&tasklist_lock, flags); @@ -627,8 +627,8 @@ #ifdef DEBUG_PTRACE printk("%s [%d]: syscall_trace\n", current->comm, current->pid); #endif - if ((current->flags & (PF_PTRACED|PF_TRACESYS)) - != (PF_PTRACED|PF_TRACESYS)) + if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) + != (PT_PTRACED|PT_TRACESYS)) return; current->exit_code = SIGTRAP; current->state = TASK_STOPPED; diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc64/kernel/signal.c linux/arch/sparc64/kernel/signal.c --- v2.4.0-test1/linux/arch/sparc64/kernel/signal.c Mon Jun 19 16:31:58 2000 +++ linux/arch/sparc64/kernel/signal.c Mon Jun 19 17:59:39 2000 @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.49 2000/04/08 02:11:46 davem Exp $ +/* $Id: signal.c,v 1.51 2000/06/19 06:24:37 davem Exp $ * arch/sparc64/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -693,7 +693,7 @@ if (!signr) break; - if ((current->flags & PF_PTRACED) && signr != SIGKILL) { + if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { current->exit_code = signr; current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); @@ -749,7 +749,7 @@ continue; case SIGSTOP: - if (current->flags & PF_PTRACED) + if (current->ptrace & PT_PTRACED) continue; current->state = TASK_STOPPED; current->exit_code = signr; diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c --- v2.4.0-test1/linux/arch/sparc64/kernel/signal32.c Mon Jun 19 16:31:58 2000 +++ linux/arch/sparc64/kernel/signal32.c Mon Jun 19 17:59:39 2000 @@ -1,4 +1,4 @@ -/* $Id: signal32.c,v 1.62 2000/04/12 08:10:19 davem Exp $ +/* $Id: signal32.c,v 1.64 2000/06/19 06:24:37 davem Exp $ * arch/sparc64/kernel/signal32.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -1314,7 +1314,7 @@ if (!signr) break; - if ((current->flags & PF_PTRACED) && signr != SIGKILL) { + if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { current->exit_code = signr; current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); @@ -1370,7 +1370,7 @@ continue; case SIGSTOP: - if (current->flags & PF_PTRACED) + if (current->ptrace & PT_PTRACED) continue; current->state = TASK_STOPPED; current->exit_code = signr; diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc64/kernel/sys_sparc.c linux/arch/sparc64/kernel/sys_sparc.c --- v2.4.0-test1/linux/arch/sparc64/kernel/sys_sparc.c Thu May 11 15:30:06 2000 +++ linux/arch/sparc64/kernel/sys_sparc.c Thu Jun 22 07:21:12 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.39 2000/04/27 02:49:03 davem Exp $ +/* $Id: sys_sparc.c,v 1.41 2000/06/22 11:42:25 davem Exp $ * linux/arch/sparc64/kernel/sys_sparc.c * * This file contains various random system calls that diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c --- v2.4.0-test1/linux/arch/sparc64/kernel/sys_sparc32.c Mon Jun 19 16:31:58 2000 +++ linux/arch/sparc64/kernel/sys_sparc32.c Fri Jun 23 21:09:14 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.147 2000/05/22 07:29:40 davem Exp $ +/* $Id: sys_sparc32.c,v 1.152 2000/06/22 17:44:47 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -2624,7 +2624,8 @@ * the cmsg_len for MSG_TRUNC cases, we need not check that case either. */ ucmsg = (struct cmsghdr *) orig_cmsg_uptr; - while(((unsigned long)ucmsg) < ((unsigned long)kmsg->msg_control)) { + while(((unsigned long)ucmsg) <= + (((unsigned long)kmsg->msg_control) - sizeof(struct cmsghdr))) { struct cmsghdr32 *kcmsg32 = (struct cmsghdr32 *) wp; int clen64, clen32; @@ -3776,8 +3777,6 @@ { return copy_to_user(res32, kres, sizeof(*res32)); } - -extern asmlinkage int sys_nfsservctl(int cmd, void *arg, void *resp); int asmlinkage sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32) { diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c --- v2.4.0-test1/linux/arch/sparc64/kernel/sys_sunos32.c Tue May 23 15:31:34 2000 +++ linux/arch/sparc64/kernel/sys_sunos32.c Thu Jun 22 07:21:12 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos32.c,v 1.47 2000/05/22 07:29:40 davem Exp $ +/* $Id: sys_sunos32.c,v 1.49 2000/06/22 11:42:25 davem Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc64/solaris/socksys.c linux/arch/sparc64/solaris/socksys.c --- v2.4.0-test1/linux/arch/sparc64/solaris/socksys.c Tue Apr 11 15:09:15 2000 +++ linux/arch/sparc64/solaris/socksys.c Thu Jun 22 07:21:12 2000 @@ -1,4 +1,4 @@ -/* $Id: socksys.c,v 1.13 2000/03/29 11:56:54 davem Exp $ +/* $Id: socksys.c,v 1.14 2000/06/22 11:42:25 davem Exp $ * socksys.c: /dev/inet/ stuff for Solaris emulation. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -181,9 +181,9 @@ printk ("Couldn't create socket\n"); return ret; } - devfs_handle = devfs_register (NULL, "socksys", 0, DEVFS_FL_NONE, + devfs_handle = devfs_register (NULL, "socksys", DEVFS_FL_DEFAULT, 30, 0, - S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR, &socksys_fops, NULL); file = fcheck(ret); /* N.B. Is this valid? Suppose the f_ops are in a module ... */ diff -u --recursive --new-file v2.4.0-test1/linux/arch/sparc64/solaris/timod.c linux/arch/sparc64/solaris/timod.c --- v2.4.0-test1/linux/arch/sparc64/solaris/timod.c Tue Apr 11 15:09:15 2000 +++ linux/arch/sparc64/solaris/timod.c Mon Jun 19 17:59:39 2000 @@ -1,4 +1,4 @@ -/* $Id: timod.c,v 1.6 2000/03/25 03:23:21 davem Exp $ +/* $Id: timod.c,v 1.7 2000/06/09 07:35:30 davem Exp $ * timod.c: timod emulation. * * Copyright (C) 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz) @@ -18,6 +18,8 @@ #include #include +#include + #include #include @@ -151,8 +153,10 @@ SOLD("wakeing socket"); sock = ¤t->files->fd[fd]->f_dentry->d_inode->u.socket_i; wake_up_interruptible(&sock->wait); + read_lock(&sock->sk->callback_lock); if (sock->fasync_list && !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags)) - kill_fasync(sock->fasync_list, SIGIO, POLL_IN); + __kill_fasync(sock->fasync_list, SIGIO, POLL_IN); + read_unlock(&sock->sk->callback_lock); SOLD("done"); } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/acorn/char/Makefile linux/drivers/acorn/char/Makefile --- v2.4.0-test1/linux/drivers/acorn/char/Makefile Thu Mar 2 14:36:22 2000 +++ linux/drivers/acorn/char/Makefile Tue Jun 20 07:24:52 2000 @@ -18,7 +18,7 @@ # Object file lists. -obj-y := i2c.o pcf8583.o +obj-y := obj-m := obj-n := obj- := @@ -34,7 +34,8 @@ obj-$(CONFIG_ATOMWIDE_SERIAL) += serial-atomwide.o obj-$(CONFIG_DUALSP_SERIAL) += serial-dualsp.o -obj-y += $(obj-$(MACHINE)) +# Do the i2c and rtc last +obj-y += $(obj-$(MACHINE)) i2c.o pcf8583.o O_OBJS := $(filter-out $(export-objs), $(obj-y)) OX_OBJS := $(filter $(export-objs), $(obj-y)) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/acorn/char/keyb_arc.c linux/drivers/acorn/char/keyb_arc.c --- v2.4.0-test1/linux/drivers/acorn/char/keyb_arc.c Fri Oct 22 13:21:47 1999 +++ linux/drivers/acorn/char/keyb_arc.c Tue Jun 20 07:24:52 2000 @@ -415,7 +415,7 @@ #ifdef CONFIG_KBDMOUSE static struct busmouse a5kkbd_mouse = { - 6, "kbdmouse", NULL, NULL, 7 + 6, "kbdmouse", NULL, NULL, NULL, 7 }; #endif diff -u --recursive --new-file v2.4.0-test1/linux/drivers/acorn/char/mouse_rpc.c linux/drivers/acorn/char/mouse_rpc.c --- v2.4.0-test1/linux/drivers/acorn/char/mouse_rpc.c Tue Dec 14 01:27:23 1999 +++ linux/drivers/acorn/char/mouse_rpc.c Tue Jun 20 07:24:52 2000 @@ -46,7 +46,7 @@ } static struct busmouse rpcmouse = { - 6, "arcmouse", NULL, NULL, 7 + 6, "arcmouse", NULL, NULL, NULL, 7 }; static int __init mouse_rpc_init(void) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/acorn/net/etherh.c linux/drivers/acorn/net/etherh.c --- v2.4.0-test1/linux/drivers/acorn/net/etherh.c Tue May 23 15:31:34 2000 +++ linux/drivers/acorn/net/etherh.c Tue Jun 20 07:24:52 2000 @@ -621,8 +621,6 @@ if (load_8390_module("etherh.c")) return -ENOSYS; - lock_8390_module(); - ecard_startfind(); for (i = 0; i < MAX_ECARDS; i++) { @@ -643,7 +641,7 @@ } if (ret) - unlock_8390_module(); + unload_8390_module(); return ret; } @@ -665,7 +663,7 @@ e_card[i] = NULL; } } - unlock_8390_module(); + unload_8390_module(); } module_init(etherh_init); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/atm/Config.in linux/drivers/atm/Config.in --- v2.4.0-test1/linux/drivers/atm/Config.in Wed Apr 26 16:34:07 2000 +++ linux/drivers/atm/Config.in Tue Jun 20 07:24:52 2000 @@ -59,7 +59,7 @@ if [ "$CONFIG_ATM_FORE200E_PCA" = "y" ]; then bool ' Use default PCA-200E firmware (normally enabled)' CONFIG_ATM_FORE200E_PCA_DEFAULT_FW if [ "$CONFIG_ATM_FORE200E_PCA_DEFAULT_FW" = "n" ]; then - string ' Pathname of user-supplied binary firmware' CONFIG_ATM_FORE200E_PCA_FW + string ' Pathname of user-supplied binary firmware' CONFIG_ATM_FORE200E_PCA_FW "" fi fi fi diff -u --recursive --new-file v2.4.0-test1/linux/drivers/atm/Makefile linux/drivers/atm/Makefile --- v2.4.0-test1/linux/drivers/atm/Makefile Wed Apr 26 16:34:07 2000 +++ linux/drivers/atm/Makefile Tue Jun 20 07:24:52 2000 @@ -45,7 +45,7 @@ NEED_SUNI_MX = suni.o endif ifeq ($(CONFIG_ATM_NICSTAR_USE_IDT77105),y) - NEED_SUNI_MX = idt77105.o + NEED_IDT77105_MX = idt77105.o endif endif endif diff -u --recursive --new-file v2.4.0-test1/linux/drivers/atm/ambassador.c linux/drivers/atm/ambassador.c --- v2.4.0-test1/linux/drivers/atm/ambassador.c Thu May 11 15:30:06 2000 +++ linux/drivers/atm/ambassador.c Tue Jun 20 13:58:42 2000 @@ -290,10 +290,12 @@ /********** microcode **********/ #ifdef AMB_NEW_MICROCODE -#define UCODE(x) "atmsar12" "." #x +#define UCODE(x) UCODE1(atmsar12.,x) #else -#define UCODE(x) "atmsar11" "." #x +#define UCODE(x) UCODE1(atmsar11.,x) #endif +#define UCODE2(x) #x +#define UCODE1(x,y) UCODE2(x ## y) static const u32 __initdata ucode_start = #include UCODE(start) @@ -326,45 +328,43 @@ /********** access to adapter **********/ -static inline void wr_plain (const amb_dev * dev, const u32 * addr, u32 data) { - PRINTD (DBG_FLOW|DBG_REGS, "wr: %p <- %08x", addr, data); +static inline void wr_plain (const amb_dev * dev, size_t addr, u32 data) { + PRINTD (DBG_FLOW|DBG_REGS, "wr: %08x <- %08x", addr, data); #ifdef AMB_MMIO - dev->membase[addr - (u32 *) 0] = data; + dev->membase[addr / sizeof(u32)] = data; #else - outl (data, dev->iobase + (addr - (u32 *) 0) * sizeof(u32)); + outl (data, dev->iobase + addr); #endif } -static inline u32 rd_plain (const amb_dev * dev, const u32 * addr) { +static inline u32 rd_plain (const amb_dev * dev, size_t addr) { #ifdef AMB_MMIO - u32 data = dev->membase[addr - (u32 *) 0]; + u32 data = dev->membase[addr / sizeof(u32)]; #else - u32 data = inl (dev->iobase + (addr - (u32 *) 0) * sizeof(u32)); + u32 data = inl (dev->iobase + addr); #endif - PRINTD (DBG_FLOW|DBG_REGS, "rd: %p -> %08x", addr, data); + PRINTD (DBG_FLOW|DBG_REGS, "rd: %08x -> %08x", addr, data); return data; } -static const amb_mem * const mem = 0; - -static inline void wr_mem (const amb_dev * dev, const u32 * addr, u32 data) { +static inline void wr_mem (const amb_dev * dev, size_t addr, u32 data) { u32 be = cpu_to_be32 (data); - PRINTD (DBG_FLOW|DBG_REGS, "wr: %p <- %08x b[%08x]", addr, data, be); + PRINTD (DBG_FLOW|DBG_REGS, "wr: %08x <- %08x b[%08x]", addr, data, be); #ifdef AMB_MMIO - dev->membase[addr - (u32 *) 0] = be; + dev->membase[addr / sizeof(u32)] = be; #else - outl (be, dev->iobase + (addr - (u32 *) 0) * sizeof(u32)); + outl (be, dev->iobase + addr); #endif } -static inline u32 rd_mem (const amb_dev * dev, const u32 * addr) { +static inline u32 rd_mem (const amb_dev * dev, size_t addr) { #ifdef AMB_MMIO - u32 be = dev->membase[addr - (u32 *) 0]; + u32 be = dev->membase[addr / sizeof(u32)]; #else - u32 be = inl (dev->iobase + (addr - (u32 *) 0) * sizeof(u32)); + u32 be = inl (dev->iobase + addr); #endif u32 data = be32_to_cpu (be); - PRINTD (DBG_FLOW|DBG_REGS, "rd: %p -> %08x b[%08x]", addr, data, be); + PRINTD (DBG_FLOW|DBG_REGS, "rd: %08x -> %08x b[%08x]", addr, data, be); return data; } @@ -600,7 +600,7 @@ ptrs->in = NEXTQ (ptrs->in, ptrs->start, ptrs->limit); // mail the command - wr_mem (dev, &mem->mb.adapter.cmd_address, virt_to_bus (ptrs->in)); + wr_mem (dev, offsetof(amb_mem, mb.adapter.cmd_address), virt_to_bus (ptrs->in)); // prepare to wait for cq->pending milliseconds // effectively one centisecond on i386 @@ -667,8 +667,8 @@ txq->pending++; txq->in.ptr = NEXTQ (txq->in.ptr, txq->in.start, txq->in.limit); // hand over the TX and ring the bell - wr_mem (dev, &mem->mb.adapter.tx_address, virt_to_bus (txq->in.ptr)); - wr_mem (dev, &mem->doorbell, TX_FRAME); + wr_mem (dev, offsetof(amb_mem, mb.adapter.tx_address), virt_to_bus (txq->in.ptr)); + wr_mem (dev, offsetof(amb_mem, doorbell), TX_FRAME); if (txq->pending > txq->high) txq->high = txq->pending; @@ -724,7 +724,7 @@ rxq->pending++; rxq->in.ptr = NEXTQ (rxq->in.ptr, rxq->in.start, rxq->in.limit); // hand over the RX buffer - wr_mem (dev, &mem->mb.adapter.rx_address[pool], virt_to_bus (rxq->in.ptr)); + wr_mem (dev, offsetof(amb_mem, mb.adapter.rx_address[pool]), virt_to_bus (rxq->in.ptr)); spin_unlock_irqrestore (&rxq->lock, flags); return 0; @@ -855,16 +855,16 @@ /********** enable host interrupts **********/ static inline void interrupts_on (amb_dev * dev) { - wr_plain (dev, &mem->interrupt_control, - rd_plain (dev, &mem->interrupt_control) + wr_plain (dev, offsetof(amb_mem, interrupt_control), + rd_plain (dev, offsetof(amb_mem, interrupt_control)) | AMB_INTERRUPT_BITS); } /********** disable host interrupts **********/ static inline void interrupts_off (amb_dev * dev) { - wr_plain (dev, &mem->interrupt_control, - rd_plain (dev, &mem->interrupt_control) + wr_plain (dev, offsetof(amb_mem, interrupt_control), + rd_plain (dev, offsetof(amb_mem, interrupt_control)) &~ AMB_INTERRUPT_BITS); } @@ -900,7 +900,7 @@ } { - u32 interrupt = rd_plain (dev, &mem->interrupt); + u32 interrupt = rd_plain (dev, offsetof(amb_mem, interrupt)); // for us or someone else sharing the same interrupt if (!interrupt) { @@ -910,7 +910,7 @@ // definitely for us PRINTD (DBG_IRQ, "FYI: interrupt was %08x", interrupt); - wr_plain (dev, &mem->interrupt, -1); + wr_plain (dev, offsetof(amb_mem, interrupt), -1); } { @@ -959,8 +959,8 @@ cli(); PRINTK (KERN_INFO, "don't panic - putting adapter into reset"); - wr_plain (dev, &mem->reset_control, - rd_plain (dev, &mem->reset_control) | AMB_RESET_BITS); + wr_plain (dev, offsetof(amb_mem, reset_control), + rd_plain (dev, offsetof(amb_mem, reset_control)) | AMB_RESET_BITS); PRINTK (KERN_INFO, "marking all commands complete"); for (cmd = ptrs->start; cmd < ptrs->limit; ++cmd) @@ -1985,7 +1985,7 @@ lb->valid = cpu_to_be32 (DMA_VALID); // dump_registers (dev); // dump_loader_block (lb); - wr_mem (dev, &mem->doorbell, virt_to_bus (lb) & ~onegigmask); + wr_mem (dev, offsetof(amb_mem, doorbell), virt_to_bus (lb) & ~onegigmask); timeout = command_timeouts[cmd] * HZ/100; @@ -2002,7 +2002,7 @@ if (cmd == adapter_start) { // wait for start command to acknowledge... timeout = HZ/10; - while (rd_plain (dev, &mem->doorbell)) + while (rd_plain (dev, offsetof(amb_mem, doorbell))) if (timeout) { timeout = schedule_timeout (timeout); } else { @@ -2095,21 +2095,21 @@ PRINTD (DBG_FLOW|DBG_LOAD, "amb_reset"); - word = rd_plain (dev, &mem->reset_control); + word = rd_plain (dev, offsetof(amb_mem, reset_control)); // put card into reset state - wr_plain (dev, &mem->reset_control, word | AMB_RESET_BITS); + wr_plain (dev, offsetof(amb_mem, reset_control), word | AMB_RESET_BITS); // wait a short while udelay (10); #if 1 // put card into known good state - wr_plain (dev, &mem->interrupt_control, AMB_DOORBELL_BITS); + wr_plain (dev, offsetof(amb_mem, interrupt_control), AMB_DOORBELL_BITS); // clear all interrupts just in case - wr_plain (dev, &mem->interrupt, -1); + wr_plain (dev, offsetof(amb_mem, interrupt), -1); #endif // clear self-test done flag - wr_plain (dev, &mem->mb.loader.ready, 0); + wr_plain (dev, offsetof(amb_mem, mb.loader.ready), 0); // take card out of reset state - wr_plain (dev, &mem->reset_control, word &~ AMB_RESET_BITS); + wr_plain (dev, offsetof(amb_mem, reset_control), word &~ AMB_RESET_BITS); if (diags) { unsigned long timeout; @@ -2119,7 +2119,7 @@ timeout = schedule_timeout (timeout); // half second time-out timeout = HZ/2; - while (!rd_plain (dev, &mem->mb.loader.ready)) + while (!rd_plain (dev, offsetof(amb_mem, mb.loader.ready))) if (timeout) { timeout = schedule_timeout (timeout); } else { @@ -2129,7 +2129,7 @@ // get results of self-test // XXX double check byte-order - word = rd_mem (dev, &mem->mb.loader.result); + word = rd_mem (dev, offsetof(amb_mem, mb.loader.result)); if (word & SELF_TEST_FAILURE) { void sf (const char * msg) { PRINTK (KERN_ERR, "self-test failed: %s", msg); @@ -2235,7 +2235,7 @@ #endif // pass the structure - wr_mem (dev, &mem->doorbell, virt_to_bus (&a)); + wr_mem (dev, offsetof(amb_mem, doorbell), virt_to_bus (&a)); // 2.2 second wait (must not touch doorbell during 2 second DMA test) timeout = HZ*22/10; @@ -2243,7 +2243,7 @@ timeout = schedule_timeout (timeout); // give the adapter another half second? timeout = HZ/2; - while (rd_plain (dev, &mem->doorbell)) + while (rd_plain (dev, offsetof(amb_mem, doorbell))) if (timeout) { timeout = schedule_timeout (timeout); } else { @@ -2318,10 +2318,10 @@ u32 mapreg; blb = virt_to_bus (&lb); // the kernel stack had better not ever cross a 1Gb boundary! - mapreg = rd_plain (dev, &mem->stuff[10]); + mapreg = rd_plain (dev, offsetof(amb_mem, stuff[10])); mapreg &= ~onegigmask; mapreg |= blb & onegigmask; - wr_plain (dev, &mem->stuff[10], mapreg); + wr_plain (dev, offsetof(amb_mem, stuff[10]), mapreg); return; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/atm/atmtcp.c linux/drivers/atm/atmtcp.c --- v2.4.0-test1/linux/drivers/atm/atmtcp.c Mon Mar 27 08:08:23 2000 +++ linux/drivers/atm/atmtcp.c Tue Jun 20 13:58:42 2000 @@ -330,14 +330,20 @@ struct atmtcp_dev_data *dev_data; struct atm_dev *dev; + MOD_INC_USE_COUNT; + dev_data = kmalloc(sizeof(*dev_data),GFP_KERNEL); - if (!dev_data) return -ENOMEM; + if (!dev_data) { + MOD_DEC_USE_COUNT; + return -ENOMEM; + } + dev = atm_dev_register(DEV_LABEL,&atmtcp_v_dev_ops,itf,NULL); if (!dev) { kfree(dev_data); + MOD_DEC_USE_COUNT; return itf == -1 ? -ENOMEM : -EBUSY; } - MOD_INC_USE_COUNT; dev->ci_range.vpi_bits = MAX_VPI_BITS; dev->ci_range.vci_bits = MAX_VCI_BITS; PRIV(dev) = dev_data; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/atm/eni.c linux/drivers/atm/eni.c --- v2.4.0-test1/linux/drivers/atm/eni.c Tue May 23 15:31:34 2000 +++ linux/drivers/atm/eni.c Tue Jun 20 13:58:42 2000 @@ -1711,7 +1711,7 @@ dev->link_rate = ATM_OC3_PCR; eni_dev = ENI_DEV(dev); pci_dev = eni_dev->pci_dev; - real_base = pci_dev->resource[0].start; + real_base = pci_resource_start(pci_dev, 0); eni_dev->irq = pci_dev->irq; error = pci_read_config_byte(pci_dev,PCI_REVISION_ID,&revision); if (error) { @@ -2246,8 +2246,16 @@ int error = -ENOMEM; DPRINTK("eni_init_one\n"); + + MOD_INC_USE_COUNT; /* @@@ we don't support unloading yet */ + + if (pci_enable_device(pci_dev)) { + error = -EIO; + goto out0; + } + eni_dev = (struct eni_dev *) kmalloc(sizeof(struct eni_dev),GFP_KERNEL); - if (!eni_dev) return -ENOMEM; + if (!eni_dev) goto out0; if (!cpu_zeroes) { cpu_zeroes = pci_alloc_consistent(pci_dev,ENI_ZEROES_SIZE, &zeroes); @@ -2265,7 +2273,6 @@ if (error) goto out3; eni_dev->more = eni_boards; eni_boards = dev; - MOD_INC_USE_COUNT; /* @@@ we don't support unloading yet */ return 0; out3: atm_dev_deregister(dev); @@ -2274,6 +2281,8 @@ cpu_zeroes = NULL; out1: kfree(eni_dev); +out0: + MOD_DEC_USE_COUNT; /* @@@ we don't support unloading yet */ return error; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/atm/fore200e.c linux/drivers/atm/fore200e.c --- v2.4.0-test1/linux/drivers/atm/fore200e.c Thu May 11 15:30:06 2000 +++ linux/drivers/atm/fore200e.c Tue Jun 20 13:58:42 2000 @@ -1409,6 +1409,8 @@ struct fore200e* fore200e = FORE200E_DEV(vcc->dev); struct fore200e_vcc* fore200e_vcc; + MOD_INC_USE_COUNT; + /* find a free VPI/VCI */ fore200e_walk_vccs(vcc, &vpi, &vci); @@ -1416,8 +1418,10 @@ vcc->vci = vci; /* ressource checking only? */ - if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) + if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) { + MOD_DEC_USE_COUNT; return 0; + } set_bit(ATM_VF_ADDR, &vcc->flags); vcc->itf = vcc->dev->number; @@ -1435,6 +1439,7 @@ down(&fore200e->rate_sf); if (fore200e->available_cell_rate < vcc->qos.txtp.max_pcr) { up(&fore200e->rate_sf); + MOD_DEC_USE_COUNT; return -EAGAIN; } /* reserving the pseudo-CBR bandwidth at this point grants us @@ -1451,6 +1456,7 @@ down(&fore200e->rate_sf); fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; up(&fore200e->rate_sf); + MOD_DEC_USE_COUNT; return -ENOMEM; } @@ -1461,13 +1467,10 @@ down(&fore200e->rate_sf); fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; up(&fore200e->rate_sf); + MOD_DEC_USE_COUNT; return -EBUSY; } -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif - /* compute rate control parameters */ if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { @@ -2598,6 +2601,10 @@ printk(FORE200E "FORE Systems 200E-series driver - version " FORE200E_VERSION "\n"); +#if 0 /* XXX uncomment this to forbid module unloading */ + MOD_INC_USE_COUNT; +#endif + /* for each configured bus interface */ for (link = 0, bus = fore200e_bus; bus->model_name; bus++) { @@ -2624,10 +2631,8 @@ } #if 0 /* XXX uncomment this to forbid module unloading */ -#ifdef MODULE - if (link > 0) - MOD_INC_USE_COUNT; -#endif + if (link <= 0) + MOD_DEC_USE_COUNT; #endif return link; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/atm/idt77105.c linux/drivers/atm/idt77105.c --- v2.4.0-test1/linux/drivers/atm/idt77105.c Mon Mar 27 08:08:23 2000 +++ linux/drivers/atm/idt77105.c Tue Jun 20 13:58:42 2000 @@ -334,9 +334,7 @@ int __init idt77105_init(struct atm_dev *dev) { -#ifdef MODULE MOD_INC_USE_COUNT; -#endif /* MODULE */ dev->phy = &idt77105_ops; return 0; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/atm/iphase.c linux/drivers/atm/iphase.c --- v2.4.0-test1/linux/drivers/atm/iphase.c Thu May 11 15:30:06 2000 +++ linux/drivers/atm/iphase.c Tue Jun 20 13:58:42 2000 @@ -2278,7 +2278,7 @@ #endif { IADEV *iadev; - unsigned int real_base, base; + unsigned long real_base, base; unsigned short command; unsigned char revision; int error, i; @@ -2292,12 +2292,10 @@ dev->ci_range.vci_bits = NR_VCI_LD; iadev = INPH_IA_DEV(dev); + real_base = pci_resource_start (iadev->pci, 0); + iadev->irq = iadev->pci->irq; if ((error = pci_read_config_word(iadev->pci, PCI_COMMAND,&command)) - || (error = pci_read_config_dword(iadev->pci, - PCI_BASE_ADDRESS_0,&real_base)) - || (error = pci_read_config_byte(iadev->pci, - PCI_INTERRUPT_LINE,&iadev->irq)) || (error = pci_read_config_byte(iadev->pci, PCI_REVISION_ID,&revision))) { @@ -2310,26 +2308,8 @@ /* find mapping size of board */ - /* write all 1's into the base address register. - read the register whic returns us 0's in the don't care bits. - size is calculated as ~(don't cre bits) + 1 */ - - if (pci_write_config_dword(iadev->pci, - PCI_BASE_ADDRESS_0, 0xffffffff)!=PCIBIOS_SUCCESSFUL) - { - printk(DEV_LABEL "(itf %d): init error 0x%x\n",dev->number, - error); - return -EINVAL; - } - if(pci_read_config_dword(iadev->pci, PCI_BASE_ADDRESS_0, - &(iadev->pci_map_size)) !=PCIBIOS_SUCCESSFUL) - { - printk(DEV_LABEL "(itf %d): init error 0x%x\n",dev->number, - error); - return -EINVAL; - } - iadev->pci_map_size &= PCI_BASE_ADDRESS_MEM_MASK; - iadev->pci_map_size = ~iadev->pci_map_size + 1; + iadev->pci_map_size = pci_resource_len(iadev->pci, 0); + if (iadev->pci_map_size == 0x100000){ iadev->num_vc = 4096; dev->ci_range.vci_bits = NR_VCI_4K_LD; @@ -2344,25 +2324,10 @@ return -EINVAL; } IF_INIT(printk (DEV_LABEL "map size: %i\n", iadev->pci_map_size);) - if(pci_write_config_dword(iadev->pci, PCI_BASE_ADDRESS_0, - real_base)!=PCIBIOS_SUCCESSFUL) - { - printk(DEV_LABEL "(itf %d): init error 0x%x\n",dev->number, - error); - return -EINVAL; - } - /* strip flags (last 4 bits ) ---> mask with 0xfffffff0 */ - real_base &= MEM_VALID; - /* enabling the responses in memory space */ - command |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); - if ((error = pci_write_config_word(iadev->pci, - PCI_COMMAND, command))) - { - printk(DEV_LABEL "(itf %d): can't enable memory (0x%x)\n", - dev->number,error); - return -EIO; - } + /* enable bus mastering */ + pci_set_master(iadev->pci); + /* * Delay at least 1us before doing any mem accesses (how 'bout 10?) */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/atm/nicstar.c linux/drivers/atm/nicstar.c --- v2.4.0-test1/linux/drivers/atm/nicstar.c Thu May 11 15:30:06 2000 +++ linux/drivers/atm/nicstar.c Tue Jun 20 13:58:42 2000 @@ -472,7 +472,7 @@ card->index = i; card->atmdev = NULL; card->pcidev = pcidev; - card->membase = pcidev->resource[1].start; + card->membase = pci_resource_start(pcidev, 1); #ifdef __powerpc__ /* Compensate for different memory map between host CPU and PCI bus. Shouldn't we use a macro for this? */ @@ -893,10 +893,9 @@ #ifdef CONFIG_ATM_NICSTAR_USE_SUNI if (card->max_pcr == ATM_OC3_PCR) { suni_init(card->atmdev); -#ifdef MODULE + MOD_INC_USE_COUNT; /* Can't remove the nicstar driver or the suni driver would oops */ -#endif /* MODULE */ } #endif /* CONFIG_ATM_NICSTAR_USE_SUNI */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/atm/zatm.c linux/drivers/atm/zatm.c --- v2.4.0-test1/linux/drivers/atm/zatm.c Thu May 11 15:30:06 2000 +++ linux/drivers/atm/zatm.c Tue Jun 20 13:58:42 2000 @@ -1385,7 +1385,7 @@ DPRINTK(">zatm_init\n"); zatm_dev = ZATM_DEV(dev); pci_dev = zatm_dev->pci_dev; - zatm_dev->base = pci_dev->resource[0].start; + zatm_dev->base = pci_resource_start(pci_dev, 0); zatm_dev->irq = pci_dev->irq; if ((error = pci_read_config_word(pci_dev,PCI_COMMAND,&command)) || (error = pci_read_config_byte(pci_dev,PCI_REVISION_ID,&revision))) { diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/Config.in linux/drivers/block/Config.in --- v2.4.0-test1/linux/drivers/block/Config.in Tue May 23 15:31:34 2000 +++ linux/drivers/block/Config.in Wed Jun 21 10:10:02 2000 @@ -36,8 +36,6 @@ dep_tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA $CONFIG_PCI dep_tristate 'Mylex DAC960/DAC1100 PCI RAID Controller support' CONFIG_BLK_DEV_DAC960 $CONFIG_PCI -comment 'Additional Block Devices' - tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET @@ -49,14 +47,16 @@ bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD dep_tristate ' Linear (append) mode' CONFIG_MD_LINEAR $CONFIG_BLK_DEV_MD dep_tristate ' RAID-0 (striping) mode' CONFIG_MD_RAID0 $CONFIG_BLK_DEV_MD -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' RAID-1/RAID-5 code (DANGEROUS)' CONFIG_RAID15_DANGEROUS - if [ "$CONFIG_RAID15_DANGEROUS" = "y" ]; then - dep_tristate ' RAID-1 (mirroring) mode' CONFIG_MD_RAID1 $CONFIG_BLK_DEV_MD - dep_tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 $CONFIG_BLK_DEV_MD - fi +dep_tristate ' RAID-1 (mirroring) mode' CONFIG_MD_RAID1 $CONFIG_BLK_DEV_MD +dep_tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 $CONFIG_BLK_DEV_MD +if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_RAID0" = "y" -o "$CONFIG_MD_RAID1" = "y" -o "$CONFIG_MD_RAID5" = "y" ]; then + bool ' Boot support' CONFIG_MD_BOOT + bool ' Auto Detect support' CONFIG_AUTODETECT_RAID fi tristate 'RAM disk support' CONFIG_BLK_DEV_RAM +if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then + int ' Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096 +fi dep_bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM endmenu diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/DAC960.c linux/drivers/block/DAC960.c --- v2.4.0-test1/linux/drivers/block/DAC960.c Tue May 23 15:31:34 2000 +++ linux/drivers/block/DAC960.c Thu Jun 22 07:15:10 2000 @@ -1473,9 +1473,8 @@ Command->SegmentCount = Request->nr_segments; Command->BufferHeader = Request->bh; RequestBuffer = Request->buffer; - Request->rq_status = RQ_INACTIVE; blkdev_dequeue_request(Request); - wake_up(&wait_for_request); + blkdev_release_request(Request); if (Command->SegmentCount == 1) { DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/Makefile linux/drivers/block/Makefile --- v2.4.0-test1/linux/drivers/block/Makefile Fri May 12 14:18:55 2000 +++ linux/drivers/block/Makefile Tue Jun 20 14:28:05 2000 @@ -1,15 +1,9 @@ # # Makefile for the kernel block device drivers. # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definition is now inherited from the -# parent makefile. -# - -# +# 12 June 2000, Christoph Hellwig +# Rewritten to use lists instead of if-statements. +# # Note : at this point, these files are compiled on all systems. # In the future, some of these should be built conditionally. # @@ -18,172 +12,45 @@ MOD_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) paride +O_TARGET := block.o +MOD_LIST_NAME := BLOCK_MODULES -L_TARGET := block.a -L_OBJS := genhd.o elevator.o -M_OBJS := -MOD_LIST_NAME := BLOCK_MODULES -LX_OBJS := ll_rw_blk.o blkpg.o -MX_OBJS := - -ifeq ($(CONFIG_MAC_FLOPPY),y) -L_OBJS += swim3.o -endif - -ifeq ($(CONFIG_BLK_DEV_FD),y) -L_OBJS += floppy.o -else - ifeq ($(CONFIG_BLK_DEV_FD),m) - M_OBJS += floppy.o - endif -endif - -ifeq ($(CONFIG_AMIGA_FLOPPY),y) - L_OBJS += amiflop.o -else - ifeq ($(CONFIG_AMIGA_FLOPPY),m) - M_OBJS += amiflop.o - endif -endif - -ifeq ($(CONFIG_ATARI_FLOPPY),y) - L_OBJS += ataflop.o -else - ifeq ($(CONFIG_ATARI_FLOPPY),m) - M_OBJS += ataflop.o - endif -endif - -ifeq ($(CONFIG_BLK_DEV_SWIM_IOP),y) - L_OBJS += swim_iop.o -endif - -ifeq ($(CONFIG_ATARI_ACSI),y) - LX_OBJS += acsi.o -else - ifeq ($(CONFIG_ATARI_ACSI),m) - MX_OBJS += acsi.o - endif -endif - -ifeq ($(CONFIG_ATARI_SLM),y) - L_OBJS += acsi_slm.o -else - ifeq ($(CONFIG_ATARI_SLM),m) - M_OBJS += acsi_slm.o - endif -endif - -ifeq ($(CONFIG_AMIGA_Z2RAM),y) -L_OBJS += z2ram.o -else - ifeq ($(CONFIG_AMIGA_Z2RAM),m) - M_OBJS += z2ram.o - endif -endif -ifeq ($(CONFIG_BLK_DEV_RAM),y) -L_OBJS += rd.o -else - ifeq ($(CONFIG_BLK_DEV_RAM),m) - M_OBJS += rd.o - endif -endif +export-objs := ll_rw_blk.o blkpg.o loop.o DAC960.o md.o xor.o +list-multi := lvm-mod.o +lvm-mod-objs := lvm.o lvm-snap.o + +obj-y := ll_rw_blk.o blkpg.o genhd.o elevator.o + +obj-$(CONFIG_MAC_FLOPPY) += swim3.o +obj-$(CONFIG_BLK_DEV_FD) += floppy.o +obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o +obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o +obj-$(CONFIG_BLK_DEV_SWIM_IOP) += swim_iop.o +obj-$(CONFIG_ATARI_ACSI) += acsi.o +obj-$(CONFIG_ATARI_SLM) += acsi_slm.o +obj-$(CONFIG_AMIGA_Z2RAM) += z2ram.o +obj-$(CONFIG_BLK_DEV_RAM) += rd.o +obj-$(CONFIG_BLK_DEV_LOOP) += loop.o +obj-$(CONFIG_BLK_DEV_PS2) += ps2esdi.o +obj-$(CONFIG_BLK_DEV_XD) += xd.o +obj-$(CONFIG_BLK_CPQ_DA) += cpqarray.o +obj-$(CONFIG_BLK_DEV_DAC960) += DAC960.o +obj-$(CONFIG_BLK_DEV_LVM) += lvm-mod.o + +obj-$(CONFIG_BLK_DEV_MD) += md.o +obj-$(CONFIG_MD_LINEAR) += linear.o +obj-$(CONFIG_MD_RAID0) += raid0.o +obj-$(CONFIG_MD_RAID1) += raid1.o -ifeq ($(CONFIG_BLK_DEV_LOOP),y) -LX_OBJS += loop.o +ifeq ($(CONFIG_MD_RAID5),m) + obj-y += xor.o else - ifeq ($(CONFIG_BLK_DEV_LOOP),m) - MX_OBJS += loop.o - endif + obj-$(CONFIG_MD_RAID5) += xor.o endif +obj-$(CONFIG_MD_RAID5) += raid5.o -ifeq ($(CONFIG_BLK_DEV_PS2),y) -L_OBJS += ps2esdi.o -else - ifeq ($(CONFIG_BLK_DEV_PS2),m) - M_OBJS += ps2esdi.o - endif -endif - -ifeq ($(CONFIG_BLK_DEV_XD),y) -L_OBJS += xd.o -else - ifeq ($(CONFIG_BLK_DEV_XD),m) - M_OBJS += xd.o - endif -endif - -ifeq ($(CONFIG_BLK_CPQ_DA),y) -L_OBJS += cpqarray.o -else - ifeq ($(CONFIG_BLK_CPQ_DA),m) - M_OBJS += cpqarray.o - endif -endif - -ifeq ($(CONFIG_BLK_DEV_DAC960),y) -LX_OBJS += DAC960.o -else - ifeq ($(CONFIG_BLK_DEV_DAC960),m) - MX_OBJS += DAC960.o - endif -endif - -ifeq ($(CONFIG_BLK_DEV_LVM),y) -L_OBJS += lvm.o lvm-snap.o -else - ifeq ($(CONFIG_BLK_DEV_LVM),m) - M_OBJS += lvm-mod.o - endif -endif - -ifeq ($(CONFIG_BLK_DEV_MD),y) -LX_OBJS += md.o - -ifeq ($(CONFIG_MD_LINEAR),y) -L_OBJS += linear.o -else - ifeq ($(CONFIG_MD_LINEAR),m) - M_OBJS += linear.o - endif -endif - -ifeq ($(CONFIG_MD_RAID0),y) -L_OBJS += raid0.o -else - ifeq ($(CONFIG_MD_RAID0),m) - M_OBJS += raid0.o - endif -endif - -ifeq ($(CONFIG_MD_RAID1),y) -L_OBJS += raid1.o -else - ifeq ($(CONFIG_MD_RAID1),m) - M_OBJS += raid1.o - endif -endif - -ifeq ($(CONFIG_MD_RAID5),y) -LX_OBJS += xor.o -L_OBJS += raid5.o -else - ifeq ($(CONFIG_MD_RAID5),m) - LX_OBJS += xor.o - M_OBJS += raid5.o - endif -endif - -endif - -ifeq ($(CONFIG_BLK_DEV_NBD),y) -L_OBJS += nbd.o -else - ifeq ($(CONFIG_BLK_DEV_NBD),m) - M_OBJS += nbd.o - endif -endif +obj-$(CONFIG_BLK_DEV_NBD) += nbd.o ifeq ($(CONFIG_PARIDE),y) SUB_DIRS += paride @@ -194,7 +61,24 @@ endif endif + +# Extract lists of the multi-part drivers. +# The 'int-*' lists are the intermediate files used to build the multi's. +multi-y := $(filter $(list-multi), $(obj-y)) +multi-m := $(filter $(list-multi), $(obj-m)) +int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs))) +int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs))) + +# Take multi-part drivers out of obj-y and put components in. +obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y) + +# Translate to Rules.make lists. +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) + include $(TOPDIR)/Rules.make -lvm-mod.o: lvm.o lvm-snap.o - $(LD) -r -o $@ lvm.o lvm-snap.o +lvm-mod.o: $(lvm-mod-objs) + $(LD) -r -o $@ $(lvm-mod-objs) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/acsi_slm.c linux/drivers/block/acsi_slm.c --- v2.4.0-test1/linux/drivers/block/acsi_slm.c Wed Feb 16 17:03:51 2000 +++ linux/drivers/block/acsi_slm.c Wed Jun 21 22:31:00 2000 @@ -272,6 +272,7 @@ static struct timer_list slm_timer = { NULL, NULL, 0, 0, slm_test_ready }; static struct file_operations slm_fops = { + owner: THIS_MODULE, read: slm_read, write: slm_write, ioctl: slm_ioctl, @@ -1008,7 +1009,7 @@ devfs_handle = devfs_mk_dir (NULL, "slm", 3, NULL); devfs_register_series (devfs_handle, "%u", MAX_SLM, DEVFS_FL_DEFAULT, - MAJOR_NR, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + MAJOR_NR, 0, S_IFCHR | S_IRUSR | S_IWUSR, &slm_fops, NULL); return 0; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/amiflop.c linux/drivers/block/amiflop.c --- v2.4.0-test1/linux/drivers/block/amiflop.c Thu May 11 15:30:06 2000 +++ linux/drivers/block/amiflop.c Tue Jun 20 07:24:52 2000 @@ -70,6 +70,7 @@ #include #include #include +#include #include #include @@ -127,11 +128,6 @@ #define DESELECT(mask) (ciab.prb |= mask) #define SELMASK(drive) (1 << (3 + (drive & 3))) -#define DRIVE(x) ((x) & 3) -#define PROBE(x) ((x) >> 2) & 1) -#define TYPE(x) ((x) >> 3) & 2) -#define DATA(x) ((x) >> 5) & 3) - static struct fd_drive_type drive_types[] = { /* code name tr he rdsz wrsz sm pc1 pc2 sd st st*/ /* warning: times are now in milliseconds (ms) */ @@ -1794,17 +1790,26 @@ printk("fd: Unable to get major %d for floppy\n",MAJOR_NR); return -EBUSY; } - + /* + * We request DSKPTR, DSKLEN and DSKDATA only, because the other + * floppy registers are too spreaded over the custom register space + */ + if (!request_mem_region(CUSTOM_PHYSADDR+0x20, 8, "amiflop [Paula]")) { + printk("fd: cannot get floppy registers\n"); + unregister_blkdev(MAJOR_NR,"fd"); + return -EBUSY; + } if ((raw_buf = (char *)amiga_chip_alloc (RAW_BUF_SIZE, "Floppy")) == NULL) { printk("fd: cannot get chip mem buffer\n"); + release_mem_region(CUSTOM_PHYSADDR+0x20, 8); unregister_blkdev(MAJOR_NR,"fd"); return -ENOMEM; } - if (request_irq(IRQ_AMIGA_DSKBLK, fd_block_done, 0, "floppy_dma", NULL)) { printk("fd: cannot get irq for dma\n"); amiga_chip_free(raw_buf); + release_mem_region(CUSTOM_PHYSADDR+0x20, 8); unregister_blkdev(MAJOR_NR,"fd"); return -EBUSY; } @@ -1812,6 +1817,7 @@ printk("fd: cannot get irq for timer\n"); free_irq(IRQ_AMIGA_DSKBLK, NULL); amiga_chip_free(raw_buf); + release_mem_region(CUSTOM_PHYSADDR+0x20, 8); unregister_blkdev(MAJOR_NR,"fd"); return -EBUSY; } @@ -1819,6 +1825,7 @@ free_irq(IRQ_AMIGA_CIAA_TB, NULL); free_irq(IRQ_AMIGA_DSKBLK, NULL); amiga_chip_free(raw_buf); + release_mem_region(CUSTOM_PHYSADDR+0x20, 8); unregister_blkdev(MAJOR_NR,"fd"); return -ENXIO; } @@ -1889,6 +1896,7 @@ blk_size[MAJOR_NR] = NULL; blksize_size[MAJOR_NR] = NULL; blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + release_mem_region(CUSTOM_PHYSADDR+0x20, 8); unregister_blkdev(MAJOR_NR, "fd"); } #endif diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c --- v2.4.0-test1/linux/drivers/block/cpqarray.c Thu May 11 15:30:06 2000 +++ linux/drivers/block/cpqarray.c Fri Jun 23 21:13:43 2000 @@ -22,7 +22,7 @@ * driver, you'll probably need the Compaq Array Controller Interface * Specificiation (Document number ECG086/1198) */ -#include +#include /* CONFIG_PROC_FS */ #include #include #include @@ -44,8 +44,8 @@ #define SMART2_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) -#define DRIVER_NAME "Compaq SMART2 Driver (v 1.0.4)" -#define DRIVER_VERSION SMART2_DRIVER_VERSION(1,0,4) +#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.0)" +#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,0) #define MAJOR_NR COMPAQ_SMART2_MAJOR #include #include @@ -73,7 +73,7 @@ * product = Marketing Name for the board * access = Address of the struct of function pointers */ -struct board_type products[] = { +static struct board_type products[] = { { 0x0040110E, "IDA", &smart1_access }, { 0x0140110E, "IDA-2", &smart1_access }, { 0x1040110E, "IAES", &smart1_access }, @@ -87,6 +87,7 @@ { 0x40400E11, "Integrated Array", &smart4_access }, { 0x40500E11, "Smart Array 4200", &smart4_access }, { 0x40510E11, "Smart Array 4250ES", &smart4_access }, + { 0x40580E11, "Smart Array 431", &smart4_access }, }; static struct hd_struct * ida; @@ -95,7 +96,7 @@ static int * ida_hardsizes; static struct gendisk ida_gendisk[MAX_CTLR]; -struct proc_dir_entry *proc_array = NULL; +static struct proc_dir_entry *proc_array = NULL; /* Debug... */ #define DBG(s) do { s } while(0) @@ -106,7 +107,7 @@ /* Debug Extra Paranoid... */ #define DBGPX(s) do { } while(0) -void cpqarray_init(void); +int cpqarray_init(void); static int cpqarray_pci_detect(void); static int cpqarray_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn); static ulong remap_pci_mem(ulong base, ulong size); @@ -312,9 +313,8 @@ /* This is a bit of a hack... */ int __init init_module(void) { - cpqarray_init(); - if (nr_ctlr == 0) - return -EIO; + if (cpqarray_init() == 0) /* all the block dev numbers already used */ + return -EIO; /* or no controllers were found */ return 0; } @@ -357,8 +357,9 @@ /* * This is it. Find all the controllers and register them. I really hate * stealing all these major device numbers. + * returns the number of block devices registered. */ -void __init cpqarray_init(void) +int __init cpqarray_init(void) { void (*request_fns[MAX_CTLR])(request_queue_t *) = { do_ida_request0, do_ida_request1, @@ -367,31 +368,52 @@ do_ida_request6, do_ida_request7, }; int i,j; + int num_cntlrs_reg = 0; /* detect controllers */ cpqarray_pci_detect(); cpqarray_eisa_detect(); if (nr_ctlr == 0) - return; + return(num_cntlrs_reg); printk(DRIVER_NAME "\n"); printk("Found %d controller(s)\n", nr_ctlr); /* allocate space for disk structs */ ida = kmalloc(sizeof(struct hd_struct)*nr_ctlr*NWD*16, GFP_KERNEL); - if(ida==NULL) - goto bail; - ida_sizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL); + { + printk( KERN_ERR "cpqarray: out of memory"); + return(num_cntlrs_reg); + } + + ida_sizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL); if(ida_sizes==NULL) - goto bail2; + { + kfree(ida); + printk( KERN_ERR "cpqarray: out of memory"); + return(num_cntlrs_reg); + } + ida_blocksizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL); if(ida_blocksizes==NULL) - goto bail3; - ida_hardsizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL); + { + kfree(ida); + kfree(ida_sizes); + printk( KERN_ERR "cpqarray: out of memory"); + return(num_cntlrs_reg); + } + + ida_hardsizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL); if(ida_hardsizes==NULL) - goto bail4; + { + kfree(ida); + kfree(ida_sizes); + kfree(ida_blocksizes); + printk( KERN_ERR "cpqarray: out of memory"); + return(num_cntlrs_reg); + } memset(ida, 0, sizeof(struct hd_struct)*nr_ctlr*NWD*16); memset(ida_sizes, 0, sizeof(int)*nr_ctlr*NWD*16); @@ -399,74 +421,90 @@ memset(ida_hardsizes, 0, sizeof(int)*nr_ctlr*NWD*16); memset(ida_gendisk, 0, sizeof(struct gendisk)*MAX_CTLR); - /* + /* * register block devices * Find disks and fill in structs * Get an interrupt, set the Q depth and get into /proc */ for(i=0; i< nr_ctlr; i++) { + /* If this successful it should insure that we are the only */ + /* instance of the driver */ + if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &ida_fops)) { + printk(KERN_ERR "cpqarray: Unable to get major number %d for ida\n", + MAJOR_NR+i); + continue; + } + + hba[i]->access.set_intr_mask(hba[i], 0); if (request_irq(hba[i]->intr, do_ida_intr, SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i])) { - printk("Unable to get irq %d for %s\n", + printk(KERN_ERR "cpqarray: Unable to get irq %d for %s\n", hba[i]->intr, hba[i]->devname); + unregister_blkdev(MAJOR_NR+i, hba[i]->devname); continue; } - if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &ida_fops)) { - printk("Unable to get major number %d for ida\n", - MAJOR_NR+i); - continue; - } - + num_cntlrs_reg++; hba[i]->cmd_pool = (cmdlist_t *)kmalloc( NR_CMDS * sizeof(cmdlist_t), GFP_KERNEL); hba[i]->cmd_pool_bits = (__u32*)kmalloc( ((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL); - if(hba[i]->cmd_pool_bits == NULL || hba[i]->cmd_pool == NULL) + if(hba[i]->cmd_pool_bits == NULL || hba[i]->cmd_pool == NULL) { - int j; + nr_ctlr = i; if(hba[i]->cmd_pool_bits) kfree(hba[i]->cmd_pool_bits); if(hba[i]->cmd_pool) kfree(hba[i]->cmd_pool); - for(j=0;iintr, hba[j]); - unregister_blkdev(MAJOR_NR+j, hba[j]->devname); - kfree(hba[j]->cmd_pool_bits); - kfree(hba[j]->cmd_pool); - } free_irq(hba[i]->intr, hba[i]); unregister_blkdev(MAJOR_NR+i, hba[i]->devname); - goto bail5; + num_cntlrs_reg--; + printk( KERN_ERR "cpqarray: out of memory"); + + /* If num_cntlrs_reg == 0, no controllers worked. + * init_module will fail, so clean up global + * memory that clean_module would do. + */ + + if (num_cntlrs_reg == 0) + { + kfree(ida); + kfree(ida_sizes); + kfree(ida_hardsizes); + kfree(ida_blocksizes); + } + return(num_cntlrs_reg); + } memset(hba[i]->cmd_pool, 0, NR_CMDS * sizeof(cmdlist_t)); memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+31)/32)*sizeof(__u32)); - printk("Finding drives on %s", hba[i]->devname); + printk(KERN_INFO "cpqarray: Finding drives on %s", + hba[i]->devname); getgeometry(i); start_fwbk(i); hba[i]->access.set_intr_mask(hba[i], FIFO_NOT_EMPTY); + ida_procinit(i); - - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR + i), request_fns[i]); - blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR + i), 0); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR + i), + request_fns[i]); + blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR + i), 0); blksize_size[MAJOR_NR+i] = ida_blocksizes + (i*256); hardsect_size[MAJOR_NR+i] = ida_hardsizes + (i*256); - read_ahead[MAJOR_NR+i] = READ_AHEAD; + ida_gendisk[i].major = MAJOR_NR + i; ida_gendisk[i].major_name = "ida"; ida_gendisk[i].minor_shift = NWD_SHIFT; ida_gendisk[i].max_p = 16; ida_gendisk[i].part = ida + (i*256); ida_gendisk[i].sizes = ida_sizes + (i*256); - /* ida_gendisk[i].nr_real is handled by getgeometry */ - + ida_gendisk[i].nr_real = 0; + /* Get on the disk list */ ida_gendisk[i].next = gendisk_head; gendisk_head = &ida_gendisk[i]; @@ -479,21 +517,13 @@ ida_geninit(i); for(j=0; jdrv[j].nr_blks); + register_disk(&ida_gendisk[i], + MKDEV(MAJOR_NR+i,j<<4), + 16, &ida_fops, hba[i]->drv[j].nr_blks); + } /* done ! */ - return; -bail5: - kfree(ida_hardsizes); -bail4: - kfree(ida_blocksizes); -bail3: - kfree(ida_sizes); -bail2: - kfree(ida); -bail: - printk(KERN_ERR "cpqarray: out of memory.\n"); + return(num_cntlrs_reg); } /* @@ -506,103 +536,68 @@ { int index; unchar bus=0, dev_fn=0; - - /* This seems dumb, surely we could use an array of types to match ?? */ - for(index=0; ; index++) { - if (pcibios_find_device(PCI_VENDOR_ID_DEC, - PCI_DEVICE_ID_COMPAQ_42XX, index, &bus, &dev_fn)) - break; - printk(KERN_DEBUG "42XX Device has been found at %x %x\n", - bus, dev_fn); - if (index == 1000000) break; - if (nr_ctlr == 8) { - printk("This driver supports a maximum of " - "8 controllers.\n"); - break; - } - - hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL); - if(hba[nr_ctlr]==NULL) - { - printk(KERN_ERR "cpqarray: out of memory.\n"); - continue; - } - memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t)); - if (cpqarray_pci_init(hba[nr_ctlr], bus, dev_fn) != 0) - continue; - sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr); - hba[nr_ctlr]->ctlr = nr_ctlr; - nr_ctlr++; - } - - for(index=0; ; index++) { - unsigned short subvendor=0; +#define IDA_BOARD_TYPES 3 + static int ida_vendor_id[IDA_BOARD_TYPES] = { PCI_VENDOR_ID_DEC, + PCI_VENDOR_ID_NCR, PCI_VENDOR_ID_COMPAQ }; + static int ida_device_id[IDA_BOARD_TYPES] = { PCI_DEVICE_ID_COMPAQ_42XX, PCI_DEVICE_ID_NCR_53C1510, PCI_DEVICE_ID_COMPAQ_SMART2P }; + int brdtype; + + /* search for all PCI board types that could be for this driver */ + for(brdtype=0; brdtypedevname, "ida%d", nr_ctlr); - hba[nr_ctlr]->ctlr = nr_ctlr; - nr_ctlr++; - } + if (ida_device_id[brdtype] == PCI_DEVICE_ID_NCR_53C1510) { + unsigned short subvendor=0; + if(pcibios_read_config_word(bus, dev_fn, + PCI_SUBSYSTEM_VENDOR_ID, &subvendor)) + { + printk(KERN_DEBUG "cpqarray: failed to read subvendor\n"); + continue; + } + if(subvendor != PCI_VENDOR_ID_COMPAQ) + { + printk(KERN_DEBUG + "cpqarray: not a Compaq integrated array controller\n"); + continue; + } + } - for(index=0; ; index++) { - if (pcibios_find_device(PCI_VENDOR_ID_COMPAQ, - PCI_DEVICE_ID_COMPAQ_SMART2P, index, &bus, &dev_fn)) - break; + hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL); if(hba[nr_ctlr]==NULL) + { + printk(KERN_ERR "cpqarray: out of memory.\n"); + continue; + } + memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t)); + if (cpqarray_pci_init(hba[nr_ctlr], bus, dev_fn) != 0) + { + kfree(hba[nr_ctlr]); + continue; + } + sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr); + hba[nr_ctlr]->ctlr = nr_ctlr; + nr_ctlr++; - if (index == 1000000) break; - if (nr_ctlr == 8) { - printk("This driver supports a maximum of " - "8 controllers.\n"); - break; } - - hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL); - if(hba[nr_ctlr]==NULL) - { - printk(KERN_ERR "cpqarray: out of memory.\n"); - continue; - } - memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t)); - if (cpqarray_pci_init(hba[nr_ctlr], bus, dev_fn) != 0) - continue; - sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr); - hba[nr_ctlr]->ctlr = nr_ctlr; - nr_ctlr++; } return nr_ctlr; } + /* * Find the IO address of the controller, its IRQ and so forth. Fill * in some basic stuff into the ctlr_info_t structure. @@ -671,8 +666,9 @@ } } if (i == NR_PRODUCTS) { - printk("Sorry, I don't know how to access the SMART Array" - " controller %08lx\n", (unsigned long)board_id); + printk(KERN_WARNING "cpqarray: Sorry, I don't know how" + " to access the SMART Array controller %08lx\n", + (unsigned long)board_id); return -1; } @@ -734,8 +730,8 @@ while(i<8 && eisa[i]) { if (nr_ctlr == 8) { - printk("This driver supports a maximum of " - "8 controllers.\n"); + printk(KERN_WARNING "cpqarray: This driver supports" + " a maximum of 8 controllers.\n"); break; } board_id = inl(eisa[i]+0xC80); @@ -744,11 +740,11 @@ break; if (j == NR_PRODUCTS) { - printk("Sorry, I don't know how to access the SMART" - " Array controller %08lx\n", (unsigned long)board_id); + printk(KERN_WARNING "cpqarray: Sorry, I don't know how" + " to access the SMART Array controller %08lx\n", (unsigned long)board_id); continue; } - hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL); + hba[nr_ctlr] = (ctlr_info_t *) kmalloc(sizeof(ctlr_info_t), GFP_KERNEL); if(hba[nr_ctlr]==NULL) { printk(KERN_ERR "cpqarray: out of memory.\n"); @@ -885,21 +881,34 @@ queue_head = &blk_dev[MAJOR_NR+ctlr].request_queue.queue_head; if (list_empty(queue_head)) - goto doreq_done; + { + start_io(h); + return; + } + creq = blkdev_entry_next_request(queue_head); if (creq->rq_status == RQ_INACTIVE) - goto doreq_done; + { + start_io(h); + return; + } + if (ctlr != MAJOR(creq->rq_dev)-MAJOR_NR || - ctlr > nr_ctlr || h == NULL) { + ctlr > nr_ctlr || h == NULL) + { printk("doreq cmd for %d, %x at %p\n", ctlr, creq->rq_dev, creq); complete_buffers(creq->bh, 0); - goto doreq_done; + start_io(h); + return; } if ((c = cmd_alloc(h)) == NULL) - goto doreq_done; + { + start_io(h); + return; + } bh = creq->bh; @@ -972,9 +981,9 @@ /* Put the request on the tail of the request queue */ addQ(&h->reqQ, c); h->Qdepth++; - if (h->Qdepth > h->maxQsinceinit) h->maxQsinceinit = h->Qdepth; + if (h->Qdepth > h->maxQsinceinit) + h->maxQsinceinit = h->Qdepth; -doreq_done: start_io(h); } @@ -1022,28 +1031,24 @@ */ static inline void complete_command(cmdlist_t *cmd, int timeout) { - char buf[80]; int ok=1; if (cmd->req.hdr.rcode & RCODE_NONFATAL && (hba[cmd->ctlr]->misc_tflags & MISC_NONFATAL_WARN) == 0) { - sprintf(buf, "Non Fatal error on ida/c%dd%d\n", + printk(KERN_WARNING "Non Fatal error on ida/c%dd%d\n", cmd->ctlr, cmd->hdr.unit); - console_print(buf); hba[cmd->ctlr]->misc_tflags |= MISC_NONFATAL_WARN; } if (cmd->req.hdr.rcode & RCODE_FATAL) { - sprintf(buf, "Fatal error on ida/c%dd%d\n", + printk(KERN_WARNING "Fatal error on ida/c%dd%d\n", cmd->ctlr, cmd->hdr.unit); - console_print(buf); ok = 0; } if (cmd->req.hdr.rcode & RCODE_INVREQ) { - sprintf(buf, "Invalid request on ida/c%dd%d = (cmd=%x sect=%d cnt=%d sg=%d ret=%x)\n", + printk(KERN_WARNING "Invalid request on ida/c%dd%d = (cmd=%x sect=%d cnt=%d sg=%d ret=%x)\n", cmd->ctlr, cmd->hdr.unit, cmd->req.hdr.cmd, cmd->req.hdr.blk, cmd->req.hdr.blk_cnt, cmd->req.hdr.sg_cnt, cmd->req.hdr.rcode); - console_print(buf); ok = 0; } if (timeout) ok = 0; @@ -1077,10 +1082,15 @@ if (istat & FIFO_NOT_EMPTY) { while((a = h->access.command_completed(h))) { a1 = a; a &= ~3; - if ((c = h->cmpQ) == NULL) goto bad_completion; + if ((c = h->cmpQ) == NULL) + { + printk(KERN_WARNING "cpqarray: Completion of %08lx ignored\n", (unsigned long)a1); + continue; + } while(c->busaddr != a) { c = c->next; - if (c == h->cmpQ) break; + if (c == h->cmpQ) + break; } /* * If we've found the command, take it off the @@ -1096,8 +1106,6 @@ } continue; } -bad_completion: - printk("Completion of %08lx ignored\n", (unsigned long)a1); } } @@ -1227,16 +1235,27 @@ switch(io->cmd) { case PASSTHRU_A: p = kmalloc(io->sg[0].size, GFP_KERNEL); - if (!p) { error = -ENOMEM; goto ioctl_err_exit; } + if (!p) + { + error = -ENOMEM; + cmd_free(NULL, c); + return(error); + } copy_from_user(p, (void*)io->sg[0].addr, io->sg[0].size); - c->req.bp = virt_to_bus(&(io->c)); + c->req.hdr.blk = virt_to_bus(&(io->c)); c->req.sg[0].size = io->sg[0].size; c->req.sg[0].addr = virt_to_bus(p); c->req.hdr.sg_cnt = 1; break; case IDA_READ: p = kmalloc(io->sg[0].size, GFP_KERNEL); - if (!p) { error = -ENOMEM; goto ioctl_err_exit; } + if (!p) + { + error = -ENOMEM; + cmd_free(NULL, c); + return(error); + } + c->req.sg[0].size = io->sg[0].size; c->req.sg[0].addr = virt_to_bus(p); c->req.hdr.sg_cnt = 1; @@ -1245,7 +1264,12 @@ case IDA_WRITE_MEDIA: case DIAG_PASS_THRU: p = kmalloc(io->sg[0].size, GFP_KERNEL); - if (!p) { error = -ENOMEM; goto ioctl_err_exit; } + if (!p) + { + error = -ENOMEM; + cmd_free(NULL, c); + return(error); + } copy_from_user(p, (void*)io->sg[0].addr, io->sg[0].size); c->req.sg[0].size = io->sg[0].size; c->req.sg[0].addr = virt_to_bus(p); @@ -1284,10 +1308,8 @@ } io->rcode = c->req.hdr.rcode; - error = 0; -ioctl_err_exit: cmd_free(NULL, c); - return error; + return(0); } /* @@ -1390,8 +1412,8 @@ } udelay(10); DBG( - printk("ida%d: idaSendPciCmd FIFO full, waiting!\n", - ctlr); + printk(KERN_WARNING "cpqarray ida%d: idaSendPciCmd FIFO full," + " waiting!\n", ctlr); ); } /* @@ -1401,16 +1423,16 @@ complete = pollcomplete(ctlr); if (complete != 1) { if (complete != c->busaddr) { - printk( - "ida%d: idaSendPciCmd " + printk( KERN_WARNING + "cpqarray ida%d: idaSendPciCmd " "Invalid command list address returned! (%08lx)\n", ctlr, (unsigned long)complete); cmd_free(info_p, c); return (IO_ERROR); } } else { - printk( - "ida%d: idaSendPciCmd Timeout out, " + printk( KERN_WARNING + "cpqarray ida%d: idaSendPciCmd Timeout out, " "No command list address returned!\n", ctlr); cmd_free(info_p, c); @@ -1419,9 +1441,9 @@ if (c->req.hdr.rcode & 0x00FE) { if (!(c->req.hdr.rcode & BIG_PROBLEM)) { - printk( - "ida%d: idaSendPciCmd, error: Controller failed " - "at init time " + printk( KERN_WARNING + "cpqarray ida%d: idaSendPciCmd, error: " + "Controller failed at init time " "cmd: 0x%x, return code = 0x%x\n", ctlr, c->req.hdr.cmd, c->req.hdr.rcode); @@ -1461,8 +1483,8 @@ spin_lock_irqsave(&io_request_lock, flags); if (hba[ctlr]->usage_count > 1) { spin_unlock_irqrestore(&io_request_lock, flags); - printk("Device busy for volume revalidation (usage=%d)\n", - hba[ctlr]->usage_count); + printk(KERN_WARNING "cpqarray: Device busy for volume" + " revalidation (usage=%d)\n", hba[ctlr]->usage_count); return -EBUSY; } spin_unlock_irqrestore(&io_request_lock, flags); @@ -1514,8 +1536,9 @@ spin_lock_irqsave(&io_request_lock, flags); if (hba[ctlr]->drv[target].usage_count > maxusage) { spin_unlock_irqrestore(&io_request_lock, flags); - printk("Device busy for revalidation (usage=%d)\n", - hba[ctlr]->drv[target].usage_count); + printk(KERN_WARNING "cpqarray: Device busy for " + "revalidation (usage=%d)\n", + hba[ctlr]->drv[target].usage_count); return -EBUSY; } @@ -1581,22 +1604,28 @@ id_ctlr_t *id_ctlr_buf; int ret_code; - if( hba[ctlr]->board_id != 0x40400E11) + if( (hba[ctlr]->board_id != 0x40400E11) + && (hba[ctlr]->board_id != 0x40480E11) ) + /* Not a Integrated Raid, so there is nothing for us to do */ return; - printk(KERN_DEBUG "Starting firmware's background processing\n"); + printk(KERN_DEBUG "cpqarray: Starting firmware's background" + " processing\n"); /* Command does not return anything, but idasend command needs a buffer */ id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL); if(id_ctlr_buf==NULL) { - printk(KERN_WARNING "Out of memory. Unable to start background processing.\n"); + printk(KERN_WARNING "cpqarray: Out of memory. " + "Unable to start background processing.\n"); return; } ret_code = sendcmd(RESUME_BACKGROUND_ACTIVITY, ctlr, id_ctlr_buf, 0, 0, 0, 0); if(ret_code != IO_OK) - printk(KERN_WARNING "Unable to start background processing\n"); + printk(KERN_WARNING "cpqarray: Unable to start" + " background processing\n"); + kfree(id_ctlr_buf); } /***************************************************************** @@ -1620,16 +1649,38 @@ id_ldrive = (id_log_drv_t *)kmalloc(sizeof(id_log_drv_t), GFP_KERNEL); if(id_ldrive == NULL) + { + printk( KERN_ERR "cpqarray: out of memory.\n"); return; + } + id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL); if(id_ctlr_buf == NULL) - goto bail2; + { + kfree(id_ldrive); + printk( KERN_ERR "cpqarray: out of memory.\n"); + return; + } + id_lstatus_buf = (sense_log_drv_stat_t *)kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL); if(id_lstatus_buf == NULL) - goto bail3; + { + kfree(id_ctlr_buf); + kfree(id_ldrive); + printk( KERN_ERR "cpqarray: out of memory.\n"); + return; + } + sense_config_buf = (config_t *)kmalloc(sizeof(config_t), GFP_KERNEL); if(sense_config_buf == NULL) - goto bail4; + { + kfree(id_lstatus_buf); + kfree(id_ctlr_buf); + kfree(id_ldrive); + printk( KERN_ERR "cpqarray: out of memory.\n"); + return; + } + memset(id_ldrive, 0, sizeof(id_log_drv_t)); memset(id_ctlr_buf, 0, sizeof(id_ctlr_t)); memset(id_lstatus_buf, 0, sizeof(sense_log_drv_stat_t)); @@ -1648,8 +1699,15 @@ * so the idastubopen will fail on all logical drives * on the controller. */ - goto geo_ret; /* release the buf and return */ - } + /* Free all the buffers and return */ + printk(KERN_ERR "cpqarray: error sending ID controller\n"); + kfree(sense_config_buf); + kfree(id_lstatus_buf); + kfree(id_ctlr_buf); + kfree(id_ldrive); + return; + } + info_p->log_drives = id_ctlr_buf->nr_drvs;; *(__u32*)(info_p->firm_rev) = *(__u32*)(id_ctlr_buf->firm_rev); info_p->ctlr_sig = id_ctlr_buf->cfg_sig; @@ -1663,8 +1721,9 @@ * Get drive geometry for all logical drives */ if (id_ctlr_buf->nr_drvs > 16) - printk("ida%d: This driver supports 16 logical drives " - "per controller.\n. Additional drives will not be " + printk(KERN_WARNING "cpqarray ida%d: This driver supports " + "16 logical drives per controller.\n. " + " Additional drives will not be " "detected\n", ctlr); for (log_unit = 0; @@ -1687,13 +1746,17 @@ on the controller. */ info_p->log_drv_map = 0; - printk( - "ida%d: idaGetGeometry - Controller failed " - "to report status of logical drive %d\n" + printk( KERN_WARNING + "cpqarray ida%d: idaGetGeometry - Controller" + " failed to report status of logical drive %d\n" "Access to this controller has been disabled\n", ctlr, log_unit); - goto geo_ret; /* release the buf and return */ - + /* Free all the buffers and return */ + kfree(sense_config_buf); + kfree(id_lstatus_buf); + kfree(id_ctlr_buf); + kfree(id_ldrive); + return; } /* Make sure the logical drive is configured @@ -1715,14 +1778,21 @@ drv->sectors = id_ldrive->drv.sect_per_track; info_p->log_drv_map |= (1 << log_unit); - printk("ida/c%dd%d: blksz=%d nr_blks=%d\n", + printk(KERN_INFO "cpqarray ida/c%dd%d: blksz=%d nr_blks=%d\n", ctlr, log_unit, drv->blk_size, drv->nr_blks); ret_code = sendcmd(SENSE_CONFIG, ctlr, sense_config_buf, sizeof(config_t), 0, 0, log_unit); if (ret_code == IO_ERROR) { info_p->log_drv_map = 0; - goto geo_ret; /* release the buf and return */ + /* Free all the buffers and return */ + printk(KERN_ERR "cpqarray: error sending sense config\n"); + kfree(sense_config_buf); + kfree(id_lstatus_buf); + kfree(id_ctlr_buf); + kfree(id_ldrive); + return; + } info_p->phys_drives = sense_config_buf->ctlr_phys_drv; @@ -1736,12 +1806,10 @@ log_index = log_index + 1; } /* end of if logical drive configured */ } /* end of for log_unit */ -geo_ret: kfree(sense_config_buf); -bail4: - kfree(id_ldrive); -bail3: - kfree(id_lstatus_buf); -bail2: + kfree(id_ldrive); + kfree(id_lstatus_buf); kfree(id_ctlr_buf); + return; + } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/elevator.c linux/drivers/block/elevator.c --- v2.4.0-test1/linux/drivers/block/elevator.c Tue May 23 15:31:34 2000 +++ linux/drivers/block/elevator.c Fri Jun 23 19:47:06 2000 @@ -4,6 +4,16 @@ * Block device elevator/IO-scheduler. * * Copyright (C) 2000 Andrea Arcangeli SuSE + * + * 30042000 Jens Axboe : + * + * Split the elevator a bit so that it is possible to choose a different + * one or even write a new "plug in". There are three pieces: + * - elevator_fn, inserts a new request in the queue list + * - elevator_merge_fn, decides whether a new buffer can be merged with + * an existing request + * - elevator_dequeue_fn, called when a request is taken off the active list + * */ #include @@ -12,9 +22,9 @@ #include #include -static void elevator_default(struct request * req, elevator_t * elevator, - struct list_head * real_head, - struct list_head * head, int orig_latency) +void elevator_default(struct request *req, elevator_t * elevator, + struct list_head * real_head, + struct list_head * head, int orig_latency) { struct list_head * entry = real_head, * point = NULL; struct request * tmp; @@ -22,6 +32,12 @@ int latency = orig_latency -= elevator->nr_segments, pass = 0; int point_latency = 0xbeefbeef; + if (list_empty(real_head)) { + req->elevator_sequence = elevator_sequence(elevator, orig_latency); + list_add(&req->queue, real_head); + return; + } + while ((entry = entry->prev) != head) { if (!point && latency >= 0) { point = entry; @@ -49,19 +65,189 @@ req->elevator_sequence = elevator_sequence(elevator, latency); } +int elevator_default_merge(request_queue_t *q, struct request **req, + struct buffer_head *bh, int rw, + int *max_sectors, int *max_segments) +{ + struct list_head *entry, *head = &q->queue_head; + unsigned int count = bh->b_size >> 9; + elevator_t *elevator = &q->elevator; + int orig_latency, latency, sequence, action, starving = 0; + + /* + * Avoid write-bombs as not to hurt interactiveness of reads + */ + if (rw == WRITE) + *max_segments = elevator->max_bomb_segments; + + latency = orig_latency = elevator_request_latency(elevator, rw); + sequence = elevator->sequence; + + entry = head; + if (q->head_active && !q->plugged) + head = head->next; + + while ((entry = entry->prev) != head && !starving) { + *req = blkdev_entry_to_request(entry); + latency += (*req)->nr_segments; + if (elevator_sequence_before((*req)->elevator_sequence, sequence)) + starving = 1; + if (latency < 0) + continue; + if ((*req)->sem) + continue; + if ((*req)->cmd != rw) + continue; + if ((*req)->nr_sectors + count > *max_sectors) + continue; + if ((*req)->rq_dev != bh->b_rdev) + continue; + if ((*req)->sector + (*req)->nr_sectors == bh->b_rsector) { + if (latency - (*req)->nr_segments < 0) + break; + action = ELEVATOR_BACK_MERGE; + } else if ((*req)->sector - count == bh->b_rsector) { + if (starving) + break; + action = ELEVATOR_FRONT_MERGE; + } else { + continue; + } + q->elevator.sequence++; + return action; + } + return ELEVATOR_NO_MERGE; +} + +inline void elevator_default_dequeue(struct request *req) +{ + if (req->cmd == READ) + req->e->read_pendings--; + + req->e->nr_segments -= req->nr_segments; +} + +/* + * Order ascending, but only allow a request to be skipped a certain + * number of times + */ +void elevator_linus(struct request *req, elevator_t *elevator, + struct list_head *real_head, + struct list_head *head, int orig_latency) +{ + struct list_head *entry = real_head; + struct request *tmp; + + if (list_empty(real_head)) { + list_add(&req->queue, real_head); + return; + } + + while ((entry = entry->prev) != head) { + tmp = blkdev_entry_to_request(entry); + if (!tmp->elevator_sequence) + break; + if (IN_ORDER(tmp, req)) + break; + tmp->elevator_sequence--; + } + list_add(&req->queue, entry); +} + +int elevator_linus_merge(request_queue_t *q, struct request **req, + struct buffer_head *bh, int rw, + int *max_sectors, int *max_segments) +{ + struct list_head *entry, *head = &q->queue_head; + unsigned int count = bh->b_size >> 9; + + entry = head; + if (q->head_active && !q->plugged) + head = head->next; + + while ((entry = entry->prev) != head) { + *req = blkdev_entry_to_request(entry); + if (!(*req)->elevator_sequence) + break; + if ((*req)->sem) + continue; + if ((*req)->cmd != rw) + continue; + if ((*req)->nr_sectors + count > *max_sectors) + continue; + if ((*req)->rq_dev != bh->b_rdev) + continue; + if ((*req)->sector + (*req)->nr_sectors == bh->b_rsector) + return ELEVATOR_BACK_MERGE; + if ((*req)->sector - count == bh->b_rsector) + return ELEVATOR_FRONT_MERGE; + (*req)->elevator_sequence--; + } + return ELEVATOR_NO_MERGE; +} + +/* + * No request sorting, just add it to the back of the list + */ +void elevator_noop(struct request *req, elevator_t *elevator, + struct list_head *real_head, struct list_head *head, + int orig_latency) +{ + list_add_tail(&req->queue, real_head); +} + +/* + * See if we can find a request that is buffer can be coalesced with. + */ +int elevator_noop_merge(request_queue_t *q, struct request **req, + struct buffer_head *bh, int rw, + int *max_sectors, int *max_segments) +{ + struct list_head *entry, *head = &q->queue_head; + unsigned int count = bh->b_size >> 9; + + if (q->head_active && !q->plugged) + head = head->next; + + entry = head; + while ((entry = entry->prev) != head) { + *req = blkdev_entry_to_request(entry); + if ((*req)->sem) + continue; + if ((*req)->cmd != rw) + continue; + if ((*req)->nr_sectors + count > *max_sectors) + continue; + if ((*req)->rq_dev != bh->b_rdev) + continue; + if ((*req)->sector + (*req)->nr_sectors == bh->b_rsector) + return ELEVATOR_BACK_MERGE; + if ((*req)->sector - count == bh->b_rsector) + return ELEVATOR_FRONT_MERGE; + } + return ELEVATOR_NO_MERGE; +} + +/* + * The noop "elevator" does not do any accounting + */ +void elevator_noop_dequeue(struct request *req) {} + #ifdef ELEVATOR_DEBUG -void elevator_debug(request_queue_t * q, kdev_t dev) +void elevator_default_debug(request_queue_t * q, kdev_t dev) { int read_pendings = 0, nr_segments = 0; elevator_t * elevator = &q->elevator; struct list_head * entry = &q->queue_head; static int counter; + if (elevator->elevator_fn != elevator_default) + return; + if (counter++ % 100) return; - while ((entry = entry->prev) != &q->queue_head) - { + while ((entry = entry->prev) != &q->queue_head) { struct request * req; req = blkdev_entry_to_request(entry); @@ -81,16 +267,14 @@ nr_segments += req->nr_segments; } - if (read_pendings != elevator->read_pendings) - { + if (read_pendings != elevator->read_pendings) { printk(KERN_WARNING "%s: elevator read_pendings %d should be %d\n", kdevname(dev), elevator->read_pendings, read_pendings); elevator->read_pendings = read_pendings; } - if (nr_segments != elevator->nr_segments) - { + if (nr_segments != elevator->nr_segments) { printk(KERN_WARNING "%s: elevator nr_segments %d should be %d\n", kdevname(dev), elevator->nr_segments, @@ -102,7 +286,6 @@ int blkelvget_ioctl(elevator_t * elevator, blkelv_ioctl_arg_t * arg) { - int ret; blkelv_ioctl_arg_t output; output.queue_ID = elevator->queue_ID; @@ -110,44 +293,37 @@ output.write_latency = elevator->write_latency; output.max_bomb_segments = elevator->max_bomb_segments; - ret = -EFAULT; if (copy_to_user(arg, &output, sizeof(blkelv_ioctl_arg_t))) - goto out; - ret = 0; - out: - return ret; + return -EFAULT; + + return 0; } int blkelvset_ioctl(elevator_t * elevator, const blkelv_ioctl_arg_t * arg) { blkelv_ioctl_arg_t input; - int ret; - ret = -EFAULT; if (copy_from_user(&input, arg, sizeof(blkelv_ioctl_arg_t))) - goto out; + return -EFAULT; - ret = -EINVAL; if (input.read_latency < 0) - goto out; + return -EINVAL; if (input.write_latency < 0) - goto out; + return -EINVAL; if (input.max_bomb_segments <= 0) - goto out; + return -EINVAL; elevator->read_latency = input.read_latency; elevator->write_latency = input.write_latency; elevator->max_bomb_segments = input.max_bomb_segments; - ret = 0; - out: - return ret; + return 0; } -void elevator_init(elevator_t * elevator) +void elevator_init(elevator_t * elevator, elevator_t type) { static unsigned int queue_ID; - *elevator = ELEVATOR_DEFAULTS; + *elevator = type; elevator->queue_ID = queue_ID++; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v2.4.0-test1/linux/drivers/block/floppy.c Tue May 23 15:31:34 2000 +++ linux/drivers/block/floppy.c Wed Jun 21 22:31:00 2000 @@ -3878,10 +3878,10 @@ char name[16]; sprintf (name, "%d%s", drive, table[table_sup[UDP->cmos][i]]); - devfs_register (devfs_handle, name, 0, DEVFS_FL_DEFAULT, MAJOR_NR, + devfs_register (devfs_handle, name, DEVFS_FL_DEFAULT, MAJOR_NR, base_minor + (table_sup[UDP->cmos][i] << 2), S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP |S_IWGRP, - 0, 0, &floppy_fops, NULL); + &floppy_fops, NULL); } while (table_sup[UDP->cmos][i++]); } } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/ida_cmd.h linux/drivers/block/ida_cmd.h --- v2.4.0-test1/linux/drivers/block/ida_cmd.h Mon Jul 5 19:52:13 1999 +++ linux/drivers/block/ida_cmd.h Fri Jun 23 21:04:36 2000 @@ -191,7 +191,7 @@ __u8 expn_fail; __u8 unit_flags; __u16 big_fail_map[8]; - __u16 big_remap_map[8]; + __u16 big_remap_map[128]; __u16 big_repl_map[8]; __u16 big_act_spare_map[8]; __u8 big_spar_repl_map[128]; @@ -336,7 +336,7 @@ __u32 sense_info; __u8 sense_code; __u8 sense_qual; - __u8 residual; + __u32 residual; __u8 reserved[4]; __u8 cdb[12]; } scsi_param_t; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/linear.c linux/drivers/block/linear.c --- v2.4.0-test1/linux/drivers/block/linear.c Fri May 12 14:18:55 2000 +++ linux/drivers/block/linear.c Wed Jun 21 10:10:02 2000 @@ -148,7 +148,7 @@ return -1; } bh->b_rdev = tmp_dev->dev; - bh->b_rsector = (block - tmp_dev->offset) << 1; + bh->b_rsector = ((block - tmp_dev->offset) << 1) + (bh->b_rsector & 1); return 1; } @@ -183,17 +183,11 @@ static mdk_personality_t linear_personality= { - "linear", - linear_make_request, - NULL, - linear_run, - linear_stop, - linear_status, - 0, - NULL, - NULL, - NULL, - NULL + name: "linear", + make_request: linear_make_request, + run: linear_run, + stop: linear_stop, + status: linear_status, }; #ifndef MODULE diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v2.4.0-test1/linux/drivers/block/ll_rw_blk.c Mon Jun 19 16:31:58 2000 +++ linux/drivers/block/ll_rw_blk.c Fri Jun 23 19:47:06 2000 @@ -4,6 +4,7 @@ * Copyright (C) 1991, 1992 Linus Torvalds * Copyright (C) 1994, Karl Keyte: Added support for disk statistics * Elevator latency, (C) 2000 Andrea Arcangeli SuSE + * Queue request tables / lock, selectable elevator, Jens Axboe */ /* @@ -37,10 +38,9 @@ #endif /* - * The request-struct contains all necessary data - * to load a nr of sectors into memory + * For the allocated request tables */ -static struct request all_requests[NR_REQUEST]; +static kmem_cache_t *request_cachep; /* * The "disk" task queue is used to start the actual requests @@ -62,11 +62,6 @@ */ spinlock_t io_request_lock = SPIN_LOCK_UNLOCKED; -/* - * used to wait on when there are no free requests - */ -DECLARE_WAIT_QUEUE_HEAD(wait_for_request); - /* This specifies how many sectors to read ahead on the disk. */ int read_ahead[MAX_BLKDEV]; @@ -127,29 +122,61 @@ return max_sectors[MAJOR(dev)][MINOR(dev)]; } +static inline request_queue_t *__blk_get_queue(kdev_t dev) +{ + struct blk_dev_struct *bdev = blk_dev + MAJOR(dev); + + if (bdev->queue) + return bdev->queue(dev); + else + return &blk_dev[MAJOR(dev)].request_queue; +} + /* * NOTE: the device-specific queue() functions * have to be atomic! */ -request_queue_t * blk_get_queue (kdev_t dev) +request_queue_t *blk_get_queue(kdev_t dev) { - int major = MAJOR(dev); - struct blk_dev_struct *bdev = blk_dev + major; - unsigned long flags; request_queue_t *ret; + unsigned long flags; spin_lock_irqsave(&io_request_lock,flags); - if (bdev->queue) - ret = bdev->queue(dev); - else - ret = &blk_dev[major].request_queue; + ret = __blk_get_queue(dev); spin_unlock_irqrestore(&io_request_lock,flags); return ret; } +/* + * Hopefully the low level driver has finished any out standing requests + * first... + */ void blk_cleanup_queue(request_queue_t * q) { + struct list_head *entry; + struct request *rq; + int i = QUEUE_NR_REQUESTS; + + if (list_empty(&q->request_freelist)) + return; + + if (q->queue_requests) + BUG(); + + entry = &q->request_freelist; + entry = entry->next; + do { + rq = list_entry(entry, struct request, table); + entry = entry->next; + list_del(&rq->table); + kmem_cache_free(request_cachep, rq); + i--; + } while (!list_empty(&q->request_freelist)); + + if (i) + printk("blk_cleanup_queue: leaked requests (%d)\n", i); + memset(q, 0, sizeof(*q)); } @@ -222,7 +249,7 @@ * This is called with interrupts off and no requests on the queue. * (and with the request spinlock aquired) */ -static void generic_plug_device (request_queue_t *q, kdev_t dev) +static void generic_plug_device(request_queue_t *q, kdev_t dev) { #ifdef CONFIG_BLK_DEV_MD if (MAJOR(dev) == MD_MAJOR) { @@ -230,25 +257,51 @@ BUG(); } #endif - if (!list_empty(&q->queue_head)) + /* + * no need to replug device + */ + if (!list_empty(&q->queue_head) || q->plugged) return; q->plugged = 1; queue_task(&q->plug_tq, &tq_disk); } +static void blk_init_free_list(request_queue_t *q) +{ + struct request *rq; + int i; + + /* + * Divide requests in half between read and write. This used to + * be a 2/3 advantage for reads, but now reads can steal from + * the write free list. + */ + for (i = 0; i < QUEUE_NR_REQUESTS; i++) { + rq = kmem_cache_alloc(request_cachep, SLAB_KERNEL); + rq->rq_status = RQ_INACTIVE; + list_add(&rq->table, &q->request_freelist); + } + + q->queue_requests = 0; + init_waitqueue_head(&q->wait_for_request); + spin_lock_init(&q->request_lock); +} + void blk_init_queue(request_queue_t * q, request_fn_proc * rfn) { INIT_LIST_HEAD(&q->queue_head); - elevator_init(&q->elevator); + INIT_LIST_HEAD(&q->request_freelist); + elevator_init(&q->elevator, ELEVATOR_LINUS); + blk_init_free_list(q); q->request_fn = rfn; q->back_merge_fn = ll_back_merge_fn; q->front_merge_fn = ll_front_merge_fn; q->merge_requests_fn = ll_merge_requests_fn; q->make_request_fn = NULL; - q->plug_tq.sync = 0; + q->plug_tq.sync = 0; q->plug_tq.routine = &generic_unplug_device; - q->plug_tq.data = q; + q->plug_tq.data = q; q->plugged = 0; /* * These booleans describe the queue properties. We set the @@ -263,89 +316,88 @@ /* * remove the plug and let it rip.. */ -void generic_unplug_device(void * data) +static inline void __generic_unplug_device(request_queue_t *q) { - request_queue_t * q = (request_queue_t *) data; - unsigned long flags; - - spin_lock_irqsave(&io_request_lock,flags); if (q->plugged) { q->plugged = 0; if (!list_empty(&q->queue_head)) - (q->request_fn)(q); + q->request_fn(q); } - spin_unlock_irqrestore(&io_request_lock,flags); } +void generic_unplug_device(void *data) +{ + request_queue_t *q = (request_queue_t *) data; + unsigned long flags; + + spin_lock_irqsave(&io_request_lock, flags); + __generic_unplug_device(q); + spin_unlock_irqrestore(&io_request_lock, flags); +} + +#define blkdev_free_rq(list) list_entry((list)->next, struct request, table); /* - * look for a free request in the first N entries. - * NOTE: interrupts must be disabled on the way in (on SMP the request queue - * spinlock has to be aquired), and will still be disabled on the way out. + * Get a free request. io_request_lock must be held and interrupts + * disabled on the way in. */ -static inline struct request * get_request(int n, kdev_t dev) +static inline struct request *get_request(request_queue_t *q, int rw) { - static struct request *prev_found = NULL, *prev_limit = NULL; - register struct request *req, *limit; + register struct request *rq = NULL; - if (n <= 0) - panic("get_request(%d): impossible!\n", n); + if (!list_empty(&q->request_freelist)) { + elevator_t *e = &q->elevator; - limit = all_requests + n; - if (limit != prev_limit) { - prev_limit = limit; - prev_found = all_requests; - } - req = prev_found; - for (;;) { - req = ((req > all_requests) ? req : limit) - 1; - if (req->rq_status == RQ_INACTIVE) - break; - if (req == prev_found) + if ((q->queue_requests > QUEUE_WRITES_MAX) && (rw == WRITE)) return NULL; + + rq = blkdev_free_rq(&q->request_freelist); + list_del(&rq->table); + rq->rq_status = RQ_ACTIVE; + rq->special = NULL; + rq->q = q; + if (rq->cmd == READ) + rq->elevator_sequence = e->read_latency; + else + rq->elevator_sequence = e->write_latency; + q->queue_requests++; } - prev_found = req; - req->rq_status = RQ_ACTIVE; - req->rq_dev = dev; - req->special = NULL; - return req; + return rq; } /* - * wait until a free request in the first N entries is available. + * No available requests for this queue, unplug the device. */ -static struct request * __get_request_wait(int n, kdev_t dev) +static struct request *__get_request_wait(request_queue_t *q, int rw) { - register struct request *req; + register struct request *rq; DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - add_wait_queue_exclusive(&wait_for_request, &wait); + add_wait_queue_exclusive(&q->wait_for_request, &wait); for (;;) { - __set_current_state(TASK_UNINTERRUPTIBLE|TASK_EXCLUSIVE); - spin_lock_irqsave(&io_request_lock,flags); - req = get_request(n, dev); - spin_unlock_irqrestore(&io_request_lock,flags); - if (req) + __set_current_state(TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + spin_lock_irq(&io_request_lock); + rq = get_request(q, rw); + spin_unlock_irq(&io_request_lock); + if (rq) break; - run_task_queue(&tq_disk); + generic_unplug_device(q); schedule(); } - remove_wait_queue(&wait_for_request, &wait); + remove_wait_queue(&q->wait_for_request, &wait); current->state = TASK_RUNNING; - return req; + return rq; } -static inline struct request * get_request_wait(int n, kdev_t dev) +static inline struct request *get_request_wait(request_queue_t *q, int rw) { - register struct request *req; - unsigned long flags; + register struct request *rq; - spin_lock_irqsave(&io_request_lock,flags); - req = get_request(n, dev); - spin_unlock_irqrestore(&io_request_lock,flags); - if (req) - return req; - return __get_request_wait(n, dev); + spin_lock_irq(&io_request_lock); + rq = get_request(q, rw); + spin_unlock_irq(&io_request_lock); + if (rq) + return rq; + return __get_request_wait(q, rw); } /* RO fail safe mechanism */ @@ -405,35 +457,45 @@ */ static inline void add_request(request_queue_t * q, struct request * req, - struct list_head * head, int latency) + struct list_head *head, int lat) { int major; drive_stat_acct(req->rq_dev, req->cmd, req->nr_sectors, 1); - - if (list_empty(head)) { - req->elevator_sequence = elevator_sequence(&q->elevator, latency); - list_add(&req->queue, &q->queue_head); - return; - } - q->elevator.elevator_fn(req, &q->elevator, &q->queue_head, head, latency); - + elevator_account_request(req); /* + * let selected elevator insert the request + */ + q->elevator.elevator_fn(req, &q->elevator, &q->queue_head, head, lat); + + /* * FIXME(eric) I don't understand why there is a need for this * special case code. It clearly doesn't fit any more with * the new queueing architecture, and it got added in 2.3.10. * I am leaving this in here until I hear back from the COMPAQ * people. - */ + */ major = MAJOR(req->rq_dev); if (major >= COMPAQ_SMART2_MAJOR+0 && major <= COMPAQ_SMART2_MAJOR+7) - { (q->request_fn)(q); - } - if (major >= DAC960_MAJOR+0 && major <= DAC960_MAJOR+7) - { (q->request_fn)(q); +} + +/* + * Must be called with io_request_lock held and interrupts disabled + */ +void inline blkdev_release_request(struct request *req) +{ + req->rq_status = RQ_INACTIVE; + + /* + * Request may not have originated from ll_rw_blk + */ + if (req->q) { + list_add(&req->table, &req->q->request_freelist); + req->q->queue_requests--; + wake_up(&req->q->wait_for_request); } } @@ -461,13 +523,12 @@ if(!(q->merge_requests_fn)(q, req, next, max_segments)) return; - elevator_merge_requests(&q->elevator, req, next); + elevator_merge_requests(req, next); req->bhtail->b_reqnext = next->bh; req->bhtail = next->bhtail; req->nr_sectors = req->hard_nr_sectors += next->hard_nr_sectors; - next->rq_status = RQ_INACTIVE; list_del(&next->queue); - wake_up (&wait_for_request); + blkdev_release_request(next); } static inline void attempt_back_merge(request_queue_t * q, @@ -495,18 +556,16 @@ } static inline void __make_request(request_queue_t * q, int rw, - struct buffer_head * bh) + struct buffer_head * bh) { int major = MAJOR(bh->b_rdev); unsigned int sector, count; int max_segments = MAX_SEGMENTS; - struct request * req; - int rw_ahead, max_req, max_sectors; - unsigned long flags; - - int orig_latency, latency, starving, sequence; - struct list_head * entry, * head = &q->queue_head; - elevator_t * elevator; + struct request * req = NULL; + int rw_ahead, max_sectors, el_ret; + struct list_head *head = &q->queue_head; + int latency; + elevator_t *elevator = &q->elevator; count = bh->b_size >> 9; sector = bh->b_rsector; @@ -540,7 +599,6 @@ if (buffer_uptodate(bh)) /* Hmmph! Already have it */ goto end_io; kstat.pgpgin++; - max_req = NR_REQUEST; /* reads take precedence */ break; case WRITERAW: rw = WRITE; @@ -557,7 +615,6 @@ * requests are only for reads. */ kstat.pgpgout++; - max_req = (NR_REQUEST * 2) / 3; break; default: BUG(); @@ -582,158 +639,82 @@ /* look for a free request. */ /* - * Loop uses two requests, 1 for loop and 1 for the real device. - * Cut max_req in half to avoid running out and deadlocking. - */ - if ((major == LOOP_MAJOR) || (major == NBD_MAJOR)) - max_req >>= 1; - - /* * Try to coalesce the new request with old requests */ max_sectors = get_max_sectors(bh->b_rdev); - elevator = &q->elevator; - orig_latency = elevator_request_latency(elevator, rw); + latency = elevator_request_latency(elevator, rw); /* * Now we acquire the request spinlock, we have to be mega careful * not to schedule or do something nonatomic */ - spin_lock_irqsave(&io_request_lock,flags); - elevator_debug(q, bh->b_rdev); + spin_lock_irq(&io_request_lock); + elevator_default_debug(q, bh->b_rdev); if (list_empty(head)) { q->plug_device_fn(q, bh->b_rdev); /* is atomic */ goto get_rq; } - /* avoid write-bombs to not hurt iteractiveness of reads */ - if (rw != READ && elevator->read_pendings) - max_segments = elevator->max_bomb_segments; - - sequence = elevator->sequence; - latency = orig_latency - elevator->nr_segments; - starving = 0; - entry = head; - - /* - * The scsi disk and cdrom drivers completely remove the request - * from the queue when they start processing an entry. For this - * reason it is safe to continue to add links to the top entry - * for those devices. - * - * All other drivers need to jump over the first entry, as that - * entry may be busy being processed and we thus can't change - * it. - */ - if (q->head_active && !q->plugged) - head = head->next; - - while ((entry = entry->prev) != head && !starving) { - req = blkdev_entry_to_request(entry); - if (!req->q) - break; - latency += req->nr_segments; - if (elevator_sequence_before(req->elevator_sequence, sequence)) - starving = 1; - if (latency < 0) - continue; + el_ret = elevator->elevator_merge_fn(q, &req, bh, rw, &max_sectors, &max_segments); + switch (el_ret) { - if (req->sem) - continue; - if (req->cmd != rw) - continue; - if (req->nr_sectors + count > max_sectors) - continue; - if (req->rq_dev != bh->b_rdev) - continue; - /* Can we add it to the end of this request? */ - if (req->sector + req->nr_sectors == sector) { - if (latency - req->nr_segments < 0) - break; - /* - * The merge_fn is a more advanced way - * of accomplishing the same task. Instead - * of applying a fixed limit of some sort - * we instead define a function which can - * determine whether or not it is safe to - * merge the request or not. - * - * See if this queue has rules that - * may suggest that we shouldn't merge - * this - */ - if(!(q->back_merge_fn)(q, req, bh, max_segments)) + case ELEVATOR_BACK_MERGE: + if (!q->back_merge_fn(q, req, bh, max_segments)) break; req->bhtail->b_reqnext = bh; req->bhtail = bh; - req->nr_sectors = req->hard_nr_sectors += count; + req->nr_sectors = req->hard_nr_sectors += count; + req->e = elevator; drive_stat_acct(req->rq_dev, req->cmd, count, 0); - - elevator_merge_after(elevator, req, latency); - - /* Can we now merge this req with the next? */ attempt_back_merge(q, req, max_sectors, max_segments); - /* or to the beginning? */ - } else if (req->sector - count == sector) { - if (starving) - break; - /* - * The merge_fn is a more advanced way - * of accomplishing the same task. Instead - * of applying a fixed limit of some sort - * we instead define a function which can - * determine whether or not it is safe to - * merge the request or not. - * - * See if this queue has rules that - * may suggest that we shouldn't merge - * this - */ - if(!(q->front_merge_fn)(q, req, bh, max_segments)) + goto out; + + case ELEVATOR_FRONT_MERGE: + if (!q->front_merge_fn(q, req, bh, max_segments)) break; - bh->b_reqnext = req->bh; - req->bh = bh; - req->buffer = bh->b_data; - req->current_nr_sectors = count; - req->sector = req->hard_sector = sector; - req->nr_sectors = req->hard_nr_sectors += count; + bh->b_reqnext = req->bh; + req->bh = bh; + req->buffer = bh->b_data; + req->current_nr_sectors = count; + req->sector = req->hard_sector = sector; + req->nr_sectors = req->hard_nr_sectors += count; + req->e = elevator; drive_stat_acct(req->rq_dev, req->cmd, count, 0); - - elevator_merge_before(elevator, req, latency); - attempt_front_merge(q, head, req, max_sectors, max_segments); - } else - continue; - - q->elevator.sequence++; - spin_unlock_irqrestore(&io_request_lock,flags); - return; + goto out; + /* + * elevator says don't/can't merge. get new request + */ + case ELEVATOR_NO_MERGE: + break; + default: + printk("elevator returned crap (%d)\n", el_ret); + BUG(); } - -/* find an unused request. */ -get_rq: - req = get_request(max_req, bh->b_rdev); - + /* - * if no request available: if rw_ahead, forget it, - * otherwise try again blocking.. + * Grab a free request from the freelist. Read first try their + * own queue - if that is empty, we steal from the write list. + * Writes must block if the write list is empty, and read aheads + * are not crucial. */ - if (!req) { - spin_unlock_irqrestore(&io_request_lock,flags); +get_rq: + if ((req = get_request(q, rw)) == NULL) { + spin_unlock_irq(&io_request_lock); if (rw_ahead) goto end_io; - req = __get_request_wait(max_req, bh->b_rdev); - spin_lock_irqsave(&io_request_lock,flags); - /* revalidate elevator */ - head = &q->queue_head; - if (q->head_active && !q->plugged) - head = head->next; + req = __get_request_wait(q, rw); + spin_lock_irq(&io_request_lock); } + head = &q->queue_head; + if (q->head_active && !q->plugged) + head = head->next; + /* fill up the request-info, and add it to the queue */ req->cmd = rw; req->errors = 0; @@ -746,20 +727,18 @@ req->sem = NULL; req->bh = bh; req->bhtail = bh; - req->q = q; - add_request(q, req, head, orig_latency); - elevator_account_request(elevator, req); - - spin_unlock_irqrestore(&io_request_lock, flags); + req->rq_dev = bh->b_rdev; + req->e = elevator; + add_request(q, req, head, latency); +out: + spin_unlock_irq(&io_request_lock); return; - end_io: bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state)); } int generic_make_request (request_queue_t *q, int rw, struct buffer_head * bh) { - unsigned long flags; int ret; /* @@ -767,7 +746,6 @@ * still free to implement/resolve their own stacking * by explicitly returning 0) */ - while (q->make_request_fn) { ret = q->make_request_fn(q, rw, bh); if (ret > 0) { @@ -781,10 +759,10 @@ * the IO request? (normal case) */ __make_request(q, rw, bh); - spin_lock_irqsave(&io_request_lock,flags); + spin_lock_irq(&io_request_lock); if (q && !q->plugged) (q->request_fn)(q); - spin_unlock_irqrestore(&io_request_lock,flags); + spin_unlock_irq(&io_request_lock); return 0; } @@ -923,28 +901,27 @@ void end_that_request_last(struct request *req) { - if (req->q) + if (req->e) { + printk("end_that_request_last called with non-dequeued req\n"); BUG(); + } if (req->sem != NULL) up(req->sem); - req->rq_status = RQ_INACTIVE; - wake_up(&wait_for_request); + + blkdev_release_request(req); } int __init blk_dev_init(void) { - struct request * req; struct blk_dev_struct *dev; - for (dev = blk_dev + MAX_BLKDEV; dev-- != blk_dev;) { + request_cachep = kmem_cache_create("blkdev_requests", + sizeof(struct request), + 0, SLAB_HWCACHE_ALIGN, NULL, NULL); + + for (dev = blk_dev + MAX_BLKDEV; dev-- != blk_dev;) dev->queue = NULL; - blk_init_queue(&dev->request_queue, NULL); - } - req = all_requests + NR_REQUEST; - while (--req >= all_requests) { - req->rq_status = RQ_INACTIVE; - } memset(ro_bits,0,sizeof(ro_bits)); memset(max_readahead, 0, sizeof(max_readahead)); memset(max_sectors, 0, sizeof(max_sectors)); @@ -1070,3 +1047,4 @@ EXPORT_SYMBOL(blk_queue_pluggable); EXPORT_SYMBOL(blk_queue_make_request); EXPORT_SYMBOL(generic_make_request); +EXPORT_SYMBOL(blkdev_release_request); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/loop.c linux/drivers/block/loop.c --- v2.4.0-test1/linux/drivers/block/loop.c Tue May 23 15:31:34 2000 +++ linux/drivers/block/loop.c Wed Jun 21 22:31:00 2000 @@ -238,7 +238,8 @@ kaddr = (char*)kmap(page); if ((lo->transfer)(lo,READ,kaddr+offset,p->data,size,IV)) { size = 0; - printk(KERN_ERR "loop: transfer error block %ld\n",page->index); + printk(KERN_ERR "loop: transfer error block %ld\n", + page->index); desc->error = -EINVAL; } kunmap(page); @@ -345,9 +346,11 @@ } } - if ((lo->transfer)(lo, current_request->cmd, bh->b_data + offset, - dest_addr, size, block)) { - printk(KERN_ERR "loop: transfer error block %d\n", block); + if ((lo->transfer)(lo, current_request->cmd, + bh->b_data + offset, + dest_addr, size, block)) { + printk(KERN_ERR "loop: transfer error block %d\n", + block); brelse(bh); goto error_out_lock; } @@ -469,7 +472,7 @@ lo->lo_backing_file->f_owner = file->f_owner; lo->lo_backing_file->f_dentry = file->f_dentry; lo->lo_backing_file->f_vfsmnt = mntget(file->f_vfsmnt); - lo->lo_backing_file->f_op = file->f_op; + lo->lo_backing_file->f_op = fops_get(file->f_op); lo->lo_backing_file->private_data = file->private_data; file_moveto(lo->lo_backing_file, file); @@ -539,8 +542,10 @@ lo->lo_dentry = NULL; if (lo->lo_backing_file != NULL) { - put_write_access(lo->lo_backing_file->f_dentry->d_inode); - fput(lo->lo_backing_file); + struct file *filp = lo->lo_backing_file; + if ((filp->f_mode & FMODE_WRITE) == 0) + put_write_access(filp->f_dentry->d_inode); + fput(filp); lo->lo_backing_file = NULL; } else { dput(dentry); @@ -636,7 +641,8 @@ if (!inode) return -EINVAL; if (MAJOR(inode->i_rdev) != MAJOR_NR) { - printk(KERN_WARNING "lo_ioctl: pseudo-major != %d\n", MAJOR_NR); + printk(KERN_WARNING "lo_ioctl: pseudo-major != %d\n", + MAJOR_NR); return -ENODEV; } dev = MINOR(inode->i_rdev); @@ -698,7 +704,8 @@ if (!inode) return 0; if (MAJOR(inode->i_rdev) != MAJOR_NR) { - printk(KERN_WARNING "lo_release: pseudo-major != %d\n", MAJOR_NR); + printk(KERN_WARNING "lo_release: pseudo-major != %d\n", + MAJOR_NR); return 0; } dev = MINOR(inode->i_rdev); @@ -706,7 +713,8 @@ return 0; lo = &loop_dev[dev]; if (lo->lo_refcnt <= 0) - printk(KERN_ERR "lo_release: refcount(%d) <= 0\n", lo->lo_refcnt); + printk(KERN_ERR "lo_release: refcount(%d) <= 0\n", + lo->lo_refcnt); else { int type = lo->lo_encrypt_type; --lo->lo_refcnt; @@ -761,6 +769,10 @@ EXPORT_SYMBOL(loop_register_transfer); EXPORT_SYMBOL(loop_unregister_transfer); +static void no_plug_device(request_queue_t *q, kdev_t device) +{ +} + int __init loop_init(void) { int i; @@ -773,7 +785,7 @@ devfs_handle = devfs_mk_dir (NULL, "loop", 0, NULL); devfs_register_series (devfs_handle, "%u", max_loop, DEVFS_FL_DEFAULT, MAJOR_NR, 0, - S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, &lo_fops, NULL); if ((max_loop < 1) || (max_loop > 255)) { @@ -806,6 +818,7 @@ } blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); + blk_queue_pluggable(BLK_DEFAULT_QUEUE(MAJOR_NR), no_plug_device); blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0); for (i=0; i < max_loop; i++) { memset(&loop_dev[i], 0, sizeof(struct loop_device)); @@ -828,6 +841,7 @@ if (devfs_unregister_blkdev(MAJOR_NR, "loop") != 0) printk(KERN_WARNING "loop: cannot unregister blkdev\n"); + blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); kfree (loop_dev); kfree (loop_sizes); kfree (loop_blksizes); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/md.c linux/drivers/block/md.c --- v2.4.0-test1/linux/drivers/block/md.c Mon Jun 19 16:31:58 2000 +++ linux/drivers/block/md.c Wed Jun 21 22:31:00 2000 @@ -22,10 +22,10 @@ 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. - + You should have received a copy of the GNU General Public License (for example /usr/src/linux/COPYING); if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include @@ -43,7 +43,7 @@ #include extern asmlinkage int sys_sched_yield(void); -extern asmlinkage int sys_setsid(void); +extern asmlinkage long sys_setsid(void); #define MAJOR_NR MD_MAJOR #define MD_DRIVER @@ -258,7 +258,7 @@ /* * The 'base' mddev is the one with data NULL. - * personalities can create additional mddevs + * personalities can create additional mddevs * if necessary. */ add_mddev_mapping(mddev, dev, 0); @@ -327,11 +327,13 @@ * ok, add this new device name to the list */ hd = find_gendisk (dev); - - if (!hd) - sprintf (dname->name, "[dev %s]", kdevname(dev)); - else - disk_name (hd, MINOR(dev), dname->name); + dname->name = NULL; + if (hd) + dname->name = disk_name (hd, MINOR(dev), dname->namebuf); + if (!dname->name) { + sprintf (dname->namebuf, "[dev %s]", kdevname(dev)); + dname->name = dname->namebuf; + } dname->dev = dev; MD_INIT_LIST_HEAD(&dname->list); @@ -435,7 +437,7 @@ if (rdev->desc_nr == i) c++; } - if (c == 0) { + if (!c) { printk("md: md%d, missing disk #%d, aborting.\n", mdidx(mddev), i); goto abort; @@ -1010,7 +1012,7 @@ skip: return 0; } -#undef GETBLK_FAILED KERN_ERR +#undef GETBLK_FAILED static void set_this_disk(mddev_t *mddev, mdk_rdev_t *rdev) { @@ -1425,7 +1427,7 @@ break; } } - if (found) + if (found) continue; printk("md%d: former device %s is unavailable, removing from array!\n", mdidx(mddev), partition_name(dev)); @@ -1525,7 +1527,7 @@ * Do device size calculation. Bail out if too small. * (we have to do this after having validated chunk_size, * because device size has to be modulo chunk_size) - */ + */ persistent = !mddev->sb->not_persistent; ITERATE_RDEV(mddev,rdev,tmp) { if (rdev->faulty) @@ -1576,7 +1578,7 @@ readahead = MD_READAHEAD; if ((sb->level == 0) || (sb->level == 4) || (sb->level == 5)) readahead = mddev->sb->chunk_size * 4 * data_disks; - if (readahead < data_disks * MAX_SECTORS*512*2) + if (readahead < data_disks * MAX_SECTORS*512*2) readahead = data_disks * MAX_SECTORS*512*2; else { if (sb->level == -3) @@ -1617,7 +1619,7 @@ MD_BUG(); return -EINVAL; } - + if (mddev->pers) return -EBUSY; @@ -1629,7 +1631,7 @@ /* * Analyze all RAID superblock(s) - */ + */ if (analyze_sbs(mddev)) { MD_BUG(); return -EINVAL; @@ -1683,7 +1685,7 @@ #endif return -EINVAL; } - + if (device_size_calculation(mddev)) return -EINVAL; @@ -1698,9 +1700,9 @@ fsync_dev(rdev->dev); invalidate_buffers(rdev->dev); } - + mddev->pers = pers[pnum]; - + err = mddev->pers->run(mddev); if (err) { printk("pers->run() failed ...\n"); @@ -1717,7 +1719,7 @@ */ md_hd_struct[mdidx(mddev)].start_sect = 0; md_hd_struct[mdidx(mddev)].nr_sects = md_size[mdidx(mddev)] << 1; - + read_ahead[MD_MAJOR] = 1024; return (0); } @@ -1730,7 +1732,7 @@ static int restart_array (mddev_t *mddev) { int err = 0; - + /* * Complain if it has no devices */ @@ -1754,7 +1756,7 @@ mddev->pers->restart_resync(mddev); } else err = -EINVAL; - + out: return err; } @@ -1766,12 +1768,12 @@ { int err = 0, resync_interrupted = 0; kdev_t dev = mddev_to_kdev(mddev); - + if (!ro && get_super(dev)) { printk (STILL_MOUNTED, mdidx(mddev)); OUT(-EBUSY); } - + if (mddev->pers) { /* * It is safe to call stop here, it only frees private @@ -1833,14 +1835,14 @@ if (ro) set_device_ro(dev, 1); } - + /* * Free resources if final stop */ if (!ro) { + printk (KERN_INFO "md%d stopped.\n", mdidx(mddev)); free_mddev(mddev); - printk (KERN_INFO "md%d stopped.\n", mdidx(mddev)); } else printk (KERN_INFO "md%d switched to read-only mode.\n", mdidx(mddev)); @@ -2069,14 +2071,25 @@ } raid_setup_args md__initdata = { 0, 0 }; +void md_setup_drive(void) md__init; + /* * Searches all registered partitions for autorun RAID arrays * at boot time. */ -void md__init autodetect_raid(void) +#ifdef CONFIG_AUTODETECT_RAID +static int detected_devices[128] md__initdata; +static int dev_cnt md__initdata=0; +void md__init md_autodetect_dev(kdev_t dev) +{ + if (dev_cnt < 127) + detected_devices[dev_cnt++] = dev; +} +#endif + +void md__init md_run_setup(void) { #ifdef CONFIG_AUTODETECT_RAID - struct gendisk *disk; mdk_rdev_t *rdev; int i; @@ -2086,36 +2099,35 @@ } printk(KERN_INFO "autodetecting RAID arrays\n"); - for (disk = gendisk_head ; disk ; disk = disk->next) { - for (i = 0; i < disk->max_p*disk->nr_real; i++) { - kdev_t dev = MKDEV(disk->major,i); + for (i=0; ipart[i].type != LINUX_RAID_PARTITION) - continue; - - if (md_import_device(dev,1)) { - printk(KERN_ALERT "could not import %s!\n", - partition_name(dev)); - continue; - } - /* - * Sanity checks: - */ - rdev = find_rdev_all(dev); - if (!rdev) { - MD_BUG(); - continue; - } - if (rdev->faulty) { - MD_BUG(); - continue; - } - md_list_add(&rdev->pending, &pending_raid_disks); + if (md_import_device(dev,1)) { + printk(KERN_ALERT "could not import %s!\n", + partition_name(dev)); + continue; + } + /* + * Sanity checks: + */ + rdev = find_rdev_all(dev); + if (!rdev) { + MD_BUG(); + continue; } + if (rdev->faulty) { + MD_BUG(); + continue; + } + md_list_add(&rdev->pending, &pending_raid_disks); } autorun_devices(); #endif +#ifdef CONFIG_MD_BOOT + md_setup_drive(); +#endif + } static int get_version (void * arg) @@ -2196,41 +2208,62 @@ } #undef SET_FROM_SB -#define SET_SB(x) mddev->sb->disks[nr].x = info.x +#define SET_SB(x) mddev->sb->disks[nr].x = info->x -static int add_new_disk (mddev_t * mddev, void * arg) +static int add_new_disk (mddev_t * mddev, mdu_disk_info_t *info) { int err, size, persistent; - mdu_disk_info_t info; mdk_rdev_t *rdev; unsigned int nr; kdev_t dev; - - if (!mddev->sb) - return -EINVAL; - - if (md_copy_from_user(&info, arg, sizeof(info))) - return -EFAULT; - - nr = info.number; - if (nr >= mddev->sb->nr_disks) - return -EINVAL; - - dev = MKDEV(info.major,info.minor); + dev = MKDEV(info->major,info->minor); if (find_rdev_all(dev)) { - printk("device %s already used in a RAID array!\n", + printk("device %s already used in a RAID array!\n", partition_name(dev)); return -EBUSY; } + if (!mddev->sb) { + /* expecting a device which has a superblock */ + err = md_import_device(dev, 1); + if (err) { + printk("md error, md_import_device returned %d\n", err); + return -EINVAL; + } + rdev = find_rdev_all(dev); + if (!rdev) { + MD_BUG(); + return -EINVAL; + } + if (mddev->nb_dev) { + mdk_rdev_t *rdev0 = md_list_entry(mddev->disks.next, + mdk_rdev_t, same_set); + if (!uuid_equal(rdev0, rdev)) { + printk("md: %s has different UUID to %s\n", partition_name(rdev->dev), partition_name(rdev0->dev)); + export_rdev(rdev); + return -EINVAL; + } + if (!sb_equal(rdev0->sb, rdev->sb)) { + printk("md: %s has same UUID but different superblock to %s\n", partition_name(rdev->dev), partition_name(rdev0->dev)); + export_rdev(rdev); + return -EINVAL; + } + } + bind_rdev_to_array(rdev, mddev); + return 0; + } + + nr = info->number; + if (nr >= mddev->sb->nr_disks) + return -EINVAL; SET_SB(number); SET_SB(major); SET_SB(minor); SET_SB(raid_disk); SET_SB(state); - - if ((info.state & (1<state & (1<old_dev = dev; - rdev->desc_nr = info.number; - + rdev->desc_nr = info->number; + bind_rdev_to_array(rdev, mddev); - + persistent = !mddev->sb->not_persistent; if (!persistent) printk("nonpersistent superblock ...\n"); if (!mddev->sb->chunk_size) printk("no chunksize?\n"); - + size = calc_dev_size(dev, mddev, persistent); rdev->sb_offset = calc_dev_sboffset(dev, mddev, persistent); - + if (!mddev->sb->size || (mddev->sb->size > size)) mddev->sb->size = size; } - + /* * sync all other superblocks with the main superblock */ @@ -2444,19 +2477,9 @@ return err; } -#define SET_SB(x) mddev->sb->x = info.x -static int set_array_info (mddev_t * mddev, void * arg) +#define SET_SB(x) mddev->sb->x = info->x +static int set_array_info (mddev_t * mddev, mdu_array_info_t *info) { - mdu_array_info_t info; - - if (mddev->sb) { - printk("array md%d already has a superblock!\n", - mdidx(mddev)); - return -EBUSY; - } - - if (md_copy_from_user(&info, arg, sizeof(info))) - return -EFAULT; if (alloc_array_sb(mddev)) return -ENOMEM; @@ -2634,11 +2657,25 @@ printk("ioctl, reason %d, cmd %d\n", err, cmd); goto abort; } - err = set_array_info(mddev, (void *)arg); - if (err) { - printk("couldnt set array info. %d\n", err); + + if (mddev->sb) { + printk("array md%d already has a superblock!\n", + mdidx(mddev)); + err = -EBUSY; goto abort_unlock; } + if (arg) { + mdu_array_info_t info; + if (md_copy_from_user(&info, (void*)arg, sizeof(info))) { + err = -EFAULT; + goto abort_unlock; + } + err = set_array_info(mddev, &info); + if (err) { + printk("couldnt set array info. %d\n", err); + goto abort_unlock; + } + } goto done_unlock; case START_ARRAY: @@ -2669,6 +2706,11 @@ printk("ioctl lock interrupted, reason %d, cmd %d\n",err, cmd); goto abort; } + /* if we don't have a superblock yet, only ADD_NEW_DISK or STOP_ARRAY is allowed */ + if (!mddev->sb && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY && cmd != RUN_ARRAY) { + err = -ENODEV; + goto abort_unlock; + } /* * Commands even a read-only array can execute: @@ -2689,7 +2731,10 @@ case STOP_ARRAY: err = do_md_stop (mddev, 0); - goto done; + if (err) + goto done_unlock; + else + goto done; case STOP_ARRAY_RO: err = do_md_stop (mddev, 1); @@ -2738,9 +2783,14 @@ goto done_unlock; case ADD_NEW_DISK: - err = add_new_disk(mddev, (void *)arg); + { + mdu_disk_info_t info; + if (md_copy_from_user(&info, (void*)arg, sizeof(info))) + err = -EFAULT; + else + err = add_new_disk(mddev, (void *)arg); goto done_unlock; - + } case HOT_REMOVE_DISK: err = hot_remove_disk(mddev, (kdev_t)arg); goto done_unlock; @@ -2771,13 +2821,13 @@ case RUN_ARRAY: { +/* The data is never used.... mdu_param_t param; - err = md_copy_from_user(¶m, (mdu_param_t *)arg, sizeof(param)); if (err) goto abort_unlock; - +*/ err = do_md_run (mddev); /* * we have to clean up the mess if @@ -2825,7 +2875,7 @@ open: md_open, ioctl: md_ioctl, }; - + int md_thread(void * arg) { @@ -3020,9 +3070,9 @@ static int status_resync (char * page, mddev_t * mddev) { int sz = 0; - unsigned int max_blocks, resync, res, dt, tt, et; + unsigned long max_blocks, resync, res, dt, db, rt; - resync = mddev->curr_resync; + resync = mddev->curr_resync - atomic_read(&mddev->recovery_active); max_blocks = mddev->sb->size; /* @@ -3047,13 +3097,13 @@ /* * true resync */ - sz += sprintf(page + sz, " resync =%3u.%u%% (%u/%u)", + sz += sprintf(page + sz, " resync =%3lu.%lu%% (%lu/%lu)", res/10, res % 10, resync, max_blocks); else /* * recovery ... */ - sz += sprintf(page + sz, " recovery =%3u.%u%% (%u/%u)", + sz += sprintf(page + sz, " recovery =%3lu.%lu%% (%lu/%lu)", res/10, res % 10, resync, max_blocks); /* @@ -3061,21 +3111,18 @@ * the * 100 / 100 trick are important. We do a +1 to be * safe against division by zero. We only estimate anyway. * - * dt: time until now - * tt: total time - * et: estimated finish time - */ - dt = ((jiffies - mddev->resync_start) / HZ); - tt = (dt * (max_blocks / (resync/100+1)))/100; - if (tt > dt) - et = tt - dt; - else - /* - * ignore rounding effects near finish time - */ - et = 0; + * dt: time from mark until now + * db: blocks written from mark until now + * rt: remaining time + */ + dt = ((jiffies - mddev->resync_mark) / HZ); + if (!dt) dt++; + db = resync - mddev->resync_mark_cnt; + rt = (dt * ((max_blocks-resync) / (db/100+1)))/100; - sz += sprintf(page + sz, " finish=%u.%umin", et / 60, (et % 60)/6); + sz += sprintf(page + sz, " finish=%lu.%lumin", rt / 60, (rt % 60)/6); + + sz += sprintf(page + sz, " speed=%ldK/sec", db/dt); return sz; } @@ -3101,7 +3148,7 @@ sz += sprintf(page+sz, "not set\n"); else sz += sprintf(page+sz, "%d sectors\n", read_ahead[MD_MAJOR]); - + ITERATE_MDDEV(mddev,tmp) { sz += sprintf(page + sz, "md%d : %sactive", mdidx(mddev), mddev->pers ? "" : "in"); @@ -3158,7 +3205,7 @@ if (pers[pnum]) return -EBUSY; - + pers[pnum] = p; printk(KERN_INFO "%s personality registered\n", p->name); return 0; @@ -3172,7 +3219,7 @@ printk(KERN_INFO "%s personality unregistered\n", pers[pnum]->name); pers[pnum] = NULL; return 0; -} +} static mdp_disk_t *get_spare(mddev_t *mddev) { @@ -3236,13 +3283,17 @@ } } +#define SYNC_MARKS 10 +#define SYNC_MARK_STEP (3*HZ) int md_do_sync(mddev_t *mddev, mdp_disk_t *spare) { mddev_t *mddev2; unsigned int max_blocks, currspeed, j, window, err, serialize; kdev_t read_disk = mddev_to_kdev(mddev); - unsigned long starttime; + unsigned long mark[SYNC_MARKS]; + unsigned long mark_cnt[SYNC_MARKS]; + int last_mark,m; struct md_list_head *tmp; unsigned long last_check; @@ -3287,8 +3338,13 @@ current->priority = 1; is_mddev_idle(mddev); /* this also initializes IO event counters */ - starttime = jiffies; - mddev->resync_start = starttime; + for (m = 0; m < SYNC_MARKS; m++) { + mark[m] = jiffies; + mark_cnt[m] = 0; + } + last_mark = 0; + mddev->resync_mark = mark[last_mark]; + mddev->resync_mark_cnt = mark_cnt[last_mark]; /* * Tune reconstruction: @@ -3301,12 +3357,7 @@ last_check = 0; for (j = 0; j < max_blocks;) { int blocks; - if (j) - mddev->curr_resync = j; -/* wait_event(mddev->recovery_wait, - atomic_read(&mddev->recovery_active) < window); -*/ blocks = mddev->pers->sync_request(mddev, j); if (blocks < 0) { @@ -3315,12 +3366,24 @@ } atomic_add(blocks, &mddev->recovery_active); j += blocks; + mddev->curr_resync = j; if (last_check + window > j) continue; run_task_queue(&tq_disk); //?? + if (jiffies >= mark[last_mark] + SYNC_MARK_STEP ) { + /* step marks */ + int next = (last_mark+1) % SYNC_MARKS; + + mddev->resync_mark = mark[next]; + mddev->resync_mark_cnt = mark_cnt[next]; + mark[next] = jiffies; + mark_cnt[next] = j - atomic_read(&mddev->recovery_active); + last_mark = next; + } + if (md_signal_pending(current)) { /* @@ -3345,7 +3408,8 @@ if (md_need_resched(current)) schedule(); - currspeed = j/((jiffies-starttime)/HZ + 1) + 1; + currspeed = (j-mddev->resync_mark_cnt)/((jiffies-mddev->resync_mark)/HZ +1) +1; + if (currspeed > sysctl_speed_limit_min) { current->priority = 1; @@ -3359,7 +3423,6 @@ } else current->priority = 40; } - wait_event(mddev->recovery_wait, atomic_read(&mddev->recovery_active)==0); fsync_dev(read_disk); printk(KERN_INFO "md: md%d: sync done.\n",mdidx(mddev)); err = 0; @@ -3367,6 +3430,7 @@ * this also signals 'finished resyncing' to md_stop */ out: + wait_event(mddev->recovery_wait, atomic_read(&mddev->recovery_active)==0); up(&mddev->resync_sem); out_nolock: mddev->curr_resync = 0; @@ -3433,9 +3497,9 @@ if (disk_faulty(spare)) mddev->pers->diskop(mddev, &spare, DISKOP_SPARE_INACTIVE); - if (err == -EINTR) { + if (err == -EINTR || err == -ENOMEM) { /* - * Recovery got interrupted ... + * Recovery got interrupted, or ran out of mem ... * signal back that we have finished using the array. */ mddev->pers->diskop(mddev, &spare, @@ -3565,7 +3629,7 @@ } devfs_handle = devfs_mk_dir (NULL, "md", 0, NULL); devfs_register_series (devfs_handle, "%u",MAX_MD_DEVS,DEVFS_FL_DEFAULT, - MAJOR_NR, 0, S_IFBLK | S_IRUSR | S_IWUSR, 0, 0, + MAJOR_NR, 0, S_IFBLK | S_IRUSR | S_IWUSR, &md_fops, NULL); blk_dev[MD_MAJOR].queue = md_get_queue; @@ -3603,6 +3667,173 @@ md_geninit(); return (0); } + +#ifdef CONFIG_MD_BOOT +#define MAX_MD_BOOT_DEVS 8 +struct { + unsigned long set; + int pers[MAX_MD_BOOT_DEVS]; + int chunk[MAX_MD_BOOT_DEVS]; + kdev_t devices[MAX_MD_BOOT_DEVS][MAX_REAL]; +} md_setup_args md__initdata; + +/* + * Parse the command-line parameters given our kernel, but do not + * actually try to invoke the MD device now; that is handled by + * md_setup_drive after the low-level disk drivers have initialised. + * + * 27/11/1999: Fixed to work correctly with the 2.3 kernel (which + * assigns the task of parsing integer arguments to the + * invoked program now). Added ability to initialise all + * the MD devices (by specifying multiple "md=" lines) + * instead of just one. -- KTK + * 18May2000: Added support for persistant-superblock arrays: + * md=n,0,factor,fault,device-list uses RAID0 for device n + * md=n,-1,factor,fault,device-list uses LINEAR for device n + * md=n,device-list reads a RAID superblock from the devices + * elements in device-list are read by name_to_kdev_t so can be + * a hex number or something like /dev/hda1 /dev/sdb + */ +extern kdev_t name_to_kdev_t(char *line) md__init; +static int md__init md_setup(char *str) +{ + int minor, level, factor, fault, i=0; + kdev_t device; + char *devnames, *pername = ""; + + if(get_option(&str, &minor) != 2) { /* MD Number */ + printk("md: Too few arguments supplied to md=.\n"); + return 0; + } + if (minor >= MAX_MD_BOOT_DEVS) { + printk ("md: Minor device number too high.\n"); + return 0; + } else if (md_setup_args.set & (1 << minor)) { + printk ("md: Warning - md=%d,... has been specified twice;\n" + " will discard the first definition.\n", minor); + } + switch(get_option(&str, &level)) { /* RAID Personality */ + case 2: /* could be 0 or -1.. */ + if (level == 0 || level == -1) { + if (get_option(&str, &factor) != 2 || /* Chunk Size */ + get_option(&str, &fault) != 2) { + printk("md: Too few arguments supplied to md=.\n"); + return 0; + } + md_setup_args.pers[minor] = level; + md_setup_args.chunk[minor] = 1 << (factor+12); + switch(level) { + case -1: + level = LINEAR; + pername = "linear"; + break; + case 0: + level = RAID0; + pername = "raid0"; + break; + default: + printk ("md: The kernel has not been configured for raid%d" + " support!\n", level); + return 0; + } + md_setup_args.pers[minor] = level; + break; + } + /* FALL THROUGH */ + case 1: /* the first device is numeric */ + md_setup_args.devices[minor][i++] = level; + /* FALL THROUGH */ + case 0: + md_setup_args.pers[minor] = 0; + pername="super-block"; + } + devnames = str; + for (; isb->nr_disks++; + mddev->sb->raid_disks++; + mddev->sb->active_disks++; + mddev->sb->working_disks++; + err = add_new_disk (mddev, &dinfo); + } + } else { + /* persistent */ + for (i = 0; (dev = md_setup_args.devices[minor][i]); i++) { + dinfo.major = MAJOR(dev); + dinfo.minor = MINOR(dev); + add_new_disk (mddev, &dinfo); + } + } + if (!err) + err = do_md_run(mddev); + if (err) { + mddev->sb_dirty = 0; + do_md_stop(mddev, 0); + printk("md: starting md%d failed\n", minor); + } + } +} + +__setup("md=", md_setup); +#endif + MD_EXPORT_SYMBOL(md_size); MD_EXPORT_SYMBOL(register_md_personality); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/nbd.c linux/drivers/block/nbd.c --- v2.4.0-test1/linux/drivers/block/nbd.c Tue Apr 11 15:09:16 2000 +++ linux/drivers/block/nbd.c Wed Jun 21 22:31:00 2000 @@ -38,6 +38,8 @@ #include #include +#include + #include #include #include @@ -53,6 +55,7 @@ static u64 nbd_bytesizes[MAX_NBD]; static struct nbd_device nbd_dev[MAX_NBD]; +static devfs_handle_t devfs_handle = NULL; #define DEBUG( s ) /* #define DEBUG( s ) printk( s ) @@ -514,12 +517,20 @@ register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &nbd_fops, nbd_bytesizes[i]>>9); } + devfs_handle = devfs_mk_dir (NULL, "nbd", 0, NULL); + devfs_register_series (devfs_handle, "%u", MAX_NBD, + DEVFS_FL_DEFAULT, MAJOR_NR, 0, + S_IFBLK | S_IRUSR | S_IWUSR, + &nbd_fops, NULL); + return 0; } #ifdef MODULE void cleanup_module(void) { + devfs_unregister (devfs_handle); + if (unregister_blkdev(MAJOR_NR, "nbd") != 0) printk("nbd: cleanup_module failed\n"); else diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/paride/paride.c linux/drivers/block/paride/paride.c --- v2.4.0-test1/linux/drivers/block/paride/paride.c Mon Mar 27 08:08:23 2000 +++ linux/drivers/block/paride/paride.c Tue Jun 20 07:24:52 2000 @@ -120,8 +120,8 @@ pi->claimed = 1; #ifdef CONFIG_PARPORT if (pi->pardev) - while (parport_claim((struct pardevice *)(pi->pardev))) - sleep_on(&(pi->parq)); + wait_event (pi->parq, + !parport_claim ((struct pardevice *)pi->pardev)); #endif } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/paride/pd.c linux/drivers/block/paride/pd.c --- v2.4.0-test1/linux/drivers/block/paride/pd.c Thu May 11 15:30:06 2000 +++ linux/drivers/block/paride/pd.c Tue Jun 20 07:24:52 2000 @@ -487,7 +487,7 @@ MOD_INC_USE_COUNT; - while (!pd_valid) sleep_on(&pd_wait_open); + wait_event (pd_wait_open, pd_valid); PD.access++; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/paride/pg.c linux/drivers/block/paride/pg.c --- v2.4.0-test1/linux/drivers/block/paride/pg.c Wed Feb 16 17:03:51 2000 +++ linux/drivers/block/paride/pg.c Wed Jun 21 22:31:00 2000 @@ -261,6 +261,7 @@ /* kernel glue structures */ static struct file_operations pg_fops = { + owner: THIS_MODULE, read: pg_read, write: pg_write, open: pg_open, @@ -308,7 +309,7 @@ } devfs_handle = devfs_mk_dir (NULL, "pg", 2, NULL); devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT, - major, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + major, 0, S_IFCHR | S_IRUSR | S_IWUSR, &pg_fops, NULL); return 0; } @@ -578,8 +579,6 @@ return -EBUSY; } - MOD_INC_USE_COUNT; - if (PG.busy) { pg_reset(unit); PG.busy = 0; @@ -591,7 +590,6 @@ PG.bufptr = kmalloc(PG_MAX_DATA,GFP_KERNEL); if (PG.bufptr == NULL) { PG.access--; - MOD_DEC_USE_COUNT; printk("%s: buffer allocation failed\n",PG.name); return -ENOMEM; } @@ -610,8 +608,6 @@ kfree(PG.bufptr); PG.bufptr = NULL; - - MOD_DEC_USE_COUNT; return 0; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/paride/pt.c linux/drivers/block/paride/pt.c --- v2.4.0-test1/linux/drivers/block/paride/pt.c Wed Feb 16 17:03:51 2000 +++ linux/drivers/block/paride/pt.c Wed Jun 21 22:31:00 2000 @@ -263,6 +263,7 @@ /* kernel glue structures */ static struct file_operations pt_fops = { + owner: THIS_MODULE, read: pt_read, write: pt_write, ioctl: pt_ioctl, @@ -313,10 +314,10 @@ devfs_handle = devfs_mk_dir (NULL, "pt", 2, NULL); devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT, - major, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + major, 0, S_IFCHR | S_IRUSR | S_IWUSR, &pt_fops, NULL); devfs_register_series (devfs_handle, "%un", 4, DEVFS_FL_DEFAULT, - major, 128, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + major, 128, S_IFCHR | S_IRUSR | S_IWUSR, &pt_fops, NULL); return 0; } @@ -701,19 +702,15 @@ return -EBUSY; } - MOD_INC_USE_COUNT; - pt_identify(unit); if (!PT.flags & PT_MEDIA) { PT.access--; - MOD_DEC_USE_COUNT; return -ENODEV; } if ((!PT.flags & PT_WRITE_OK) && (file ->f_mode & 2)) { PT.access--; - MOD_DEC_USE_COUNT; return -EROFS; } @@ -723,7 +720,6 @@ PT.bufptr = kmalloc(PT_BUFSIZE,GFP_KERNEL); if (PT.bufptr == NULL) { PT.access--; - MOD_DEC_USE_COUNT; printk("%s: buffer allocation failed\n",PT.name); return -ENOMEM; } @@ -785,8 +781,6 @@ kfree(PT.bufptr); PT.bufptr = NULL; - - MOD_DEC_USE_COUNT; return 0; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/raid0.c linux/drivers/block/raid0.c --- v2.4.0-test1/linux/drivers/block/raid0.c Fri May 12 14:18:55 2000 +++ linux/drivers/block/raid0.c Wed Jun 21 10:10:02 2000 @@ -325,17 +325,11 @@ static mdk_personality_t raid0_personality= { - "raid0", - raid0_make_request, - NULL, /* no special end_request */ - raid0_run, - raid0_stop, - raid0_status, - 0, - NULL, /* no error_handler */ - NULL, /* no diskop */ - NULL, /* no stop resync */ - NULL /* no restart resync */ + name: "raid0", + make_request: raid0_make_request, + run: raid0_run, + stop: raid0_stop, + status: raid0_status, }; #ifndef MODULE diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/raid1.c linux/drivers/block/raid1.c --- v2.4.0-test1/linux/drivers/block/raid1.c Fri May 12 14:18:55 2000 +++ linux/drivers/block/raid1.c Wed Jun 21 10:10:02 2000 @@ -7,6 +7,11 @@ * * RAID-1 management functions. * + * Better read-balancing code written by Mika Kuoppala , 2000 + * + * Fixes to reconstruction by Jakob Østergaard" + * Various fixes by Neil Brown + * * This program is free software; you can redistribute 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) @@ -26,10 +31,7 @@ #define MD_DRIVER #define MD_PERSONALITY -#define MAX_LINEAR_SECTORS 128 - -#define MAX(a,b) ((a) > (b) ? (a) : (b)) -#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX_WORK_PER_DISK 128 /* * The following can be used to debug the driver @@ -41,48 +43,256 @@ #define inline #define __inline__ #else -#define inline -#define __inline__ #define PRINTK(x...) do { } while (0) #endif static mdk_personality_t raid1_personality; static md_spinlock_t retry_list_lock = MD_SPIN_LOCK_UNLOCKED; -struct buffer_head *raid1_retry_list = NULL, **raid1_retry_tail; +struct raid1_bh *raid1_retry_list = NULL, **raid1_retry_tail; -static void * raid1_kmalloc (int size) +static struct buffer_head *raid1_alloc_bh(raid1_conf_t *conf, int cnt) { - void * ptr; - /* - * now we are rather fault tolerant than nice, but - * there are a couple of places in the RAID code where we - * simply can not afford to fail an allocation because - * there is no failure return path (eg. make_request()) - */ - while (!(ptr = kmalloc (size, GFP_KERNEL))) - printk ("raid1: out of memory, retrying...\n"); + /* return a linked list of "cnt" struct buffer_heads. + * don't take any off the free list unless we know we can + * get all we need, otherwise we could deadlock + */ + struct buffer_head *bh=NULL; + + while(cnt) { + struct buffer_head *t; + md_spin_lock_irq(&conf->device_lock); + if (conf->freebh_cnt >= cnt) + while (cnt) { + t = conf->freebh; + conf->freebh = t->b_next; + t->b_next = bh; + bh = t; + t->b_state = 0; + conf->freebh_cnt--; + cnt--; + } + md_spin_unlock_irq(&conf->device_lock); + if (cnt == 0) + break; + t = (struct buffer_head *)kmalloc(sizeof(struct buffer_head), GFP_KERNEL); + if (t) { + memset(t, 0, sizeof(*t)); + t->b_next = bh; + bh = t; + cnt--; + } else { + PRINTK("waiting for %d bh\n", cnt); + wait_event(conf->wait_buffer, conf->freebh_cnt >= cnt); + } + } + return bh; +} - memset(ptr, 0, size); - return ptr; +static inline void raid1_free_bh(raid1_conf_t *conf, struct buffer_head *bh) +{ + md_spin_lock_irq(&conf->device_lock); + while (bh) { + struct buffer_head *t = bh; + bh=bh->b_next; + if (t->b_pprev == NULL) + kfree(t); + else { + t->b_next= conf->freebh; + conf->freebh = t; + conf->freebh_cnt++; + } + } + md_spin_unlock_irq(&conf->device_lock); + wake_up(&conf->wait_buffer); } -static struct page * raid1_gfp (void) +static int raid1_grow_bh(raid1_conf_t *conf, int cnt) { - struct page *page; - /* - * now we are rather fault tolerant than nice, but - * there are a couple of places in the RAID code where we - * simply can not afford to fail an allocation because - * there is no failure return path (eg. make_request()) - * FIXME: be nicer here. - */ - while (!(page = (void*)alloc_page(GFP_KERNEL))) { - printk ("raid1: GFP out of memory, retrying...\n"); - schedule_timeout(2); + /* allocate cnt buffer_heads, possibly less if kalloc fails */ + int i = 0; + + while (i < cnt) { + struct buffer_head *bh; + bh = kmalloc(sizeof(*bh), GFP_KERNEL); + if (!bh) break; + memset(bh, 0, sizeof(*bh)); + + md_spin_lock_irq(&conf->device_lock); + bh->b_pprev = &conf->freebh; + bh->b_next = conf->freebh; + conf->freebh = bh; + conf->freebh_cnt++; + md_spin_unlock_irq(&conf->device_lock); + + i++; + } + return i; +} + +static int raid1_shrink_bh(raid1_conf_t *conf, int cnt) +{ + /* discard cnt buffer_heads, if we can find them */ + int i = 0; + + md_spin_lock_irq(&conf->device_lock); + while ((i < cnt) && conf->freebh) { + struct buffer_head *bh = conf->freebh; + conf->freebh = bh->b_next; + kfree(bh); + i++; + conf->freebh_cnt--; } + md_spin_unlock_irq(&conf->device_lock); + return i; +} + - return page; +static struct raid1_bh *raid1_alloc_r1bh(raid1_conf_t *conf) +{ + struct raid1_bh *r1_bh = NULL; + + do { + md_spin_lock_irq(&conf->device_lock); + if (conf->freer1) { + r1_bh = conf->freer1; + conf->freer1 = r1_bh->next_r1; + r1_bh->next_r1 = NULL; + r1_bh->state = 0; + r1_bh->bh_req.b_state = 0; + } + md_spin_unlock_irq(&conf->device_lock); + if (r1_bh) + return r1_bh; + r1_bh = (struct raid1_bh *) kmalloc(sizeof(struct raid1_bh), + GFP_KERNEL); + if (r1_bh) { + memset(r1_bh, 0, sizeof(*r1_bh)); + return r1_bh; + } + wait_event(conf->wait_buffer, conf->freer1); + } while (1); +} + +static inline void raid1_free_r1bh(struct raid1_bh *r1_bh) +{ + struct buffer_head *bh = r1_bh->mirror_bh_list; + raid1_conf_t *conf = mddev_to_conf(r1_bh->mddev); + + r1_bh->mirror_bh_list = NULL; + + if (test_bit(R1BH_PreAlloc, &r1_bh->state)) { + md_spin_lock_irq(&conf->device_lock); + r1_bh->next_r1 = conf->freer1; + conf->freer1 = r1_bh; + md_spin_unlock_irq(&conf->device_lock); + } else { + kfree(r1_bh); + } + raid1_free_bh(conf, bh); +} + +static int raid1_grow_r1bh (raid1_conf_t *conf, int cnt) +{ + int i = 0; + + while (i < cnt) { + struct raid1_bh *r1_bh; + r1_bh = (struct raid1_bh*)kmalloc(sizeof(*r1_bh), GFP_KERNEL); + if (!r1_bh) + break; + memset(r1_bh, 0, sizeof(*r1_bh)); + + md_spin_lock_irq(&conf->device_lock); + set_bit(R1BH_PreAlloc, &r1_bh->state); + r1_bh->next_r1 = conf->freer1; + conf->freer1 = r1_bh; + md_spin_unlock_irq(&conf->device_lock); + + i++; + } + return i; +} + +static void raid1_shrink_r1bh(raid1_conf_t *conf) +{ + md_spin_lock_irq(&conf->device_lock); + while (conf->freer1) { + struct raid1_bh *r1_bh = conf->freer1; + conf->freer1 = r1_bh->next_r1; + kfree(r1_bh); + } + md_spin_unlock_irq(&conf->device_lock); +} + + + +static inline void raid1_free_buf(struct raid1_bh *r1_bh) +{ + struct buffer_head *bh = r1_bh->mirror_bh_list; + raid1_conf_t *conf = mddev_to_conf(r1_bh->mddev); + r1_bh->mirror_bh_list = NULL; + + md_spin_lock_irq(&conf->device_lock); + r1_bh->next_r1 = conf->freebuf; + conf->freebuf = r1_bh; + md_spin_unlock_irq(&conf->device_lock); + raid1_free_bh(conf, bh); +} + +static struct raid1_bh *raid1_alloc_buf(raid1_conf_t *conf) +{ + struct raid1_bh *r1_bh; + + md_spin_lock_irq(&conf->device_lock); + wait_event_lock_irq(conf->wait_buffer, conf->freebuf, conf->device_lock); + r1_bh = conf->freebuf; + conf->freebuf = r1_bh->next_r1; + r1_bh->next_r1= NULL; + md_spin_unlock_irq(&conf->device_lock); + + return r1_bh; +} + +static int raid1_grow_buffers (raid1_conf_t *conf, int cnt) +{ + int i = 0; + + md_spin_lock_irq(&conf->device_lock); + while (i < cnt) { + struct raid1_bh *r1_bh; + struct page *page; + + page = alloc_page(GFP_KERNEL); + if (!page) + break; + + r1_bh = (struct raid1_bh *) kmalloc(sizeof(*r1_bh), GFP_KERNEL); + if (!r1_bh) { + __free_page(page); + break; + } + memset(r1_bh, 0, sizeof(*r1_bh)); + r1_bh->bh_req.b_page = page; + r1_bh->bh_req.b_data = (char *) page_address(page); + r1_bh->next_r1 = conf->freebuf; + conf->freebuf = r1_bh; + i++; + } + md_spin_unlock_irq(&conf->device_lock); + return i; +} + +static void raid1_shrink_buffers (raid1_conf_t *conf) +{ + md_spin_lock_irq(&conf->device_lock); + while (conf->freebuf) { + struct raid1_bh *r1_bh = conf->freebuf; + conf->freebuf = r1_bh->next_r1; + __free_page(r1_bh->bh_req.b_page); + kfree(r1_bh); + } + md_spin_unlock_irq(&conf->device_lock); } static int raid1_map (mddev_t *mddev, kdev_t *rdev, unsigned long size) @@ -106,19 +316,18 @@ return (-1); } -static void raid1_reschedule_retry (struct buffer_head *bh) +static void raid1_reschedule_retry (struct raid1_bh *r1_bh) { unsigned long flags; - struct raid1_bh * r1_bh = (struct raid1_bh *)(bh->b_dev_id); mddev_t *mddev = r1_bh->mddev; raid1_conf_t *conf = mddev_to_conf(mddev); md_spin_lock_irqsave(&retry_list_lock, flags); if (raid1_retry_list == NULL) raid1_retry_tail = &raid1_retry_list; - *raid1_retry_tail = bh; - raid1_retry_tail = &r1_bh->next_retry; - r1_bh->next_retry = NULL; + *raid1_retry_tail = r1_bh; + raid1_retry_tail = &r1_bh->next_r1; + r1_bh->next_r1 = NULL; md_spin_unlock_irqrestore(&retry_list_lock, flags); md_wakeup_thread(conf->thread); } @@ -166,7 +375,7 @@ test_bit(R1BH_SyncPhase, &r1_bh->state)); bh->b_end_io(bh, uptodate); - kfree(r1_bh); + raid1_free_r1bh(r1_bh); } void raid1_end_request (struct buffer_head *bh, int uptodate) { @@ -176,7 +385,7 @@ * this branch is our 'one mirror IO has finished' event handler: */ if (!uptodate) - md_error (bh->b_dev, bh->b_rdev); + md_error (mddev_to_kdev(r1_bh->mddev), bh->b_dev); else /* * Set R1BH_Uptodate in our master buffer_head, so that @@ -208,7 +417,7 @@ */ printk(KERN_ERR "raid1: %s: rescheduling block %lu\n", partition_name(bh->b_dev), bh->b_blocknr); - raid1_reschedule_retry(bh); + raid1_reschedule_retry(r1_bh); return; } @@ -219,29 +428,128 @@ * already. */ - if (atomic_dec_and_test(&r1_bh->remaining)) { - int i, disks = MD_SB_DISKS; + if (atomic_dec_and_test(&r1_bh->remaining)) + raid1_end_bh_io(r1_bh, test_bit(R1BH_Uptodate, &r1_bh->state)); +} - for ( i = 0; i < disks; i++) { - struct buffer_head *bh = r1_bh->mirror_bh[i]; - if (bh) { - // FIXME: make us a regular bcache member - kfree(bh); - } +/* + * This routine returns the disk from which the requested read should + * be done. It bookkeeps the last read position for every disk + * in array and when new read requests come, the disk which last + * position is nearest to the request, is chosen. + * + * TODO: now if there are 2 mirrors in the same 2 devices, performance + * degrades dramatically because position is mirror, not device based. + * This should be changed to be device based. Also atomic sequential + * reads should be somehow balanced. + */ + +static int raid1_read_balance (raid1_conf_t *conf, struct buffer_head *bh) +{ + int new_disk = conf->last_used; + const int sectors = bh->b_size >> 9; + const long this_sector = bh->b_blocknr * sectors; + int disk = new_disk; + unsigned long new_distance; + unsigned long current_distance; + + /* + * Check if it is sane at all to balance + */ + + if (conf->resync_mirrors) + goto rb_out; + + if (conf->working_disks < 2) { + int i = 0; + + while( !conf->mirrors[new_disk].operational && + (i < MD_SB_DISKS) ) { + new_disk = conf->mirrors[new_disk].next; + i++; } + + if (i >= MD_SB_DISKS) { + /* + * This means no working disk was found + * Nothing much to do, lets not change anything + * and hope for the best... + */ + + new_disk = conf->last_used; + } + + goto rb_out; + } - raid1_end_bh_io(r1_bh, test_bit(R1BH_Uptodate, &r1_bh->state)); + /* + * Don't touch anything for sequential reads. + */ + + if (this_sector == conf->mirrors[new_disk].head_position) + goto rb_out; + + /* + * If reads have been done only on a single disk + * for a time, lets give another disk a change. + * This is for kicking those idling disks so that + * they would find work near some hotspot. + */ + + if (conf->sect_count >= conf->mirrors[new_disk].sect_limit) { + conf->sect_count = 0; + + while( new_disk != conf->mirrors[new_disk].next ) { + if ((conf->mirrors[new_disk].write_only) || + (!conf->mirrors[new_disk].operational) ) + continue; + + new_disk = conf->mirrors[new_disk].next; + break; + } + + goto rb_out; } + + current_distance = abs(this_sector - + conf->mirrors[disk].head_position); + + /* Find the disk which is closest */ + + while( conf->mirrors[disk].next != conf->last_used ) { + disk = conf->mirrors[disk].next; + + if ((conf->mirrors[disk].write_only) || + (!conf->mirrors[disk].operational)) + continue; + + new_distance = abs(this_sector - + conf->mirrors[disk].head_position); + + if (new_distance < current_distance) { + conf->sect_count = 0; + current_distance = new_distance; + new_disk = disk; + } + } + +rb_out: + conf->mirrors[new_disk].head_position = this_sector + sectors; + + conf->last_used = new_disk; + conf->sect_count += sectors; + + return new_disk; } static int raid1_make_request (request_queue_t *q, mddev_t *mddev, int rw, struct buffer_head * bh) { raid1_conf_t *conf = mddev_to_conf(mddev); - struct buffer_head *mirror_bh[MD_SB_DISKS], *bh_req; + struct buffer_head *bh_req, *bhl; struct raid1_bh * r1_bh; int disks = MD_SB_DISKS; - int i, sum_bhs = 0, switch_disks = 0, sectors; + int i, sum_bhs = 0, sectors; struct mirror_info *mirror; DECLARE_WAITQUEUE(wait, current); @@ -279,8 +587,7 @@ return 0; } } - r1_bh = raid1_kmalloc (sizeof (struct raid1_bh)); - + r1_bh = raid1_alloc_r1bh (conf); spin_lock_irq(&conf->segment_lock); wait_event_lock_irq(conf->wait_done, @@ -305,41 +612,20 @@ r1_bh->master_bh = bh; r1_bh->mddev = mddev; r1_bh->cmd = rw; - bh->b_rsector = bh->b_blocknr * (bh->b_size>>9); + sectors = bh->b_size >> 9; if (rw == READ) { - int last_used = conf->last_used; - /* * read balancing logic: */ - mirror = conf->mirrors + last_used; - bh->b_rdev = mirror->dev; - sectors = bh->b_size >> 9; - - switch_disks = 0; - if (bh->b_blocknr * sectors == conf->next_sect) { - conf->sect_count += sectors; - if (conf->sect_count >= mirror->sect_limit) - switch_disks = 1; - } else - switch_disks = 1; - conf->next_sect = (bh->b_blocknr + 1) * sectors; - /* - * Do not switch disks if full resync is in progress ... - */ - if (switch_disks && !conf->resync_mirrors) { - conf->sect_count = 0; - last_used = conf->last_used = mirror->next; - /* - * Do not switch to write-only disks ... - * reconstruction is in progress - */ - while (conf->mirrors[last_used].write_only) - conf->last_used = conf->mirrors[last_used].next; - } + mirror = conf->mirrors + raid1_read_balance(conf, bh); + bh_req = &r1_bh->bh_req; memcpy(bh_req, bh, sizeof(*bh)); + bh_req->b_blocknr = bh->b_rsector * sectors; + bh_req->b_dev = mirror->dev; + bh_req->b_rdev = mirror->dev; + /* bh_req->b_rsector = bh->n_rsector; */ bh_req->b_end_io = raid1_end_request; bh_req->b_dev_id = r1_bh; q = blk_get_queue(bh_req->b_rdev); @@ -351,15 +637,11 @@ * WRITE: */ + bhl = raid1_alloc_bh(conf, conf->raid_disks); for (i = 0; i < disks; i++) { - - if (!conf->mirrors[i].operational) { - /* - * the r1_bh->mirror_bh[i] pointer remains NULL - */ - mirror_bh[i] = NULL; + struct buffer_head *mbh; + if (!conf->mirrors[i].operational) continue; - } /* * We should use a private pool (size depending on NR_REQUEST), @@ -373,30 +655,38 @@ * manner in the write branch. Look how we lock the buffer at the * beginning of this function to grok the difference ;) */ - mirror_bh[i] = raid1_kmalloc(sizeof(struct buffer_head)); - mirror_bh[i]->b_this_page = (struct buffer_head *)1; + mbh = bhl; + if (mbh == NULL) { + MD_BUG(); + break; + } + bhl = mbh->b_next; + mbh->b_next = NULL; + mbh->b_this_page = (struct buffer_head *)1; /* - * prepare mirrored bh (fields ordered for max mem throughput): + * prepare mirrored mbh (fields ordered for max mem throughput): */ - mirror_bh[i]->b_blocknr = bh->b_blocknr; - mirror_bh[i]->b_dev = bh->b_dev; - mirror_bh[i]->b_rdev = conf->mirrors[i].dev; - mirror_bh[i]->b_rsector = bh->b_rsector; - mirror_bh[i]->b_state = (1<b_blocknr = bh->b_rsector * sectors; + mbh->b_dev = conf->mirrors[i].dev; + mbh->b_rdev = conf->mirrors[i].dev; + mbh->b_rsector = bh->b_rsector; + mbh->b_state = (1<b_count, 1); - mirror_bh[i]->b_size = bh->b_size; - mirror_bh[i]->b_data = bh->b_data; - mirror_bh[i]->b_list = BUF_LOCKED; - mirror_bh[i]->b_end_io = raid1_end_request; - mirror_bh[i]->b_dev_id = r1_bh; - - r1_bh->mirror_bh[i] = mirror_bh[i]; + atomic_set(&mbh->b_count, 1); + mbh->b_size = bh->b_size; + mbh->b_page = bh->b_page; + mbh->b_data = bh->b_data; + mbh->b_list = BUF_LOCKED; + mbh->b_end_io = raid1_end_request; + mbh->b_dev_id = r1_bh; + + mbh->b_next = r1_bh->mirror_bh_list; + r1_bh->mirror_bh_list = mbh; sum_bhs++; } - + if (bhl) raid1_free_bh(conf,bhl); md_atomic_set(&r1_bh->remaining, sum_bhs); /* @@ -410,12 +700,12 @@ * all requests finish until we had a chance to set up the * semaphore correctly ... lots of races). */ - for (i = 0; i < disks; i++) { - struct buffer_head *mbh = mirror_bh[i]; - if (mbh) { - q = blk_get_queue(mbh->b_rdev); - generic_make_request(q, rw, mbh); - } + bh = r1_bh->mirror_bh_list; + while(bh) { + struct buffer_head *bh2 = bh; + bh = bh->b_next; + q = blk_get_queue(bh2->b_rdev); + generic_make_request(q, rw, bh2); } return (0); } @@ -792,6 +1082,7 @@ adisk->write_only = 0; adisk->spare = 1; adisk->used_slot = 1; + adisk->head_position = 0; conf->nr_disks++; break; @@ -803,6 +1094,10 @@ } abort: md_spin_unlock_irq(&conf->device_lock); + if (state == DISKOP_SPARE_ACTIVE || state == DISKOP_SPARE_INACTIVE) + /* should move to "END_REBUILD" when such exists */ + raid1_shrink_buffers(conf); + print_raid1_conf(conf); return err; } @@ -836,19 +1131,19 @@ for (;;) { md_spin_lock_irqsave(&retry_list_lock, flags); - bh = raid1_retry_list; - if (!bh) + r1_bh = raid1_retry_list; + if (!r1_bh) break; - r1_bh = (struct raid1_bh *)(bh->b_dev_id); - raid1_retry_list = r1_bh->next_retry; + raid1_retry_list = r1_bh->next_r1; md_spin_unlock_irqrestore(&retry_list_lock, flags); - mddev = kdev_to_mddev(bh->b_dev); + mddev = r1_bh->mddev; if (mddev->sb_dirty) { printk(KERN_INFO "dirty sb detected, updating.\n"); mddev->sb_dirty = 0; md_update_sb(mddev); } + bh = &r1_bh->bh_req; switch(r1_bh->cmd) { case SPECIAL: /* have to allocate lots of bh structures and @@ -857,68 +1152,74 @@ if (test_bit(R1BH_Uptodate, &r1_bh->state)) { int i, sum_bhs = 0; int disks = MD_SB_DISKS; - struct buffer_head *mirror_bh[MD_SB_DISKS]; + struct buffer_head *bhl, *mbh; raid1_conf_t *conf; + int sectors = bh->b_size >> 9; conf = mddev_to_conf(mddev); + bhl = raid1_alloc_bh(conf, conf->raid_disks); /* don't really need this many */ for (i = 0; i < disks ; i++) { - if (!conf->mirrors[i].operational) { - mirror_bh[i] = NULL; + if (!conf->mirrors[i].operational) continue; - } - if (i==conf->last_used) { + if (i==conf->last_used) /* we read from here, no need to write */ - mirror_bh[i] = NULL; continue; - } if (i < conf->raid_disks - && !conf->resync_mirrors) { + && !conf->resync_mirrors) /* don't need to write this, * we are just rebuilding */ - mirror_bh[i] = NULL; continue; + mbh = bhl; + if (!mbh) { + MD_BUG(); + break; } + bhl = mbh->b_next; + mbh->b_this_page = (struct buffer_head *)1; - mirror_bh[i] = raid1_kmalloc(sizeof(struct buffer_head)); - mirror_bh[i]->b_this_page = (struct buffer_head *)1; /* * prepare mirrored bh (fields ordered for max mem throughput): */ - mirror_bh[i]->b_blocknr = bh->b_blocknr; - mirror_bh[i]->b_dev = bh->b_dev; - mirror_bh[i]->b_rdev = conf->mirrors[i].dev; - mirror_bh[i]->b_rsector = bh->b_rsector; - mirror_bh[i]->b_state = (1<b_blocknr = bh->b_blocknr; + mbh->b_dev = conf->mirrors[i].dev; + mbh->b_rdev = conf->mirrors[i].dev; + mbh->b_rsector = bh->b_blocknr * sectors; + mbh->b_state = (1<b_count, 1); + mbh->b_size = bh->b_size; + mbh->b_page = bh->b_page; + mbh->b_data = bh->b_data; + mbh->b_list = BUF_LOCKED; + mbh->b_end_io = end_sync_write; + mbh->b_dev_id = r1_bh; + + mbh->b_next = r1_bh->mirror_bh_list; + r1_bh->mirror_bh_list = mbh; - atomic_set(&mirror_bh[i]->b_count, 1); - mirror_bh[i]->b_size = bh->b_size; - mirror_bh[i]->b_data = bh->b_data; - mirror_bh[i]->b_list = BUF_LOCKED; - mirror_bh[i]->b_end_io = end_sync_write; - mirror_bh[i]->b_dev_id = r1_bh; - - r1_bh->mirror_bh[i] = mirror_bh[i]; sum_bhs++; } md_atomic_set(&r1_bh->remaining, sum_bhs); - for ( i = 0; i < disks ; i++) { - struct buffer_head *mbh = mirror_bh[i]; - if (mbh) { - q = blk_get_queue(mbh->b_rdev); - generic_make_request(q, WRITE, mbh); - } + if (bhl) raid1_free_bh(conf, bhl); + mbh = r1_bh->mirror_bh_list; + while (mbh) { + struct buffer_head *bh1 = mbh; + mbh = mbh->b_next; + q = blk_get_queue(bh1->b_rdev); + generic_make_request(q, WRITE, bh1); + drive_stat_acct(bh1->b_rdev, WRITE, -bh1->b_size/512, 0); } } else { - dev = bh->b_rdev; - raid1_map (mddev, &bh->b_rdev, bh->b_size >> 9); - if (bh->b_rdev == dev) { + dev = bh->b_dev; + raid1_map (mddev, &bh->b_dev, bh->b_size >> 9); + if (bh->b_dev == dev) { printk (IO_ERROR, partition_name(bh->b_dev), bh->b_blocknr); md_done_sync(mddev, bh->b_size>>10, 0); } else { printk (REDIRECT_SECTOR, partition_name(bh->b_dev), bh->b_blocknr); + bh->b_rdev = bh->b_dev; q = blk_get_queue(bh->b_rdev); generic_make_request (q, READ, bh); } @@ -927,15 +1228,16 @@ break; case READ: case READA: - dev = bh->b_rdev; + dev = bh->b_dev; - raid1_map (mddev, &bh->b_rdev, bh->b_size >> 9); - if (bh->b_rdev == dev) { + raid1_map (mddev, &bh->b_dev, bh->b_size >> 9); + if (bh->b_dev == dev) { printk (IO_ERROR, partition_name(bh->b_dev), bh->b_blocknr); raid1_end_bh_io(r1_bh, 0); } else { printk (REDIRECT_SECTOR, partition_name(bh->b_dev), bh->b_blocknr); + bh->b_rdev = bh->b_dev; q = blk_get_queue(bh->b_rdev); generic_make_request (q, r1_bh->cmd, bh); } @@ -961,15 +1263,37 @@ if (conf->resync_mirrors == 2) return; down(&mddev->recovery_sem); - if (md_do_sync(mddev, NULL)) { - up(&mddev->recovery_sem); - return; + if (!md_do_sync(mddev, NULL)) { + /* + * Only if everything went Ok. + */ + conf->resync_mirrors = 0; } - /* - * Only if everything went Ok. + + /* If reconstruction was interrupted, we need to close the "active" and "pending" + * holes. + * we know that there are no active rebuild requests, os cnt_active == cnt_ready ==0 */ - conf->resync_mirrors = 0; + /* this is really needed when recovery stops too... */ + spin_lock_irq(&conf->segment_lock); + conf->start_active = conf->start_pending; + conf->start_ready = conf->start_pending; + wait_event_lock_irq(conf->wait_ready, !conf->cnt_pending, conf->segment_lock); + conf->start_active =conf->start_ready = conf->start_pending = conf->start_future; + conf->start_future = mddev->sb->size+1; + conf->cnt_pending = conf->cnt_future; + conf->cnt_future = 0; + conf->phase = conf->phase ^1; + wait_event_lock_irq(conf->wait_ready, !conf->cnt_pending, conf->segment_lock); + conf->start_active = conf->start_ready = conf->start_pending = conf->start_future = 0; + conf->phase = 0; + conf->cnt_future = conf->cnt_done;; + conf->cnt_done = 0; + spin_unlock_irq(&conf->segment_lock); + wake_up(&conf->wait_done); + up(&mddev->recovery_sem); + raid1_shrink_buffers(conf); } /* @@ -1032,12 +1356,19 @@ spin_lock_irq(&conf->segment_lock); if (!block_nr) { /* initialize ...*/ + int buffs; conf->start_active = 0; conf->start_ready = 0; conf->start_pending = 0; conf->start_future = 0; conf->phase = 0; - conf->window = 128; + /* we want enough buffers to hold twice the window of 128*/ + buffs = 128 *2 / (PAGE_SIZE>>9); + buffs = raid1_grow_buffers(conf, buffs); + if (buffs < 2) + goto nomem; + + conf->window = buffs*(PAGE_SIZE>>9)/2; conf->cnt_future += conf->cnt_done+conf->cnt_pending; conf->cnt_done = conf->cnt_pending = 0; if (conf->cnt_ready || conf->cnt_active) @@ -1057,7 +1388,7 @@ conf->start_ready = conf->start_pending; conf->start_pending = conf->start_future; conf->start_future = conf->start_future+conf->window; - // Note: falling of the end is not a problem + // Note: falling off the end is not a problem conf->phase = conf->phase ^1; conf->cnt_active = conf->cnt_ready; conf->cnt_ready = 0; @@ -1075,12 +1406,11 @@ */ mirror = conf->mirrors+conf->last_used; - r1_bh = raid1_kmalloc (sizeof (struct raid1_bh)); + r1_bh = raid1_alloc_buf (conf); r1_bh->master_bh = NULL; r1_bh->mddev = mddev; r1_bh->cmd = SPECIAL; bh = &r1_bh->bh_req; - memset(bh, 0, sizeof(*bh)); bh->b_blocknr = block_nr; bsize = 1024; @@ -1091,11 +1421,15 @@ } bh->b_size = bsize; bh->b_list = BUF_LOCKED; - bh->b_dev = mddev_to_kdev(mddev); + bh->b_dev = mirror->dev; bh->b_rdev = mirror->dev; bh->b_state = (1<b_page = raid1_gfp(); - bh->b_data = (char *) page_address(bh->b_page); + if (!bh->b_page) + BUG(); + if (!bh->b_data) + BUG(); + if (bh->b_data != (char *) page_address(bh->b_page)) + BUG(); bh->b_end_io = end_sync_read; bh->b_dev_id = (void *) r1_bh; bh->b_rsector = block_nr<<1; @@ -1106,6 +1440,11 @@ drive_stat_acct(bh->b_rdev, READ, -bh->b_size/512, 0); return (bsize >> 10); + +nomem: + raid1_shrink_buffers(conf); + spin_unlock_irq(&conf->segment_lock); + return -ENOMEM; } static void end_sync_read(struct buffer_head *bh, int uptodate) @@ -1117,10 +1456,10 @@ * We don't do much here, just schedule handling by raid1d */ if (!uptodate) - md_error (bh->b_dev, bh->b_rdev); + md_error (mddev_to_kdev(r1_bh->mddev), bh->b_dev); else set_bit(R1BH_Uptodate, &r1_bh->state); - raid1_reschedule_retry(bh); + raid1_reschedule_retry(r1_bh); } static void end_sync_write(struct buffer_head *bh, int uptodate) @@ -1128,22 +1467,12 @@ struct raid1_bh * r1_bh = (struct raid1_bh *)(bh->b_dev_id); if (!uptodate) - md_error (bh->b_dev, bh->b_rdev); + md_error (mddev_to_kdev(r1_bh->mddev), bh->b_dev); if (atomic_dec_and_test(&r1_bh->remaining)) { - int i, disks = MD_SB_DISKS; mddev_t *mddev = r1_bh->mddev; - unsigned long sect = bh->b_rsector; + unsigned long sect = bh->b_blocknr * (bh->b_size>>9); int size = bh->b_size; - - free_page((unsigned long)bh->b_data); - for ( i = 0; i < disks; i++) { - struct buffer_head *bh = r1_bh->mirror_bh[i]; - if (bh) { - // FIXME: make us a regular bcache member - kfree(bh); - } - } - kfree(r1_bh); + raid1_free_buf(r1_bh); sync_request_done(sect, mddev_to_conf(mddev)); md_done_sync(mddev,size>>10, uptodate); } @@ -1277,12 +1606,13 @@ * should be freed in raid1_stop()] */ - conf = raid1_kmalloc(sizeof(raid1_conf_t)); + conf = kmalloc(sizeof(raid1_conf_t), GFP_KERNEL); mddev->private = conf; if (!conf) { printk(MEM_ERROR, mdidx(mddev)); goto out; } + memset(conf, 0, sizeof(*conf)); ITERATE_RDEV(mddev,rdev,tmp) { if (rdev->faulty) { @@ -1305,11 +1635,12 @@ disk->number = descriptor->number; disk->raid_disk = disk_idx; disk->dev = rdev->dev; - disk->sect_limit = MAX_LINEAR_SECTORS; + disk->sect_limit = MAX_WORK_PER_DISK; disk->operational = 0; disk->write_only = 0; disk->spare = 0; disk->used_slot = 1; + disk->head_position = 0; continue; } if (disk_active(descriptor)) { @@ -1336,11 +1667,12 @@ disk->number = descriptor->number; disk->raid_disk = disk_idx; disk->dev = rdev->dev; - disk->sect_limit = MAX_LINEAR_SECTORS; + disk->sect_limit = MAX_WORK_PER_DISK; disk->operational = 1; disk->write_only = 0; disk->spare = 0; disk->used_slot = 1; + disk->head_position = 0; conf->working_disks++; } else { /* @@ -1350,27 +1682,43 @@ disk->number = descriptor->number; disk->raid_disk = disk_idx; disk->dev = rdev->dev; - disk->sect_limit = MAX_LINEAR_SECTORS; + disk->sect_limit = MAX_WORK_PER_DISK; disk->operational = 0; disk->write_only = 0; disk->spare = 1; disk->used_slot = 1; + disk->head_position = 0; } } - if (!conf->working_disks) { - printk(NONE_OPERATIONAL, mdidx(mddev)); - goto out_free_conf; - } - conf->raid_disks = sb->raid_disks; conf->nr_disks = sb->nr_disks; conf->mddev = mddev; conf->device_lock = MD_SPIN_LOCK_UNLOCKED; conf->segment_lock = MD_SPIN_LOCK_UNLOCKED; + init_waitqueue_head(&conf->wait_buffer); init_waitqueue_head(&conf->wait_done); init_waitqueue_head(&conf->wait_ready); + if (!conf->working_disks) { + printk(NONE_OPERATIONAL, mdidx(mddev)); + goto out_free_conf; + } + + + /* pre-allocate some buffer_head structures. + * As a minimum, 1 r1bh and raid_disks buffer_heads + * would probably get us by in tight memory situations, + * but a few more is probably a good idea. + * For now, try 16 r1bh and 16*raid_disks bufferheads + * This will allow at least 16 concurrent reads or writes + * even if kmalloc starts failing + */ + if (raid1_grow_r1bh(conf, 16) < 16 || + raid1_grow_bh(conf, 16*conf->raid_disks)< 16*conf->raid_disks) { + printk(MEM_ERROR, mdidx(mddev)); + goto out_free_conf; + } for (i = 0; i < MD_SB_DISKS; i++) { @@ -1389,6 +1737,7 @@ disk->write_only = 0; disk->spare = 0; disk->used_slot = 1; + disk->head_position = 0; } } @@ -1476,6 +1825,9 @@ return 0; out_free_conf: + raid1_shrink_r1bh(conf); + raid1_shrink_bh(conf, conf->freebh_cnt); + raid1_shrink_buffers(conf); kfree(conf); mddev->private = NULL; out: @@ -1504,29 +1856,6 @@ conf->resync_mirrors = 2; md_interrupt_thread(conf->resync_thread); - /* this is really needed when recovery stops too... */ - spin_lock_irq(&conf->segment_lock); - wait_event_lock_irq(conf->wait_done, !conf->cnt_active, conf->segment_lock); - conf->start_active = conf->start_ready; - conf->start_ready = conf->start_pending; - conf->cnt_active = conf->cnt_ready; - conf->cnt_ready = 0; - wait_event_lock_irq(conf->wait_done, !conf->cnt_active, conf->segment_lock); - conf->start_active = conf->start_ready; - conf->cnt_ready = 0; - wait_event_lock_irq(conf->wait_ready, !conf->cnt_pending, conf->segment_lock); - conf->start_active =conf->start_ready = conf->start_pending = conf->start_future; - conf->start_future = mddev->sb->size+1; - conf->cnt_pending = conf->cnt_future; - conf->cnt_future = 0; - conf->phase = conf->phase ^1; - wait_event_lock_irq(conf->wait_ready, !conf->cnt_pending, conf->segment_lock); - conf->start_active = conf->start_ready = conf->start_pending = conf->start_future = 0; - conf->phase = 0; - conf->cnt_done = conf->cnt_future; - conf->cnt_future = 0; - wake_up(&conf->wait_done); - printk(KERN_INFO "raid1: mirror resync was not fully finished, restarting next time.\n"); return 1; } @@ -1558,6 +1887,9 @@ md_unregister_thread(conf->thread); if (conf->resync_thread) md_unregister_thread(conf->resync_thread); + raid1_shrink_r1bh(conf); + raid1_shrink_bh(conf, conf->freebh_cnt); + raid1_shrink_buffers(conf); kfree(conf); mddev->private = NULL; MOD_DEC_USE_COUNT; @@ -1566,18 +1898,16 @@ static mdk_personality_t raid1_personality= { - "raid1", - raid1_make_request, - raid1_end_request, - raid1_run, - raid1_stop, - raid1_status, - 0, - raid1_error, - raid1_diskop, - raid1_stop_resync, - raid1_restart_resync, - raid1_sync_request + name: "raid1", + make_request: raid1_make_request, + run: raid1_run, + stop: raid1_stop, + status: raid1_status, + error_handler: raid1_error, + diskop: raid1_diskop, + stop_resync: raid1_stop_resync, + restart_resync: raid1_restart_resync, + sync_request: raid1_sync_request }; int raid1_init (void) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/raid5.c linux/drivers/block/raid5.c --- v2.4.0-test1/linux/drivers/block/raid5.c Fri May 12 14:18:55 2000 +++ linux/drivers/block/raid5.c Wed Jun 21 10:10:02 2000 @@ -16,6 +16,7 @@ */ +#include #include #include #include @@ -40,18 +41,21 @@ * The following can be used to debug the driver */ #define RAID5_DEBUG 0 -#define RAID5_PARANOIA 1 -#define CHECK_DEVLOCK() if (!spin_is_locked(&conf->device_lock)) BUG() -#define CHECK_SHLOCK(sh) if (!stripe_locked(sh)) BUG() +#define RAID5_PARANOIA 1 +#if RAID5_PARANOIA && CONFIG_SMP +# define CHECK_DEVLOCK() if (!spin_is_locked(&conf->device_lock)) BUG() +# define CHECK_SHLOCK(sh) if (!stripe_locked(sh)) BUG() +#else +# define CHECK_DEVLOCK() +# define CHECK_SHLOCK(unused) +#endif #if RAID5_DEBUG -#define PRINTK(x...) printk(x) +#define PRINTK(x...) printk(x) #define inline #define __inline__ #else -#define inline -#define __inline__ -#define PRINTK(x...) do { } while (0) +#define PRINTK(x...) do { } while (0) #endif static void print_raid5_conf (raid5_conf_t *conf); @@ -365,8 +369,8 @@ out: md_spin_unlock_irq(&conf->device_lock); PRINTK("shrink completed, nr_hashed_stripes %d, nr_pending_strips %d\n", - atomic_read(&conf->nr_hashed_stripes), - atomic_read(&conf->nr_pending_stripes)); + atomic_read(&conf->nr_hashed_stripes), + atomic_read(&conf->nr_pending_stripes)); return count; } @@ -422,7 +426,7 @@ sh = get_free_stripe(conf); if (!sh && cnt < (conf->max_nr_stripes/8)) { md_wakeup_thread(conf->thread); - PRINTK("waiting for some stripes to complete - %d %d\n", cnt, conf->max_nr_stripes/8); + PRINTK("waiting for some stripes to complete - %d %d\n", cnt, conf->max_nr_stripes/8); schedule(); } remove_wait_queue(&conf->wait_for_stripe, &wait); @@ -570,7 +574,7 @@ { struct buffer_head *bh = sh->bh_new[i]; - PRINTK("raid5_end_buffer_io %lu, uptodate: %d.\n", bh->b_rsector, uptodate); + PRINTK("raid5_end_buffer_io %lu, uptodate: %d.\n", bh->b_blocknr, uptodate); sh->bh_new[i] = NULL; raid5_free_bh(sh, sh->bh_req[i]); sh->bh_req[i] = NULL; @@ -578,7 +582,9 @@ bh->b_end_io(bh, uptodate); if (!uptodate) printk(KERN_ALERT "raid5: %s: unrecoverable I/O error for " - "block %lu\n", partition_name(bh->b_dev), bh->b_blocknr); + "block %lu\n", + partition_name(mddev_to_kdev(sh->raid_conf->mddev)), + bh->b_blocknr); } static inline void raid5_mark_buffer_uptodate (struct buffer_head *bh, int uptodate) @@ -600,14 +606,14 @@ md_spin_lock_irqsave(&sh->stripe_lock, flags); raid5_mark_buffer_uptodate(bh, uptodate); if (!uptodate) - md_error(bh->b_dev, bh->b_rdev); + md_error(mddev_to_kdev(conf->mddev), bh->b_dev); if (conf->failed_disks) { for (i = 0; i < disks; i++) { if (conf->disks[i].operational) continue; if (bh != sh->bh_old[i] && bh != sh->bh_req[i] && bh != sh->bh_copy[i]) continue; - if (bh->b_rdev != conf->disks[i].dev) + if (bh->b_dev != conf->disks[i].dev) continue; set_bit(STRIPE_ERROR, &sh->state); } @@ -623,10 +629,8 @@ static void raid5_build_block (struct stripe_head *sh, struct buffer_head *bh, int i) { raid5_conf_t *conf = sh->raid_conf; - mddev_t *mddev = conf->mddev; char *b_data; struct page *b_page; - kdev_t dev = mddev_to_kdev(mddev); int block = sh->sector / (sh->size >> 9); b_data = bh->b_data; @@ -634,14 +638,14 @@ memset (bh, 0, sizeof (struct buffer_head)); init_waitqueue_head(&bh->b_wait); init_buffer(bh, raid5_end_request, sh); - bh->b_dev = dev; + bh->b_dev = conf->disks[i].dev; bh->b_blocknr = block; bh->b_data = b_data; bh->b_page = b_page; bh->b_rdev = conf->disks[i].dev; - bh->b_rsector = sh->sector; + bh->b_rsector = sh->sector; bh->b_state = (1 << BH_Req) | (1 << BH_Mapped); bh->b_size = sh->size; @@ -708,14 +712,14 @@ } /* - * Input: a 'big' sector number, + * Input: a 'big' sector number, * Output: index of the data and parity disk, and the sector # in them. */ static unsigned long raid5_compute_sector(int r_sector, unsigned int raid_disks, unsigned int data_disks, unsigned int * dd_idx, unsigned int * pd_idx, raid5_conf_t *conf) { - unsigned int stripe; + unsigned int stripe; int chunk_number, chunk_offset; unsigned long new_sector; int sectors_per_chunk = conf->chunk_size >> 9; @@ -770,15 +774,6 @@ * Finally, compute the new sector number */ new_sector = stripe * sectors_per_chunk + chunk_offset; - -#if 0 - if ( *dd_idx > data_disks || *pd_idx > data_disks || - chunk_offset + bh->b_size / 512 > sectors_per_chunk ) - - printk ("raid5: bug: dd_idx == %d, pd_idx == %d, chunk_offset == %d\n", - *dd_idx, *pd_idx, chunk_offset); -#endif - return new_sector; } @@ -849,9 +844,8 @@ count = 1; } } - if(count != 1) { + if (count != 1) xor_block(count, &bh_ptr[0]); - } raid5_mark_buffer_uptodate(sh->bh_old[dd_idx], 1); } @@ -1092,20 +1086,20 @@ if (!operational[i] && !conf->resync_parity) { PRINTK("writing spare %d\n", i); atomic_inc(&sh->nr_pending); - bh->b_rdev = conf->spare->dev; + bh->b_dev = bh->b_rdev = conf->spare->dev; q = blk_get_queue(bh->b_rdev); generic_make_request(q, WRITERAW, bh); } else { #if 0 atomic_inc(&sh->nr_pending); - bh->b_rdev = conf->disks[i].dev; + bh->b_dev = bh->b_rdev = conf->disks[i].dev; q = blk_get_queue(bh->b_rdev); generic_make_request(q, WRITERAW, bh); #else if (!allclean || (i==sh->pd_idx)) { PRINTK("writing dirty %d\n", i); atomic_inc(&sh->nr_pending); - bh->b_rdev = conf->disks[i].dev; + bh->b_dev = bh->b_rdev = conf->disks[i].dev; q = blk_get_queue(bh->b_rdev); generic_make_request(q, WRITERAW, bh); } else { @@ -1151,7 +1145,7 @@ continue; lock_get_bh(sh->bh_old[i]); atomic_inc(&sh->nr_pending); - sh->bh_old[i]->b_rdev = conf->disks[i].dev; + sh->bh_old[i]->b_dev = sh->bh_old[i]->b_rdev = conf->disks[i].dev; q = blk_get_queue(sh->bh_old[i]->b_rdev); generic_make_request(q, READ, sh->bh_old[i]); atomic_dec(&sh->bh_old[i]->b_count); @@ -1198,7 +1192,7 @@ raid5_build_block(sh, sh->bh_old[i], i); lock_get_bh(sh->bh_old[i]); atomic_inc(&sh->nr_pending); - sh->bh_old[i]->b_rdev = conf->disks[i].dev; + sh->bh_old[i]->b_dev = sh->bh_old[i]->b_rdev = conf->disks[i].dev; q = blk_get_queue(sh->bh_old[i]->b_rdev); generic_make_request(q, READ, sh->bh_old[i]); atomic_dec(&sh->bh_old[i]->b_count); @@ -1228,7 +1222,7 @@ #endif lock_get_bh(sh->bh_req[i]); atomic_inc(&sh->nr_pending); - sh->bh_req[i]->b_rdev = conf->disks[i].dev; + sh->bh_req[i]->b_dev = sh->bh_req[i]->b_rdev = conf->disks[i].dev; q = blk_get_queue(sh->bh_req[i]->b_rdev); generic_make_request(q, READ, sh->bh_req[i]); atomic_dec(&sh->bh_req[i]->b_count); @@ -1252,8 +1246,7 @@ * in bh_old */ PRINTK("handle_stripe_sync: sec=%lu disks=%d nr_cache=%d\n", sh->sector, disks, nr_cache); - if (nr_cache < disks-1 - || (nr_cache==disks-1 && !(parity_failed+nr_failed_other+nr_failed_overwrite)) + if ((nr_cache < disks-1) || ((nr_cache == disks-1) && !(parity_failed+nr_failed_other+nr_failed_overwrite)) ) { sh->phase = PHASE_READ_OLD; for (i = 0; i < disks; i++) { @@ -1267,7 +1260,7 @@ raid5_build_block(sh, bh, i); lock_get_bh(bh); atomic_inc(&sh->nr_pending); - bh->b_rdev = conf->disks[i].dev; + bh->b_dev = bh->b_rdev = conf->disks[i].dev; q = blk_get_queue(bh->b_rdev); generic_make_request(q, READ, bh); drive_stat_acct(bh->b_rdev, READ, -bh->b_size/512, 0); @@ -1297,7 +1290,7 @@ } atomic_inc(&sh->nr_pending); lock_get_bh(bh); - bh->b_rdev = conf->spare->dev; + bh->b_dev = bh->b_rdev = conf->spare->dev; q = blk_get_queue(bh->b_rdev); generic_make_request(q, WRITERAW, bh); drive_stat_acct(bh->b_rdev, WRITE, -bh->b_size/512, 0); @@ -1310,7 +1303,7 @@ } /* nr_cache == disks: - * check parity and compute/write if needed + * check parity and compute/write if needed */ compute_parity(sh, RECONSTRUCT_WRITE); @@ -1324,13 +1317,13 @@ atomic_set_buffer_dirty(bh); lock_get_bh(bh); atomic_inc(&sh->nr_pending); - bh->b_rdev = conf->disks[pd_idx].dev; + bh->b_dev = bh->b_rdev = conf->disks[pd_idx].dev; q = blk_get_queue(bh->b_rdev); generic_make_request(q, WRITERAW, bh); drive_stat_acct(bh->b_rdev, WRITE, -bh->b_size/512, 0); atomic_dec(&bh->b_count); PRINTK("handle_stripe_sync() %lu phase WRITE, pending %d buffers\n", - sh->sector, md_atomic_read(&sh->nr_pending)); + sh->sector, md_atomic_read(&sh->nr_pending)); } } @@ -1374,8 +1367,8 @@ } if ((sh->cmd == STRIPE_WRITE && sh->phase == PHASE_WRITE) || - (sh->cmd == STRIPE_READ && sh->phase == PHASE_READ) || - (sh->cmd == STRIPE_SYNC && sh->phase == PHASE_WRITE) + (sh->cmd == STRIPE_READ && sh->phase == PHASE_READ) || + (sh->cmd == STRIPE_SYNC && sh->phase == PHASE_WRITE) ) { /* * Completed @@ -1500,7 +1493,7 @@ raid5_conf_t *conf = (raid5_conf_t *) mddev->private; const unsigned int raid_disks = conf->raid_disks; const unsigned int data_disks = raid_disks - 1; - unsigned int dd_idx, pd_idx; + unsigned int dd_idx, pd_idx; unsigned long new_sector; struct stripe_head *sh; @@ -1508,7 +1501,7 @@ if (rw == READA) rw = READ; - new_sector = raid5_compute_sector(bh->b_blocknr*(bh->b_size>>9), + new_sector = raid5_compute_sector(bh->b_rsector, raid_disks, data_disks, &dd_idx, &pd_idx, conf); PRINTK("raid5_make_request, sector %lu\n", new_sector); @@ -1567,13 +1560,12 @@ if (!conf->buffer_size) conf->buffer_size = /* device_bsize(mddev_to_kdev(mddev))*/ PAGE_SIZE; bufsize = conf->buffer_size; - /* Hmm... race on buffer_size ?? */ + /* Hmm... race on buffer_size ?? */ redone = block_nr% (bufsize>>10); block_nr -= redone; sh = get_lock_stripe(conf, block_nr<<1, bufsize); - first_sector = raid5_compute_sector(stripe*data_disks*sectors_per_chunk+chunk_offset, - raid_disks, data_disks, - &dd_idx, &pd_idx, conf); + first_sector = raid5_compute_sector(stripe*data_disks*sectors_per_chunk + + chunk_offset, raid_disks, data_disks, &dd_idx, &pd_idx, conf); sh->pd_idx = pd_idx; sh->cmd = STRIPE_SYNC; sh->phase = PHASE_BEGIN; @@ -2147,7 +2139,7 @@ } /* * When we activate a spare disk we _must_ have a disk in - * the lower (active) part of the array to replace. + * the lower (active) part of the array to replace. */ if ((failed_disk == -1) || (failed_disk >= conf->raid_disks)) { MD_BUG(); @@ -2380,18 +2372,16 @@ static mdk_personality_t raid5_personality= { - "raid5", - raid5_make_request, - raid5_end_request, - raid5_run, - raid5_stop, - raid5_status, - 0, - raid5_error, - raid5_diskop, - raid5_stop_resync, - raid5_restart_resync, - raid5_sync_request + name: "raid5", + make_request: raid5_make_request, + run: raid5_run, + stop: raid5_stop, + status: raid5_status, + error_handler: raid5_error, + diskop: raid5_diskop, + stop_resync: raid5_stop_resync, + restart_resync: raid5_restart_resync, + sync_request: raid5_sync_request }; int raid5_init (void) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/rd.c linux/drivers/block/rd.c --- v2.4.0-test1/linux/drivers/block/rd.c Mon Jun 19 16:31:58 2000 +++ linux/drivers/block/rd.c Wed Jun 21 22:31:00 2000 @@ -411,7 +411,7 @@ devfs_handle = devfs_mk_dir (NULL, "rd", 0, NULL); devfs_register_series (devfs_handle, "%u", NUM_RAMDISKS, DEVFS_FL_DEFAULT, MAJOR_NR, 0, - S_IFBLK | S_IRUSR | S_IWUSR, 0, 0, + S_IFBLK | S_IRUSR | S_IWUSR, &fd_fops, NULL); for (i = 0; i < NUM_RAMDISKS; i++) @@ -693,6 +693,9 @@ iput(inode); } +#ifdef CONFIG_MAC_FLOPPY +int swim3_fd_eject(int devnum); +#endif static void __init rd_load_disk(int n) { @@ -713,6 +716,12 @@ if (rd_prompt) { #ifdef CONFIG_BLK_DEV_FD floppy_eject(); +#endif +#ifdef CONFIG_MAC_FLOPPY + if(MAJOR(ROOT_DEV) == FLOPPY_MAJOR) + swim3_fd_eject(MINOR(ROOT_DEV)); + else if(MAJOR(real_root_dev) == FLOPPY_MAJOR) + swim3_fd_eject(MINOR(real_root_dev)); #endif printk(KERN_NOTICE "VFS: Insert root floppy disk to be loaded into RAM disk and press ENTER\n"); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/smart1,2.h linux/drivers/block/smart1,2.h --- v2.4.0-test1/linux/drivers/block/smart1,2.h Mon Jul 5 19:52:52 1999 +++ linux/drivers/block/smart1,2.h Fri Jun 23 21:04:36 2000 @@ -62,13 +62,14 @@ } /* - * For this card fifo is full if reading this port returns 0! + * For older cards FIFO Full = 0. + * On this card 0 means there is room, anything else FIFO Full. * */ static unsigned long smart4_fifo_full(ctlr_info_t *h) { - return (~readl(h->vaddr + S42XX_REQUEST_PORT_OFFSET)); + return (!readl(h->vaddr + S42XX_REQUEST_PORT_OFFSET)); } /* This type of controller returns -1 if the fifo is empty, @@ -81,7 +82,7 @@ = readl(h->vaddr + S42XX_REPLY_PORT_OFFSET); /* Fifo is empty */ - if( register_value == -1) + if( register_value == 0xffffffff) return 0; /* Need to let it know we got the reply */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/swim3.c linux/drivers/block/swim3.c --- v2.4.0-test1/linux/drivers/block/swim3.c Wed Feb 16 17:03:51 2000 +++ linux/drivers/block/swim3.c Tue Jun 20 07:24:52 2000 @@ -801,6 +801,16 @@ return err; } +int swim3_fd_eject(int devnum) +{ + if (devnum >= floppy_count) + return -ENODEV; + /* Do not check this - this function should ONLY be called early + * in the boot process! */ + /* if (floppy_states[devnum].ref_count != 1) return -EBUSY; */ + return fd_eject(&floppy_states[devnum]); +} + static struct floppy_struct floppy_type = { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL }; /* 7 1.44MB 3.5" */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/xd.c linux/drivers/block/xd.c --- v2.4.0-test1/linux/drivers/block/xd.c Thu May 11 15:30:06 2000 +++ linux/drivers/block/xd.c Tue Jun 20 07:24:52 2000 @@ -258,20 +258,19 @@ { int dev = DEVICE_NR(inode->i_rdev); + MOD_INC_USE_COUNT; + if (dev < xd_drives) { while (!xd_valid[dev]) sleep_on(&xd_wait_open); -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif /* MODULE */ - xd_access[dev]++; return (0); } - else - return -ENXIO; + + MOD_DEC_USE_COUNT; + return -ENXIO; } /* do_xd_request: handle an incoming request */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/xor.c linux/drivers/block/xor.c --- v2.4.0-test1/linux/drivers/block/xor.c Tue May 23 15:31:34 2000 +++ linux/drivers/block/xor.c Wed Jun 21 10:10:02 2000 @@ -1814,7 +1814,7 @@ fastest = f; } #ifdef CONFIG_X86_XMM - if (boot_cpu_data.mmu_cr4_features & X86_CR4_OSXMMEXCPT) { + if (cpu_has_xmm) { fastest = &t_xor_block_pIII_kni; } #endif @@ -1849,7 +1849,7 @@ #endif #ifdef CONFIG_X86_XMM - if (boot_cpu_data.mmu_cr4_features & X86_CR4_OSXMMEXCPT) { + if (cpu_has_xmm) { printk(KERN_INFO "raid5: KNI detected, trying cache-avoiding KNI checksum routine\n"); /* we force the use of the KNI xor block because it @@ -1892,4 +1892,3 @@ #endif /* __sparc_v9__ */ MD_EXPORT_SYMBOL(xor_block); - diff -u --recursive --new-file v2.4.0-test1/linux/drivers/block/z2ram.c linux/drivers/block/z2ram.c --- v2.4.0-test1/linux/drivers/block/z2ram.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/block/z2ram.c Tue Jun 20 07:24:52 2000 @@ -165,12 +165,16 @@ sizeof( z2ram_map[0] ); int max_chip_map = ( amiga_chip_size / Z2RAM_CHUNKSIZE ) * sizeof( z2ram_map[0] ); + int rc = -ENOMEM; + + MOD_INC_USE_COUNT; device = DEVICE_NR( inode->i_rdev ); if ( current_device != -1 && current_device != device ) { - return -EBUSY; + rc = -EBUSY; + goto err_out; } if ( current_device == -1 ) @@ -188,7 +192,7 @@ if (index >= m68k_realnum_memory) { printk( KERN_ERR DEVICE_NAME ": no such entry in z2ram_map\n" ); - return -ENOMEM; + goto err_out; } paddr = m68k_memory[index].addr; @@ -215,7 +219,7 @@ { printk( KERN_ERR DEVICE_NAME ": cannot get mem for z2ram_map\n" ); - return -ENOMEM; + goto err_out; } while (size) { @@ -240,7 +244,7 @@ { printk( KERN_ERR DEVICE_NAME ": cannot get mem for z2ram_map\n" ); - return -ENOMEM; + goto err_out; } get_z2ram(); @@ -261,7 +265,7 @@ { printk( KERN_ERR DEVICE_NAME ": cannot get mem for z2ram_map\n" ); - return -ENOMEM; + goto err_out; } get_z2ram(); @@ -279,7 +283,7 @@ { printk( KERN_ERR DEVICE_NAME ": cannot get mem for z2ram_map\n" ); - return -ENOMEM; + goto err_out; } get_chipram(); @@ -292,15 +296,17 @@ break; default: - return -ENODEV; + rc = -ENODEV; + goto err_out; + + break; } if ( z2ram_size == 0 ) { - kfree( z2ram_map ); printk( KERN_NOTICE DEVICE_NAME ": no unused ZII/Chip RAM found\n" ); - return -ENOMEM; + goto err_out_kfree; } current_device = device; @@ -309,9 +315,13 @@ blk_size[ MAJOR_NR ] = z2_sizes; } - MOD_INC_USE_COUNT; - return 0; + +err_out_kfree: + kfree( z2ram_map ); +err_out: + MOD_DEC_USE_COUNT; + return rc; } static int diff -u --recursive --new-file v2.4.0-test1/linux/drivers/cdrom/aztcd.c linux/drivers/cdrom/aztcd.c --- v2.4.0-test1/linux/drivers/cdrom/aztcd.c Mon Jun 19 16:31:58 2000 +++ linux/drivers/cdrom/aztcd.c Wed Jun 21 22:31:00 2000 @@ -1543,14 +1543,17 @@ #ifdef AZT_DEBUG printk("aztcd: starting aztcd_open\n"); #endif + if (aztPresent == 0) return -ENXIO; /* no hardware */ + MOD_INC_USE_COUNT; + if (!azt_open_count && azt_state == AZT_S_IDLE) { azt_invalidate_buffers(); st = getAztStatus(); /* check drive status */ - if (st == -1) return -EIO; /* drive doesn't respond */ + if (st == -1) goto err_out; /* drive doesn't respond */ if (st & AST_DOOR_OPEN) { /* close door, then get the status again. */ @@ -1563,18 +1566,20 @@ { printk("aztcd: Disk Changed or No Disk in Drive?\n"); aztTocUpToDate=0; } - if (aztUpdateToc()) return -EIO; + if (aztUpdateToc()) goto err_out; } ++azt_open_count; - MOD_INC_USE_COUNT; aztLockDoor(); - #ifdef AZT_DEBUG printk("aztcd: exiting aztcd_open\n"); #endif return 0; + +err_out: + MOD_DEC_USE_COUNT; + return -EIO; } @@ -1786,8 +1791,8 @@ return -EIO; } } - devfs_register (NULL, "aztcd", 0, DEVFS_FL_DEFAULT, MAJOR_NR, 0, - S_IFBLK | S_IRUGO | S_IWUGO, 0, 0, &azt_fops, NULL); + devfs_register (NULL, "aztcd", DEVFS_FL_DEFAULT, MAJOR_NR, 0, + S_IFBLK | S_IRUGO | S_IWUGO, &azt_fops, NULL); if (devfs_register_blkdev(MAJOR_NR, "aztcd", &azt_fops) != 0) { printk("aztcd: Unable to get major %d for Aztech CD-ROM\n", diff -u --recursive --new-file v2.4.0-test1/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- v2.4.0-test1/linux/drivers/cdrom/cdrom.c Thu May 11 15:30:06 2000 +++ linux/drivers/cdrom/cdrom.c Wed Jun 21 22:31:00 2000 @@ -193,7 +193,7 @@ 3.07 Feb 2, 2000 - Jens Axboe -- Do same "read header length" trick in cdrom_get_disc_info() as - we do in cdrom_get_track_info() -- some drive don't obbey specs and + we do in cdrom_get_track_info() -- some drive don't obey specs and fail if they can't supply the full Mt Fuji size table. -- Deleted stuff related to setting up write modes. It has a different home now. @@ -211,10 +211,24 @@ dvd_do_auth passed uninitialized data to drive because init_cdrom_command did not clear a 0 sized buffer. + 3.09 May 12, 2000 - Jens Axboe + -- Fix Video-CD on SCSI drives that don't support READ_CD command. In + that case switch block size and issue plain READ_10 again, then switch + back. + + 3.10 Jun 10, 2000 - Jens Axboe + -- Fix volume control on CD's - old SCSI-II drives now use their own + code, as doing MODE6 stuff in here is really not my intention. + -- Use READ_DISC_INFO for more reliable end-of-disc. + + 3.11 Jun 12, 2000 - Jens Axboe + -- Fix bug in getting rpc phase 2 region info. + -- Reinstate "correct" CDROMPLAYTRKIND + -------------------------------------------------------------------------*/ -#define REVISION "Revision: 3.08" -#define VERSION "Id: cdrom.c 3.08 2000/05/01" +#define REVISION "Revision: 3.11" +#define VERSION "Id: cdrom.c 3.11 2000/06/12" /* I use an error-log mask to give fine grain control over the type of messages dumped to the system logs. The available masks include: */ @@ -285,7 +299,7 @@ /* The (cdo->capability & ~cdi->mask & CDC_XXX) construct was used in a lot of places. This macro makes the code more clear. */ -#define CDROM_CAN(type) (cdi->ops->capability & ~cdi->mask & type) +#define CDROM_CAN(type) (cdi->ops->capability & ~cdi->mask & (type)) /* used in the audio ioctls */ #define CHECKAUDIO if ((ret=check_for_audio_disc(cdi, cdo))) return ret @@ -394,9 +408,9 @@ } else { cdi->de = - devfs_register (devfs_handle, vname, 0, DEVFS_FL_DEFAULT, + devfs_register (devfs_handle, vname, DEVFS_FL_DEFAULT, MAJOR (cdi->dev), MINOR (cdi->dev), - S_IFBLK | S_IRUGO | S_IWUGO, 0, 0, + S_IFBLK | S_IRUGO | S_IWUGO, &cdrom_fops, NULL); } cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); @@ -465,7 +479,7 @@ if ((cdi = cdrom_find_device(dev)) == NULL) return -ENODEV; - if (fp->f_mode & FMODE_WRITE) + if ((fp->f_mode & FMODE_WRITE) && !CDROM_CAN(CDC_DVD_RAM)) return -EROFS; /* if this was a O_NONBLOCK open and we should honor the flags, @@ -993,6 +1007,7 @@ u_char buf[20]; struct cdrom_generic_command cgc; struct cdrom_device_ops *cdo = cdi->ops; + rpc_state_t rpc_state; memset(buf, 0, sizeof(buf)); init_cdrom_command(&cgc, buf, 0, CGC_DATA_READ); @@ -1099,18 +1114,19 @@ case DVD_LU_SEND_RPC_STATE: cdinfo(CD_DVD, "entering DVD_LU_SEND_RPC_STATE\n"); setup_report_key(&cgc, 0, 8); + memset(&rpc_state, 0, sizeof(rpc_state_t)); if ((ret = cdo->generic_packet(cdi, &cgc))) return ret; - ai->lrpcs.type = (buf[4] >> 6) & 3; - ai->lrpcs.vra = (buf[4] >> 3) & 7; - ai->lrpcs.ucca = buf[4] & 7; - ai->lrpcs.region_mask = buf[5]; - ai->lrpcs.rpc_scheme = buf[6]; + ai->lrpcs.type = rpc_state.type_code; + ai->lrpcs.vra = rpc_state.vra; + ai->lrpcs.ucca = rpc_state.ucca; + ai->lrpcs.region_mask = rpc_state.region_mask; + ai->lrpcs.rpc_scheme = rpc_state.rpc_scheme; break; - /* Set region settings */ + /* Set region settings */ case DVD_HOST_SEND_RPC_STATE: cdinfo(CD_DVD, "entering DVD_HOST_SEND_RPC_STATE\n"); setup_send_key(&cgc, 0, 6); @@ -1371,6 +1387,28 @@ return 0; } +/* + * Specific READ_10 interface + */ +static int cdrom_read_cd(struct cdrom_device_info *cdi, + struct cdrom_generic_command *cgc, int lba, + int blocksize, int nblocks) +{ + struct cdrom_device_ops *cdo = cdi->ops; + + memset(&cgc->cmd, 0, sizeof(cgc->cmd)); + cgc->cmd[0] = GPCMD_READ_10; + cgc->cmd[2] = (lba >> 24) & 0xff; + cgc->cmd[3] = (lba >> 16) & 0xff; + cgc->cmd[4] = (lba >> 8) & 0xff; + cgc->cmd[5] = lba & 0xff; + cgc->cmd[6] = (nblocks >> 16) & 0xff; + cgc->cmd[7] = (nblocks >> 8) & 0xff; + cgc->cmd[8] = nblocks & 0xff; + cgc->buflen = blocksize * nblocks; + return cdo->generic_packet(cdi, cgc); +} + /* very generic interface for reading the various types of blocks */ static int cdrom_read_block(struct cdrom_device_info *cdi, struct cdrom_generic_command *cgc, @@ -1787,6 +1825,43 @@ return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET; } +/* + * Required when we need to use READ_10 to issue other than 2048 block + * reads + */ +static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size) +{ + struct cdrom_device_ops *cdo = cdi->ops; + struct cdrom_generic_command cgc; + struct modesel_head mh; + int ret; + + memset(&mh, 0, sizeof(mh)); + mh.block_desc_length = 0x08; + mh.block_length_med = (size >> 8) & 0xff; + mh.block_length_lo = size & 0xff; + + memset(&cgc, 0, sizeof(cgc)); + cgc.cmd[0] = 0x15; + cgc.cmd[1] = 1 << 4; + cgc.cmd[4] = 12; + cgc.buflen = sizeof(mh); + cgc.buffer = (char *) &mh; + cgc.data_direction = CGC_DATA_WRITE; + mh.block_desc_length = 0x08; + mh.block_length_med = (size >> 8) & 0xff; + mh.block_length_lo = size & 0xff; + + ret = cdo->generic_packet(cdi, &cgc); + if (ret) { + printk("switch_blocksize failed, ret %x ", ret); + if (cgc.sense) + printk("sense %02x.%02x.%02x", cgc.sense->sense_key, cgc.sense->asc, cgc.sense->ascq); + printk("\n"); + } + return ret; +} + static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, unsigned long arg) { @@ -1829,8 +1904,27 @@ return -ENOMEM; cgc.data_direction = CGC_DATA_READ; ret = cdrom_read_block(cdi, &cgc, lba, 1, format, blocksize); - if (!ret) - if (copy_to_user((char *)arg, cgc.buffer, blocksize)) + if (ret) { + /* + * SCSI-II devices are not required to support + * READ_CD, so let's try switching block size + */ + /* FIXME: switch back again... */ + if ((ret = cdrom_switch_blocksize(cdi, blocksize))) { + kfree(cgc.buffer); + return ret; + } + cgc.sense = NULL; + ret = cdrom_read_cd(cdi, &cgc, lba, blocksize, 1); + if (ret) { + printk("read_cd failed, ret %x ", ret); + if (cgc.sense) + printk("sense %02x.%02x.%02x", cgc.sense->sense_key, cgc.sense->asc, cgc.sense->ascq); + printk("\n"); + } + ret |= cdrom_switch_blocksize(cdi, blocksize); + } + if (!ret && copy_to_user((char *)arg, cgc.buffer, blocksize)) ret = -EFAULT; kfree(cgc.buffer); return ret; @@ -1867,8 +1961,7 @@ } cgc.data_direction = CGC_DATA_READ; while (ra.nframes > 0) { - ret = cdrom_read_block(cdi, &cgc, lba, frames, 1, - CD_FRAMESIZE_RAW); + ret = cdrom_read_block(cdi, &cgc, lba, frames, 1, CD_FRAMESIZE_RAW); if (ret) break; __copy_to_user(ra.buf, cgc.buffer, CD_FRAMESIZE_RAW * frames); @@ -1899,37 +1992,15 @@ } case CDROMPLAYTRKIND: { struct cdrom_ti ti; - struct cdrom_tocentry entry; - struct cdrom_tochdr tochdr; cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n"); IOCTL_IN(arg, struct cdrom_ti, ti); - entry.cdte_format = CDROM_MSF; - - /* get toc entry for start and end track */ - if (cdo->audio_ioctl(cdi, CDROMREADTOCHDR, &tochdr)) - return -EINVAL; - if ((entry.cdte_track = ti.cdti_trk0) > tochdr.cdth_trk1) - return -EINVAL; - if (cdo->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry)) - return -EINVAL; - - cgc.cmd[3] = entry.cdte_addr.msf.minute; - cgc.cmd[4] = entry.cdte_addr.msf.second; - cgc.cmd[5] = entry.cdte_addr.msf.frame; - - entry.cdte_track = ti.cdti_trk1 + 1; - if (entry.cdte_track > tochdr.cdth_trk1) - entry.cdte_track = CDROM_LEADOUT; - if (cdo->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry)) - return -EINVAL; - - cgc.cmd[6] = entry.cdte_addr.msf.minute; - cgc.cmd[7] = entry.cdte_addr.msf.second; - cgc.cmd[8] = entry.cdte_addr.msf.frame; - cgc.cmd[0] = GPCMD_PLAY_AUDIO_MSF; - cgc.data_direction = CGC_DATA_NONE; + cgc.cmd[0] = GPCMD_PLAY_AUDIO_TI; + cgc.cmd[4] = ti.cdti_trk0; + cgc.cmd[5] = ti.cdti_ind0; + cgc.cmd[7] = ti.cdti_trk1; + cgc.cmd[8] = ti.cdti_ind1; return cdo->generic_packet(cdi, &cgc); } case CDROMPLAYMSF: { @@ -2158,6 +2229,7 @@ return cdo->generic_packet(cdi, &cgc); } +/* requires CD R/RW */ int cdrom_get_disc_info(kdev_t dev, disc_information *di) { struct cdrom_device_info *cdi = cdrom_find_device(dev); @@ -2199,6 +2271,9 @@ int ret = -1; if (!CDROM_CAN(CDC_GENERIC_PACKET)) + goto use_toc; + + if (!CDROM_CAN(CDC_CD_R | CDC_CD_RW | CDC_DVD_R | CDC_DVD_RAM)) goto use_toc; if ((ret = cdrom_get_disc_info(dev, &di))) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/cdrom/cm206.c linux/drivers/cdrom/cm206.c --- v2.4.0-test1/linux/drivers/cdrom/cm206.c Thu May 11 15:30:06 2000 +++ linux/drivers/cdrom/cm206.c Mon Jun 19 17:59:42 2000 @@ -736,13 +736,14 @@ static int cm206_open(struct cdrom_device_info * cdi, int purpose) { + MOD_INC_USE_COUNT; if (!cd->openfiles) { /* reset only first time */ cd->background=0; reset_cm260(); cd->adapter_last = -1; /* invalidate adapter memory */ cd->sector_last = -1; } - ++cd->openfiles; MOD_INC_USE_COUNT; + ++cd->openfiles; stats(open); return 0; } @@ -757,7 +758,8 @@ cd->sector_last = -1; /* Make our internal buffer invalid */ FIRST_TRACK = 0; /* No valid disc status */ } - --cd->openfiles; MOD_DEC_USE_COUNT; + --cd->openfiles; + MOD_DEC_USE_COUNT; } /* Empty buffer empties $sectors$ sectors of the adapter card buffer, @@ -1258,6 +1260,7 @@ &cm206_dops, /* device operations */ NULL, /* link */ NULL, /* handle (not used by cm206) */ + 0, /* devfs handle */ 0, /* dev */ 0, /* mask */ 2, /* maximum speed */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/cdrom/gscd.c linux/drivers/cdrom/gscd.c --- v2.4.0-test1/linux/drivers/cdrom/gscd.c Wed Feb 16 17:03:51 2000 +++ linux/drivers/cdrom/gscd.c Wed Jun 21 22:31:00 2000 @@ -1075,8 +1075,8 @@ MAJOR_NR); return -EIO; } - devfs_register (NULL, "gscd", 0, DEVFS_FL_DEFAULT, MAJOR_NR, 0, - S_IFBLK | S_IRUGO | S_IWUGO, 0, 0, &gscd_fops, NULL); + devfs_register (NULL, "gscd", DEVFS_FL_DEFAULT, MAJOR_NR, 0, + S_IFBLK | S_IRUGO | S_IWUGO, &gscd_fops, NULL); blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); blksize_size[MAJOR_NR] = gscd_blocksizes; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/cdrom/mcd.c linux/drivers/cdrom/mcd.c --- v2.4.0-test1/linux/drivers/cdrom/mcd.c Wed Feb 16 17:03:51 2000 +++ linux/drivers/cdrom/mcd.c Mon Jun 19 17:59:42 2000 @@ -1110,12 +1110,16 @@ if (mcdPresent == 0) return -ENXIO; /* no hardware */ - if (!mcd_open_count && mcd_state == MCD_S_IDLE) { + MOD_INC_USE_COUNT; + + if (mcd_open_count || mcd_state != MCD_S_IDLE) + goto bump_count; + mcd_invalidate_buffers(); do { st = statusCmd(); /* check drive status */ if (st == -1) - return -EIO; /* drive doesn't respond */ + goto err_out; /* drive doesn't respond */ if ((st & MST_READY) == 0) { /* no disk? wait a sec... */ current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ); @@ -1123,11 +1127,15 @@ } while (((st & MST_READY) == 0) && count++ < MCD_RETRY_ATTEMPTS); if (updateToc() < 0) - return -EIO; - } + goto err_out; + +bump_count: ++mcd_open_count; - MOD_INC_USE_COUNT; return 0; + +err_out: + MOD_DEC_USE_COUNT; + return -EIO; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/cdrom/optcd.c linux/drivers/cdrom/optcd.c --- v2.4.0-test1/linux/drivers/cdrom/optcd.c Thu May 11 15:30:06 2000 +++ linux/drivers/cdrom/optcd.c Wed Jun 21 22:31:00 2000 @@ -1871,6 +1871,8 @@ { DEBUG((DEBUG_VFS, "starting opt_open")); + MOD_INC_USE_COUNT; + if (!open_count && state == S_IDLE) { int status; @@ -1885,12 +1887,12 @@ status = drive_status(); if (status < 0) { DEBUG((DEBUG_VFS, "drive_status: %02x", -status)); - return -EIO; + goto err_out; } DEBUG((DEBUG_VFS, "status: %02x", status)); if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) { printk(KERN_INFO "optcd: no disk or door open\n"); - return -EIO; + goto err_out; } status = exec_cmd(COMLOCK); /* Lock door */ if (status < 0) { @@ -1904,15 +1906,18 @@ DEBUG((DEBUG_VFS, "exec_cmd COMUNLOCK: %02x", -status)); } - return -EIO; + goto err_out; } open_count++; } - MOD_INC_USE_COUNT; DEBUG((DEBUG_VFS, "exiting opt_open")); return 0; + +err_out: + MOD_DEC_USE_COUNT; + return -EIO; } @@ -2059,8 +2064,8 @@ printk(KERN_ERR "optcd: unable to get major %d\n", MAJOR_NR); return -EIO; } - devfs_register (NULL, "optcd", 0, DEVFS_FL_DEFAULT, MAJOR_NR, 0, - S_IFBLK | S_IRUGO | S_IWUGO, 0, 0, &opt_fops, NULL); + devfs_register (NULL, "optcd", DEVFS_FL_DEFAULT, MAJOR_NR, 0, + S_IFBLK | S_IRUGO | S_IWUGO, &opt_fops, NULL); hardsect_size[MAJOR_NR] = &hsecsize; blksize_size[MAJOR_NR] = &blksize; blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/cdrom/sbpcd.c linux/drivers/cdrom/sbpcd.c --- v2.4.0-test1/linux/drivers/cdrom/sbpcd.c Thu May 11 15:30:06 2000 +++ linux/drivers/cdrom/sbpcd.c Wed Jun 21 22:31:00 2000 @@ -5803,9 +5803,9 @@ sprintf (nbuff, "c%dt%d/cd", SBPCD_ISSUE - 1, D_S[j].drv_id); sbpcd_infop->de = - devfs_register (devfs_handle, nbuff, 0, DEVFS_FL_DEFAULT, + devfs_register (devfs_handle, nbuff, DEVFS_FL_DEFAULT, MAJOR_NR, j, S_IFBLK | S_IRUGO | S_IWUGO, - 0, 0, &cdrom_fops, NULL); + &cdrom_fops, NULL); if (register_cdrom(sbpcd_infop)) { printk(" sbpcd: Unable to register with Uniform CD-ROm driver\n"); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/cdrom/sjcd.c linux/drivers/cdrom/sjcd.c --- v2.4.0-test1/linux/drivers/cdrom/sjcd.c Thu May 11 15:30:06 2000 +++ linux/drivers/cdrom/sjcd.c Wed Jun 21 22:31:00 2000 @@ -58,10 +58,7 @@ #define SJCD_VERSION_MAJOR 1 #define SJCD_VERSION_MINOR 7 -#ifdef MODULE #include -#endif /* MODULE */ - #include #include #include @@ -1339,6 +1336,8 @@ */ if( fp->f_mode & 2 ) return( -EROFS ); + MOD_INC_USE_COUNT; + if( sjcd_open_count == 0 ){ int s, sjcd_open_tries; /* We don't know that, do we? */ @@ -1360,7 +1359,7 @@ #if defined( SJCD_DIAGNOSTIC ) printk( "SJCD: open: timed out when check status.\n" ); #endif - return( -EIO ); + goto err_out; } else if( !sjcd_media_is_available ){ #if defined( SJCD_DIAGNOSTIC ) printk("SJCD: open: no disk in drive\n"); @@ -1375,10 +1374,10 @@ #if defined( SJCD_DIAGNOSTIC ) printk("SJCD: open: tray close attempt failed\n"); #endif - return( -EIO ); + goto err_out; } continue; - } else return( -EIO ); + } else goto err_out; } break; } @@ -1387,17 +1386,19 @@ #if defined( SJCD_DIAGNOSTIC ) printk("SJCD: open: tray lock attempt failed\n"); #endif - return( -EIO ); + goto err_out; } #if defined( SJCD_TRACE ) printk( "SJCD: open: done\n" ); #endif } -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif + ++sjcd_open_count; return( 0 ); + +err_out: + MOD_DEC_USE_COUNT; + return( -EIO ); } /* @@ -1564,8 +1565,8 @@ } printk(KERN_INFO "SJCD: Status: port=0x%x.\n", sjcd_base); - devfs_register (NULL, "sjcd", 0, DEVFS_FL_DEFAULT, MAJOR_NR, 0, - S_IFBLK | S_IRUGO | S_IWUGO, 0, 0, &sjcd_fops, NULL); + devfs_register (NULL, "sjcd", DEVFS_FL_DEFAULT, MAJOR_NR, 0, + S_IFBLK | S_IRUGO | S_IWUGO, &sjcd_fops, NULL); sjcd_present++; return( 0 ); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/cdrom/sonycd535.c linux/drivers/cdrom/sonycd535.c --- v2.4.0-test1/linux/drivers/cdrom/sonycd535.c Wed Feb 16 17:03:51 2000 +++ linux/drivers/cdrom/sonycd535.c Wed Jun 21 22:31:00 2000 @@ -1587,11 +1587,11 @@ printk("IRQ%d, ", tmp_irq); printk("using %d byte buffer\n", sony_buffer_size); - devfs_register (NULL, CDU535_HANDLE, 0, + devfs_register (NULL, CDU535_HANDLE, DEVFS_FL_DEFAULT, MAJOR_NR, 0, S_IFBLK | S_IRUGO | S_IWUGO, - 0, 0, &cdu_fops, NULL); + &cdu_fops, NULL); if (devfs_register_blkdev(MAJOR_NR, CDU535_HANDLE, &cdu_fops)) { printk("Unable to get major %d for %s\n", MAJOR_NR, CDU535_MESSAGE_NAME); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v2.4.0-test1/linux/drivers/char/Config.in Mon Jun 19 16:31:59 2000 +++ linux/drivers/char/Config.in Tue Jun 20 13:58:42 2000 @@ -124,6 +124,7 @@ tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT + tristate ' SBC-60XX Watchdog Timer' CONFIG_60XX_WDT tristate ' Mixcom Watchdog' CONFIG_MIXCOMWD if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then tristate ' DC21285 watchdog' CONFIG_21285_WATCHDOG @@ -143,6 +144,7 @@ tristate 'NetWinder flash support' CONFIG_NWFLASH fi +dep_tristate 'Intel i8x0 Random Number Generator support' CONFIG_INTEL_RNG $CONFIG_PCI tristate '/dev/nvram support' CONFIG_NVRAM tristate 'Enhanced Real Time Clock Support' CONFIG_RTC if [ "$CONFIG_IA64" = "y" ]; then @@ -206,7 +208,7 @@ fi comment 'Video Adapters' if [ "$CONFIG_I2C_ALGOBIT" = "y" -o "$CONFIG_I2C_ALGOBIT" = "m" ]; then - dep_tristate ' BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C_ALGOBIT $CONFIG_SOUND + dep_tristate ' BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C_ALGOBIT fi dep_tristate ' Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV if [ "$CONFIG_ALL_PPC" = "y" ]; then diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.4.0-test1/linux/drivers/char/Makefile Tue May 23 15:31:34 2000 +++ linux/drivers/char/Makefile Tue Jun 20 13:58:42 2000 @@ -56,7 +56,7 @@ ifdef CONFIG_AMIGA KEYBD = amikeyb.o else - KEYBD = + KEYBD = endif SERIAL = endif @@ -65,7 +65,6 @@ KEYMAP = KEYBD = CONSOLE = - SERIAL = endif ifeq ($(ARCH),sh) @@ -73,6 +72,11 @@ KEYBD = CONSOLE = SERIAL = + ifeq ($(CONFIG_SH_HP600),y) + KEYMAP = defkeymap.o + KEYBD = scan_keyb.o hp600_keyb.o + CONSOLE = console.o + endif ifeq ($(CONFIG_SERIAL),y) SERIAL = generic_serial.o sh-sci.o else @@ -134,40 +138,22 @@ obj-$(CONFIG_N_HDLC) += n_hdlc.o obj-$(CONFIG_SPECIALIX) += specialix.o obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o -obj-$(CONFIG_SX) += sx.o -# If either SX or RIO is in the kernel, generic_serial goes in the -# kernel, and the module is no longer required. The "in kernel" case -# is last to be able to override the module case.... This is an -# example of the new "makefile automatically figures out the -# dependencies".... -- REW - -GS=n -ifeq ($(CONFIG_RIO),m) - M_OBJS += generic_serial.o - MOD_SUB_DIRS += rio - GS = m -endif - -ifeq ($(CONFIG_SX),m) - GS = m - M_OBJS += sx.o -endif +# After much ado, we found that an object can safely be declared as +# both a module and into the kernel. Below that is filtered out. +# So this should simply provide the wanted functionality! +obj-$(CONFIG_SX) += sx.o generic_serial.o +obj-$(CONFIG_RIO) += rio/rio.o generic_serial.o + ifeq ($(CONFIG_RIO),y) - L_OBJS += rio/rio.o generic_serial.o SUB_DIRS += rio - MOD_SUB_DIRS += rio - GS = y -endif - -ifeq ($(CONFIG_SX),y) - L_OBJS += sx.o - GS = y +else + ifeq ($(CONFIG_RIO),m) + MOD_SUB_DIRS += rio + endif endif -obj-$(GS) += generic_serial.o - obj-$(CONFIG_ATIXL_BUSMOUSE) += atixlmouse.o obj-$(CONFIG_LOGIBUSMOUSE) += logibusmouse.o obj-$(CONFIG_PRINTER) += lp.o @@ -200,6 +186,7 @@ obj-$(CONFIG_PCWATCHDOG) += pcwd.o obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o obj-$(CONFIG_MIXCOMWD) += mixcomwd.o +obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o obj-$(CONFIG_AMIGAMOUSE) += amigamouse.o obj-$(CONFIG_ATARIMOUSE) += atarimouse.o obj-$(CONFIG_ADBMOUSE) += adbmouse.o @@ -217,6 +204,7 @@ obj-$(CONFIG_21285_WATCHDOG) += wdt285.o obj-$(CONFIG_977_WATCHDOG) += wdt977.o obj-$(CONFIG_DS1620) += ds1620.o +obj-$(CONFIG_INTEL_RNG) += i810_rng.o # # for external dependencies in arm/config.in and video/config.in @@ -238,6 +226,7 @@ L_TUNERS=m endif endif +obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o obj-$(CONFIG_VIDEO_ZR36120) += zoran.o ifeq ($(CONFIG_VIDEO_ZR36120),y) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/acquirewdt.c linux/drivers/char/acquirewdt.c --- v2.4.0-test1/linux/drivers/char/acquirewdt.c Mon Mar 27 08:08:23 2000 +++ linux/drivers/char/acquirewdt.c Tue Jun 20 07:25:51 2000 @@ -125,7 +125,6 @@ spin_unlock(&acq_lock); return -EBUSY; } - MOD_INC_USE_COUNT; /* * Activate */ @@ -150,7 +149,6 @@ acq_is_open=0; spin_unlock(&acq_lock); } - MOD_DEC_USE_COUNT; return 0; } @@ -175,6 +173,7 @@ static struct file_operations acq_fops = { + owner: THIS_MODULE, read: acq_read, write: acq_write, ioctl: acq_ioctl, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/adbmouse.c linux/drivers/char/adbmouse.c --- v2.4.0-test1/linux/drivers/char/adbmouse.c Sun Nov 7 16:37:34 1999 +++ linux/drivers/char/adbmouse.c Tue Jun 20 07:25:51 2000 @@ -132,20 +132,22 @@ static int release_mouse(struct inode *inode, struct file *file) { adb_mouse_interrupt_hook = NULL; - MOD_DEC_USE_COUNT; + /* + * FIXME?: adb_mouse_interrupt_hook may still be executing + * on another CPU. + */ return 0; } static int open_mouse(struct inode *inode, struct file *file) { - MOD_INC_USE_COUNT; adb_mouse_interrupt_hook = adb_mouse_interrupt; return 0; } static struct busmouse adb_mouse = { - ADB_MOUSE_MINOR, "adbmouse", open_mouse, release_mouse, 7 + ADB_MOUSE_MINOR, "adbmouse", THIS_MODULE, open_mouse, release_mouse, 7 }; static int __init adb_mouse_init(void) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/agp/agp.h linux/drivers/char/agp/agp.h --- v2.4.0-test1/linux/drivers/char/agp/agp.h Tue Mar 7 14:32:25 2000 +++ linux/drivers/char/agp/agp.h Mon Jun 19 17:59:42 2000 @@ -31,6 +31,7 @@ U8_APER_SIZE, U16_APER_SIZE, U32_APER_SIZE, + LVL2_APER_SIZE, FIXED_APER_SIZE }; @@ -63,6 +64,12 @@ u32 size_value; } aper_size_info_32; +typedef struct _aper_size_info_lvl2 { + int size; + int num_entries; + u32 size_value; +} aper_size_info_lvl2; + typedef struct _aper_size_info_fixed { int size; int num_entries; @@ -124,10 +131,12 @@ #define A_SIZE_8(x) ((aper_size_info_8 *) x) #define A_SIZE_16(x) ((aper_size_info_16 *) x) #define A_SIZE_32(x) ((aper_size_info_32 *) x) +#define A_SIZE_LVL2(x) ((aper_size_info_lvl2 *) x) #define A_SIZE_FIX(x) ((aper_size_info_fixed *) x) #define A_IDX8() (A_SIZE_8(agp_bridge.aperture_sizes) + i) #define A_IDX16() (A_SIZE_16(agp_bridge.aperture_sizes) + i) #define A_IDX32() (A_SIZE_32(agp_bridge.aperture_sizes) + i) +#define A_IDXLVL2() (A_SIZE_LVL2(agp_bridge.aperture_sizes) + i) #define A_IDXFIX() (A_SIZE_FIX(agp_bridge.aperture_sizes) + i) #define MAXKEY (4096 * 32) @@ -151,6 +160,9 @@ #ifndef PCI_DEVICE_ID_INTEL_810_0 #define PCI_DEVICE_ID_INTEL_810_0 0x7120 #endif +#ifndef PCI_DEVICE_ID_INTEL_840_0 +#define PCI_DEVICE_ID_INTEL_840_0 0x1a21 +#endif #ifndef PCI_DEVICE_ID_INTEL_810_DC100_0 #define PCI_DEVICE_ID_INTEL_810_DC100_0 0x7122 #endif @@ -189,6 +201,10 @@ #define INTEL_AGPCTRL 0xb0 #define INTEL_NBXCFG 0x50 #define INTEL_ERRSTS 0x91 + +/* intel i840 registers */ +#define INTEL_I840_MCHCFG 0x50 +#define INTEL_I840_ERRSTS 0xc8 /* intel i810 registers */ #define I810_GMADDR 0x10 diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/agp/agpgart_be.c linux/drivers/char/agp/agpgart_be.c --- v2.4.0-test1/linux/drivers/char/agp/agpgart_be.c Wed Apr 26 16:34:07 2000 +++ linux/drivers/char/agp/agpgart_be.c Mon Jun 19 17:59:42 2000 @@ -315,6 +315,9 @@ case U32_APER_SIZE: current_size = A_SIZE_32(temp)->size; break; + case LVL2_APER_SIZE: + current_size = A_SIZE_LVL2(temp)->size; + break; case FIXED_APER_SIZE: current_size = A_SIZE_FIX(temp)->size; break; @@ -539,6 +542,11 @@ int i; void *temp; + /* The generic routines can't handle 2 level gatt's */ + if (agp_bridge.size_type == LVL2_APER_SIZE) { + return -EINVAL; + } + table = NULL; i = agp_bridge.aperture_size_idx; temp = agp_bridge.current_size; @@ -566,6 +574,7 @@ break; /* This case will never really happen. */ case FIXED_APER_SIZE: + case LVL2_APER_SIZE: default: size = page_order = num_entries = 0; break; @@ -590,6 +599,7 @@ * happen. */ case FIXED_APER_SIZE: + case LVL2_APER_SIZE: default: agp_bridge.current_size = agp_bridge.current_size; @@ -663,6 +673,10 @@ case FIXED_APER_SIZE: page_order = A_SIZE_FIX(temp)->page_order; break; + case LVL2_APER_SIZE: + /* The generic routines can't deal with 2 level gatt's */ + return -EINVAL; + break; default: page_order = 0; break; @@ -706,6 +720,10 @@ case FIXED_APER_SIZE: num_entries = A_SIZE_FIX(temp)->num_entries; break; + case LVL2_APER_SIZE: + /* The generic routines can't deal with 2 level gatt's */ + return -EINVAL; + break; default: num_entries = 0; break; @@ -1126,6 +1144,38 @@ return 0; } +static int intel_840_configure(void) +{ + u32 temp; + u16 temp2; + aper_size_info_16 *current_size; + + current_size = A_SIZE_16(agp_bridge.current_size); + + /* aperture size */ + pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, + (char)current_size->size_value); + + /* address to map to */ + pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + /* attbase - aperture base */ + pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, + agp_bridge.gatt_bus_addr); + + /* agpctrl */ + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); + + /* mcgcfg */ + pci_read_config_word(agp_bridge.dev, INTEL_I840_MCHCFG, &temp2); + pci_write_config_word(agp_bridge.dev, INTEL_I840_MCHCFG, + temp2 | (1 << 9)); + /* clear any possible error conditions */ + pci_write_config_word(agp_bridge.dev, INTEL_I840_ERRSTS, 0xc000); + return 0; +} + static unsigned long intel_mask_memory(unsigned long addr, int type) { /* Memory type is ignored */ @@ -1179,6 +1229,34 @@ (void) pdev; /* unused */ } +static int __init intel_840_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = intel_generic_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) intel_generic_sizes; + agp_bridge.size_type = U16_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = intel_840_configure; + agp_bridge.fetch_size = intel_fetch_size; + agp_bridge.cleanup = intel_cleanup; + agp_bridge.tlb_flush = intel_tlbflush; + agp_bridge.mask_memory = intel_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_insert_memory; + agp_bridge.remove_memory = agp_generic_remove_memory; + agp_bridge.alloc_by_type = agp_generic_alloc_by_type; + agp_bridge.free_by_type = agp_generic_free_by_type; + + return 0; + + (void) pdev; /* unused */ +} + #endif /* CONFIG_AGP_INTEL */ #ifdef CONFIG_AGP_VIA @@ -1403,19 +1481,180 @@ #ifdef CONFIG_AGP_AMD +typedef struct _amd_page_map { + unsigned long *real; + unsigned long *remapped; +} amd_page_map; + static struct _amd_irongate_private { volatile u8 *registers; + amd_page_map **gatt_pages; + int num_tables; } amd_irongate_private; +static int amd_create_page_map(amd_page_map *page_map) +{ + int i; + + page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL); + if (page_map->real == NULL) { + return -ENOMEM; + } + set_bit(PG_reserved, &mem_map[MAP_NR(page_map->real)].flags); + CACHE_FLUSH(); + page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), + PAGE_SIZE); + if (page_map->remapped == NULL) { + clear_bit(PG_reserved, + &mem_map[MAP_NR(page_map->real)].flags); + free_page((unsigned long) page_map->real); + page_map->real = NULL; + return -ENOMEM; + } + CACHE_FLUSH(); + + for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) { + page_map->remapped[i] = agp_bridge.scratch_page; + } + + return 0; +} + +static void amd_free_page_map(amd_page_map *page_map) +{ + iounmap(page_map->remapped); + clear_bit(PG_reserved, + &mem_map[MAP_NR(page_map->real)].flags); + free_page((unsigned long) page_map->real); +} + +static void amd_free_gatt_pages(void) +{ + int i; + amd_page_map **tables; + amd_page_map *entry; + + tables = amd_irongate_private.gatt_pages; + for(i = 0; i < amd_irongate_private.num_tables; i++) { + entry = tables[i]; + if (entry != NULL) { + if (entry->real != NULL) { + amd_free_page_map(entry); + } + kfree(entry); + } + } + kfree(tables); +} + +static int amd_create_gatt_pages(int nr_tables) +{ + amd_page_map **tables; + amd_page_map *entry; + int retval = 0; + int i; + + tables = kmalloc((nr_tables + 1) * sizeof(amd_page_map *), + GFP_KERNEL); + if (tables == NULL) { + return -ENOMEM; + } + memset(tables, 0, sizeof(amd_page_map *) * (nr_tables + 1)); + for (i = 0; i < nr_tables; i++) { + entry = kmalloc(sizeof(amd_page_map), GFP_KERNEL); + if (entry == NULL) { + retval = -ENOMEM; + break; + } + memset(entry, 0, sizeof(amd_page_map)); + tables[i] = entry; + retval = amd_create_page_map(entry); + if (retval != 0) break; + } + amd_irongate_private.num_tables = nr_tables; + amd_irongate_private.gatt_pages = tables; + + if (retval != 0) amd_free_gatt_pages(); + + return retval; +} + +/* Since we don't need contigious memory we just try + * to get the gatt table once + */ + +#define GET_PAGE_DIR_OFF(addr) (addr >> 22) +#define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \ + GET_PAGE_DIR_OFF(agp_bridge.gart_bus_addr)) +#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12) +#define GET_GATT(addr) (amd_irongate_private.gatt_pages[\ + GET_PAGE_DIR_IDX(addr)]->remapped) + +static int amd_create_gatt_table(void) +{ + aper_size_info_lvl2 *value; + amd_page_map page_dir; + unsigned long addr; + int retval; + u32 temp; + int i; + + value = A_SIZE_LVL2(agp_bridge.current_size); + retval = amd_create_page_map(&page_dir); + if (retval != 0) { + return retval; + } + + retval = amd_create_gatt_pages(value->num_entries / 1024); + if (retval != 0) { + amd_free_page_map(&page_dir); + return retval; + } + + agp_bridge.gatt_table_real = page_dir.real; + agp_bridge.gatt_table = page_dir.remapped; + agp_bridge.gatt_bus_addr = virt_to_bus(page_dir.real); + + /* Get the address for the gart region. + * This is a bus address even on the alpha, b/c its + * used to program the agp master not the cpu + */ + + pci_read_config_dword(agp_bridge.dev, AMD_APBASE, &temp); + addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + agp_bridge.gart_bus_addr = addr; + + /* Calculate the agp offset */ + for(i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) { + page_dir.remapped[GET_PAGE_DIR_OFF(addr)] = + virt_to_bus(amd_irongate_private.gatt_pages[i]->real); + page_dir.remapped[GET_PAGE_DIR_OFF(addr)] |= 0x00000001; + } + + return 0; +} + +static int amd_free_gatt_table(void) +{ + amd_page_map page_dir; + + page_dir.real = agp_bridge.gatt_table_real; + page_dir.remapped = agp_bridge.gatt_table; + + amd_free_gatt_pages(); + amd_free_page_map(&page_dir); + return 0; +} + static int amd_irongate_fetch_size(void) { int i; u32 temp; - aper_size_info_32 *values; + aper_size_info_lvl2 *values; pci_read_config_dword(agp_bridge.dev, AMD_APSIZE, &temp); temp = (temp & 0x0000000e); - values = A_SIZE_32(agp_bridge.aperture_sizes); + values = A_SIZE_LVL2(agp_bridge.aperture_sizes); for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { if (temp == values[i].size_value) { agp_bridge.previous_size = @@ -1431,12 +1670,11 @@ static int amd_irongate_configure(void) { - aper_size_info_32 *current_size; - unsigned long addr; + aper_size_info_lvl2 *current_size; u32 temp; u16 enable_reg; - current_size = A_SIZE_32(agp_bridge.current_size); + current_size = A_SIZE_LVL2(agp_bridge.current_size); /* Get the memory mapped registers */ pci_read_config_dword(agp_bridge.dev, AMD_MMBASE, &temp); @@ -1451,7 +1689,7 @@ pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL, 0x80); /* Set indexing mode */ - pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL2, 0x02); + pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL2, 0x00); /* Write the enable register */ enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE); @@ -1467,28 +1705,16 @@ /* Flush the tlb */ OUTREG32(amd_irongate_private.registers, AMD_TLBFLUSH, 0x00000001); - /* Get the address for the gart region */ - pci_read_config_dword(agp_bridge.dev, AMD_APBASE, &temp); - addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); -#ifdef __alpha__ - /* ??? Presumably what is wanted is the bus address as seen - from the CPU side, since it appears that this value is - exported to userland via an ioctl. The terminology below - is confused, mixing `physical address' with `bus address', - as x86 folk are wont to do. */ - addr = virt_to_phys(ioremap(addr, 0)); -#endif - agp_bridge.gart_bus_addr = addr; return 0; } static void amd_irongate_cleanup(void) { - aper_size_info_32 *previous_size; + aper_size_info_lvl2 *previous_size; u32 temp; u16 enable_reg; - previous_size = A_SIZE_32(agp_bridge.previous_size); + previous_size = A_SIZE_LVL2(agp_bridge.previous_size); enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE); enable_reg = (enable_reg & ~(0x0004)); @@ -1521,15 +1747,76 @@ return addr | agp_bridge.masks[0].mask; } -static aper_size_info_32 amd_irongate_sizes[7] = +static int amd_insert_memory(agp_memory * mem, + off_t pg_start, int type) +{ + int i, j, num_entries; + unsigned long *cur_gatt; + unsigned long addr; + + num_entries = A_SIZE_LVL2(agp_bridge.current_size)->num_entries; + + if (type != 0 || mem->type != 0) { + return -EINVAL; + } + if ((pg_start + mem->page_count) > num_entries) { + return -EINVAL; + } + + j = pg_start; + while (j < (pg_start + mem->page_count)) { + addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr; + cur_gatt = GET_GATT(addr); + if (!PGE_EMPTY(cur_gatt[GET_GATT_OFF(addr)])) { + return -EBUSY; + } + j++; + } + + if (mem->is_flushed == FALSE) { + CACHE_FLUSH(); + mem->is_flushed = TRUE; + } + + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { + addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr; + cur_gatt = GET_GATT(addr); + cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i]; + } + agp_bridge.tlb_flush(mem); + return 0; +} + +static int amd_remove_memory(agp_memory * mem, off_t pg_start, + int type) { - {2048, 524288, 9, 0x0000000c}, - {1024, 262144, 8, 0x0000000a}, - {512, 131072, 7, 0x00000008}, - {256, 65536, 6, 0x00000006}, - {128, 32768, 5, 0x00000004}, - {64, 16384, 4, 0x00000002}, - {32, 8192, 3, 0x00000000} + int i; + unsigned long *cur_gatt; + unsigned long addr; + + if (type != 0 || mem->type != 0) { + return -EINVAL; + } + for (i = pg_start; i < (mem->page_count + pg_start); i++) { + addr = (i * PAGE_SIZE) + agp_bridge.gart_bus_addr; + cur_gatt = GET_GATT(addr); + cur_gatt[GET_GATT_OFF(addr)] = + (unsigned long) agp_bridge.scratch_page; + } + + agp_bridge.tlb_flush(mem); + return 0; +} + +static aper_size_info_lvl2 amd_irongate_sizes[7] = +{ + {2048, 524288, 0x0000000c}, + {1024, 262144, 0x0000000a}, + {512, 131072, 0x00000008}, + {256, 65536, 0x00000006}, + {128, 32768, 0x00000004}, + {64, 16384, 0x00000002}, + {32, 8192, 0x00000000} }; static gatt_mask amd_irongate_masks[] = @@ -1542,7 +1829,7 @@ agp_bridge.masks = amd_irongate_masks; agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) amd_irongate_sizes; - agp_bridge.size_type = U32_APER_SIZE; + agp_bridge.size_type = LVL2_APER_SIZE; agp_bridge.num_aperture_sizes = 7; agp_bridge.dev_private_data = (void *) &amd_irongate_private; agp_bridge.needs_scratch_page = FALSE; @@ -1553,10 +1840,10 @@ agp_bridge.mask_memory = amd_irongate_mask_memory; agp_bridge.agp_enable = agp_generic_agp_enable; agp_bridge.cache_flush = global_cache_flush; - agp_bridge.create_gatt_table = agp_generic_create_gatt_table; - agp_bridge.free_gatt_table = agp_generic_free_gatt_table; - agp_bridge.insert_memory = agp_generic_insert_memory; - agp_bridge.remove_memory = agp_generic_remove_memory; + agp_bridge.create_gatt_table = amd_create_gatt_table; + agp_bridge.free_gatt_table = amd_free_gatt_table; + agp_bridge.insert_memory = amd_insert_memory; + agp_bridge.remove_memory = amd_remove_memory; agp_bridge.alloc_by_type = agp_generic_alloc_by_type; agp_bridge.free_by_type = agp_generic_free_by_type; @@ -1755,6 +2042,12 @@ "Intel", "440GX", intel_generic_setup }, + { PCI_DEVICE_ID_INTEL_840_0, + PCI_VENDOR_ID_INTEL, + INTEL_I840, + "Intel", + "i840", + intel_840_setup }, { 0, PCI_VENDOR_ID_INTEL, INTEL_GENERIC, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/agp/agpgart_fe.c linux/drivers/char/agp/agpgart_fe.c --- v2.4.0-test1/linux/drivers/char/agp/agpgart_fe.c Thu Feb 10 17:11:07 2000 +++ linux/drivers/char/agp/agpgart_fe.c Tue Jun 20 07:25:51 2000 @@ -687,7 +687,6 @@ } agp_remove_file_private(priv); kfree(priv); - MOD_DEC_USE_COUNT; AGP_UNLOCK(); return 0; } @@ -697,19 +696,17 @@ int minor = MINOR(inode->i_rdev); agp_file_private *priv; agp_client *client; + int rc = -ENXIO; AGP_LOCK(); - if (minor != AGPGART_MINOR) { - AGP_UNLOCK(); - return -ENXIO; - } + if (minor != AGPGART_MINOR) + goto err_out; + priv = kmalloc(sizeof(agp_file_private), GFP_KERNEL); + if (priv == NULL) + goto err_out_nomem; - if (priv == NULL) { - AGP_UNLOCK(); - return -ENOMEM; - } memset(priv, 0, sizeof(agp_file_private)); set_bit(AGP_FF_ALLOW_CLIENT, &priv->access_flags); priv->my_pid = current->pid; @@ -726,9 +723,14 @@ } file->private_data = (void *) priv; agp_insert_file_private(priv); - MOD_INC_USE_COUNT; AGP_UNLOCK(); return 0; + +err_out_nomem: + rc = -ENOMEM; +err_out: + AGP_UNLOCK(); + return rc; } @@ -1059,6 +1061,7 @@ static struct file_operations agp_fops = { + owner: THIS_MODULE, llseek: agp_lseek, read: agp_read, write: agp_write, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/amigamouse.c linux/drivers/char/amigamouse.c --- v2.4.0-test1/linux/drivers/char/amigamouse.c Mon Mar 27 08:08:23 2000 +++ linux/drivers/char/amigamouse.c Mon Jun 19 13:45:52 2000 @@ -151,7 +151,6 @@ #if AMIGA_OLD_INT AMI_MSE_INT_OFF(); #endif - MOD_DEC_USE_COUNT; return 0; } @@ -162,10 +161,6 @@ static int open_mouse(struct inode * inode, struct file * file) { - /* Lock module first - request_irq might sleep */ - - MOD_INC_USE_COUNT; - /* * use VBL to poll mouse deltas */ @@ -173,7 +168,6 @@ if(request_irq(IRQ_AMIGA_VERTB, mouse_interrupt, 0, "Amiga mouse", mouse_interrupt)) { printk(KERN_INFO "Installing Amiga mouse failed.\n"); - MOD_DEC_USE_COUNT; return -EIO; } @@ -184,7 +178,7 @@ } static struct busmouse amigamouse = { - AMIGAMOUSE_MINOR, "amigamouse", open_mouse, release_mouse, 7 + AMIGAMOUSE_MINOR, "amigamouse", THIS_MODULE, open_mouse, release_mouse, 7 }; static int __init amiga_mouse_init(void) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/amikeyb.c linux/drivers/char/amikeyb.c --- v2.4.0-test1/linux/drivers/char/amikeyb.c Sun Feb 13 19:29:03 2000 +++ linux/drivers/char/amikeyb.c Mon Jun 19 13:45:52 2000 @@ -186,8 +186,8 @@ kbd_pt_regs = NULL; + init_timer(&amikeyb_rep_timer); amikeyb_rep_timer.expires = jiffies + key_repeat_rate; - amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL; add_timer(&amikeyb_rep_timer); handle_scancode(rep_scancode, 1); @@ -254,8 +254,8 @@ } else { del_timer(&amikeyb_rep_timer); rep_scancode = keycode; + init_timer(&amikeyb_rep_timer); amikeyb_rep_timer.expires = jiffies + key_repeat_delay; - amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL; add_timer(&amikeyb_rep_timer); } handle_scancode(keycode, !break_flag); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/amiserial.c linux/drivers/char/amiserial.c --- v2.4.0-test1/linux/drivers/char/amiserial.c Thu May 11 15:30:06 2000 +++ linux/drivers/char/amiserial.c Mon Jun 19 13:45:52 2000 @@ -2104,6 +2104,13 @@ if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_SERIAL)) return -ENODEV; + /* + * We request SERDAT and SERPER only, because the serial registers are + * too spreaded over the custom register space + */ + if (!request_mem_region(CUSTOM_PHYSADDR+0x30, 4, "amiserial [Paula]")) + return -EBUSY; + init_bh(SERIAL_BH, do_serial_bh); IRQ_ports = NULL; @@ -2254,6 +2261,7 @@ free_page((unsigned long) tmp_buf); tmp_buf = NULL; } + release_mem_region(CUSTOM_PHYSADDR+0x30, 4); } #endif /* MODULE */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/atarimouse.c linux/drivers/char/atarimouse.c --- v2.4.0-test1/linux/drivers/char/atarimouse.c Sun Nov 7 16:37:34 1999 +++ linux/drivers/char/atarimouse.c Tue Jun 20 07:32:13 2000 @@ -39,53 +39,50 @@ static void atari_mouse_interrupt(char *buf) { - int buttons; + int buttons; -/* ikbd_mouse_disable(); */ +/* ikbd_mouse_disable(); */ - buttons = ((buf[0] & 1) + buttons = ((buf[0] & 1) | ((buf[0] & 2) << 1) | (atari_mouse_buttons & 2)); - atari_mouse_buttons = buttons; + atari_mouse_buttons = buttons; - busmouse_add_movementbuttons(msedev, buf[1], -buf[2], buttons ^ 7); -/* ikbd_mouse_rel_pos(); */ + busmouse_add_movementbuttons(msedev, buf[1], -buf[2], buttons ^ 7); +/* ikbd_mouse_rel_pos(); */ } static int release_mouse(struct inode *inode, struct file *file) { - ikbd_mouse_disable(); - - atari_mouse_interrupt_hook = NULL; - MOD_DEC_USE_COUNT; - return 0; + ikbd_mouse_disable(); + atari_mouse_interrupt_hook = NULL; + return 0; } static int open_mouse(struct inode *inode, struct file *file) { - atari_mouse_buttons = 0; - ikbd_mouse_y0_top (); - ikbd_mouse_thresh (mouse_threshold[0], mouse_threshold[1]); - ikbd_mouse_rel_pos(); - MOD_INC_USE_COUNT; - atari_mouse_interrupt_hook = atari_mouse_interrupt; - return 0; + atari_mouse_buttons = 0; + ikbd_mouse_y0_top (); + ikbd_mouse_thresh (mouse_threshold[0], mouse_threshold[1]); + ikbd_mouse_rel_pos(); + atari_mouse_interrupt_hook = atari_mouse_interrupt; + return 0; } static struct busmouse atarimouse = { - ATARIMOUSE_MINOR, "atarimouse", open_mouse, release_mouse, 0 + ATARIMOUSE_MINOR, "atarimouse", THIS_MODULE, open_mouse, release_mouse, 0 }; static int __init atari_mouse_init(void) { - if (!MACH_IS_ATARI) - return -ENODEV; - msedev = register_busmouse(&atarimouse); - if (msedev < 0) - printk(KERN_WARNING "Unable to register Atari mouse driver.\n"); - else - printk(KERN_INFO "Atari mouse installed.\n"); - return msedev < 0 ? msedev : 0; + if (!MACH_IS_ATARI) + return -ENODEV; + msedev = register_busmouse(&atarimouse); + if (msedev < 0) + printk(KERN_WARNING "Unable to register Atari mouse driver.\n"); + else + printk(KERN_INFO "Atari mouse installed.\n"); + return msedev < 0 ? msedev : 0; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/atixlmouse.c linux/drivers/char/atixlmouse.c --- v2.4.0-test1/linux/drivers/char/atixlmouse.c Mon Mar 27 08:08:23 2000 +++ linux/drivers/char/atixlmouse.c Mon Jun 19 13:45:52 2000 @@ -86,25 +86,19 @@ { ATIXL_MSE_INT_OFF(); /* Interrupts are really shut down here */ free_irq(ATIXL_MOUSE_IRQ, NULL); - MOD_DEC_USE_COUNT; return 0; } static int open_mouse(struct inode * inode, struct file * file) { - /* Lock module as request_irq may sleep */ - MOD_INC_USE_COUNT; if (request_irq(ATIXL_MOUSE_IRQ, mouse_interrupt, 0, "ATIXL mouse", NULL)) - { - MOD_DEC_USE_COUNT; return -EBUSY; - } ATIXL_MSE_INT_ON(); /* Interrupts are really enabled here */ return 0; } static struct busmouse atixlmouse = { - ATIXL_BUSMOUSE, "atixl", open_mouse, release_mouse, 0 + ATIXL_BUSMOUSE, "atixl", THIS_MODULE, open_mouse, release_mouse, 0 }; static int __init atixl_busmouse_init(void) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/bttv.c linux/drivers/char/bttv.c --- v2.4.0-test1/linux/drivers/char/bttv.c Mon Jun 19 16:31:59 2000 +++ linux/drivers/char/bttv.c Tue Jun 20 07:32:13 2000 @@ -64,7 +64,6 @@ /* insmod args */ MODULE_PARM(triton1,"i"); -MODULE_PARM(remap,"1-4i"); MODULE_PARM(radio,"1-4i"); MODULE_PARM(card,"1-4i"); MODULE_PARM(pll,"1-4i"); @@ -76,6 +75,7 @@ MODULE_PARM(gbuffers,"i"); MODULE_PARM(gbufsize,"i"); +EXPORT_SYMBOL(bttv_get_cardinfo); EXPORT_SYMBOL(bttv_get_id); EXPORT_SYMBOL(bttv_gpio_enable); EXPORT_SYMBOL(bttv_read_gpio); @@ -91,7 +91,6 @@ static unsigned int bigendian=0; #endif static int triton1=0; -static unsigned long remap[BTTV_MAX]; static unsigned int radio[BTTV_MAX]; static unsigned int card[BTTV_MAX] = { 0, 0, 0, 0 }; static unsigned int pll[BTTV_MAX] = { -1, -1, -1, -1}; @@ -123,8 +122,19 @@ /* gpio ports (IR for example) */ /* see bttv.h for comments */ +int bttv_get_cardinfo(unsigned int card, int *type, int *cardid) +{ + if (card >= bttv_num) { + return -1; + } + *type = bttvs[card].type; + *cardid = bttvs[card].cardid; + return 0; +} + int bttv_get_id(unsigned int card) { + printk("bttv_get_id is obsolete, use bttv_get_cardinfo instead\n"); if (card >= bttv_num) { return -1; } @@ -180,7 +190,7 @@ return 0; } -WAIT_QUEUE* bttv_get_gpio_queue(unsigned int card) +wait_queue_head_t* bttv_get_gpio_queue(unsigned int card) { struct bttv *btv; @@ -467,7 +477,7 @@ NULL }; -static int __init init_bttv_i2c(struct bttv *btv) +static int __devinit init_bttv_i2c(struct bttv *btv) { /* i2c bit_adapter */ memcpy(&btv->i2c_adap, &i2c_adap_template, sizeof(struct i2c_adapter)); @@ -489,7 +499,7 @@ } /* read I2C */ -static int __init I2CRead(struct bttv *btv, unsigned char addr, char *probe_for) +static int I2CRead(struct bttv *btv, unsigned char addr, char *probe_for) { unsigned char buffer = 0; @@ -514,7 +524,7 @@ } /* write I2C */ -static int __init I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, +static int I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, unsigned char b2, int both) { unsigned char buffer[2]; @@ -531,7 +541,7 @@ } /* read EEPROM */ -static void __init readee(struct bttv *btv, unsigned char *eedata, int addr) +static void __devinit readee(struct bttv *btv, unsigned char *eedata, int addr) { int i; @@ -558,7 +568,7 @@ int id; char *name; } -hauppauge_tuner[] __initdata = +hauppauge_tuner[] __devinitdata = { { TUNER_ABSENT, "" }, { TUNER_ABSENT, "External" }, @@ -606,7 +616,7 @@ { TUNER_ABSENT, "Temic 4046FM5" }, }; -static void __init hauppauge_eeprom(struct bttv *btv) +static void __devinit hauppauge_eeprom(struct bttv *btv) { if (eeprom_data[9] < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) { @@ -615,11 +625,9 @@ printk("bttv%d: Hauppauge eeprom: tuner=%s (%d)\n",btv->nr, hauppauge_tuner[eeprom_data[9]].name,btv->tuner_type); } - - return; } -static void __init hauppauge_boot_msp34xx(struct bttv *btv) +static void __devinit hauppauge_boot_msp34xx(struct bttv *btv) { int i; @@ -655,7 +663,7 @@ /* This is basically the same procedure as * used by Alessandro Rubini in his pxc200 * driver, but using BTTV functions */ -static void __init init_PXC200(struct bttv *btv) +static void __devinit init_PXC200(struct bttv *btv) { static const int vals[] = { 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0d, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, @@ -705,7 +713,7 @@ unsigned id; int cardnr; char *name; -} cards[] __initdata = { +} cards[] __devinitdata = { { 0x00011002, BTTV_HAUPPAUGE878, "ATI TV Wonder" }, { 0x00011461, BTTV_AVPHONE98, "AVerMedia TVPhone98" }, { 0x00031461, BTTV_AVPHONE98, "AVerMedia TVPhone98" }, @@ -813,7 +821,7 @@ /* 0x10 */ { "Pixelview PlayTV (bt878)", - 3, 1, 0, 2, 0x01fe00, { 2, 0, 1, 1}, + 3, 1, 0, 2, 0x01fe00, { 2, 3, 1, 1}, { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 },0, 1,1,1,1,0,0,0,1, PLL_28, -1 }, { "Leadtek WinView 601", @@ -910,10 +918,18 @@ { "ProVideo PV951", /* pic16c54 */ 3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0, 0,0,0,0,0,0,0,0, PLL_28, 1 }, + { "Little OnAir TV", + 3, 1, 0, 2, 0xe00b, {2, 3, 1, 1}, + {0xff9ff6, 0xff9ff6, 0xff1ff7, 0, 0xff3ffc},0, + 0,0,0,0,0,0,0,0, PLL_NONE, -1 }, + + { "Sigma TVII-FM", + 2, 1, 0, -1, 3, {2, 3, 1, 1}, {1, 1, 0, 2, 3},0, + 0,0,0,0,0,0,0,0, PLL_NONE, -1 }, }; #define TVCARDS (sizeof(tvcards)/sizeof(struct tvcard)) -static void __init dump_eeprom(struct bttv *btv,int addr) +static void __devinit dump_eeprom(struct bttv *btv,int addr) { int i; @@ -930,7 +946,7 @@ } } -static int __init idcard_eeprom(struct bttv *btv) +static int __devinit idcard_eeprom(struct bttv *btv) { unsigned id; int i,n; @@ -943,6 +959,7 @@ return -1; /* look for the card */ + btv->cardid = id; for (n = -1, i = 0; cards[i].id != 0; i++) if (cards[i].id == id) n = i; @@ -1203,7 +1220,7 @@ unsigned int *po=(unsigned int *) btv->vbi_odd; unsigned int *pe=(unsigned int *) btv->vbi_even; - if (debug) + if (debug > 1) printk("bttv%d: vbi1: po=%08lx pe=%08lx\n", btv->nr,virt_to_bus(po), virt_to_bus(pe)); @@ -1225,7 +1242,7 @@ *(pe++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(0x01<<16)); *(pe++)=cpu_to_le32(virt_to_bus(btv->risc_jmp+10)); - if (debug) + if (debug > 1) printk("bttv%d: vbi2: po=%08lx pe=%08lx\n", btv->nr,virt_to_bus(po), virt_to_bus(pe)); } @@ -1302,7 +1319,7 @@ unsigned long vadr=(unsigned long) vbuf; int shift, csize; - if (debug) + if (debug > 1) printk("bttv%d: prisc1: ro=%08lx re=%08lx\n", btv->nr,virt_to_bus(ro), virt_to_bus(re)); @@ -1399,7 +1416,7 @@ *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16)); *(re++)=cpu_to_le32(btv->bus_vbi_odd); - if (debug) + if (debug > 1) printk("bttv%d: prisc2: ro=%08lx re=%08lx\n", btv->nr,virt_to_bus(ro), virt_to_bus(re)); @@ -1424,7 +1441,7 @@ if (palette>=VIDEO_PALETTE_PLANAR) return make_prisctab(btv, ro, re, vbuf, width, height, palette); - if (debug) + if (debug > 1) printk("bttv%d: vrisc1: ro=%08lx re=%08lx\n", btv->nr,virt_to_bus(ro), virt_to_bus(re)); @@ -1476,7 +1493,7 @@ *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16)); *(re++)=cpu_to_le32(btv->bus_vbi_odd); - if (debug) + if (debug > 1) printk("bttv%d: vrisc2: ro=%08lx re=%08lx\n", btv->nr,virt_to_bus(ro), virt_to_bus(re)); @@ -1494,7 +1511,7 @@ int W, l, r; int i; - if (debug) + if (debug > 1) printk("bttv clip: %dx%d+%d+%d\n",w,h,x,y); /* bitmap is fixed width, 128 bytes (1024 pixels represented) */ @@ -1559,7 +1576,7 @@ inter=(btv->win.interlace&1)^1; width=btv->win.width; height=btv->win.height; - if (debug) + if (debug > 1) printk("bttv%d: clip1: pal=%d size=%dx%d, bpl=%d bpp=%d\n", btv->nr,btv->picture.palette,width,height,bpl,bpp); if(width > 1023) @@ -1573,7 +1590,7 @@ printk("bttv%d: clip: ro=%08lx re=%08lx\n", btv->nr,virt_to_bus(ro), virt_to_bus(re)); - if ((clipmap=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) { + if ((clipmap=vmalloc_32(VIDEO_CLIPMAP_SIZE))==NULL) { /* can't clip, don't generate any risc code */ *(ro++)=cpu_to_le32(BT848_RISC_JUMP); *(ro++)=cpu_to_le32(btv->bus_vbi_even); @@ -1668,7 +1685,7 @@ *(re++)=cpu_to_le32(BT848_RISC_JUMP); *(re++)=cpu_to_le32(btv->bus_vbi_odd); - if (debug) + if (debug > 1) printk("bttv%d: clip2: pal=%d size=%dx%d, bpl=%d bpp=%d\n", btv->nr,btv->picture.palette,width,height,bpl,bpp); } @@ -1734,9 +1751,6 @@ u16 ewidth, eheight, owidth, oheight; u16 format, bswap; struct tvnorm *tvn; - unsigned long flags; - - spin_lock_irqsave(&btv->s_lock, flags); tvn=&tvnorms[btv->win.norm]; @@ -1789,8 +1803,6 @@ btwrite(format, BT848_COLOR_FMT); btwrite(bswap | BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL); - - spin_unlock_irqrestore(&btv->s_lock, flags); } @@ -1847,7 +1859,6 @@ /* * Grab into virtual memory. - * Currently only does double buffering. Do we need more? */ static int vgrab(struct bttv *btv, struct video_mmap *mp) @@ -1904,16 +1915,16 @@ btv->gbuf[mp->frame].ro = 0; #endif - if (btv->gq_in == btv->gq_out) { + if (-1 == btv->gq_grab && btv->gq_in == btv->gq_out) { btv->gq_start = 1; btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ); } btv->gqueue[btv->gq_in++] = mp->frame; btv->gq_in = btv->gq_in % MAX_GBUFFERS; - spin_unlock_irqrestore(&btv->s_lock, flags); btor(3, BT848_CAP_CTL); btor(3, BT848_GPIO_DMA_CTL); + spin_unlock_irqrestore(&btv->s_lock, flags); return 0; } @@ -1927,39 +1938,43 @@ { struct bttv *btv= (struct bttv *)v; int q,todo; + DECLARE_WAITQUEUE(wait, current); /* BROKEN: RETURNS VBI WHEN IT SHOULD RETURN GRABBED VIDEO FRAME */ todo=count; while (todo && todo>(q=VBIBUF_SIZE-btv->vbip)) { - unsigned long flags; - if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, q)) return -EFAULT; todo-=q; buf+=q; - spin_lock_irqsave(&btv->s_lock, flags); + add_wait_queue(&btv->vbiq, &wait); + current->state = TASK_INTERRUPTIBLE; if (todo && q==VBIBUF_SIZE-btv->vbip) { if(nonblock) { - spin_unlock_irqrestore(&btv->s_lock, flags); + remove_wait_queue(&btv->vbiq, &wait); + current->state = TASK_RUNNING; if(count==todo) return -EWOULDBLOCK; return count-todo; } - spin_unlock_irqrestore(&btv->s_lock, flags); - interruptible_sleep_on(&btv->vbiq); + schedule(); if(signal_pending(current)) { + remove_wait_queue(&btv->vbiq, &wait); + current->state = TASK_RUNNING; + if(todo==count) return -EINTR; else return count-todo; } - } else - spin_unlock_irqrestore(&btv->s_lock, flags); + } + remove_wait_queue(&btv->vbiq, &wait); + current->state = TASK_RUNNING; } if (todo) { @@ -1980,9 +1995,11 @@ static void bt848_restart(struct bttv *btv) { + unsigned long irq_flags; + if (verbose) printk("bttv%d: resetting chip\n",btv->nr); - btwrite(~0x0UL, BT848_INT_STAT); + btwrite(0xfffffUL, BT848_INT_STAT); btand(~15, BT848_GPIO_DMA_CTL); btwrite(0, BT848_SRESET); btwrite(virt_to_bus(btv->risc_jmp+2), @@ -1994,8 +2011,10 @@ btv->errors = 0; btv->needs_restart = 0; + spin_lock_irqsave(&btv->s_lock, irq_flags); bt848_set_geo(btv,0); bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); } /* @@ -2042,13 +2061,16 @@ static void bttv_close(struct video_device *dev) { struct bttv *btv=(struct bttv *)dev; + unsigned long irq_flags; down(&btv->lock); btv->user--; + spin_lock_irqsave(&btv->s_lock, irq_flags); btv->scr_on = 0; btv->risc_cap_odd = 0; btv->risc_cap_even = 0; bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); /* * A word of warning. At this point the chip @@ -2133,9 +2155,11 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) { struct bttv *btv=(struct bttv *)dev; + unsigned long irq_flags; int i,ret = 0; - if (debug) printk("bttv%d: ioctl 0x%x\n",btv->nr,cmd); + if (debug > 1) + printk("bttv%d: ioctl 0x%x\n",btv->nr,cmd); switch (cmd) { case VIDIOCGCAP: @@ -2206,7 +2230,9 @@ if (btv->win.norm != v.norm) { btv->win.norm = v.norm; make_vbitab(btv); + spin_lock_irqsave(&btv->s_lock, irq_flags); bt848_set_winsize(btv); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); } up(&btv->lock); return 0; @@ -2248,7 +2274,9 @@ down(&btv->lock); set_pll(btv); make_vbitab(btv); + spin_lock_irqsave(&btv->s_lock, irq_flags); bt848_set_winsize(btv); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); up(&btv->lock); } return 0; @@ -2289,12 +2317,13 @@ if(copy_from_user(&vw,arg,sizeof(vw))) return -EFAULT; + down(&btv->lock); if(vw.flags || vw.width < 16 || vw.height < 16) { - down(&btv->lock); + spin_lock_irqsave(&btv->s_lock, irq_flags); btv->scr_on = 0; bt848_set_risc_jmps(btv,-1); - up(&btv->lock); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); return -EINVAL; } if (btv->win.bpp < 4) @@ -2302,18 +2331,17 @@ vw.x = (vw.x + 3) & ~3; vw.width &= ~3; } - down(&btv->lock); if (btv->needs_restart) bt848_restart(btv); btv->win.x=vw.x; btv->win.y=vw.y; btv->win.width=vw.width; btv->win.height=vw.height; - + + spin_lock_irqsave(&btv->s_lock, irq_flags); bt848_set_risc_jmps(btv,0); - bt848_set_winsize(btv); - up(&btv->lock); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); /* * Do any clips. @@ -2337,11 +2365,12 @@ return -EFAULT; } } - down(&btv->lock); make_clip_tab(btv, vcp, vw.clipcount); if (vw.clipcount != 0) vfree(vcp); + spin_lock_irqsave(&btv->s_lock, irq_flags); bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); up(&btv->lock); return 0; } @@ -2370,13 +2399,13 @@ return -EINVAL; if (btv->win.width==0 || btv->win.height==0) return -EINVAL; - down(&btv->lock); + spin_lock_irqsave(&btv->s_lock, irq_flags); if (v == 1 && btv->win.vidadr != 0) btv->scr_on = 1; if (v == 0) btv->scr_on = 0; bt848_set_risc_jmps(btv,-1); - up(&btv->lock); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); return 0; } case VIDIOCGFBUF: @@ -2500,9 +2529,7 @@ if(!(v.flags&VIDEO_AUDIO_MUTE)) audio(btv, AUDIO_UNMUTE, 1); - up(&btv->lock); call_i2c_clients(btv,cmd,&v); - down(&btv->lock); if (btv->type == BTTV_TERRATV) { unsigned int con = 0; @@ -2554,6 +2581,9 @@ } case VIDIOCSYNC: + { + DECLARE_WAITQUEUE(wait, current); + if(copy_from_user((void *)&i,arg,sizeof(int))) return -EFAULT; if (i < 0 || i >= gbuffers) @@ -2563,13 +2593,20 @@ ret = -EINVAL; break; case GBUFFER_GRABBING: + add_wait_queue(&btv->capq, &wait); + current->state = TASK_INTERRUPTIBLE; while(btv->gbuf[i].stat==GBUFFER_GRABBING) { if (debug) printk("bttv%d: cap sync: sleep on %d\n",btv->nr,i); - interruptible_sleep_on(&btv->capq); - if(signal_pending(current)) + schedule(); + if(signal_pending(current)) { + remove_wait_queue(&btv->capq, &wait); + current->state = TASK_RUNNING; return -EINTR; + } } + remove_wait_queue(&btv->capq, &wait); + current->state = TASK_RUNNING; /* fall throuth */ case GBUFFER_DONE: case GBUFFER_ERROR: @@ -2584,6 +2621,7 @@ up(&btv->lock); } return ret; + } case BTTV_FIELDNR: if(copy_to_user((void *) arg, (void *) &btv->last_field, @@ -2602,7 +2640,6 @@ btv->pll.pll_ofreq = p.pll_ofreq; btv->pll.pll_crystal = p.pll_crystal; up(&btv->lock); - break; } @@ -2749,12 +2786,11 @@ { struct bttv *btv=(struct bttv *)(v-2); int q,todo; + DECLARE_WAITQUEUE(wait, current); todo=count; while (todo && todo>(q=VBIBUF_SIZE-btv->vbip)) { - unsigned long flags; - if (btv->needs_restart) { down(&btv->lock); bt848_restart(btv); @@ -2765,27 +2801,31 @@ todo-=q; buf+=q; - spin_lock_irqsave(&btv->s_lock, flags); + add_wait_queue(&btv->vbiq, &wait); + current->state = TASK_INTERRUPTIBLE; if (todo && q==VBIBUF_SIZE-btv->vbip) { if(nonblock) { - spin_unlock_irqrestore(&btv->s_lock, flags); + remove_wait_queue(&btv->vbiq, &wait); + current->state = TASK_RUNNING; if(count==todo) return -EWOULDBLOCK; return count-todo; } - spin_unlock_irqrestore(&btv->s_lock, flags); - interruptible_sleep_on(&btv->vbiq); + schedule(); if(signal_pending(current)) { + remove_wait_queue(&btv->vbiq, &wait); + current->state = TASK_RUNNING; if(todo==count) return -EINTR; else return count-todo; } - } else - spin_unlock_irqrestore(&btv->s_lock, flags); + } + remove_wait_queue(&btv->vbiq, &wait); + current->state = TASK_RUNNING; } if (todo) { @@ -2813,15 +2853,18 @@ static int vbi_open(struct video_device *dev, int flags) { struct bttv *btv=(struct bttv *)(dev-2); + unsigned long irq_flags; MOD_INC_USE_COUNT; - down(&btv->lock); if (btv->needs_restart) bt848_restart(btv); + set_pll(btv); btv->vbip=VBIBUF_SIZE; + spin_lock_irqsave(&btv->s_lock, irq_flags); btv->vbi_on = 1; bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); up(&btv->lock); return 0; @@ -2830,12 +2873,12 @@ static void vbi_close(struct video_device *dev) { struct bttv *btv=(struct bttv *)(dev-2); + unsigned long irq_flags; - down(&btv->lock); + spin_lock_irqsave(&btv->s_lock, irq_flags); btv->vbi_on = 0; bt848_set_risc_jmps(btv,-1); - up(&btv->lock); - + spin_unlock_irqrestore(&btv->s_lock, irq_flags); MOD_DEC_USE_COUNT; } @@ -3018,7 +3061,7 @@ #define TRITON_PEER_CONCURRENCY (1<<3) -static void __init handle_chipset(void) +static void __devinit handle_chipset(void) { struct pci_dev *dev = NULL; @@ -3050,7 +3093,7 @@ /* can tda9855.c handle this too maybe? */ -static void __init init_tda9840(struct bttv *btv) +static void __devinit init_tda9840(struct bttv *btv) { /* Horrible Hack */ I2CWrite(btv, I2C_TDA9840, TDA9840_SW, 0x2a, 1); /* sound mode switching */ @@ -3066,12 +3109,11 @@ /* Figure out card and tuner type */ -static void __init idcard(struct bttv *btv) +static void __devinit idcard(struct bttv *btv) { int type,eeprom = 0; btwrite(0, BT848_GPIO_OUT_EN); - DEBUG(printk(KERN_DEBUG "bttv%d: GPIO: 0x%08x\n", btv->nr, btread(BT848_GPIO_DATA))); /* Default the card to the user-selected one. */ if (card[btv->nr] >= 0 && card[btv->nr] < TVCARDS) @@ -3114,7 +3156,6 @@ (btv->id==848 && btv->revision==0x12) ? "A" : "", tvcards[btv->type].name); printk(KERN_INFO "bttv%d: model: %s\n",btv->nr,btv->video_dev.name); - /* board specific initialisations */ if (btv->type == BTTV_MIRO || btv->type == BTTV_MIROPRO) { @@ -3228,10 +3269,6 @@ static void bt848_set_risc_jmps(struct bttv *btv, int flags) { - unsigned long irq_flags; - - spin_lock_irqsave(&btv->s_lock, irq_flags); - if (-1 == flags) { /* defaults */ flags = 0; @@ -3241,8 +3278,9 @@ flags |= 0x0c; } - if (debug) printk("bttv%d: set_risc_jmp %08lx:", - btv->nr,virt_to_bus(btv->risc_jmp)); + if (debug > 1) + printk("bttv%d: set_risc_jmp %08lx:", + btv->nr,virt_to_bus(btv->risc_jmp)); /* Sync to start of odd field */ btv->risc_jmp[0]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC @@ -3252,24 +3290,29 @@ /* Jump to odd vbi sub */ btv->risc_jmp[2]=cpu_to_le32(BT848_RISC_JUMP|(0xd<<20)); if (flags&8) { - if (debug) printk(" ev=%08lx",virt_to_bus(btv->vbi_odd)); + if (debug > 1) + printk(" ev=%08lx",virt_to_bus(btv->vbi_odd)); btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->vbi_odd)); } else { - if (debug) printk(" -----------"); + if (debug > 1) + printk(" -----------"); btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->risc_jmp+4)); } /* Jump to odd sub */ btv->risc_jmp[4]=cpu_to_le32(BT848_RISC_JUMP|(0xe<<20)); if (0 != btv->risc_cap_odd) { - if (debug) printk(" e%d=%08x",btv->gq_grab,btv->risc_cap_odd); + if (debug > 1) + printk(" e%d=%08x",btv->gq_grab,btv->risc_cap_odd); flags |= 3; btv->risc_jmp[5]=cpu_to_le32(btv->risc_cap_odd); } else if (flags&2) { - if (debug) printk(" eo=%08lx",virt_to_bus(btv->risc_scr_odd)); + if (debug > 1) + printk(" eo=%08lx",virt_to_bus(btv->risc_scr_odd)); btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_scr_odd)); } else { - if (debug) printk(" -----------"); + if (debug > 1) + printk(" -----------"); btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_jmp+6)); } @@ -3282,24 +3325,29 @@ /* Jump to even vbi sub */ btv->risc_jmp[8]=cpu_to_le32(BT848_RISC_JUMP); if (flags&4) { - if (debug) printk(" ov=%08lx",virt_to_bus(btv->vbi_even)); + if (debug > 1) + printk(" ov=%08lx",virt_to_bus(btv->vbi_even)); btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->vbi_even)); } else { - if (debug) printk(" -----------"); + if (debug > 1) + printk(" -----------"); btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->risc_jmp+10)); } /* Jump to even sub */ btv->risc_jmp[10]=cpu_to_le32(BT848_RISC_JUMP|(8<<20)); if (0 != btv->risc_cap_even) { - if (debug) printk(" o%d=%08x",btv->gq_grab,btv->risc_cap_even); + if (debug > 1) + printk(" o%d=%08x",btv->gq_grab,btv->risc_cap_even); flags |= 3; btv->risc_jmp[11]=cpu_to_le32(btv->risc_cap_even); } else if (flags&1) { - if (debug) printk(" oo=%08lx",virt_to_bus(btv->risc_scr_even)); + if (debug > 1) + printk(" oo=%08lx",virt_to_bus(btv->risc_scr_even)); btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_scr_even)); } else { - if (debug) printk(" -----------"); + if (debug > 1) + printk(" -----------"); btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_jmp+12)); } @@ -3311,18 +3359,17 @@ btv->risc_jmp[13]=cpu_to_le32(virt_to_bus(btv->risc_jmp)); /* enable cpaturing and DMA */ - if (debug) printk(" flags=0x%x dma=%s\n", - flags,(flags&0x0f) ? "on" : "off"); + if (debug > 1) + printk(" flags=0x%x dma=%s\n", + flags,(flags&0x0f) ? "on" : "off"); btaor(flags, ~0x0f, BT848_CAP_CTL); if (flags&0x0f) bt848_dma(btv, 3); else bt848_dma(btv, 0); - - spin_unlock_irqrestore(&btv->s_lock, irq_flags); } -static int __init init_video_dev(struct bttv *btv) +static int __devinit init_video_dev(struct bttv *btv) { memcpy(&btv->video_dev,&bttv_template, sizeof(bttv_template)); memcpy(&btv->vbi_dev,&vbi_template, sizeof(vbi_template)); @@ -3349,9 +3396,10 @@ return 1; } -static int __init init_bt848(struct bttv *btv) +static int __devinit init_bt848(struct bttv *btv) { int j; + unsigned long irq_flags; btv->user=0; init_MUTEX(&btv->lock); @@ -3412,14 +3460,13 @@ return -1; if (!(btv->risc_jmp =(unsigned int *) kmalloc(2048, GFP_KERNEL))) return -1; - DEBUG(printk(KERN_DEBUG "risc_jmp: %p\n",btv->risc_jmp)); btv->vbi_odd=btv->risc_jmp+16; btv->vbi_even=btv->vbi_odd+256; btv->bus_vbi_odd=virt_to_bus(btv->risc_jmp+12); btv->bus_vbi_even=virt_to_bus(btv->risc_jmp+6); btwrite(virt_to_bus(btv->risc_jmp+2), BT848_RISC_STRT_ADD); - btv->vbibuf=(unsigned char *) vmalloc(VBIBUF_SIZE); + btv->vbibuf=(unsigned char *) vmalloc_32(VBIBUF_SIZE); if (!btv->vbibuf) return -1; if (!(btv->gbuf = kmalloc(sizeof(struct bttv_gbuf)*gbuffers,GFP_KERNEL))) @@ -3475,7 +3522,7 @@ btwrite(0x00, BT848_O_SCLOOP); /* clear interrupt status */ - btwrite(~0x0UL, BT848_INT_STAT); + btwrite(0xfffffUL, BT848_INT_STAT); /* set interrupt mask */ btwrite(btv->triton1| @@ -3489,8 +3536,10 @@ BT848_INT_MASK); make_vbitab(btv); + spin_lock_irqsave(&btv->s_lock, irq_flags); bt848_set_risc_jmps(btv,-1); - + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + /* * Now add the template and register the device unit. */ @@ -3505,7 +3554,8 @@ u32 dstat; int count,i; struct bttv *btv; - + unsigned long irq_flags; + btv=(struct bttv *)dev_id; count=0; while (1) @@ -3515,6 +3565,7 @@ astat=stat&btread(BT848_INT_MASK); if (!astat) return; + btwrite(astat,BT848_INT_STAT); IDEBUG(printk ("bttv%d: astat=%08x\n", btv->nr, astat)); IDEBUG(printk ("bttv%d: stat=%08x\n", btv->nr, stat)); @@ -3550,15 +3601,18 @@ btread(BT848_RISC_COUNT)); btv->errors++; if (btv->errors < BTTV_ERRORS) { + spin_lock_irqsave(&btv->s_lock, irq_flags); btand(~15, BT848_GPIO_DMA_CTL); btwrite(virt_to_bus(btv->risc_jmp+2), BT848_RISC_STRT_ADD); bt848_set_geo(btv,0); bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); } else { if (verbose) printk("bttv%d: aiee: error loops\n",btv->nr); /* cancel all outstanding grab requests */ + spin_lock_irqsave(&btv->s_lock, irq_flags); btv->gq_in = 0; btv->gq_out = 0; btv->gq_grab = -1; @@ -3569,8 +3623,9 @@ btv->risc_cap_odd = 0; btv->risc_cap_even = 0; bt848_set_risc_jmps(btv,0); - btv->needs_restart = 1; + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + wake_up_interruptible(&btv->vbiq); wake_up_interruptible(&btv->capq); } @@ -3596,6 +3651,7 @@ if (debug) printk("bttv%d: cap irq: done %d\n",btv->nr,btv->gq_grab); do_gettimeofday(&btv->gbuf[btv->gq_grab].tv); + spin_lock_irqsave(&btv->s_lock, irq_flags); btv->gbuf[btv->gq_grab].stat = GBUFFER_DONE; btv->gq_grab = -1; if (btv->gq_in != btv->gq_out) @@ -3618,22 +3674,25 @@ btwrite(btv->fb_color_ctl | BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL); } + spin_unlock_irqrestore(&btv->s_lock, irq_flags); wake_up_interruptible(&btv->capq); break; } if (stat&(8<<28)) { + spin_lock_irqsave(&btv->s_lock, irq_flags); btv->gq_start = 0; btv->gq_grab = btv->gqueue[btv->gq_out++]; btv->gq_out = btv->gq_out % MAX_GBUFFERS; if (debug) - printk("bttv%d: cap irq: capture %d\n",btv->nr,btv->gq_grab); + printk("bttv%d: cap irq: capture %d [start]\n",btv->nr,btv->gq_grab); btv->risc_cap_odd = btv->gbuf[btv->gq_grab].ro; btv->risc_cap_even = btv->gbuf[btv->gq_grab].re; bt848_set_risc_jmps(btv,-1); bt848_set_geo(btv,0); btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); } } if (astat&BT848_INT_OCERR) @@ -3676,9 +3735,6 @@ { IDEBUG(printk ("bttv%d: IRQ_I2CDONE\n", btv->nr)); } - - btwrite(astat,BT848_INT_STAT); - count++; if (count > 10) printk (KERN_WARNING "bttv%d: irq loop %d\n", @@ -3698,11 +3754,11 @@ * Scan for a Bt848 card, request the irq and map the io memory */ -static void __init bttv_remove(struct pci_dev *pci_dev) +static void __devinit bttv_remove(struct pci_dev *pci_dev) { u8 command; int j; - struct bttv *btv = pci_dev->driver_data; + struct bttv *btv = PCI_GET_DRIVER_DATA(pci_dev); /* unregister i2c_bus */ i2c_bit_del_bus(&btv->i2c_adap); @@ -3767,7 +3823,7 @@ } -static int __init bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) +static int __devinit bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) { int result; unsigned char command; @@ -3788,20 +3844,17 @@ btv->vbi_even=NULL; init_waitqueue_head(&btv->vbiq); init_waitqueue_head(&btv->capq); - init_waitqueue_head(&btv->capqo); - init_waitqueue_head(&btv->capqe); btv->vbip=VBIBUF_SIZE; - - init_waitqueue_head(&btv->gpioq); btv->s_lock = SPIN_LOCK_UNLOCKED; + init_waitqueue_head(&btv->gpioq); btv->shutdown=0; btv->id=dev->device; btv->irq=dev->irq; - btv->bt848_adr=pci_resource_start(dev, 0); + btv->bt848_adr=pci_resource_start(dev,0); if (pci_enable_device(dev)) return -EIO; - if (!request_mem_region(btv->bt848_adr, + if (!request_mem_region(pci_resource_start(dev,0), pci_resource_len(dev,0), "bttv")) { return -EBUSY; @@ -3871,24 +3924,23 @@ } } - dev->driver_data = btv; + PCI_SET_DRIVER_DATA(dev,btv); if(init_bt848(btv) < 0) { bttv_remove(dev); return -EIO; } - bttv_num++; return 0; fail: - release_mem_region(btv->bt848_adr, + release_mem_region(pci_resource_start(btv->dev,0), pci_resource_len(btv->dev,0)); return result; } -static struct pci_device_id bttv_pci_tbl[] __initdata = { +static struct pci_device_id bttv_pci_tbl[] __devinitdata = { {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849, @@ -3903,13 +3955,13 @@ MODULE_DEVICE_TABLE(pci, bttv_pci_tbl); static struct pci_driver bttv_pci_driver = { - name:"bttv", - id_table:bttv_pci_tbl, - probe:bttv_probe, - remove:bttv_remove, + name: "bttv", + id_table: bttv_pci_tbl, + probe: bttv_probe, + remove: bttv_remove, }; -static int __init bttv_init_module(void) +int bttv_init_module(void) { bttv_num = 0; @@ -3930,10 +3982,10 @@ return pci_module_init(&bttv_pci_driver); } -static void __exit bttv_cleanup_module(void) +void bttv_cleanup_module(void) { pci_unregister_driver(&bttv_pci_driver); - return; + return; } module_init(bttv_init_module); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/bttv.h linux/drivers/char/bttv.h --- v2.4.0-test1/linux/drivers/char/bttv.h Tue May 23 15:31:34 2000 +++ linux/drivers/char/bttv.h Tue Jun 20 07:32:13 2000 @@ -21,7 +21,12 @@ #ifndef _BTTV_H_ #define _BTTV_H_ -#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,28) +#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,31) + +#ifndef PCI_GET_DRIVER_DATA +# define PCI_GET_DRIVER_DATA(pdev) ((pdev)->driver_data) +# define PCI_SET_DRIVER_DATA(pdev,data) (((pdev)->driver_data) = (data)) +#endif /* PCI_GET_DRIVER_DATA */ #include #include @@ -32,12 +37,13 @@ #include "audiochip.h" #include "bt848.h" -#define WAIT_QUEUE wait_queue_head_t - -/* returns card type, +/* returns card type + card ID (for bt878-based ones) for possible values see lines below beginning with #define BTTV_UNKNOWN returns negative value if error ocurred */ +extern int bttv_get_cardinfo(unsigned int card, int *type, int *cardid); + +/* obsolete, use bttv_get_cardinfo instead */ extern int bttv_get_id(unsigned int card); /* sets GPOE register (BT848_GPIO_OUT_EN) to new value: @@ -68,7 +74,7 @@ WARNING: because there is no buffer for GPIO data, one MUST process data ASAP */ -extern WAIT_QUEUE* bttv_get_gpio_queue(unsigned int card); +extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card); #ifndef O_NONCAP @@ -130,6 +136,7 @@ struct video_picture picture; /* Current picture params */ struct video_audio audio_dev; /* Current audio params */ + spinlock_t s_lock; struct semaphore lock; int user; int capuser; @@ -143,8 +150,6 @@ int tuner_type; int channel; - - spinlock_t s_lock; unsigned int nr; unsigned short id; @@ -160,6 +165,7 @@ struct bttv_window win; int fb_color_ctl; int type; /* card type */ + int cardid; int audio; /* audio mode */ int audio_chip; /* set to one of the chips supported by bttv.c */ int radio; @@ -169,10 +175,8 @@ u32 *vbi_even; u32 bus_vbi_even; u32 bus_vbi_odd; - WAIT_QUEUE vbiq; - WAIT_QUEUE capq; - WAIT_QUEUE capqo; - WAIT_QUEUE capqe; + wait_queue_head_t vbiq; + wait_queue_head_t capq; int vbip; u32 *risc_scr_odd; @@ -198,7 +202,7 @@ int errors; int needs_restart; - WAIT_QUEUE gpioq; + wait_queue_head_t gpioq; int shutdown; }; #endif @@ -277,6 +281,8 @@ #define BTTV_STB2 0x28 #define BTTV_AVPHONE98 0x29 #define BTTV_PV951 0x2a +#define BTTV_ONAIR_TV 0x2b +#define BTTV_SIGMA_TVII_FM 0x2c #define PLL_NONE 0 #define PLL_28 1 diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/busmouse.c linux/drivers/char/busmouse.c --- v2.4.0-test1/linux/drivers/char/busmouse.c Wed Apr 26 16:34:07 2000 +++ linux/drivers/char/busmouse.c Wed Jun 21 10:10:02 2000 @@ -110,8 +110,7 @@ if (changed) { wake_up(&mse->wait); - if (mse->fasyncptr) - kill_fasync(mse->fasyncptr, SIGIO, POLL_IN); + kill_fasync(&mse->fasyncptr, SIGIO, POLL_IN); } } @@ -171,13 +170,13 @@ busmouse_fasync(-1, file, 0); if (--mse->active == 0) { - if (mse->ops && - mse->ops->release) - ret = mse->ops->release(inode, file); - + if (mse->ops) { + if (mse->ops->release) + ret = mse->ops->release(inode, file); + if (mse->ops->owner) + __MOD_DEC_USE_COUNT(mse->ops->owner); + } mse->ready = 0; - - MOD_DEC_USE_COUNT; } return ret; @@ -192,16 +191,20 @@ mousedev = DEV_TO_MOUSE(inode->i_rdev); if (mousedev >= NR_MICE) return -EINVAL; - + down(&mouse_sem); mse = busmouse_data[mousedev]; if (!mse) /* shouldn't happen, but... */ goto end; - if (mse->ops && - mse->ops->open) + if (mse->ops && mse->ops->owner) + __MOD_INC_USE_COUNT(mse->ops->owner); + if (mse->ops && mse->ops->open) { ret = mse->ops->open(inode, file); + if (ret && mse->ops->owner) + __MOD_DEC_USE_COUNT(mse->ops->owner); + } if (ret) goto end; @@ -211,8 +214,6 @@ if (mse->active++) goto end; - MOD_INC_USE_COUNT; - spin_lock_irq(&mse->lock); mse->ready = 0; @@ -333,6 +334,7 @@ struct file_operations busmouse_fops= { + owner: THIS_MODULE, read: busmouse_read, write: busmouse_write, poll: busmouse_poll, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/busmouse.h linux/drivers/char/busmouse.h --- v2.4.0-test1/linux/drivers/char/busmouse.h Wed Apr 26 16:34:07 2000 +++ linux/drivers/char/busmouse.h Mon Jun 19 13:25:06 2000 @@ -11,6 +11,7 @@ struct busmouse { int minor; const char *name; + struct module *owner; int (*open)(struct inode * inode, struct file * file); int (*release)(struct inode * inode, struct file * file); int init_button_state; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/buz.c linux/drivers/char/buz.c --- v2.4.0-test1/linux/drivers/char/buz.c Thu May 11 15:30:06 2000 +++ linux/drivers/char/buz.c Mon Jun 19 17:59:42 2000 @@ -48,6 +48,7 @@ #include #include #include +#include #include diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/c-qcam.c linux/drivers/char/c-qcam.c --- v2.4.0-test1/linux/drivers/char/c-qcam.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/char/c-qcam.c Mon Jun 19 17:59:42 2000 @@ -12,9 +12,15 @@ * probe=1 -- use IEEE-1284 autoprobe data only (default) * probe=2 -- probe aggressively for cameras * + * force_rgb=1 -- force data format to RGB (default is BGR) + * * The parport parameter controls which parports will be scanned. * Scanning all parports causes some printers to print a garbage page. * -- March 14, 1999 Billy Donahue + * + * Fixed data format to BGR, added force_rgb parameter. Added missing + * parport_unregister_driver() on module removal. + * -- May 28, 2000 Claudio Matsuoka */ #include @@ -62,6 +68,7 @@ static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 }; static int probe = 2; +static int force_rgb = 0; static inline void qcam_set_ack(struct qcam_device *qcam, unsigned int i) { @@ -278,6 +285,7 @@ static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, unsigned int nbytes) { unsigned int bytes = 0; + qcam_set_ack(q, 0); if (q->bidirectional) { @@ -285,6 +293,8 @@ while (bytes < nbytes) { unsigned int lo1, hi1, lo2, hi2; + unsigned char r, g, b; + if (qcam_await_ready2(q, 1)) return bytes; lo1 = parport_read_data(q->pport) >> 1; hi1 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10; @@ -293,17 +303,30 @@ lo2 = parport_read_data(q->pport) >> 1; hi2 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10; qcam_set_ack(q, 0); - buf[bytes++] = (lo1 | ((hi1 & 1)<<7)); - buf[bytes++] = ((hi1 & 0x1e)<<3) | ((hi2 & 0x1e)>>1); - buf[bytes++] = (lo2 | ((hi2 & 1)<<7)); + r = (lo1 | ((hi1 & 1)<<7)); + g = ((hi1 & 0x1e)<<3) | ((hi2 & 0x1e)>>1); + b = (lo2 | ((hi2 & 1)<<7)); + if (force_rgb) { + buf[bytes++] = r; + buf[bytes++] = g; + buf[bytes++] = b; + } else { + buf[bytes++] = b; + buf[bytes++] = g; + buf[bytes++] = r; + } } } else { /* It's a unidirectional port */ + int i = 0, n = bytes; + unsigned char rgb[3]; + while (bytes < nbytes) { unsigned int hi, lo; + if (qcam_await_ready1(q, 1)) return bytes; hi = (parport_read_status(q->pport) & 0xf0); qcam_set_ack(q, 1); @@ -311,7 +334,23 @@ lo = (parport_read_status(q->pport) & 0xf0); qcam_set_ack(q, 0); /* flip some bits */ - buf[bytes++] = (hi | (lo >> 4)) ^ 0x88; + rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88; + if (i >= 2) { +get_fragment: + if (force_rgb) { + buf[n++] = rgb[0]; + buf[n++] = rgb[1]; + buf[n++] = rgb[2]; + } else { + buf[n++] = rgb[2]; + buf[n++] = rgb[1]; + buf[n++] = rgb[0]; + } + } + } + if (i) { + i = 0; + goto get_fragment; } } return bytes; @@ -408,8 +447,13 @@ if (current->need_resched) schedule(); } while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e)); - if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) - printk("qcam: bad EOF\n"); + if (force_rgb) { + if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) + printk("qcam: bad EOF\n"); + } else { + if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe) + printk("qcam: bad EOF\n"); + } qcam_set_ack(q, 0); if (qcam_await_ready1(q, 1)) { @@ -437,8 +481,13 @@ schedule(); } while (l && tmpbuf[0] == 0x7e); l = qcam_read_bytes(q, tmpbuf+1, 2); - if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) - printk("qcam: bad EOF\n"); + if (force_rgb) { + if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) + printk("qcam: bad EOF\n"); + } else { + if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe) + printk("qcam: bad EOF\n"); + } } qcam_write_data(q, 0); @@ -829,19 +878,24 @@ return parport_register_driver(&cqcam_driver); } -MODULE_AUTHOR("Philip Blundell "); -MODULE_DESCRIPTION(BANNER); -MODULE_PARM_DESC(parport ,"parport= for port detection method \n\ -probe=<0|1|2> # for camera detection method"); -MODULE_PARM(parport, "1-" __MODULE_STRING(MAX_CAMS) "i"); -MODULE_PARM(probe, "i"); - static void __exit cqcam_cleanup (void) { unsigned int i; + for (i = 0; i < num_cams; i++) close_cqcam(qcams[i]); + + parport_unregister_driver(&cqcam_driver); } + +MODULE_AUTHOR("Philip Blundell "); +MODULE_DESCRIPTION(BANNER); +MODULE_PARM_DESC(parport ,"parport= for port detection method\n\ +probe=<0|1|2> for camera detection method\n\ +force_rgb=<0|1> for RGB data format (default BGR)"); +MODULE_PARM(parport, "1-" __MODULE_STRING(MAX_CAMS) "i"); +MODULE_PARM(probe, "i"); +MODULE_PARM(force_rgb, "i"); module_init(cqcam_init); module_exit(cqcam_cleanup); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/console.c linux/drivers/char/console.c --- v2.4.0-test1/linux/drivers/char/console.c Tue Apr 11 15:09:16 2000 +++ linux/drivers/char/console.c Mon Jun 19 13:25:06 2000 @@ -2290,10 +2290,13 @@ static void con_flush_chars(struct tty_struct *tty) { + unsigned long flags; struct vt_struct *vt = (struct vt_struct *)tty->driver_data; pm_access(pm_con); + spin_lock_irqsave(&console_lock, flags); set_cursor(vt->vc_num); + spin_unlock_irqrestore(&console_lock, flags); } /* diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c --- v2.4.0-test1/linux/drivers/char/cyclades.c Fri May 12 14:18:55 2000 +++ linux/drivers/char/cyclades.c Tue Jun 20 07:32:13 2000 @@ -1,7 +1,8 @@ #undef BLOCKMOVE #define Z_WAKE +#undef Z_EXT_CHARS_IN_BUFFER static char rcsid[] = -"$Revision: 2.3.2.6 $$Date: 2000/05/05 13:56:05 $"; +"$Revision: 2.3.2.7 $$Date: 2000/06/01 18:26:34 $"; /* * linux/drivers/char/cyclades.c @@ -24,6 +25,12 @@ * This version supports shared IRQ's (only for PCI boards). * * $Log: cyclades.c,v $ + * Revision 2.3.2.7 2000/06/01 18:26:34 ivan + * Request PLX I/O region, although driver doesn't use it, to avoid + * problems with other drivers accessing it. + * Removed count for on-board buffer characters in cy_chars_in_buffer + * (Cyclades-Z only). + * * Revision 2.3.2.6 2000/05/05 13:56:05 ivan * Driver now reports physical instead of virtual memory addresses. * Masks were added to some Cyclades-Z read accesses. @@ -636,6 +643,7 @@ #include #include #include +#include #include #include #include @@ -882,9 +890,8 @@ static long cyz_polling_cycle = CZ_DEF_POLL; static int cyz_timeron = 0; -static struct timer_list -cyz_timerlist = { - NULL, NULL, 0, 0, cyz_poll +static struct timer_list cyz_timerlist = { + function: cyz_poll }; #else /* CONFIG_CYZ_INTR */ static void cyz_rx_restart(unsigned long); @@ -3122,12 +3129,15 @@ card = info->card; channel = (info->line) - (cy_card[card].first_line); +#ifdef Z_EXT_CHARS_IN_BUFFER if (!IS_CYC_Z(cy_card[card])) { +#endif /* Z_EXT_CHARS_IN_BUFFER */ #ifdef CY_DEBUG_IO printk("cyc:cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt); /* */ #endif return info->xmit_cnt; +#ifdef Z_EXT_CHARS_IN_BUFFER } else { static volatile struct FIRM_ID *firm_id; static volatile struct ZFW_CTRL *zfw_ctrl; @@ -3156,6 +3166,7 @@ #endif return (info->xmit_cnt + char_count); } +#endif /* Z_EXT_CHARS_IN_BUFFER */ } /* cy_chars_in_buffer */ @@ -4856,7 +4867,7 @@ struct pci_dev *pdev = NULL; unsigned char cyy_rev_id; unsigned char cy_pci_irq = 0; - uclong cy_pci_phys0, cy_pci_phys2; + uclong cy_pci_phys0, cy_pci_phys1, cy_pci_phys2; uclong cy_pci_addr0, cy_pci_addr2; unsigned short i,j,cy_pci_nchan, plx_ver; unsigned short device_id,dev_index = 0; @@ -4885,6 +4896,7 @@ /* read PCI configuration area */ cy_pci_irq = pdev->irq; cy_pci_phys0 = pci_resource_start(pdev, 0); + cy_pci_phys1 = pci_resource_start(pdev, 1); cy_pci_phys2 = pci_resource_start(pdev, 2); pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id); @@ -4907,6 +4919,11 @@ pdev->resource[2].flags &= ~IORESOURCE_IO; } + /* Although we don't use this I/O region, we should + request it from the kernel anyway, to avoid problems + with other drivers accessing it. */ + request_region(cy_pci_phys1, CyPCI_Yctl, "Cyclom-Y"); + #if defined(__alpha__) if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */ printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ", @@ -5054,6 +5071,12 @@ "Ignoring it...\n"); pdev->resource[2].flags &= ~IORESOURCE_IO; } + + /* Although we don't use this I/O region, we should + request it from the kernel anyway, to avoid problems + with other drivers accessing it. */ + request_region(cy_pci_phys1, CyPCI_Zctl, "Cyclades-Z"); + if (mailbox == ZE_V1) { #if !defined(__alpha__) cy_pci_addr2 = (ulong)ioremap(cy_pci_phys2, CyPCI_Ze_win); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/dn_keyb.c linux/drivers/char/dn_keyb.c --- v2.4.0-test1/linux/drivers/char/dn_keyb.c Thu Nov 11 20:11:33 1999 +++ linux/drivers/char/dn_keyb.c Mon Jun 19 13:25:06 2000 @@ -357,17 +357,14 @@ mouse_dy+=mouse_packet[2] == 0xff ? 0 : (signed char)mouse_packet[2]; wake_up_interruptible(&mouse_wait); if (mouse_dx < -2048) - mouse_dx = -2048; - else - if (mouse_dx > 2048) - mouse_dx = 2048; - if (mouse_dy < -2048) - mouse_dy = -2048; - else - if (mouse_dy > 2048) - mouse_dy = 2048; - if (mouse_fasyncptr) - kill_fasync(mouse_fasyncptr, SIGIO, POLL_IN); + mouse_dx = -2048; + else if (mouse_dx > 2048) + mouse_dx = 2048; + if (mouse_dy < -2048) + mouse_dy = -2048; + else if (mouse_dy > 2048) + mouse_dy = 2048; + kill_fasync(&mouse_fasyncptr, SIGIO, POLL_IN); } mouse_byte_count=0; /* printk("mouse: %d, %d, %x\n",mouse_x,mouse_y,buttons); */ @@ -450,20 +447,8 @@ } -static int release_mouse(struct inode * inode, struct file * file) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -static int open_mouse(struct inode * inode, struct file * file) -{ - MOD_INC_USE_COUNT; - return 0; -} - static struct busmouse apollo_mouse = { - APOLLO_MOUSE_MINOR, "apollomouse", open_mouse, release_mouse,7 + APOLLO_MOUSE_MINOR, "apollomouse", THIS_MODULE, NULL, NULL, 7 }; int __init dn_keyb_init(void){ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/drm/Makefile linux/drivers/char/drm/Makefile --- v2.4.0-test1/linux/drivers/char/drm/Makefile Tue Jan 4 13:57:16 2000 +++ linux/drivers/char/drm/Makefile Wed Jun 21 10:10:02 2000 @@ -39,6 +39,17 @@ endif endif +ifeq ($(CONFIG_DRM_FFB),y) + OX_OBJS += ffb_drv.o + O_OBJS += ffb_context.o +else + ifeq ($(CONFIG_DRM_FFB),m) + MIX_OBJC += ffb_drv.o + MI_OBJS += ffb_context.o + M_OBJS += ffb.o + endif +endif + O_OBJS += $(L_OBJS) include $(TOPDIR)/Rules.make @@ -48,3 +59,6 @@ tdfx.o: tdfx_drv.o tdfx_context.o $(L_OBJS) $(LD) $(LD_RFLAG) -r -o $@ tdfx_drv.o tdfx_context.o $(L_OBJS) + +ffb.o: ffb_drv.o ffb_context.o $(L_OBJS) + $(LD) $(LD_RFLAG) -r -o $@ ffb_drv.o ffb_context.o $(L_OBJS) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/drm/bufs.c linux/drivers/char/drm/bufs.c --- v2.4.0-test1/linux/drivers/char/drm/bufs.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/char/drm/bufs.c Wed Jun 21 10:10:02 2000 @@ -72,11 +72,13 @@ switch (map->type) { case _DRM_REGISTERS: case _DRM_FRAME_BUFFER: +#ifndef __sparc__ if (map->offset + map->size < map->offset || map->offset < virt_to_phys(high_memory)) { drm_free(map, sizeof(*map), DRM_MEM_MAPS); return -EINVAL; } +#endif #ifdef CONFIG_MTRR if (map->type == _DRM_FRAME_BUFFER || (map->flags & _DRM_WRITE_COMBINING)) { @@ -478,8 +480,10 @@ -EFAULT); if (request.count >= dma->buf_count) { + down(¤t->mm->mmap_sem); virtual = do_mmap(filp, 0, dma->byte_count, PROT_READ|PROT_WRITE, MAP_SHARED, 0); + up(¤t->mm->mmap_sem); if (virtual > -1024UL) { /* Real error */ retcode = (signed long)virtual; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/drm/drmP.h linux/drivers/char/drm/drmP.h --- v2.4.0-test1/linux/drivers/char/drm/drmP.h Sun Mar 19 18:35:30 2000 +++ linux/drivers/char/drm/drmP.h Fri Jun 23 21:30:23 2000 @@ -433,9 +433,9 @@ /* Context support */ int irq; /* Interrupt used by board */ - __volatile__ int context_flag; /* Context swapping flag */ - __volatile__ int interrupt_flag;/* Interruption handler flag */ - __volatile__ int dma_flag; /* DMA dispatch flag */ + __volatile__ long context_flag; /* Context swapping flag */ + __volatile__ long interrupt_flag;/* Interruption handler flag */ + __volatile__ long dma_flag; /* DMA dispatch flag */ struct timer_list timer; /* Timer for delaying ctx switch */ wait_queue_head_t context_wait; /* Processes waiting on ctx switch */ int last_checked; /* Last context checked for DMA */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/drm/ffb_context.c linux/drivers/char/drm/ffb_context.c --- v2.4.0-test1/linux/drivers/char/drm/ffb_context.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/drm/ffb_context.c Wed Jun 21 10:10:02 2000 @@ -0,0 +1,530 @@ +/* $Id: ffb_context.c,v 1.3 2000/06/09 03:46:53 davem Exp $ + * ffb_context.c: Creator/Creator3D DRI/DRM context switching. + * + * Copyright (C) 2000 David S. Miller (davem@redhat.com) + * + * Almost entirely stolen from tdfx_context.c, see there + * for authors. + */ + +#include +#include + +#include "drmP.h" + +#include "ffb_drv.h" + +static int ffb_alloc_queue(drm_device_t *dev, int is_2d_only) +{ + ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1); + int i; + + for (i = 0; i < FFB_MAX_CTXS; i++) { + if (fpriv->hw_state[i] == NULL) + break; + } + if (i == FFB_MAX_CTXS) + return -1; + + fpriv->hw_state[i] = kmalloc(sizeof(struct ffb_hw_context), GFP_KERNEL); + if (fpriv->hw_state[i] == NULL) + return -1; + + fpriv->hw_state[i]->is_2d_only = is_2d_only; + + /* Plus one because 0 is the special DRM_KERNEL_CONTEXT. */ + return i + 1; +} + +static void ffb_save_context(ffb_dev_priv_t *fpriv, int idx) +{ + ffb_fbcPtr ffb = fpriv->regs; + struct ffb_hw_context *ctx; + int i; + + ctx = fpriv->hw_state[idx - 1]; + if (idx == 0 || ctx == NULL) + return; + + if (ctx->is_2d_only) { + /* 2D applications only care about certain pieces + * of state. + */ + ctx->drawop = upa_readl(&ffb->drawop); + ctx->ppc = upa_readl(&ffb->ppc); + ctx->wid = upa_readl(&ffb->wid); + ctx->fg = upa_readl(&ffb->fg); + ctx->bg = upa_readl(&ffb->bg); + ctx->xclip = upa_readl(&ffb->xclip); + ctx->fbc = upa_readl(&ffb->fbc); + ctx->rop = upa_readl(&ffb->rop); + ctx->cmp = upa_readl(&ffb->cmp); + ctx->matchab = upa_readl(&ffb->matchab); + ctx->magnab = upa_readl(&ffb->magnab); + ctx->pmask = upa_readl(&ffb->pmask); + ctx->xpmask = upa_readl(&ffb->xpmask); + ctx->lpat = upa_readl(&ffb->lpat); + ctx->fontxy = upa_readl(&ffb->fontxy); + ctx->fontw = upa_readl(&ffb->fontw); + ctx->fontinc = upa_readl(&ffb->fontinc); + + /* stencil/stencilctl only exists on FFB2+ and later + * due to the introduction of 3DRAM-III. + */ + if (fpriv->ffb_type == ffb2_vertical_plus || + fpriv->ffb_type == ffb2_horizontal_plus) { + ctx->stencil = upa_readl(&ffb->stencil); + ctx->stencilctl = upa_readl(&ffb->stencilctl); + } + + for (i = 0; i < 32; i++) + ctx->area_pattern[i] = upa_readl(&ffb->pattern[i]); + ctx->ucsr = upa_readl(&ffb->ucsr); + return; + } + + /* Fetch drawop. */ + ctx->drawop = upa_readl(&ffb->drawop); + + /* If we were saving the vertex registers, this is where + * we would do it. We would save 32 32-bit words starting + * at ffb->suvtx. + */ + + /* Capture rendering attributes. */ + + ctx->ppc = upa_readl(&ffb->ppc); /* Pixel Processor Control */ + ctx->wid = upa_readl(&ffb->wid); /* Current WID */ + ctx->fg = upa_readl(&ffb->fg); /* Constant FG color */ + ctx->bg = upa_readl(&ffb->bg); /* Constant BG color */ + ctx->consty = upa_readl(&ffb->consty); /* Constant Y */ + ctx->constz = upa_readl(&ffb->constz); /* Constant Z */ + ctx->xclip = upa_readl(&ffb->xclip); /* X plane clip */ + ctx->dcss = upa_readl(&ffb->dcss); /* Depth Cue Scale Slope */ + ctx->vclipmin = upa_readl(&ffb->vclipmin); /* Primary XY clip, minimum */ + ctx->vclipmax = upa_readl(&ffb->vclipmax); /* Primary XY clip, maximum */ + ctx->vclipzmin = upa_readl(&ffb->vclipzmin); /* Primary Z clip, minimum */ + ctx->vclipzmax = upa_readl(&ffb->vclipzmax); /* Primary Z clip, maximum */ + ctx->dcsf = upa_readl(&ffb->dcsf); /* Depth Cue Scale Front Bound */ + ctx->dcsb = upa_readl(&ffb->dcsb); /* Depth Cue Scale Back Bound */ + ctx->dczf = upa_readl(&ffb->dczf); /* Depth Cue Scale Z Front */ + ctx->dczb = upa_readl(&ffb->dczb); /* Depth Cue Scale Z Back */ + ctx->blendc = upa_readl(&ffb->blendc); /* Alpha Blend Control */ + ctx->blendc1 = upa_readl(&ffb->blendc1); /* Alpha Blend Color 1 */ + ctx->blendc2 = upa_readl(&ffb->blendc2); /* Alpha Blend Color 2 */ + ctx->fbc = upa_readl(&ffb->fbc); /* Frame Buffer Control */ + ctx->rop = upa_readl(&ffb->rop); /* Raster Operation */ + ctx->cmp = upa_readl(&ffb->cmp); /* Compare Controls */ + ctx->matchab = upa_readl(&ffb->matchab); /* Buffer A/B Match Ops */ + ctx->matchc = upa_readl(&ffb->matchc); /* Buffer C Match Ops */ + ctx->magnab = upa_readl(&ffb->magnab); /* Buffer A/B Magnitude Ops */ + ctx->magnc = upa_readl(&ffb->magnc); /* Buffer C Magnitude Ops */ + ctx->pmask = upa_readl(&ffb->pmask); /* RGB Plane Mask */ + ctx->xpmask = upa_readl(&ffb->xpmask); /* X Plane Mask */ + ctx->ypmask = upa_readl(&ffb->ypmask); /* Y Plane Mask */ + ctx->zpmask = upa_readl(&ffb->zpmask); /* Z Plane Mask */ + + /* Auxiliary Clips. */ + ctx->auxclip0min = upa_readl(&ffb->auxclip[0].min); + ctx->auxclip0max = upa_readl(&ffb->auxclip[0].max); + ctx->auxclip1min = upa_readl(&ffb->auxclip[1].min); + ctx->auxclip1max = upa_readl(&ffb->auxclip[1].max); + ctx->auxclip2min = upa_readl(&ffb->auxclip[2].min); + ctx->auxclip2max = upa_readl(&ffb->auxclip[2].max); + ctx->auxclip3min = upa_readl(&ffb->auxclip[3].min); + ctx->auxclip3max = upa_readl(&ffb->auxclip[3].max); + + ctx->lpat = upa_readl(&ffb->lpat); /* Line Pattern */ + ctx->fontxy = upa_readl(&ffb->fontxy); /* XY Font Coordinate */ + ctx->fontw = upa_readl(&ffb->fontw); /* Font Width */ + ctx->fontinc = upa_readl(&ffb->fontinc); /* Font X/Y Increment */ + + /* These registers/features only exist on FFB2 and later chips. */ + if (fpriv->ffb_type >= ffb2_prototype) { + ctx->dcss1 = upa_readl(&ffb->dcss1); /* Depth Cue Scale Slope 1 */ + ctx->dcss2 = upa_readl(&ffb->dcss2); /* Depth Cue Scale Slope 2 */ + ctx->dcss2 = upa_readl(&ffb->dcss3); /* Depth Cue Scale Slope 3 */ + ctx->dcs2 = upa_readl(&ffb->dcs2); /* Depth Cue Scale 2 */ + ctx->dcs3 = upa_readl(&ffb->dcs3); /* Depth Cue Scale 3 */ + ctx->dcs4 = upa_readl(&ffb->dcs4); /* Depth Cue Scale 4 */ + ctx->dcd2 = upa_readl(&ffb->dcd2); /* Depth Cue Depth 2 */ + ctx->dcd3 = upa_readl(&ffb->dcd3); /* Depth Cue Depth 3 */ + ctx->dcd4 = upa_readl(&ffb->dcd4); /* Depth Cue Depth 4 */ + + /* And stencil/stencilctl only exists on FFB2+ and later + * due to the introduction of 3DRAM-III. + */ + if (fpriv->ffb_type == ffb2_vertical_plus || + fpriv->ffb_type == ffb2_horizontal_plus) { + ctx->stencil = upa_readl(&ffb->stencil); + ctx->stencilctl = upa_readl(&ffb->stencilctl); + } + } + + /* Save the 32x32 area pattern. */ + for (i = 0; i < 32; i++) + ctx->area_pattern[i] = upa_readl(&ffb->pattern[i]); + + /* Finally, stash away the User Constol/Status Register. */ + ctx->ucsr = upa_readl(&ffb->ucsr); +} + +static void ffb_restore_context(ffb_dev_priv_t *fpriv, int old, int idx) +{ + ffb_fbcPtr ffb = fpriv->regs; + struct ffb_hw_context *ctx; + int i; + + ctx = fpriv->hw_state[idx - 1]; + if (idx == 0 || ctx == NULL) + return; + + if (ctx->is_2d_only) { + /* 2D applications only care about certain pieces + * of state. + */ + upa_writel(ctx->drawop, &ffb->drawop); + + /* If we were restoring the vertex registers, this is where + * we would do it. We would restore 32 32-bit words starting + * at ffb->suvtx. + */ + + upa_writel(ctx->ppc, &ffb->ppc); + upa_writel(ctx->wid, &ffb->wid); + upa_writel(ctx->fg, &ffb->fg); + upa_writel(ctx->bg, &ffb->bg); + upa_writel(ctx->xclip, &ffb->xclip); + upa_writel(ctx->fbc, &ffb->fbc); + upa_writel(ctx->rop, &ffb->rop); + upa_writel(ctx->cmp, &ffb->cmp); + upa_writel(ctx->matchab, &ffb->matchab); + upa_writel(ctx->magnab, &ffb->magnab); + upa_writel(ctx->pmask, &ffb->pmask); + upa_writel(ctx->xpmask, &ffb->xpmask); + upa_writel(ctx->lpat, &ffb->lpat); + upa_writel(ctx->fontxy, &ffb->fontxy); + upa_writel(ctx->fontw, &ffb->fontw); + upa_writel(ctx->fontinc, &ffb->fontinc); + + /* stencil/stencilctl only exists on FFB2+ and later + * due to the introduction of 3DRAM-III. + */ + if (fpriv->ffb_type == ffb2_vertical_plus || + fpriv->ffb_type == ffb2_horizontal_plus) { + upa_writel(ctx->stencil, &ffb->stencil); + upa_writel(ctx->stencilctl, &ffb->stencilctl); + upa_writel(0x80000000, &ffb->fbc); + upa_writel((ctx->stencilctl | 0x80000), + &ffb->rawstencilctl); + upa_writel(ctx->fbc, &ffb->fbc); + } + + for (i = 0; i < 32; i++) + upa_writel(ctx->area_pattern[i], &ffb->pattern[i]); + upa_writel((ctx->ucsr & 0xf0000), &ffb->ucsr); + return; + } + + /* Restore drawop. */ + upa_writel(ctx->drawop, &ffb->drawop); + + /* If we were restoring the vertex registers, this is where + * we would do it. We would restore 32 32-bit words starting + * at ffb->suvtx. + */ + + /* Restore rendering attributes. */ + + upa_writel(ctx->ppc, &ffb->ppc); /* Pixel Processor Control */ + upa_writel(ctx->wid, &ffb->wid); /* Current WID */ + upa_writel(ctx->fg, &ffb->fg); /* Constant FG color */ + upa_writel(ctx->bg, &ffb->bg); /* Constant BG color */ + upa_writel(ctx->consty, &ffb->consty); /* Constant Y */ + upa_writel(ctx->constz, &ffb->constz); /* Constant Z */ + upa_writel(ctx->xclip, &ffb->xclip); /* X plane clip */ + upa_writel(ctx->dcss, &ffb->dcss); /* Depth Cue Scale Slope */ + upa_writel(ctx->vclipmin, &ffb->vclipmin); /* Primary XY clip, minimum */ + upa_writel(ctx->vclipmax, &ffb->vclipmax); /* Primary XY clip, maximum */ + upa_writel(ctx->vclipzmin, &ffb->vclipzmin); /* Primary Z clip, minimum */ + upa_writel(ctx->vclipzmax, &ffb->vclipzmax); /* Primary Z clip, maximum */ + upa_writel(ctx->dcsf, &ffb->dcsf); /* Depth Cue Scale Front Bound */ + upa_writel(ctx->dcsb, &ffb->dcsb); /* Depth Cue Scale Back Bound */ + upa_writel(ctx->dczf, &ffb->dczf); /* Depth Cue Scale Z Front */ + upa_writel(ctx->dczb, &ffb->dczb); /* Depth Cue Scale Z Back */ + upa_writel(ctx->blendc, &ffb->blendc); /* Alpha Blend Control */ + upa_writel(ctx->blendc1, &ffb->blendc1); /* Alpha Blend Color 1 */ + upa_writel(ctx->blendc2, &ffb->blendc2); /* Alpha Blend Color 2 */ + upa_writel(ctx->fbc, &ffb->fbc); /* Frame Buffer Control */ + upa_writel(ctx->rop, &ffb->rop); /* Raster Operation */ + upa_writel(ctx->cmp, &ffb->cmp); /* Compare Controls */ + upa_writel(ctx->matchab, &ffb->matchab); /* Buffer A/B Match Ops */ + upa_writel(ctx->matchc, &ffb->matchc); /* Buffer C Match Ops */ + upa_writel(ctx->magnab, &ffb->magnab); /* Buffer A/B Magnitude Ops */ + upa_writel(ctx->magnc, &ffb->magnc); /* Buffer C Magnitude Ops */ + upa_writel(ctx->pmask, &ffb->pmask); /* RGB Plane Mask */ + upa_writel(ctx->xpmask, &ffb->xpmask); /* X Plane Mask */ + upa_writel(ctx->ypmask, &ffb->ypmask); /* Y Plane Mask */ + upa_writel(ctx->zpmask, &ffb->zpmask); /* Z Plane Mask */ + + /* Auxiliary Clips. */ + upa_writel(ctx->auxclip0min, &ffb->auxclip[0].min); + upa_writel(ctx->auxclip0max, &ffb->auxclip[0].max); + upa_writel(ctx->auxclip1min, &ffb->auxclip[1].min); + upa_writel(ctx->auxclip1max, &ffb->auxclip[1].max); + upa_writel(ctx->auxclip2min, &ffb->auxclip[2].min); + upa_writel(ctx->auxclip2max, &ffb->auxclip[2].max); + upa_writel(ctx->auxclip3min, &ffb->auxclip[3].min); + upa_writel(ctx->auxclip3max, &ffb->auxclip[3].max); + + upa_writel(ctx->lpat, &ffb->lpat); /* Line Pattern */ + upa_writel(ctx->fontxy, &ffb->fontxy); /* XY Font Coordinate */ + upa_writel(ctx->fontw, &ffb->fontw); /* Font Width */ + upa_writel(ctx->fontinc, &ffb->fontinc); /* Font X/Y Increment */ + + /* These registers/features only exist on FFB2 and later chips. */ + if (fpriv->ffb_type >= ffb2_prototype) { + upa_writel(ctx->dcss1, &ffb->dcss1); /* Depth Cue Scale Slope 1 */ + upa_writel(ctx->dcss2, &ffb->dcss2); /* Depth Cue Scale Slope 2 */ + upa_writel(ctx->dcss3, &ffb->dcss2); /* Depth Cue Scale Slope 3 */ + upa_writel(ctx->dcs2, &ffb->dcs2); /* Depth Cue Scale 2 */ + upa_writel(ctx->dcs3, &ffb->dcs3); /* Depth Cue Scale 3 */ + upa_writel(ctx->dcs4, &ffb->dcs4); /* Depth Cue Scale 4 */ + upa_writel(ctx->dcd2, &ffb->dcd2); /* Depth Cue Depth 2 */ + upa_writel(ctx->dcd3, &ffb->dcd3); /* Depth Cue Depth 3 */ + upa_writel(ctx->dcd4, &ffb->dcd4); /* Depth Cue Depth 4 */ + + /* And stencil/stencilctl only exists on FFB2+ and later + * due to the introduction of 3DRAM-III. + */ + if (fpriv->ffb_type == ffb2_vertical_plus || + fpriv->ffb_type == ffb2_horizontal_plus) { + /* Unfortunately, there is a hardware bug on + * the FFB2+ chips which prevents a normal write + * to the stencil control register from working + * as it should. + * + * The state controlled by the FFB stencilctl register + * really gets transferred to the per-buffer instances + * of the stencilctl register in the 3DRAM chips. + * + * The bug is that FFB does not update buffer C correctly, + * so we have to do it by hand for them. + */ + + /* This will update buffers A and B. */ + upa_writel(ctx->stencil, &ffb->stencil); + upa_writel(ctx->stencilctl, &ffb->stencilctl); + + /* Force FFB to use buffer C 3dram regs. */ + upa_writel(0x80000000, &ffb->fbc); + upa_writel((ctx->stencilctl | 0x80000), + &ffb->rawstencilctl); + + /* Now restore the correct FBC controls. */ + upa_writel(ctx->fbc, &ffb->fbc); + } + } + + /* Restore the 32x32 area pattern. */ + for (i = 0; i < 32; i++) + upa_writel(ctx->area_pattern[i], &ffb->pattern[i]); + + /* Finally, stash away the User Constol/Status Register. + * The only state we really preserve here is the picking + * control. + */ + upa_writel((ctx->ucsr & 0xf0000), &ffb->ucsr); +} + +#define FFB_UCSR_FB_BUSY 0x01000000 +#define FFB_UCSR_RP_BUSY 0x02000000 +#define FFB_UCSR_ALL_BUSY (FFB_UCSR_RP_BUSY|FFB_UCSR_FB_BUSY) + +static void FFBWait(ffb_fbcPtr ffb) +{ + int limit = 100000; + + do { + u32 regval = upa_readl(&ffb->ucsr); + + if ((regval & FFB_UCSR_ALL_BUSY) == 0) + break; + } while (--limit); +} + +int ffb_context_switch(drm_device_t *dev, int old, int new) +{ + ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1); + + atomic_inc(&dev->total_ctx); + +#if DRM_DMA_HISTOGRAM + dev->ctx_start = get_cycles(); +#endif + + DRM_DEBUG("Context switch from %d to %d\n", old, new); + + if (new == dev->last_context || + dev->last_context == 0) { + dev->last_context = new; + return 0; + } + + FFBWait(fpriv->regs); + ffb_save_context(fpriv, old); + ffb_restore_context(fpriv, old, new); + FFBWait(fpriv->regs); + + dev->last_context = new; + + return 0; +} + +int ffb_resctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_ctx_res_t res; + drm_ctx_t ctx; + int i; + + DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS); + copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT); + if (res.count >= DRM_RESERVED_CONTEXTS) { + memset(&ctx, 0, sizeof(ctx)); + for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { + ctx.handle = i; + copy_to_user_ret(&res.contexts[i], + &i, + sizeof(i), + -EFAULT); + } + } + res.count = DRM_RESERVED_CONTEXTS; + copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT); + return 0; +} + + +int ffb_addctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + int idx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + idx = ffb_alloc_queue(dev, (ctx.flags & _DRM_CONTEXT_2DONLY)); + if (idx < 0) + return -ENFILE; + + DRM_DEBUG("%d\n", ctx.handle); + ctx.handle = idx; + copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT); + return 0; +} + +int ffb_modctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1); + struct ffb_hw_context *hwctx; + drm_ctx_t ctx; + int idx; + + copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT); + + idx = ctx.handle; + if (idx <= 0 || idx >= FFB_MAX_CTXS) + return -EINVAL; + + hwctx = fpriv->hw_state[idx - 1]; + if (hwctx == NULL) + return -EINVAL; + + if ((ctx.flags & _DRM_CONTEXT_2DONLY) == 0) + hwctx->is_2d_only = 0; + else + hwctx->is_2d_only = 1; + + return 0; +} + +int ffb_getctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1); + struct ffb_hw_context *hwctx; + drm_ctx_t ctx; + int idx; + + copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT); + + idx = ctx.handle; + if (idx <= 0 || idx >= FFB_MAX_CTXS) + return -EINVAL; + + hwctx = fpriv->hw_state[idx - 1]; + if (hwctx == NULL) + return -EINVAL; + + if (hwctx->is_2d_only != 0) + ctx.flags = _DRM_CONTEXT_2DONLY; + else + ctx.flags = 0; + + copy_to_user_ret((drm_ctx_t*)arg, &ctx, sizeof(ctx), -EFAULT); + + return 0; +} + +int ffb_switchctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + DRM_DEBUG("%d\n", ctx.handle); + return ffb_context_switch(dev, dev->last_context, ctx.handle); +} + +int ffb_newctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + DRM_DEBUG("%d\n", ctx.handle); + + return 0; +} + +int ffb_rmctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_ctx_t ctx; + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1); + int idx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + DRM_DEBUG("%d\n", ctx.handle); + + idx = ctx.handle - 1; + if (idx < 0 || idx >= FFB_MAX_CTXS) + return -EINVAL; + + if (fpriv->hw_state[idx] != NULL) { + kfree(fpriv->hw_state[idx]); + fpriv->hw_state[idx] = NULL; + } + return 0; +} diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/drm/ffb_drv.c linux/drivers/char/drm/ffb_drv.c --- v2.4.0-test1/linux/drivers/char/drm/ffb_drv.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/drm/ffb_drv.c Wed Jun 21 10:10:02 2000 @@ -0,0 +1,842 @@ +/* $Id: ffb_drv.c,v 1.3 2000/06/01 04:24:39 davem Exp $ + * ffb_drv.c: Creator/Creator3D direct rendering driver. + * + * Copyright (C) 2000 David S. Miller (davem@redhat.com) + */ + +#include "drmP.h" + +#include +#include + +#include "ffb_drv.h" + +#define FFB_NAME "ffb" +#define FFB_DESC "Creator/Creator3D" +#define FFB_DATE "20000517" +#define FFB_MAJOR 0 +#define FFB_MINOR 0 +#define FFB_PATCHLEVEL 1 + +/* Forward declarations. */ +int ffb_init(void); +void ffb_cleanup(void); +static int ffb_version(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +static int ffb_open(struct inode *inode, struct file *filp); +static int ffb_release(struct inode *inode, struct file *filp); +static int ffb_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +static int ffb_lock(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +static int ffb_unlock(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +static int ffb_mmap(struct file *filp, struct vm_area_struct *vma); + +/* From ffb_context.c */ +extern int ffb_resctx(struct inode *, struct file *, unsigned int, unsigned long); +extern int ffb_addctx(struct inode *, struct file *, unsigned int, unsigned long); +extern int ffb_modctx(struct inode *, struct file *, unsigned int, unsigned long); +extern int ffb_getctx(struct inode *, struct file *, unsigned int, unsigned long); +extern int ffb_switchctx(struct inode *, struct file *, unsigned int, unsigned long); +extern int ffb_newctx(struct inode *, struct file *, unsigned int, unsigned long); +extern int ffb_rmctx(struct inode *, struct file *, unsigned int, unsigned long); +extern int ffb_context_switch(drm_device_t *, int, int); + +static struct file_operations ffb_fops = { + open: ffb_open, + flush: drm_flush, + release: ffb_release, + ioctl: ffb_ioctl, + mmap: ffb_mmap, + read: drm_read, + fasync: drm_fasync, + poll: drm_poll, +}; + +/* This is just a template, we make a new copy for each FFB + * we discover at init time so that each one gets a unique + * misc device minor number. + */ +static struct miscdevice ffb_misc = { + minor: MISC_DYNAMIC_MINOR, + name: FFB_NAME, + fops: &ffb_fops, +}; + +static drm_ioctl_desc_t ffb_ioctls[] = { + [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { ffb_version, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { drm_getunique, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { drm_getmagic, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { drm_irq_busid, 0, 1 }, /* XXX */ + + [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { drm_setunique, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = { drm_block, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = { drm_unblock, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { drm_authmagic, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { drm_addmap, 1, 1 }, + + /* The implementation is currently a nop just like on tdfx. + * Later we can do something more clever. -DaveM + */ + [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { ffb_addctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { ffb_rmctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { ffb_modctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { ffb_getctx, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { ffb_switchctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { ffb_newctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { ffb_resctx, 1, 0 }, + + [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = { drm_adddraw, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = { drm_rmdraw, 1, 1 }, + + [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { ffb_lock, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { ffb_unlock, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_finish, 1, 0 }, +}; +#define FFB_IOCTL_COUNT DRM_ARRAY_SIZE(ffb_ioctls) + +#ifdef MODULE +static char *ffb = NULL; +#endif + +MODULE_AUTHOR("David S. Miller (davem@redhat.com)"); +MODULE_DESCRIPTION("Sun Creator/Creator3D DRI"); + +static int ffb_takedown(drm_device_t *dev) +{ + int i; + drm_magic_entry_t *pt, *next; + drm_map_t *map; + drm_vma_entry_t *vma, *vma_next; + + DRM_DEBUG("\n"); + + down(&dev->struct_sem); + del_timer(&dev->timer); + + if (dev->devname) { + drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER); + dev->devname = NULL; + } + + if (dev->unique) { + drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER); + dev->unique = NULL; + dev->unique_len = 0; + } + + /* Clear pid list */ + for (i = 0; i < DRM_HASH_SIZE; i++) { + for (pt = dev->magiclist[i].head; pt; pt = next) { + next = pt->next; + drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); + } + dev->magiclist[i].head = dev->magiclist[i].tail = NULL; + } + + /* Clear vma list (only built for debugging) */ + if (dev->vmalist) { + for (vma = dev->vmalist; vma; vma = vma_next) { + vma_next = vma->next; + drm_free(vma, sizeof(*vma), DRM_MEM_VMAS); + } + dev->vmalist = NULL; + } + + /* Clear map area information */ + if (dev->maplist) { + for (i = 0; i < dev->map_count; i++) { + map = dev->maplist[i]; + switch (map->type) { + case _DRM_REGISTERS: + case _DRM_FRAME_BUFFER: + drm_ioremapfree(map->handle, map->size); + break; + + case _DRM_SHM: + drm_free_pages((unsigned long)map->handle, + drm_order(map->size) + - PAGE_SHIFT, + DRM_MEM_SAREA); + break; + }; + + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + } + + drm_free(dev->maplist, + dev->map_count * sizeof(*dev->maplist), + DRM_MEM_MAPS); + dev->maplist = NULL; + dev->map_count = 0; + } + + if (dev->lock.hw_lock) { + dev->lock.hw_lock = NULL; /* SHM removed */ + dev->lock.pid = 0; + wake_up_interruptible(&dev->lock.lock_queue); + } + up(&dev->struct_sem); + + return 0; +} + +drm_device_t **ffb_dev_table; +static int ffb_dev_table_size; + +static void get_ffb_type(ffb_dev_priv_t *ffb_priv, int instance) +{ + volatile unsigned char *strap_bits; + unsigned char val; + + strap_bits = (volatile unsigned char *) + (ffb_priv->card_phys_base + 0x00200000UL); + + /* Don't ask, you have to read the value twice for whatever + * reason to get correct contents. + */ + val = upa_readb(strap_bits); + val = upa_readb(strap_bits); + switch (val & 0x78) { + case (0x0 << 5) | (0x0 << 3): + ffb_priv->ffb_type = ffb1_prototype; + printk("ffb%d: Detected FFB1 pre-FCS prototype\n", instance); + break; + case (0x0 << 5) | (0x1 << 3): + ffb_priv->ffb_type = ffb1_standard; + printk("ffb%d: Detected FFB1\n", instance); + break; + case (0x0 << 5) | (0x3 << 3): + ffb_priv->ffb_type = ffb1_speedsort; + printk("ffb%d: Detected FFB1-SpeedSort\n", instance); + break; + case (0x1 << 5) | (0x0 << 3): + ffb_priv->ffb_type = ffb2_prototype; + printk("ffb%d: Detected FFB2/vertical pre-FCS prototype\n", instance); + break; + case (0x1 << 5) | (0x1 << 3): + ffb_priv->ffb_type = ffb2_vertical; + printk("ffb%d: Detected FFB2/vertical\n", instance); + break; + case (0x1 << 5) | (0x2 << 3): + ffb_priv->ffb_type = ffb2_vertical_plus; + printk("ffb%d: Detected FFB2+/vertical\n", instance); + break; + case (0x2 << 5) | (0x0 << 3): + ffb_priv->ffb_type = ffb2_horizontal; + printk("ffb%d: Detected FFB2/horizontal\n", instance); + break; + case (0x2 << 5) | (0x2 << 3): + ffb_priv->ffb_type = ffb2_horizontal; + printk("ffb%d: Detected FFB2+/horizontal\n", instance); + break; + default: + ffb_priv->ffb_type = ffb2_vertical; + printk("ffb%d: Unknown boardID[%08x], assuming FFB2\n", instance, val); + break; + }; +} + +static int ffb_init_one(int prom_node, int instance) +{ + struct linux_prom64_registers regs[2*PROMREG_MAX]; + drm_device_t *dev; + ffb_dev_priv_t *ffb_priv; + int ret, i; + + dev = kmalloc(sizeof(drm_device_t) + sizeof(ffb_dev_priv_t), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + memset(dev, 0, sizeof(*dev)); + spin_lock_init(&dev->count_lock); + sema_init(&dev->struct_sem, 1); + + ffb_priv = (ffb_dev_priv_t *) (dev + 1); + ffb_priv->prom_node = prom_node; + if (prom_getproperty(ffb_priv->prom_node, "reg", + (void *)regs, sizeof(regs)) <= 0) { + kfree(dev); + return -EINVAL; + } + ffb_priv->card_phys_base = regs[0].phys_addr; + ffb_priv->regs = (ffb_fbcPtr) + (regs[0].phys_addr + 0x00600000UL); + get_ffb_type(ffb_priv, instance); + for (i = 0; i < FFB_MAX_CTXS; i++) + ffb_priv->hw_state[i] = NULL; + + ffb_dev_table[instance] = dev; + +#ifdef MODULE + drm_parse_options(ffb); +#endif + + memcpy(&ffb_priv->miscdev, &ffb_misc, sizeof(ffb_misc)); + ret = misc_register(&ffb_priv->miscdev); + if (ret) { + ffb_dev_table[instance] = NULL; + kfree(dev); + return ret; + } + + dev->device = MKDEV(MISC_MAJOR, ffb_priv->miscdev.minor); + dev->name = FFB_NAME; + + drm_mem_init(); + drm_proc_init(dev); + + DRM_INFO("Initialized %s %d.%d.%d %s on minor %d at %016lx\n", + FFB_NAME, + FFB_MAJOR, + FFB_MINOR, + FFB_PATCHLEVEL, + FFB_DATE, + ffb_priv->miscdev.minor, + ffb_priv->card_phys_base); + + return 0; +} + +static int ffb_init_dev_table(void) +{ + int root, node; + int total = 0; + + root = prom_getchild(prom_root_node); + for (node = prom_searchsiblings(root, "SUNW,ffb"); node; + node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) + total++; + + ffb_dev_table = kmalloc(sizeof(drm_device_t *) * total, GFP_KERNEL); + if (!ffb_dev_table) + return -ENOMEM; + + ffb_dev_table_size = total; + + return 0; +} + +int ffb_init(void) +{ + int root, node, instance, ret; + + ret = ffb_init_dev_table(); + if (ret) + return ret; + + instance = 0; + root = prom_getchild(prom_root_node); + for (node = prom_searchsiblings(root, "SUNW,ffb"); node; + node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) { + ret = ffb_init_one(node, instance); + if (ret) + return ret; + instance++; + } + + return 0; +} + +void ffb_cleanup(void) +{ + int instance; + + DRM_DEBUG("\n"); + + drm_proc_cleanup(); + for (instance = 0; instance < ffb_dev_table_size; instance++) { + drm_device_t *dev = ffb_dev_table[instance]; + ffb_dev_priv_t *ffb_priv; + + if (!dev) + continue; + + ffb_priv = (ffb_dev_priv_t *) (dev + 1); + if (misc_deregister(&ffb_priv->miscdev)) { + DRM_ERROR("Cannot unload module\n"); + } else { + DRM_INFO("Module unloaded\n"); + } + ffb_takedown(dev); + kfree(dev); + ffb_dev_table[instance] = NULL; + } + kfree(ffb_dev_table); + ffb_dev_table = NULL; + ffb_dev_table_size = 0; +} + +static int ffb_version(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) +{ + drm_version_t version; + int len, ret; + + ret = copy_from_user(&version, (drm_version_t *)arg, sizeof(version)); + if (ret) + return -EFAULT; + + version.version_major = FFB_MAJOR; + version.version_minor = FFB_MINOR; + version.version_patchlevel = FFB_PATCHLEVEL; + + len = strlen(FFB_NAME); + if (len > version.name_len) + len = version.name_len; + version.name_len = len; + if (len && version.name) { + ret = copy_to_user(version.name, FFB_NAME, len); + if (ret) + return -EFAULT; + } + + len = strlen(FFB_DATE); + if (len > version.date_len) + len = version.date_len; + version.date_len = len; + if (len && version.date) { + ret = copy_to_user(version.date, FFB_DATE, len); + if (ret) + return -EFAULT; + } + + len = strlen(FFB_DESC); + if (len > version.desc_len) + len = version.desc_len; + version.desc_len = len; + if (len && version.desc) { + ret = copy_to_user(version.desc, FFB_DESC, len); + if (ret) + return -EFAULT; + } + + ret = copy_to_user((drm_version_t *) arg, &version, sizeof(version)); + if (ret) + ret = -EFAULT; + + return ret; +} + +static int ffb_setup(drm_device_t *dev) +{ + int i; + + atomic_set(&dev->ioctl_count, 0); + atomic_set(&dev->vma_count, 0); + dev->buf_use = 0; + atomic_set(&dev->buf_alloc, 0); + + atomic_set(&dev->total_open, 0); + atomic_set(&dev->total_close, 0); + atomic_set(&dev->total_ioctl, 0); + atomic_set(&dev->total_irq, 0); + atomic_set(&dev->total_ctx, 0); + atomic_set(&dev->total_locks, 0); + atomic_set(&dev->total_unlocks, 0); + atomic_set(&dev->total_contends, 0); + atomic_set(&dev->total_sleeps, 0); + + for (i = 0; i < DRM_HASH_SIZE; i++) { + dev->magiclist[i].head = NULL; + dev->magiclist[i].tail = NULL; + } + + dev->maplist = NULL; + dev->map_count = 0; + dev->vmalist = NULL; + dev->lock.hw_lock = NULL; + init_waitqueue_head(&dev->lock.lock_queue); + dev->queue_count = 0; + dev->queue_reserved = 0; + dev->queue_slots = 0; + dev->queuelist = NULL; + dev->irq = 0; + dev->context_flag = 0; + dev->interrupt_flag = 0; + dev->dma = 0; + dev->dma_flag = 0; + dev->last_context = 0; + dev->last_switch = 0; + dev->last_checked = 0; + init_timer(&dev->timer); + init_waitqueue_head(&dev->context_wait); + + dev->ctx_start = 0; + dev->lck_start = 0; + + dev->buf_rp = dev->buf; + dev->buf_wp = dev->buf; + dev->buf_end = dev->buf + DRM_BSZ; + dev->buf_async = NULL; + init_waitqueue_head(&dev->buf_readers); + init_waitqueue_head(&dev->buf_writers); + + return 0; +} + +static int ffb_open(struct inode *inode, struct file *filp) +{ + drm_device_t *dev; + int minor, i; + int ret = 0; + + minor = MINOR(inode->i_rdev); + for (i = 0; i < ffb_dev_table_size; i++) { + ffb_dev_priv_t *ffb_priv; + + ffb_priv = (ffb_dev_priv_t *) (ffb_dev_table[i] + 1); + + if (ffb_priv->miscdev.minor == minor) + break; + } + + if (i >= ffb_dev_table_size) + return -EINVAL; + + dev = ffb_dev_table[i]; + if (!dev) + return -EINVAL; + + DRM_DEBUG("open_count = %d\n", dev->open_count); + ret = drm_open_helper(inode, filp, dev); + if (!ret) { + MOD_INC_USE_COUNT; + atomic_inc(&dev->total_open); + spin_lock(&dev->count_lock); + if (!dev->open_count++) { + spin_unlock(&dev->count_lock); + return ffb_setup(dev); + } + spin_unlock(&dev->count_lock); + } + + return ret; +} + +static int ffb_release(struct inode *inode, struct file *filp) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + int ret = 0; + + DRM_DEBUG("open_count = %d\n", dev->open_count); + if (dev->lock.hw_lock != NULL + && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) + && dev->lock.pid == current->pid) { + ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1); + int context = _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock); + int idx; + + /* We have to free up the rogue hw context state + * holding error or else we will leak it. + */ + idx = context - 1; + if (fpriv->hw_state[idx] != NULL) { + kfree(fpriv->hw_state[idx]); + fpriv->hw_state[idx] = NULL; + } + } + + ret = drm_release(inode, filp); + + if (!ret) { + MOD_DEC_USE_COUNT; + atomic_inc(&dev->total_close); + spin_lock(&dev->count_lock); + if (!--dev->open_count) { + if (atomic_read(&dev->ioctl_count) || dev->blocked) { + DRM_ERROR("Device busy: %d %d\n", + atomic_read(&dev->ioctl_count), + dev->blocked); + spin_unlock(&dev->count_lock); + return -EBUSY; + } + spin_unlock(&dev->count_lock); + return ffb_takedown(dev); + } + spin_unlock(&dev->count_lock); + } + + return ret; +} + +static int ffb_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) +{ + int nr = DRM_IOCTL_NR(cmd); + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ioctl_desc_t *ioctl; + drm_ioctl_t *func; + int ret; + + atomic_inc(&dev->ioctl_count); + atomic_inc(&dev->total_ioctl); + ++priv->ioctl_count; + + DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n", + current->pid, cmd, nr, dev->device, priv->authenticated); + + if (nr >= FFB_IOCTL_COUNT) { + ret = -EINVAL; + } else { + ioctl = &ffb_ioctls[nr]; + func = ioctl->func; + + if (!func) { + DRM_DEBUG("no function\n"); + ret = -EINVAL; + } else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN)) + || (ioctl->auth_needed && !priv->authenticated)) { + ret = -EACCES; + } else { + ret = (func)(inode, filp, cmd, arg); + } + } + + atomic_dec(&dev->ioctl_count); + + return ret; +} + +static int ffb_lock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + DECLARE_WAITQUEUE(entry, current); + int ret = 0; + drm_lock_t lock; + + ret = copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)); + if (ret) + return -EFAULT; + + if (lock.context == DRM_KERNEL_CONTEXT) { + DRM_ERROR("Process %d using kernel context %d\n", + current->pid, lock.context); + return -EINVAL; + } + + DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", + lock.context, current->pid, dev->lock.hw_lock->lock, + lock.flags); + + add_wait_queue(&dev->lock.lock_queue, &entry); + for (;;) { + if (!dev->lock.hw_lock) { + /* Device has been unregistered */ + ret = -EINTR; + break; + } + if (drm_lock_take(&dev->lock.hw_lock->lock, + lock.context)) { + dev->lock.pid = current->pid; + dev->lock.lock_time = jiffies; + atomic_inc(&dev->total_locks); + break; /* Got lock */ + } + + /* Contention */ + atomic_inc(&dev->total_sleeps); + current->state = TASK_INTERRUPTIBLE; + current->policy |= SCHED_YIELD; + schedule(); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&dev->lock.lock_queue, &entry); + + if (!ret && + (dev->last_context != lock.context)) + ffb_context_switch(dev, dev->last_context, lock.context); + + DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock"); + + return ret; +} + +int ffb_unlock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_lock_t lock; + unsigned int old, new, prev, ctx; + int ret; + + ret = copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)); + if (ret) + return -EFAULT; + + if ((ctx = lock.context) == DRM_KERNEL_CONTEXT) { + DRM_ERROR("Process %d using kernel context %d\n", + current->pid, lock.context); + return -EINVAL; + } + + DRM_DEBUG("%d frees lock (%d holds)\n", + lock.context, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + atomic_inc(&dev->total_unlocks); + if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock)) + atomic_inc(&dev->total_contends); + + /* We no longer really hold it, but if we are the next + * agent to request it then we should just be able to + * take it immediately and not eat the ioctl. + */ + dev->lock.pid = 0; + { + __volatile__ unsigned int *plock = &dev->lock.hw_lock->lock; + + do { + old = *plock; + new = ctx; + prev = cmpxchg(plock, old, new); + } while (prev != old); + } + + wake_up_interruptible(&dev->lock.lock_queue); + + return 0; +} + +static void align_fb_mapping(struct vm_area_struct *vma) +{ + unsigned long j, alignment; + + j = vma->vm_end - vma->vm_start; + for (alignment = (4 * 1024 * 1024); alignment > PAGE_SIZE; alignment >>= 3) + if (j >= alignment) + break; + if (alignment > PAGE_SIZE) { + j = alignment; + alignment = j - (vma->vm_start & (j - 1)); + if (alignment != j) { + struct vm_area_struct *vmm = find_vma(current->mm,vma->vm_start); + + if (!vmm || vmm->vm_start >= vma->vm_end + alignment) { + vma->vm_start += alignment; + vma->vm_end += alignment; + } + } + } +} + +/* The problem here is, due to virtual cache aliasing, + * we must make sure the shared memory area lands in the + * same dcache line for both the kernel and all drm clients. + */ +static void align_shm_mapping(struct vm_area_struct *vma, unsigned long kvirt) +{ + kvirt &= PAGE_SIZE; + if ((vma->vm_start & PAGE_SIZE) != kvirt) { + struct vm_area_struct *vmm = find_vma(current->mm, vma->vm_start); + + if (!vmm || vmm->vm_start >= vma->vm_end + PAGE_SIZE) { + vma->vm_start += PAGE_SIZE; + vma->vm_end += PAGE_SIZE; + } + } +} + +extern struct vm_operations_struct drm_vm_ops; +extern struct vm_operations_struct drm_vm_shm_ops; + +static int ffb_mmap(struct file *filp, struct vm_area_struct *vma) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_map_t *map = NULL; + ffb_dev_priv_t *ffb_priv; + int i, minor; + + DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", + vma->vm_start, vma->vm_end, VM_OFFSET(vma)); + + minor = MINOR(filp->f_dentry->d_inode->i_rdev); + ffb_priv = NULL; + for (i = 0; i < ffb_dev_table_size; i++) { + ffb_priv = (ffb_dev_priv_t *) (ffb_dev_table[i] + 1); + if (ffb_priv->miscdev.minor == minor) + break; + } + if (i >= ffb_dev_table_size) + return -EINVAL; + + /* We don't support/need dma mappings, so... */ + if (!VM_OFFSET(vma)) + return -EINVAL; + + for (i = 0; i < dev->map_count; i++) { + unsigned long off; + + map = dev->maplist[i]; + + /* Ok, a little hack to make 32-bit apps work. */ + off = (map->offset & 0xffffffff); + if (off == VM_OFFSET(vma)) + break; + } + + if (i >= dev->map_count) + return -EINVAL; + + if (!map || + ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) + return -EPERM; + + if (map->size != (vma->vm_end - vma->vm_start)) + return -EINVAL; + + /* Set read-only attribute before mappings are created + * so it works for fb/reg maps too. + */ + if (map->flags & _DRM_READ_ONLY) + vma->vm_page_prot = __pgprot(pte_val(pte_wrprotect( + __pte(pgprot_val(vma->vm_page_prot))))); + + switch (map->type) { + case _DRM_FRAME_BUFFER: + align_fb_mapping(vma); + /* FALLTHROUGH */ + + case _DRM_REGISTERS: + /* In order to handle 32-bit drm apps/xserver we + * play a trick. The mappings only really specify + * the 32-bit offset from the cards 64-bit base + * address, and we just add in the base here. + */ + vma->vm_flags |= VM_IO; + if (io_remap_page_range(vma->vm_start, + ffb_priv->card_phys_base + VM_OFFSET(vma), + vma->vm_end - vma->vm_start, + vma->vm_page_prot, 0)) + return -EAGAIN; + + vma->vm_ops = &drm_vm_ops; + break; + case _DRM_SHM: + align_shm_mapping(vma, (unsigned long)dev->lock.hw_lock); + vma->vm_ops = &drm_vm_shm_ops; + + /* Don't let this area swap. Change when + * DRM_KERNEL advisory is supported. + */ + vma->vm_flags |= VM_LOCKED; + break; + default: + return -EINVAL; /* This should never happen. */ + }; + + vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */ + + vma->vm_file = filp; /* Needed for drm_vm_open() */ + drm_vm_open(vma); + return 0; +} + +module_init(ffb_init); +module_exit(ffb_cleanup); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/drm/ffb_drv.h linux/drivers/char/drm/ffb_drv.h --- v2.4.0-test1/linux/drivers/char/drm/ffb_drv.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/drm/ffb_drv.h Wed Jun 21 10:10:02 2000 @@ -0,0 +1,276 @@ +/* $Id: ffb_drv.h,v 1.1 2000/06/01 04:24:39 davem Exp $ + * ffb_drv.h: Creator/Creator3D direct rendering driver. + * + * Copyright (C) 2000 David S. Miller (davem@redhat.com) + */ + +/* Auxilliary clips. */ +typedef struct { + volatile unsigned int min; + volatile unsigned int max; +} ffb_auxclip, *ffb_auxclipPtr; + +/* FFB register set. */ +typedef struct _ffb_fbc { + /* Next vertex registers, on the right we list which drawops + * use said register and the logical name the register has in + * that context. + */ /* DESCRIPTION DRAWOP(NAME) */ +/*0x00*/unsigned int pad1[3]; /* Reserved */ +/*0x0c*/volatile unsigned int alpha; /* ALPHA Transparency */ +/*0x10*/volatile unsigned int red; /* RED */ +/*0x14*/volatile unsigned int green; /* GREEN */ +/*0x18*/volatile unsigned int blue; /* BLUE */ +/*0x1c*/volatile unsigned int z; /* DEPTH */ +/*0x20*/volatile unsigned int y; /* Y triangle(DOYF) */ + /* aadot(DYF) */ + /* ddline(DYF) */ + /* aaline(DYF) */ +/*0x24*/volatile unsigned int x; /* X triangle(DOXF) */ + /* aadot(DXF) */ + /* ddline(DXF) */ + /* aaline(DXF) */ +/*0x28*/unsigned int pad2[2]; /* Reserved */ +/*0x30*/volatile unsigned int ryf; /* Y (alias to DOYF) ddline(RYF) */ + /* aaline(RYF) */ + /* triangle(RYF) */ +/*0x34*/volatile unsigned int rxf; /* X ddline(RXF) */ + /* aaline(RXF) */ + /* triangle(RXF) */ +/*0x38*/unsigned int pad3[2]; /* Reserved */ +/*0x40*/volatile unsigned int dmyf; /* Y (alias to DOYF) triangle(DMYF) */ +/*0x44*/volatile unsigned int dmxf; /* X triangle(DMXF) */ +/*0x48*/unsigned int pad4[2]; /* Reserved */ +/*0x50*/volatile unsigned int ebyi; /* Y (alias to RYI) polygon(EBYI) */ +/*0x54*/volatile unsigned int ebxi; /* X polygon(EBXI) */ +/*0x58*/unsigned int pad5[2]; /* Reserved */ +/*0x60*/volatile unsigned int by; /* Y brline(RYI) */ + /* fastfill(OP) */ + /* polygon(YI) */ + /* rectangle(YI) */ + /* bcopy(SRCY) */ + /* vscroll(SRCY) */ +/*0x64*/volatile unsigned int bx; /* X brline(RXI) */ + /* polygon(XI) */ + /* rectangle(XI) */ + /* bcopy(SRCX) */ + /* vscroll(SRCX) */ + /* fastfill(GO) */ +/*0x68*/volatile unsigned int dy; /* destination Y fastfill(DSTY) */ + /* bcopy(DSRY) */ + /* vscroll(DSRY) */ +/*0x6c*/volatile unsigned int dx; /* destination X fastfill(DSTX) */ + /* bcopy(DSTX) */ + /* vscroll(DSTX) */ +/*0x70*/volatile unsigned int bh; /* Y (alias to RYI) brline(DYI) */ + /* dot(DYI) */ + /* polygon(ETYI) */ + /* Height fastfill(H) */ + /* bcopy(H) */ + /* vscroll(H) */ + /* Y count fastfill(NY) */ +/*0x74*/volatile unsigned int bw; /* X dot(DXI) */ + /* brline(DXI) */ + /* polygon(ETXI) */ + /* fastfill(W) */ + /* bcopy(W) */ + /* vscroll(W) */ + /* fastfill(NX) */ +/*0x78*/unsigned int pad6[2]; /* Reserved */ +/*0x80*/unsigned int pad7[32]; /* Reserved */ + + /* Setup Unit's vertex state register */ +/*100*/ volatile unsigned int suvtx; +/*104*/ unsigned int pad8[63]; /* Reserved */ + + /* Frame Buffer Control Registers */ +/*200*/ volatile unsigned int ppc; /* Pixel Processor Control */ +/*204*/ volatile unsigned int wid; /* Current WID */ +/*208*/ volatile unsigned int fg; /* FG data */ +/*20c*/ volatile unsigned int bg; /* BG data */ +/*210*/ volatile unsigned int consty; /* Constant Y */ +/*214*/ volatile unsigned int constz; /* Constant Z */ +/*218*/ volatile unsigned int xclip; /* X Clip */ +/*21c*/ volatile unsigned int dcss; /* Depth Cue Scale Slope */ +/*220*/ volatile unsigned int vclipmin; /* Viewclip XY Min Bounds */ +/*224*/ volatile unsigned int vclipmax; /* Viewclip XY Max Bounds */ +/*228*/ volatile unsigned int vclipzmin; /* Viewclip Z Min Bounds */ +/*22c*/ volatile unsigned int vclipzmax; /* Viewclip Z Max Bounds */ +/*230*/ volatile unsigned int dcsf; /* Depth Cue Scale Front Bound */ +/*234*/ volatile unsigned int dcsb; /* Depth Cue Scale Back Bound */ +/*238*/ volatile unsigned int dczf; /* Depth Cue Z Front */ +/*23c*/ volatile unsigned int dczb; /* Depth Cue Z Back */ +/*240*/ unsigned int pad9; /* Reserved */ +/*244*/ volatile unsigned int blendc; /* Alpha Blend Control */ +/*248*/ volatile unsigned int blendc1; /* Alpha Blend Color 1 */ +/*24c*/ volatile unsigned int blendc2; /* Alpha Blend Color 2 */ +/*250*/ volatile unsigned int fbramitc; /* FB RAM Interleave Test Control */ +/*254*/ volatile unsigned int fbc; /* Frame Buffer Control */ +/*258*/ volatile unsigned int rop; /* Raster OPeration */ +/*25c*/ volatile unsigned int cmp; /* Frame Buffer Compare */ +/*260*/ volatile unsigned int matchab; /* Buffer AB Match Mask */ +/*264*/ volatile unsigned int matchc; /* Buffer C(YZ) Match Mask */ +/*268*/ volatile unsigned int magnab; /* Buffer AB Magnitude Mask */ +/*26c*/ volatile unsigned int magnc; /* Buffer C(YZ) Magnitude Mask */ +/*270*/ volatile unsigned int fbcfg0; /* Frame Buffer Config 0 */ +/*274*/ volatile unsigned int fbcfg1; /* Frame Buffer Config 1 */ +/*278*/ volatile unsigned int fbcfg2; /* Frame Buffer Config 2 */ +/*27c*/ volatile unsigned int fbcfg3; /* Frame Buffer Config 3 */ +/*280*/ volatile unsigned int ppcfg; /* Pixel Processor Config */ +/*284*/ volatile unsigned int pick; /* Picking Control */ +/*288*/ volatile unsigned int fillmode; /* FillMode */ +/*28c*/ volatile unsigned int fbramwac; /* FB RAM Write Address Control */ +/*290*/ volatile unsigned int pmask; /* RGB PlaneMask */ +/*294*/ volatile unsigned int xpmask; /* X PlaneMask */ +/*298*/ volatile unsigned int ypmask; /* Y PlaneMask */ +/*29c*/ volatile unsigned int zpmask; /* Z PlaneMask */ +/*2a0*/ ffb_auxclip auxclip[4]; /* Auxilliary Viewport Clip */ + + /* New 3dRAM III support regs */ +/*2c0*/ volatile unsigned int rawblend2; +/*2c4*/ volatile unsigned int rawpreblend; +/*2c8*/ volatile unsigned int rawstencil; +/*2cc*/ volatile unsigned int rawstencilctl; +/*2d0*/ volatile unsigned int threedram1; +/*2d4*/ volatile unsigned int threedram2; +/*2d8*/ volatile unsigned int passin; +/*2dc*/ volatile unsigned int rawclrdepth; +/*2e0*/ volatile unsigned int rawpmask; +/*2e4*/ volatile unsigned int rawcsrc; +/*2e8*/ volatile unsigned int rawmatch; +/*2ec*/ volatile unsigned int rawmagn; +/*2f0*/ volatile unsigned int rawropblend; +/*2f4*/ volatile unsigned int rawcmp; +/*2f8*/ volatile unsigned int rawwac; +/*2fc*/ volatile unsigned int fbramid; + +/*300*/ volatile unsigned int drawop; /* Draw OPeration */ +/*304*/ unsigned int pad10[2]; /* Reserved */ +/*30c*/ volatile unsigned int lpat; /* Line Pattern control */ +/*310*/ unsigned int pad11; /* Reserved */ +/*314*/ volatile unsigned int fontxy; /* XY Font coordinate */ +/*318*/ volatile unsigned int fontw; /* Font Width */ +/*31c*/ volatile unsigned int fontinc; /* Font Increment */ +/*320*/ volatile unsigned int font; /* Font bits */ +/*324*/ unsigned int pad12[3]; /* Reserved */ +/*330*/ volatile unsigned int blend2; +/*334*/ volatile unsigned int preblend; +/*338*/ volatile unsigned int stencil; +/*33c*/ volatile unsigned int stencilctl; + +/*340*/ unsigned int pad13[4]; /* Reserved */ +/*350*/ volatile unsigned int dcss1; /* Depth Cue Scale Slope 1 */ +/*354*/ volatile unsigned int dcss2; /* Depth Cue Scale Slope 2 */ +/*358*/ volatile unsigned int dcss3; /* Depth Cue Scale Slope 3 */ +/*35c*/ volatile unsigned int widpmask; +/*360*/ volatile unsigned int dcs2; +/*364*/ volatile unsigned int dcs3; +/*368*/ volatile unsigned int dcs4; +/*36c*/ unsigned int pad14; /* Reserved */ +/*370*/ volatile unsigned int dcd2; +/*374*/ volatile unsigned int dcd3; +/*378*/ volatile unsigned int dcd4; +/*37c*/ unsigned int pad15; /* Reserved */ +/*380*/ volatile unsigned int pattern[32]; /* area Pattern */ +/*400*/ unsigned int pad16[8]; /* Reserved */ +/*420*/ volatile unsigned int reset; /* chip RESET */ +/*424*/ unsigned int pad17[247]; /* Reserved */ +/*800*/ volatile unsigned int devid; /* Device ID */ +/*804*/ unsigned int pad18[63]; /* Reserved */ +/*900*/ volatile unsigned int ucsr; /* User Control & Status Register */ +/*904*/ unsigned int pad19[31]; /* Reserved */ +/*980*/ volatile unsigned int mer; /* Mode Enable Register */ +/*984*/ unsigned int pad20[1439]; /* Reserved */ +} ffb_fbc, *ffb_fbcPtr; + +struct ffb_hw_context { + int is_2d_only; + + unsigned int ppc; + unsigned int wid; + unsigned int fg; + unsigned int bg; + unsigned int consty; + unsigned int constz; + unsigned int xclip; + unsigned int dcss; + unsigned int vclipmin; + unsigned int vclipmax; + unsigned int vclipzmin; + unsigned int vclipzmax; + unsigned int dcsf; + unsigned int dcsb; + unsigned int dczf; + unsigned int dczb; + unsigned int blendc; + unsigned int blendc1; + unsigned int blendc2; + unsigned int fbc; + unsigned int rop; + unsigned int cmp; + unsigned int matchab; + unsigned int matchc; + unsigned int magnab; + unsigned int magnc; + unsigned int pmask; + unsigned int xpmask; + unsigned int ypmask; + unsigned int zpmask; + unsigned int auxclip0min; + unsigned int auxclip0max; + unsigned int auxclip1min; + unsigned int auxclip1max; + unsigned int auxclip2min; + unsigned int auxclip2max; + unsigned int auxclip3min; + unsigned int auxclip3max; + unsigned int drawop; + unsigned int lpat; + unsigned int fontxy; + unsigned int fontw; + unsigned int fontinc; + unsigned int area_pattern[32]; + unsigned int ucsr; + unsigned int stencil; + unsigned int stencilctl; + unsigned int dcss1; + unsigned int dcss2; + unsigned int dcss3; + unsigned int dcs2; + unsigned int dcs3; + unsigned int dcs4; + unsigned int dcd2; + unsigned int dcd3; + unsigned int dcd4; + unsigned int mer; +}; + +#define FFB_MAX_CTXS 32 + +enum ffb_chip_type { + ffb1_prototype = 0, /* Early pre-FCS FFB */ + ffb1_standard, /* First FCS FFB, 100Mhz UPA, 66MHz gclk */ + ffb1_speedsort, /* Second FCS FFB, 100Mhz UPA, 75MHz gclk */ + ffb2_prototype, /* Early pre-FCS vertical FFB2 */ + ffb2_vertical, /* First FCS FFB2/vertical, 100Mhz UPA, 100MHZ gclk, + 75(SingleBuffer)/83(DoubleBuffer) MHz fclk */ + ffb2_vertical_plus, /* Second FCS FFB2/vertical, same timings */ + ffb2_horizontal, /* First FCS FFB2/horizontal, same timings as FFB2/vert */ + ffb2_horizontal_plus, /* Second FCS FFB2/horizontal, same timings */ + afb_m3, /* FCS Elite3D, 3 float chips */ + afb_m6 /* FCS Elite3D, 6 float chips */ +}; + +typedef struct ffb_dev_priv { + /* Misc software state. */ + int prom_node; + enum ffb_chip_type ffb_type; + u64 card_phys_base; + struct miscdevice miscdev; + + /* Controller registers. */ + ffb_fbcPtr regs; + + /* Context table. */ + struct ffb_hw_context *hw_state[FFB_MAX_CTXS]; +} ffb_dev_priv_t; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/drm/fops.c linux/drivers/char/drm/fops.c --- v2.4.0-test1/linux/drivers/char/drm/fops.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/char/drm/fops.c Wed Jun 21 10:10:02 2000 @@ -92,7 +92,8 @@ DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n", current->pid, dev->device, dev->open_count); - if (_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) + if (dev->lock.hw_lock != NULL + && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) && dev->lock.pid == current->pid) { DRM_ERROR("Process %d dead, freeing lock for context %d\n", current->pid, @@ -216,7 +217,7 @@ if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO); #else /* Parameter added in 2.3.21 */ - if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO, POLL_IN); + kill_fasync(&dev->buf_async, SIGIO, POLL_IN); #endif DRM_DEBUG("waking\n"); wake_up_interruptible(&dev->buf_readers); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/drm/init.c linux/drivers/char/drm/init.c --- v2.4.0-test1/linux/drivers/char/drm/init.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/char/drm/init.c Wed Jun 21 10:10:02 2000 @@ -104,5 +104,9 @@ #if defined(__i386__) if (boot_cpu_data.x86 == 3) return 0; /* No cmpxchg on a 386 */ #endif +#if defined(__sparc__) && !defined(__sparc_v9__) + if (1) + return 0; /* No cmpxchg before v9 sparc. */ +#endif return 1; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/drm/proc.c linux/drivers/char/drm/proc.c --- v2.4.0-test1/linux/drivers/char/drm/proc.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/char/drm/proc.c Wed Jun 21 10:10:02 2000 @@ -512,9 +512,9 @@ } else { DRM_PROC_PRINT("lock none\n"); } - DRM_PROC_PRINT("context_flag 0x%08x\n", dev->context_flag); - DRM_PROC_PRINT("interrupt_flag 0x%08x\n", dev->interrupt_flag); - DRM_PROC_PRINT("dma_flag 0x%08x\n", dev->dma_flag); + DRM_PROC_PRINT("context_flag 0x%08lx\n", dev->context_flag); + DRM_PROC_PRINT("interrupt_flag 0x%08lx\n", dev->interrupt_flag); + DRM_PROC_PRINT("dma_flag 0x%08lx\n", dev->dma_flag); DRM_PROC_PRINT("queue_count %10d\n", dev->queue_count); DRM_PROC_PRINT("last_context %10d\n", dev->last_context); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/ds1620.c linux/drivers/char/ds1620.c --- v2.4.0-test1/linux/drivers/char/ds1620.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/char/ds1620.c Tue Jun 20 07:32:13 2000 @@ -311,22 +311,6 @@ return 0; } -static int -ds1620_open(struct inode *inode, struct file *file) -{ - MOD_INC_USE_COUNT; - - return 0; -} - -static int -ds1620_release(struct inode *inode, struct file *file) -{ - MOD_DEC_USE_COUNT; - - return 0; -} - #ifdef THERM_USE_PROC static int proc_therm_ds1620_read(char *buf, char **start, off_t offset, @@ -352,10 +336,9 @@ #endif static struct file_operations ds1620_fops = { + owner: THIS_MODULE, read: ds1620_read, ioctl: ds1620_ioctl, - open: ds1620_open, - release: ds1620_release, }; static struct miscdevice ds1620_miscdev = { diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/dsp56k.c linux/drivers/char/dsp56k.c --- v2.4.0-test1/linux/drivers/char/dsp56k.c Fri Mar 10 16:40:42 2000 +++ linux/drivers/char/dsp56k.c Wed Jun 21 22:31:00 2000 @@ -472,10 +472,6 @@ return -ENXIO; } -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif /* MODULE */ - return 0; } @@ -495,13 +491,11 @@ return -ENXIO; } -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif return 0; } static struct file_operations dsp56k_fops = { + owner: THIS_MODULE, read: dsp56k_read, write: dsp56k_write, ioctl: dsp56k_ioctl, @@ -525,9 +519,9 @@ printk("DSP56k driver: Unable to register driver\n"); return -ENODEV; } - devfs_handle = devfs_register (NULL, "dsp56k", 0, DEVFS_FL_NONE, + devfs_handle = devfs_register (NULL, "dsp56k", DEVFS_FL_DEFAULT, DSP56K_MAJOR, 0, - S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR, &dsp56k_fops, NULL); dsp56k.in_use = 0; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/dtlk.c linux/drivers/char/dtlk.c --- v2.4.0-test1/linux/drivers/char/dtlk.c Thu May 11 15:30:06 2000 +++ linux/drivers/char/dtlk.c Wed Jun 21 22:31:00 2000 @@ -102,6 +102,7 @@ static struct file_operations dtlk_fops = { + owner: THIS_MODULE, read: dtlk_read, write: dtlk_write, poll: dtlk_poll, @@ -306,7 +307,6 @@ static int dtlk_open(struct inode *inode, struct file *file) { - MOD_INC_USE_COUNT; TRACE_TEXT("(dtlk_open"); switch (MINOR(inode->i_rdev)) { @@ -322,7 +322,6 @@ static int dtlk_release(struct inode *inode, struct file *file) { - MOD_DEC_USE_COUNT; TRACE_TEXT("(dtlk_release"); switch (MINOR(inode->i_rdev)) { @@ -353,9 +352,9 @@ } if (dtlk_dev_probe() == 0) printk(", MAJOR %d\n", dtlk_major); - devfs_handle = devfs_register (NULL, "dtlk", 0, DEVFS_FL_NONE, + devfs_handle = devfs_register (NULL, "dtlk", DEVFS_FL_DEFAULT, dtlk_major, DTLK_MINOR, - S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR, &dtlk_fops, NULL); init_timer(&dtlk_timer); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/efirtc.c linux/drivers/char/efirtc.c --- v2.4.0-test1/linux/drivers/char/efirtc.c Wed Apr 26 16:34:07 2000 +++ linux/drivers/char/efirtc.c Tue Jun 20 07:32:13 2000 @@ -281,6 +281,7 @@ */ static struct file_operations efi_rtc_fops = { + owner: THIS_MODULE, ioctl: efi_rtc_ioctl, open: efi_rtc_open, release: efi_rtc_close, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/epca.c linux/drivers/char/epca.c --- v2.4.0-test1/linux/drivers/char/epca.c Tue May 23 15:31:34 2000 +++ linux/drivers/char/epca.c Tue Jun 20 07:32:13 2000 @@ -4007,6 +4007,9 @@ int board_idx, info_idx = ent->driver_data; unsigned long addr; + if (pci_enable_device(pdev)) + return -EIO; + board_num++; board_idx = board_num + num_cards; if (board_idx >= MAXBOARDS) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/ftape/zftape/zftape-init.c linux/drivers/char/ftape/zftape/zftape-init.c --- v2.4.0-test1/linux/drivers/char/ftape/zftape/zftape-init.c Sun Feb 20 21:12:38 2000 +++ linux/drivers/char/ftape/zftape/zftape-init.c Wed Jun 21 22:31:01 2000 @@ -439,34 +439,34 @@ char devname[9]; sprintf (devname, "qft%i", i); - devfs_register (NULL, devname, 0, DEVFS_FL_NONE, + devfs_register (NULL, devname, DEVFS_FL_DEFAULT, QIC117_TAPE_MAJOR, i, - S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR, &zft_cdev, NULL); sprintf (devname, "nqft%i", i); - devfs_register (NULL, devname, 0, DEVFS_FL_NONE, + devfs_register (NULL, devname, DEVFS_FL_DEFAULT, QIC117_TAPE_MAJOR, i + 4, - S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR, &zft_cdev, NULL); sprintf (devname, "zqft%i", i); - devfs_register (NULL, devname, 0, DEVFS_FL_NONE, + devfs_register (NULL, devname, DEVFS_FL_DEFAULT, QIC117_TAPE_MAJOR, i + 16, - S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR, &zft_cdev, NULL); sprintf (devname, "nzqft%i", i); - devfs_register (NULL, devname, 0, DEVFS_FL_NONE, + devfs_register (NULL, devname, DEVFS_FL_DEFAULT, QIC117_TAPE_MAJOR, i + 20, - S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR, &zft_cdev, NULL); sprintf (devname, "rawqft%i", i); - devfs_register (NULL, devname, 0, DEVFS_FL_NONE, + devfs_register (NULL, devname, DEVFS_FL_DEFAULT, QIC117_TAPE_MAJOR, i + 32, - S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR, &zft_cdev, NULL); sprintf (devname, "nrawqft%i", i); - devfs_register (NULL, devname, 0, DEVFS_FL_NONE, + devfs_register (NULL, devname, DEVFS_FL_DEFAULT, QIC117_TAPE_MAJOR, i + 36, - S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR, &zft_cdev, NULL); } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/generic_serial.c linux/drivers/char/generic_serial.c --- v2.4.0-test1/linux/drivers/char/generic_serial.c Tue May 23 15:31:34 2000 +++ linux/drivers/char/generic_serial.c Tue Jun 20 07:32:13 2000 @@ -330,7 +330,7 @@ int gs_real_chars_in_buffer(struct tty_struct *tty) { - struct gs_port *port = tty->driver_data; + struct gs_port *port; func_enter (); if (!tty) return 0; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/hp600_keyb.c linux/drivers/char/hp600_keyb.c --- v2.4.0-test1/linux/drivers/char/hp600_keyb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/hp600_keyb.c Tue Jun 20 07:32:13 2000 @@ -0,0 +1,119 @@ +/* + * $Id: hp600_keyb.c,v 1.1 2000/06/10 21:45:30 yaegashi Exp $ + * Copyright (C) 2000 YAEGASHI Takeshi + * HP600 keyboard scan routine and translate table + */ + +#include +#include +#include +#include "scan_keyb.h" + +#define PCDR 0xa4000124 +#define PDDR 0xa4000126 +#define PEDR 0xa4000128 +#define PFDR 0xa400012a +#define PGDR 0xa400012c +#define PHDR 0xa400012e + +static const unsigned char hp690_japanese_table[]={ + 0x00, 0x00, 0x00, 0x01, 0x00, 0x29, 0x70, 0x3a, + 0x3f, 0x3e, 0x40, 0x41, 0x42, 0x3d, 0x3c, 0x3b, + + 0x00, 0x00, 0x00, 0x2c, 0x00, 0x1c, 0x28, 0x35, + 0x31, 0x30, 0x32, 0x33, 0x34, 0x2f, 0x2e, 0x2d, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x50, + 0x7b, 0x38, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf9, 0x73, 0x53, 0x39, 0x00, 0x1d, + + 0x00, 0x00, 0x00, 0x1e, 0x00, 0x2b, 0x1b, 0x27, + 0x23, 0x22, 0x24, 0x25, 0x26, 0x21, 0x20, 0x1f, + + 0x00, 0x00, 0x00, 0x0f, 0x00, 0x36, 0x7d, 0x48, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, + + 0x00, 0x00, 0x00, 0x10, 0x00, 0x0e, 0x1a, 0x19, + 0x15, 0x14, 0x16, 0x17, 0x18, 0x13, 0x12, 0x11, + + 0x00, 0x00, 0x00, 0x02, 0x00, 0x0d, 0x0c, 0x0b, + 0x07, 0x06, 0x08, 0x09, 0x0a, 0x05, 0x04, 0x03, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + + +static void hp690_japanese_scan_kbd(unsigned char *s) +{ + ctrl_outb(0xfd, PDDR); ctrl_outb(0xff, PEDR); + *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR); + ctrl_outb(0xdf, PDDR); ctrl_outb(0xff, PEDR); + *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR); + ctrl_outb(0x7f, PDDR); ctrl_outb(0xff, PEDR); + *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR); + ctrl_outb(0xff, PDDR); ctrl_outb(0xfe, PEDR); + *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR); + ctrl_outb(0xff, PDDR); ctrl_outb(0xfd, PEDR); + *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR); + ctrl_outb(0xff, PDDR); ctrl_outb(0xf7, PEDR); + *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR); + ctrl_outb(0xff, PDDR); ctrl_outb(0xbf, PEDR); + *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR); + ctrl_outb(0xff, PDDR); ctrl_outb(0x7f, PEDR); + *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR); + *s++=ctrl_inb(PGDR); *s++=ctrl_inb(PHDR); +} + + +void __init hp600_kbd_init_hw(void) +{ + scan_kbd_init(); + register_scan_keyboard(hp690_japanese_scan_kbd, + hp690_japanese_table, 18); + printk(KERN_INFO "HP600 matrix scan keyboard registered\n"); +} + + +/**************************************************************** +HP Jornada 690(Japanese version) keyboard scan matrix + + PTC7 PTC6 PTC5 PTC4 PTC3 PTC2 PTC1 PTC0 +PTD1 REC Escape on/off Han/Zen Hira Eisu +PTD5 REC Z on/off Enter : / +PTD7 REC Right Down +PTE0 REC Windows on/off +PTE1 REC A on/off ] [ ; +PTE3 REC Tab on/off ShirtR \ Up +PTE6 REC Q on/off BS @ P +PTE7 REC 1 on/off ^ - 0 + + + PTF7 PTF6 PTF5 PTF4 PTF3 PTF2 PTF1 PTF0 +PTD1 F5 F4 F6 F7 F8 F3 F2 F1 +PTD5 N B M , . V C X +PTD7 Muhen Alt Left +PTE0 Henkan _ Del Space Ctrl +PTE1 H G J K L F D S +PTE3 ShiftL +PTE6 Y T U I O R E W +PTE7 6 5 7 8 9 4 3 2 + + PTG5 PTG4 PTG3 PTG0 PTH0 +* REC REW FWW Cover on/off + + + 7 6 5 4 3 2 1 0 +C: 0xffff 0xdf IP IP IP IP IP IP IP IP +D: 0x6786 0x59 O I O IP I F O I +E: 0x5045 0x00 O O F F O F O O +F: 0xffff 0xff IP IP IP IP IP IP IP IP +G: 0xaffe 0xfd I I IP IP IP IP IP I +H: 0x70f2 0x49 O IP F F IP IP F I +J: 0x0704 0x22 F F O IP F F O F +K: 0x0100 0x10 F F F O F F F F +L: 0x0c3c 0x26 F F IP F F IP IP F + +****************************************************************/ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/i810_rng.c linux/drivers/char/i810_rng.c --- v2.4.0-test1/linux/drivers/char/i810_rng.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/i810_rng.c Tue Jun 20 13:58:42 2000 @@ -0,0 +1,885 @@ +/* + + Hardware driver for Intel i810 Random Number Generator (RNG) + Copyright 2000 Jeff Garzik + + Driver Web site: http://gtf.org/garzik/drivers/i810_rng/ + + + + Based on: + Intel 82802AB/82802AC Firmware Hub (FWH) Datasheet + May 1999 Order Number: 290658-002 R + + Intel 82802 Firmware Hub: Random Number Generator + Programmer's Reference Manual + December 1999 Order Number: 298029-001 R + + Intel 82802 Firmware HUB Random Number Generator Driver + Copyright (c) 2000 Matt Sottek + + Special thanks to Matt Sottek. I did the "guts", he + did the "brains" and all the testing. (Anybody wanna send + me an i810 or i820?) + + ---------------------------------------------------------- + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + ---------------------------------------------------------- + + From the firmware hub datasheet: + + The Firmware Hub integrates a Random Number Generator (RNG) + using thermal noise generated from inherently random quantum + mechanical properties of silicon. When not generating new random + bits the RNG circuitry will enter a low power state. Intel will + provide a binary software driver to give third party software + access to our RNG for use as a security feature. At this time, + the RNG is only to be used with a system in an OS-present state. + + ---------------------------------------------------------- + + Theory of operation: + + This driver has TWO modes of operation: + + Mode 1 + ------ + Character driver. Using the standard open() + and read() system calls, you can read random data from + the i810 RNG device. This data is NOT CHECKED by any + fitness tests, and could potentially be bogus (if the + hardware is faulty or has been tampered with). + + /dev/intel_rng is char device major 10, minor 183. + + + Mode 2 + ------ + Injection of entropy into the kernel entropy pool via a + timer function. + + A timer is run at RNG_TIMER_LEN intervals, reading 8 bits + of data from the RNG. If the RNG has previously passed a + FIPS test, then the data will be added to the /dev/random + entropy pool. Then, those 8 bits are added to an internal + test data pool. When that pool is full, a FIPS test is + run to verify that the last N bytes read are decently random. + + Thus, the RNG will never be enabled until it passes a + FIPS test. And, data will stop flowing into the system + entropy pool if the data is determined to be non-random. + + Finally, note that the timer defaults to OFF. This ensures + that the system entropy pool will not be polluted with + RNG-originated data unless a conscious decision is made + by the user. + + HOWEVER NOTE THAT UP TO 2499 BYTES OF DATA CAN BE BOGUS + BEFORE THE SYSTEM WILL NOTICE VIA THE FIPS TEST. + + ---------------------------------------------------------- + + Driver notes: + + * You may enable and disable the RNG hardware (and this + driver) via sysctl: + + # disable RNG + echo 0 > /proc/sys/dev/i810_hw_enabled + + # enable RNG + echo 1 > /proc/sys/dev/i810_hw_enabled + + * The default number of entropy bits added by default is + the full 8 bits. If you wish to reduce this value for + paranoia's sake, you can do so via sysctl as well: + + # Add only 4 bits of entropy to /dev/random + echo 4 > /proc/sys/dev/i810_rng_entropy + + * The default number of entropy bits can also be set via + a module parameter "rng_entropy" at module load time. + + * In order to unload the i810_rng module, you must first + disable the hardware via sysctl i810_hw_enabled, as shown above, + and make sure all users of the character device + + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* + * core module and version information + */ +#define RNG_VERSION "0.6.1" +#define RNG_MODULE_NAME "i810_rng" +#define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION +#define PFX RNG_MODULE_NAME ": " + + +/* + * debugging macros + */ +#undef RNG_DEBUG /* define to 1 to enable copious debugging info */ + +#ifdef RNG_DEBUG +/* note: prints function name for you */ +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + +#define RNG_NDEBUG 0 /* define to 1 to disable lightweight runtime checks */ +#if RNG_NDEBUG +#define assert(expr) +#else +#define assert(expr) \ + if(!(expr)) { \ + printk( "Assertion failed! %s,%s,%s,line=%d\n", \ + #expr,__FILE__,__FUNCTION__,__LINE__); \ + } +#endif + + +/* + * misc helper macros + */ +#define arraysize(x) (sizeof(x)/sizeof(*(x))) + +/* + * prototypes + */ +static void rng_fips_test_store (int rng_data); +static void rng_run_fips_test (void); + + +/* + * RNG registers (offsets from rng_mem) + */ +#define RNG_HW_STATUS 0 +#define RNG_PRESENT 0x40 +#define RNG_ENABLED 0x01 +#define RNG_STATUS 1 +#define RNG_DATA_PRESENT 0x01 +#define RNG_DATA 2 + +#define RNG_ADDR 0xFFBC015F +#define RNG_ADDR_LEN 3 + +#define RNG_MAX_ENTROPY 8 /* max entropy h/w is capable of */ + +#define RNG_MISCDEV_MINOR 183 /* official */ + + +/* + * Frequency that data is added to kernel entropy pool + * HZ>>1 == every half-second + */ +#define RNG_TIMER_LEN (HZ >> 1) + + +/* + * number of bytes required for a FIPS test. + * do not alter unless you really, I mean + * REALLY know what you are doing. + */ +#define RNG_FIPS_TEST_THRESHOLD 2500 + + +/* + * various RNG status variables. they are globals + * as we only support a single RNG device + */ +static int rng_allocated = 0; /* is someone using the RNG region? */ +static int rng_hw_enabled = 0; /* is the RNG h/w, and timer, enabled? */ +static int rng_trusted = 0; /* does FIPS trust out data? */ +static int rng_enabled_sysctl; /* sysctl for enabling/disabling RNG */ +static int rng_entropy = 8; /* number of entropy bits we submit to /dev/random */ +static int rng_entropy_sysctl; /* sysctl for changing entropy bits */ +static int rng_have_mem_region = 0; /* did we grab RNG region via request_mem_region? */ +static int rng_fips_counter = 0; /* size of internal FIPS test data pool */ +static void *rng_mem = NULL; /* token to our ioremap'd RNG register area */ +static spinlock_t rng_lock = SPIN_LOCK_UNLOCKED; /* hardware lock */ +static struct timer_list rng_timer; /* kernel timer for RNG hardware reads and tests */ +static atomic_t rng_open; + +/* + * inlined helper functions for accessing RNG registers + */ +static inline u8 rng_hwstatus (void) +{ + assert (rng_mem != NULL); + return readb (rng_mem + RNG_HW_STATUS); +} + + +static inline void rng_hwstatus_set (u8 hw_status) +{ + assert (rng_mem != NULL); + writeb (hw_status, rng_mem + RNG_HW_STATUS); +} + + +static inline int rng_data_present (void) +{ + assert (rng_mem != NULL); + assert (rng_hw_enabled == 1); + + return (readb (rng_mem + RNG_STATUS) & RNG_DATA_PRESENT) ? 1 : 0; +} + + +static inline int rng_data_read (void) +{ + assert (rng_mem != NULL); + assert (rng_hw_enabled == 1); + + return readb (rng_mem + RNG_DATA); +} + + +/* + * rng_timer_ticker - executes every RNG_TIMER_LEN jiffies, + * adds a single byte to system entropy + * and internal FIPS test pools + */ +static void rng_timer_tick (unsigned long data) +{ + unsigned long flags; + int rng_data; + + spin_lock_irqsave (&rng_lock, flags); + + if (rng_data_present ()) { + /* gimme some thermal noise, baby */ + rng_data = rng_data_read (); + + /* + * if RNG has been verified in the past, add + * data just read to the /dev/random pool, + * with the entropy specified by the user + * via sysctl (defaults to 8 bits) + */ + if (rng_trusted) + batch_entropy_store (rng_data, jiffies, rng_entropy); + + /* fitness testing via FIPS, if we have enough data */ + rng_fips_test_store (rng_data); + if (rng_fips_counter > RNG_FIPS_TEST_THRESHOLD) + rng_run_fips_test (); + } + + spin_unlock_irqrestore (&rng_lock, flags); + + /* run the timer again */ + rng_timer.expires = jiffies + RNG_TIMER_LEN; + add_timer (&rng_timer); +} + + +/* + * rng_enable - enable or disable the RNG and internal timer + */ +static int rng_enable (int enable) +{ + unsigned long flags; + int rc = 0; + u8 hw_status; + + DPRINTK ("ENTER\n"); + + spin_lock_irqsave (&rng_lock, flags); + + hw_status = rng_hwstatus (); + + if (enable && !rng_hw_enabled) { + rng_hwstatus_set (hw_status | RNG_ENABLED); + + printk (KERN_INFO PFX "RNG h/w enabled\n"); + rng_hw_enabled = 1; + MOD_INC_USE_COUNT; + } + + else if (!enable && rng_hw_enabled) { + del_timer (&rng_timer); + + rng_hwstatus_set (hw_status & ~RNG_ENABLED); + + printk (KERN_INFO PFX "RNG h/w disabled\n"); + rng_hw_enabled = 0; + MOD_DEC_USE_COUNT; + } + + if (enable != (rng_hwstatus () & RNG_ENABLED) ) { + del_timer (&rng_timer); + printk (KERN_ERR PFX "Unable to %sable the RNG\n", + enable ? "en" : "dis"); + rc = -EIO; + } + + spin_unlock_irqrestore (&rng_lock, flags); + + DPRINTK ("EXIT, returning %d\n", rc); + return rc; +} + + +/* + * rng_handle_sysctl_enable - handle a read or write of our enable/disable sysctl + */ + +static int rng_handle_sysctl_enable (ctl_table * table, int write, struct file *filp, + void *buffer, size_t * lenp) +{ + unsigned long flags; + int enabled_save, rc; + + DPRINTK ("ENTER\n"); + + spin_lock_irqsave (&rng_lock, flags); + rng_enabled_sysctl = enabled_save = rng_hw_enabled; + spin_unlock_irqrestore (&rng_lock, flags); + + rc = proc_dointvec (table, write, filp, buffer, lenp); + if (rc) + return rc; + + if (enabled_save != rng_enabled_sysctl) + rng_enable (rng_enabled_sysctl); + + DPRINTK ("EXIT, returning 0\n"); + return 0; +} + + +/* + * rng_handle_sysctl_entropy - handle a read or write of our entropy bits sysctl + */ + +static int rng_handle_sysctl_entropy (ctl_table * table, int write, struct file *filp, + void *buffer, size_t * lenp) +{ + unsigned long flags; + int entropy_bits_save, rc; + + DPRINTK ("ENTER\n"); + + spin_lock_irqsave (&rng_lock, flags); + rng_entropy_sysctl = entropy_bits_save = rng_entropy; + spin_unlock_irqrestore (&rng_lock, flags); + + rc = proc_dointvec (table, write, filp, buffer, lenp); + if (rc) + return rc; + + if (entropy_bits_save == rng_entropy_sysctl) + goto out; + + if ((rng_entropy_sysctl >= 0) && + (rng_entropy_sysctl <= 8)) { + spin_lock_irqsave (&rng_lock, flags); + rng_entropy = rng_entropy_sysctl; + spin_unlock_irqrestore (&rng_lock, flags); + + printk (KERN_INFO PFX "entropy bits now %d\n", rng_entropy_sysctl); + } else { + printk (KERN_INFO PFX "ignoring invalid entropy setting (%d)\n", + rng_entropy_sysctl); + } + +out: + DPRINTK ("EXIT, returning 0\n"); + return 0; +} + + +/* + * rng_sysctl - add or remove the rng sysctl + */ +static void rng_sysctl (int add) +{ +#define DEV_I810_RNG 1 +#define DEV_I810_RNG_ENTROPY 2 + /* Definition of the sysctl */ + static ctl_table rng_sysctls[] = { + {DEV_I810_RNG, /* ID */ + RNG_MODULE_NAME "_enabled", /* name in /proc */ + &rng_enabled_sysctl, + sizeof (rng_enabled_sysctl), /* data ptr, data size */ + 0644, /* mode */ + 0, /* child */ + rng_handle_sysctl_enable, /* proc handler */ + 0, /* strategy */ + 0, /* proc control block */ + 0, 0} + , + {DEV_I810_RNG_ENTROPY, /* ID */ + RNG_MODULE_NAME "_entropy", /* name in /proc */ + &rng_entropy_sysctl, + sizeof (rng_entropy_sysctl), /* data ptr, data size */ + 0644, /* mode */ + 0, /* child */ + rng_handle_sysctl_entropy, /* proc handler */ + 0, /* strategy */ + 0, /* proc control block */ + 0, 0} + , + {0} + }; + + /* Define the parent file : /proc/sys/dev */ + static ctl_table sysctls_root[] = { + {CTL_DEV, + "dev", + NULL, 0, + 0555, + rng_sysctls}, + {0} + }; + static struct ctl_table_header *sysctls_root_header = NULL; + + if (add) { + if (!sysctls_root_header) + sysctls_root_header = register_sysctl_table (sysctls_root, 0); + } else if (sysctls_root_header) { + unregister_sysctl_table (sysctls_root_header); + sysctls_root_header = NULL; + } +} + + +static int rng_dev_open (struct inode *inode, struct file *filp) +{ + int rc = -EINVAL; + unsigned long flags; + + if ((filp->f_mode & FMODE_READ) == 0) + goto err_out; + if (filp->f_mode & FMODE_WRITE) + goto err_out; + + spin_lock_irqsave (&rng_lock, flags); + + if (atomic_read(&rng_open)) { + spin_unlock_irqrestore (&rng_lock, flags); + rc = -EBUSY; + goto err_out; + } + + atomic_set (&rng_open, 1); + + spin_unlock_irqrestore (&rng_lock, flags); + + if (rng_enable(1) != 0) { + spin_lock_irqsave (&rng_lock, flags); + atomic_set (&rng_open, 0); + spin_unlock_irqrestore (&rng_lock, flags); + rc = -EIO; + goto err_out; + } + + return 0; + +err_out: + return rc; +} + + +static int rng_dev_release (struct inode *inode, struct file *filp) +{ + unsigned long flags; + + if (rng_enable(0) != 0) + return -EIO; + + spin_lock_irqsave (&rng_lock, flags); + atomic_set (&rng_open, 0); + spin_unlock_irqrestore (&rng_lock, flags); + + return 0; +} + + +static ssize_t rng_dev_read (struct file *filp, char * buf, size_t size, + loff_t *offp) +{ + int have_data, copied = 0; + unsigned long flags; + u8 data=0; + u8 *page; + + if (size < 1) + return 0; + + page = (unsigned char *) get_zeroed_page (GFP_KERNEL); + if (!page) + return -ENOMEM; + +read_loop: + /* using the fact that read() can return >0 but + * less than the requested amount, we simply + * read up to PAGE_SIZE or buffer size, whichever + * is smaller, and return that data. + */ + if ((copied == size) || (copied == PAGE_SIZE)) { + size_t tmpsize = (copied == size) ? size : PAGE_SIZE; + int rc = copy_to_user (buf, page, tmpsize); + free_page ((long)page); + if (rc) return rc; + return tmpsize; + } + + spin_lock_irqsave (&rng_lock, flags); + + have_data = 0; + if (rng_data_present ()) { + data = rng_data_read (); + have_data = 1; + } + + spin_unlock_irqrestore (&rng_lock, flags); + + if (have_data) { + page[copied] = data; + copied++; + } else { + if (filp->f_flags & O_NONBLOCK) { + free_page ((long)page); + return -EAGAIN; + } + } + + if (current->need_resched) + schedule (); + + if (signal_pending (current)) { + free_page ((long)page); + return -ERESTARTSYS; + } + + goto read_loop; +} + + +/* + * rng_init_one - look for and attempt to init a single RNG + */ +static int __init rng_init_one (struct pci_dev *dev, + const struct pci_device_id *id) +{ + int rc; + u8 hw_status; + + DPRINTK ("ENTER\n"); + + if (rng_allocated) { + printk (KERN_ERR PFX "this driver only supports one RNG\n"); + DPRINTK ("EXIT, returning -EBUSY\n"); + return -EBUSY; + } + + /* XXX currently fails, investigate who has our mem region */ + if (request_mem_region (RNG_ADDR, RNG_ADDR_LEN, RNG_MODULE_NAME)) + rng_have_mem_region = 1; + + rng_mem = ioremap (RNG_ADDR, RNG_ADDR_LEN); + if (rng_mem == NULL) { + printk (KERN_ERR PFX "cannot ioremap RNG Memory\n"); + DPRINTK ("EXIT, returning -EBUSY\n"); + rc = -EBUSY; + goto err_out; + } + + /* Check for Intel 82802 */ + hw_status = rng_hwstatus (); + if ((hw_status & RNG_PRESENT) == 0) { + printk (KERN_ERR PFX "RNG not detected\n"); + DPRINTK ("EXIT, returning -ENODEV\n"); + rc = -ENODEV; + goto err_out; + } + + rng_allocated = 1; + + if (rng_entropy < 0 || rng_entropy > RNG_MAX_ENTROPY) + rng_entropy = RNG_MAX_ENTROPY; + + /* init core RNG timer, but do not add it */ + init_timer (&rng_timer); + rng_timer.function = rng_timer_tick; + + rc = rng_enable (0); + if (rc) { + printk (KERN_ERR PFX "cannot disable RNG, aborting\n"); + goto err_out; + } + + /* add sysctls */ + rng_sysctl (1); + + DPRINTK ("EXIT, returning 0\n"); + return 0; + +err_out: + if (rng_mem) + iounmap (rng_mem); + if (rng_have_mem_region) + release_mem_region (RNG_ADDR, RNG_ADDR_LEN); + return rc; +} + + +/* + * Data for PCI driver interface + */ +const static struct pci_device_id rng_pci_tbl[] __initdata = { + { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, }, + { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, }, + { 0, }, +}; +MODULE_DEVICE_TABLE (pci, rng_pci_tbl); + +static struct pci_driver rng_driver = { + name: RNG_MODULE_NAME, + id_table: rng_pci_tbl, + probe: rng_init_one, +}; + +MODULE_AUTHOR("Jeff Garzik, Matt Sottek"); +MODULE_DESCRIPTION("Intel i8xx chipset Random Number Generator (RNG) driver"); +MODULE_PARM(rng_entropy, "1i"); +MODULE_PARM_DESC(rng_entropy, "Bits of entropy to add to random pool per RNG byte (range: 0-8, default 8)"); + + +static struct file_operations rng_chrdev_ops = { + owner: THIS_MODULE, + open: rng_dev_open, + release: rng_dev_release, + read: rng_dev_read, +}; + + +static struct miscdevice rng_miscdev = { + RNG_MISCDEV_MINOR, + RNG_MODULE_NAME, + &rng_chrdev_ops, +}; + + +/* + * rng_init - initialize RNG module + */ +static int __init rng_init (void) +{ + int rc; + + DPRINTK ("ENTER\n"); + + MOD_INC_USE_COUNT; + + if (pci_register_driver (&rng_driver) < 1) { + DPRINTK ("EXIT, returning -ENODEV\n"); + MOD_DEC_USE_COUNT; + return -ENODEV; + } + + rc = misc_register (&rng_miscdev); + if (rc) { + pci_unregister_driver (&rng_driver); + DPRINTK ("EXIT, returning %d\n", rc); + MOD_DEC_USE_COUNT; + return rc; + } + + printk (KERN_INFO RNG_DRIVER_NAME " loaded\n"); + + /* FIXME: verify module unload logic, then remove + * this additional MOD_INC_USE_COUNT */ + MOD_INC_USE_COUNT; + + MOD_DEC_USE_COUNT; /* init complete, unload allowed now */ + + DPRINTK ("EXIT, returning 0\n"); + return 0; +} + + +/* + * rng_init - shutdown RNG module + */ +static void __exit rng_cleanup (void) +{ + unsigned long flags; + + DPRINTK ("ENTER\n"); + + spin_lock_irqsave (&rng_lock, flags); + del_timer (&rng_timer); + spin_unlock_irqrestore (&rng_lock, flags); + + rng_sysctl (0); + pci_unregister_driver (&rng_driver); + + if (rng_have_mem_region) + release_mem_region (RNG_ADDR, RNG_ADDR_LEN); + + rng_hwstatus_set (rng_hwstatus() & ~RNG_ENABLED); + + misc_deregister (&rng_miscdev); + + DPRINTK ("EXIT\n"); +} + + +module_init (rng_init); +module_exit (rng_cleanup); + + + + +/* These are the startup tests suggested by the FIPS 140-1 spec section +* 4.11.1 (http://csrc.nist.gov/fips/fips1401.htm) +* The Monobit, Poker, Runs, and Long Runs tests are implemented below. +* This test is run at periodic intervals to verify +* data is sufficently random. If the tests are failed the RNG module +* will no longer submit data to the entropy pool, but the tests will +* continue to run at the given interval. If at a later time the RNG +* passes all tests it will be re-enabled for the next period. +* The reason for this is that it is not unlikely that at some time +* during normal operation one of the tests will fail. This does not +* necessarily mean the RNG is not operating properly, it is just a +* statistically rare event. In that case we don't want to forever +* disable the RNG, we will just leave it disabled for the period of +* time until the tests are rerun and passed. +* +* For argument sake I tested /proc/urandom with these tests and it +* took 142,095 tries before I got a failure, and urandom isn't as +* random as random :) +*/ + +static int poker[16] = { 0, }, runs[12] = { 0, }; +static int ones = 0, rlength = -1, current_bit = 0, rng_test = 0; + + +/* + * rng_fips_test_store - store 8 bits of entropy in FIPS + * internal test data pool + */ +static void rng_fips_test_store (int rng_data) +{ + int j; + static int last_bit = 0; + + DPRINTK ("ENTER, rng_data = %d\n", rng_data & 0xFF); + + poker[rng_data >> 4]++; + poker[rng_data & 15]++; + + /* Note in the loop below rlength is always one less than the actual + run length. This makes things easier. */ + last_bit = (rng_data & 128) >> 7; + for (j = 7; j >= 0; j--) { + ones += current_bit = (rng_data & 1 << j) >> j; + if (current_bit != last_bit) { + /* If runlength is 1-6 count it in correct bucket. 0's go in + runs[0-5] 1's go in runs[6-11] hence the 6*current_bit below */ + if (rlength < 5) { + runs[rlength + + (6 * current_bit)]++; + } else { + runs[5 + (6 * current_bit)]++; + } + + /* Check if we just failed longrun test */ + if (rlength >= 33) + rng_test &= 8; + rlength = 0; + /* flip the current run type */ + last_bit = current_bit; + } else { + rlength++; + } + } + + DPRINTK ("EXIT\n"); +} + + +/* + * now that we have some data, run a FIPS test + */ +static void rng_run_fips_test (void) +{ + int j, i; + + DPRINTK ("ENTER\n"); + + /* add in the last (possibly incomplete) run */ + if (rlength < 5) + runs[rlength + (6 * current_bit)]++; + else { + runs[5 + (6 * current_bit)]++; + if (rlength >= 33) + rng_test &= 8; + } + /* Ones test */ + if ((ones >= 10346) || (ones <= 9654)) + rng_test &= 1; + /* Poker calcs */ + for (i = 0, j = 0; i < 16; i++) + j += poker[i] * poker[i]; + if ((j >= 1580457) || (j <= 1562821)) + rng_test &= 2; + if ((runs[0] < 2267) || (runs[0] > 2733) || + (runs[1] < 1079) || (runs[1] > 1421) || + (runs[2] < 502) || (runs[2] > 748) || + (runs[3] < 223) || (runs[3] > 402) || + (runs[4] < 90) || (runs[4] > 223) || + (runs[5] < 90) || (runs[5] > 223) || + (runs[6] < 2267) || (runs[6] > 2733) || + (runs[7] < 1079) || (runs[7] > 1421) || + (runs[8] < 502) || (runs[8] > 748) || + (runs[9] < 223) || (runs[9] > 402) || + (runs[10] < 90) || (runs[10] > 223) || + (runs[11] < 90) || (runs[11] > 223)) { + rng_test &= 4; + } + + rng_test = !rng_test; + DPRINTK ("FIPS test %sed\n", rng_test ? "pass" : "fail"); + + /* enable/disable RNG with results of the tests */ + if (rng_test && !rng_trusted) + printk (KERN_WARNING PFX "FIPS test passed, enabling RNG\n"); + else if (!rng_test && rng_trusted) + printk (KERN_WARNING PFX "FIPS test failed, disabling RNG\n"); + + rng_trusted = rng_test; + + /* finally, clear out FIPS variables for start of next run */ + memset (&poker, 0, sizeof (poker)); + memset (&runs, 0, sizeof (runs)); + ones = 0; + rlength = -1; + current_bit = 0; + rng_test = 0; + + DPRINTK ("EXIT\n"); +} + diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/ip2main.c linux/drivers/char/ip2main.c --- v2.4.0-test1/linux/drivers/char/ip2main.c Wed Apr 26 16:34:07 2000 +++ linux/drivers/char/ip2main.c Wed Jun 21 22:31:01 2000 @@ -311,6 +311,7 @@ * download the loadware to the boards. */ static struct file_operations ip2_ipl = { + owner: THIS_MODULE, read: ip2_ipl_read, write: ip2_ipl_write, ioctl: ip2_ipl_ioctl, @@ -876,19 +877,19 @@ #ifdef CONFIG_DEVFS_FS sprintf( name, "ipl%d", i ); i2BoardPtrTable[i]->devfs_ipl_handle = - devfs_register (devfs_handle, name, 0, - DEVFS_FL_NONE, + devfs_register (devfs_handle, name, + DEVFS_FL_DEFAULT, IP2_IPL_MAJOR, 4 * i, S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, - 0, 0, &ip2_ipl, NULL); + &ip2_ipl, NULL); sprintf( name, "stat%d", i ); i2BoardPtrTable[i]->devfs_stat_handle = - devfs_register (devfs_handle, name, 0, - DEVFS_FL_NONE, + devfs_register (devfs_handle, name, + DEVFS_FL_DEFAULT, IP2_IPL_MAJOR, 4 * i + 1, S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, - 0, 0, &ip2_ipl, NULL); + &ip2_ipl, NULL); for ( box = 0; box < ABS_MAX_BOXES; ++box ) { @@ -3201,8 +3202,6 @@ #ifdef IP2DEBUG_IPL printk (KERN_DEBUG "IP2IPL: open\n" ); #endif - - //MOD_INC_USE_COUNT; // Needs close entry with decrement. switch(iplminor) { // These are the IPL devices diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/isicom.c linux/drivers/char/isicom.c --- v2.4.0-test1/linux/drivers/char/isicom.c Thu May 11 15:30:06 2000 +++ linux/drivers/char/isicom.c Tue Jun 20 07:32:13 2000 @@ -86,8 +86,6 @@ static unsigned long tx_count = 0; #endif -static int ISILoad_open(struct inode *inode, struct file *filp); -static int ISILoad_release(struct inode *inode, struct file *filp); static int ISILoad_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); static void isicom_tx(unsigned long _data); @@ -109,9 +107,8 @@ */ static struct file_operations ISILoad_fops = { + owner: THIS_MODULE, ioctl: ISILoad_ioctl, - open: ISILoad_open, - release: ISILoad_release, }; struct miscdevice isiloader_device = { @@ -127,24 +124,6 @@ return 0; else return 1; -} - -static int ISILoad_open(struct inode *inode, struct file *filp) -{ -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISILoad:Firmware loader Opened!!!\n"); -#endif - MOD_INC_USE_COUNT; - return 0; -} - -static int ISILoad_release(struct inode *inode, struct file *filp) -{ -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISILoad:Firmware loader Close(Release)d\n",); -#endif - MOD_DEC_USE_COUNT; - return 0; } static int ISILoad_ioctl(struct inode *inode, struct file *filp, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/istallion.c linux/drivers/char/istallion.c --- v2.4.0-test1/linux/drivers/char/istallion.c Thu May 11 15:30:06 2000 +++ linux/drivers/char/istallion.c Wed Jun 21 22:31:01 2000 @@ -687,8 +687,6 @@ static int stli_brdinit(stlibrd_t *brdp); static int stli_startbrd(stlibrd_t *brdp); -static int stli_memopen(struct inode *ip, struct file *fp); -static int stli_memclose(struct inode *ip, struct file *fp); static ssize_t stli_memread(struct file *fp, char *buf, size_t count, loff_t *offp); static ssize_t stli_memwrite(struct file *fp, const char *buf, size_t count, loff_t *offp); static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg); @@ -780,11 +778,10 @@ * board. This is also a very useful debugging tool. */ static struct file_operations stli_fsiomem = { + owner: THIS_MODULE, read: stli_memread, write: stli_memwrite, ioctl: stli_memioctl, - open: stli_memopen, - release: stli_memclose, }; /*****************************************************************************/ @@ -5183,27 +5180,6 @@ /*****************************************************************************/ /* - * Memory device open code. Need to keep track of opens and close - * for module handling. - */ - -static int stli_memopen(struct inode *ip, struct file *fp) -{ - MOD_INC_USE_COUNT; - return(0); -} - -/*****************************************************************************/ - -static int stli_memclose(struct inode *ip, struct file *fp) -{ - MOD_DEC_USE_COUNT; - return(0); -} - -/*****************************************************************************/ - -/* * The "staliomem" device is also required to do some special operations on * the board. We need to be able to send an interrupt to the board, * reset it, and start/stop it. @@ -5334,7 +5310,7 @@ devfs_handle = devfs_mk_dir (NULL, "staliomem", 9, NULL); devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT, STL_SIOMEMMAJOR, 0, - S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR, &stli_fsiomem, NULL); /* diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/Config.in linux/drivers/char/joystick/Config.in --- v2.4.0-test1/linux/drivers/char/joystick/Config.in Wed Dec 8 14:11:26 1999 +++ linux/drivers/char/joystick/Config.in Wed Jun 21 08:22:21 2000 @@ -1,34 +1,56 @@ # -# Joystick driver +# Joystick driver configuration # mainmenu_option next_comment comment 'Joysticks' tristate 'Joystick support' CONFIG_JOYSTICK - if [ "$CONFIG_JOYSTICK" != "n" ]; then - dep_tristate ' Classic PC analog' CONFIG_JOY_ANALOG $CONFIG_JOYSTICK - dep_tristate ' FPGaming and MadCatz A3D' CONFIG_JOY_ASSASSIN $CONFIG_JOYSTICK - dep_tristate ' Gravis GrIP' CONFIG_JOY_GRAVIS $CONFIG_JOYSTICK - dep_tristate ' Logitech ADI' CONFIG_JOY_LOGITECH $CONFIG_JOYSTICK - dep_tristate ' Microsoft SideWinder' CONFIG_JOY_SIDEWINDER $CONFIG_JOYSTICK - dep_tristate ' ThrustMaster DirectConnect' CONFIG_JOY_THRUSTMASTER $CONFIG_JOYSTICK - dep_tristate ' Creative Labs Blaster' CONFIG_JOY_CREATIVE $CONFIG_JOYSTICK - dep_tristate ' PDPI Lightning 4 card' CONFIG_JOY_LIGHTNING $CONFIG_JOYSTICK - dep_tristate ' Trident 4DWave and Aureal Vortex gameport' CONFIG_JOY_PCI $CONFIG_JOYSTICK - dep_tristate ' Magellan and Space Mouse' CONFIG_JOY_MAGELLAN $CONFIG_JOYSTICK - dep_tristate ' SpaceTec SpaceOrb 360 and SpaceBall Avenger' CONFIG_JOY_SPACEORB $CONFIG_JOYSTICK - dep_tristate ' SpaceTec SpaceBall 4000 FLX' CONFIG_JOY_SPACEBALL $CONFIG_JOYSTICK - dep_tristate ' Logitech WingMan Warrior' CONFIG_JOY_WARRIOR $CONFIG_JOYSTICK + + define_tristate CONFIG_USB $CONFIG_JOYSTICK + define_tristate CONFIG_INPUT_JOYDEV $CONFIG_JOYSTICK + + comment 'Game port support' + dep_tristate ' ns558 gameports' CONFIG_INPUT_NS558 $CONFIG_JOYSTICK + dep_tristate ' PDPI Lightning 4 gamecard' CONFIG_INPUT_LIGHTNING $CONFIG_JOYSTICK + dep_tristate ' Aureal Vortex and Trident 4DWave gameports' CONFIG_INPUT_PCIGAME $CONFIG_JOYSTICK + + comment 'Gameport joysticks' + dep_tristate ' Classic PC analog joysticks and gamepads' CONFIG_INPUT_ANALOG $CONFIG_JOYSTICK + dep_tristate ' Assasin 3D and MadCatz Panther devices' CONFIG_INPUT_A3D $CONFIG_JOYSTICK + dep_tristate ' Logitech ADI digital joysticks and gamepads' CONFIG_INPUT_ADI $CONFIG_JOYSTICK + dep_tristate ' Creative Labs Blaster Cobra gamepad' CONFIG_INPUT_COBRA $CONFIG_JOYSTICK + dep_tristate ' Genius Flight2000 Digital joysticks and gamepads' CONFIG_INPUT_GF2K $CONFIG_JOYSTICK + dep_tristate ' Gravis GrIP joysticks and gamepads' CONFIG_INPUT_GRIP $CONFIG_JOYSTICK + dep_tristate ' InterAct digital joysticks and gamepads' CONFIG_INPUT_INTERACT $CONFIG_JOYSTICK + dep_tristate ' ThrustMaster DirectConnect joysticks and gamepads' CONFIG_INPUT_TMDC $CONFIG_JOYSTICK + dep_tristate ' Microsoft SideWinder digital joysticks and gamepads' CONFIG_INPUT_SIDEWINDER $CONFIG_JOYSTICK + + comment 'Serial port support' + dep_tristate ' Serial port input line discipline' CONFIG_INPUT_SERPORT $CONFIG_JOYSTICK + + comment 'Serial port joysticks' + dep_tristate ' Logitech WingMan Warrior joystick' CONFIG_INPUT_WARRIOR $CONFIG_JOYSTICK + dep_tristate ' LogiCad3d Magellan/SpaceMouse 6dof controller' CONFIG_INPUT_MAGELLAN $CONFIG_JOYSTICK + dep_tristate ' SpaceTec SpaceOrb/Avenger 6dof controller' CONFIG_INPUT_SPACEORB $CONFIG_JOYSTICK + dep_tristate ' SpaceTec SpaceBall 4000 FLX 6dof controller' CONFIG_INPUT_SPACEBALL $CONFIG_JOYSTICK + dep_tristate ' I-Force joysticks/wheels' CONFIG_INPUT_IFORCE_232 $CONFIG_JOYSTICK + if [ "$CONFIG_INPUT_IFORCE_232" != "n" ]; then + define_tristate CONFIG_INPUT_IFORCE $CONFIG_INPUT_IFORCE_232 + fi + if [ "$CONFIG_PARPORT" != "n" ]; then - dep_tristate ' NES, SNES, PSX, N64, Multi' CONFIG_JOY_CONSOLE $CONFIG_JOYSTICK $CONFIG_PARPORT - dep_tristate ' Sega, Multi' CONFIG_JOY_DB9 $CONFIG_JOYSTICK $CONFIG_PARPORT - dep_tristate ' TurboGraFX interface' CONFIG_JOY_TURBOGRAFX $CONFIG_JOYSTICK $CONFIG_PARPORT - fi + comment 'Parallel port joysticks' + dep_tristate ' Multisystem, Sega Genesis, Saturn joysticks and gamepads' CONFIG_INPUT_DB9 $CONFIG_JOYSTICK + dep_tristate ' Multisystem, NES, SNES, N64, PSX joysticks and gamepads' CONFIG_INPUT_GAMECON $CONFIG_JOYSTICK + dep_tristate ' Multisystem joysticks via TurboGraFX device' CONFIG_INPUT_TURBOGRAFX $CONFIG_JOYSTICK + fi + if [ "$CONFIG_AMIGA" = "y" ]; then - dep_tristate ' Amiga joysticks' CONFIG_JOY_AMIGA $CONFIG_JOYSTICK + comment 'System joysticks' + dep_tristate ' Amiga joysticks' CONFIG_INPUT_AMIJOY $CONFIG_JOYSTICK fi fi - + endmenu diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/Makefile linux/drivers/char/joystick/Makefile --- v2.4.0-test1/linux/drivers/char/joystick/Makefile Wed Dec 8 14:11:26 1999 +++ linux/drivers/char/joystick/Makefile Wed Jun 21 08:22:21 2000 @@ -2,154 +2,73 @@ # Makefile for the joystick drivers. # -O_TARGET := js.o -OX_OBJS := -O_OBJS := -MX_OBJS := -M_OBJS := - -ifeq ($(CONFIG_JOYSTICK),y) -OX_OBJS += joystick.o -else - ifeq ($(CONFIG_JOYSTICK),m) - MX_OBJS += joystick.o - endif -endif - -ifeq ($(CONFIG_JOY_AMIGA),y) -O_OBJS += joy-amiga.o -else - ifeq ($(CONFIG_JOY_AMIGA),m) - M_OBJS += joy-amiga.o - endif -endif - -ifeq ($(CONFIG_JOY_ANALOG),y) -O_OBJS += joy-analog.o -else - ifeq ($(CONFIG_JOY_ANALOG),m) - M_OBJS += joy-analog.o - endif -endif - -ifeq ($(CONFIG_JOY_ASSASSIN),y) -O_OBJS += joy-assassin.o -else - ifeq ($(CONFIG_JOY_ASSASSIN),m) - M_OBJS += joy-assassin.o - endif -endif - -ifeq ($(CONFIG_JOY_CONSOLE),y) -O_OBJS += joy-console.o -else - ifeq ($(CONFIG_JOY_CONSOLE),m) - M_OBJS += joy-console.o - endif -endif - -ifeq ($(CONFIG_JOY_CREATIVE),y) -O_OBJS += joy-creative.o -else - ifeq ($(CONFIG_JOY_CREATIVE),m) - M_OBJS += joy-creative.o - endif -endif - -ifeq ($(CONFIG_JOY_DB9),y) -O_OBJS += joy-db9.o -else - ifeq ($(CONFIG_JOY_DB9),m) - M_OBJS += joy-db9.o - endif -endif - -ifeq ($(CONFIG_JOY_GRAVIS),y) -O_OBJS += joy-gravis.o -else - ifeq ($(CONFIG_JOY_GRAVIS),m) - M_OBJS += joy-gravis.o - endif -endif - -ifeq ($(CONFIG_JOY_LIGHTNING),y) -O_OBJS += joy-lightning.o -else - ifeq ($(CONFIG_JOY_LIGHTNING),m) - M_OBJS += joy-lightning.o - endif -endif - -ifeq ($(CONFIG_JOY_LOGITECH),y) -O_OBJS += joy-logitech.o -else - ifeq ($(CONFIG_JOY_LOGITECH),m) - M_OBJS += joy-logitech.o - endif -endif - -ifeq ($(CONFIG_JOY_MAGELLAN),y) -O_OBJS += joy-magellan.o -else - ifeq ($(CONFIG_JOY_MAGELLAN),m) - M_OBJS += joy-magellan.o - endif -endif - -ifeq ($(CONFIG_JOY_PCI),y) -O_OBJS += joy-pci.o -else - ifeq ($(CONFIG_JOY_PCI),m) - M_OBJS += joy-pci.o - endif -endif - -ifeq ($(CONFIG_JOY_SIDEWINDER),y) -O_OBJS += joy-sidewinder.o -else - ifeq ($(CONFIG_JOY_SIDEWINDER),m) - M_OBJS += joy-sidewinder.o - endif -endif - -ifeq ($(CONFIG_JOY_SPACEORB),y) -O_OBJS += joy-spaceorb.o -else - ifeq ($(CONFIG_JOY_SPACEORB),m) - M_OBJS += joy-spaceorb.o - endif -endif - -ifeq ($(CONFIG_JOY_SPACEBALL),y) -O_OBJS += joy-spaceball.o -else - ifeq ($(CONFIG_JOY_SPACEBALL),m) - M_OBJS += joy-spaceball.o - endif -endif - -ifeq ($(CONFIG_JOY_THRUSTMASTER),y) -O_OBJS += joy-thrustmaster.o -else - ifeq ($(CONFIG_JOY_THRUSTMASTER),m) - M_OBJS += joy-thrustmaster.o - endif -endif - -ifeq ($(CONFIG_JOY_TURBOGRAFX),y) -O_OBJS += joy-turbografx.o -else - ifeq ($(CONFIG_JOY_TURBOGRAFX),m) - M_OBJS += joy-turbografx.o - endif -endif - -ifeq ($(CONFIG_JOY_WARRIOR),y) -O_OBJS += joy-warrior.o -else - ifeq ($(CONFIG_JOY_WARRIOR),m) - M_OBJS += joy-warrior.o - endif -endif +# Subdirs. + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +MOD_IN_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +# The target object and module list name. + +O_TARGET := js.o +M_OBJS := +O_OBJS := +#MOD_LIST_NAME := INPUT_MODULES + +# Objects that export symbols. + +export-objs := serio.o gameport.o + +# Object file lists. + +obj-y := +obj-m := +obj-n := +obj- := + +# Each configuration option enables a list of files. + +obj-$(CONFIG_INPUT_SERPORT) += serport.o serio.o + +obj-$(CONFIG_INPUT_NS558) += ns558.o gameport.o +obj-$(CONFIG_INPUT_LIGHTNING) += lightning.o gameport.o +obj-$(CONFIG_INPUT_PCIGAME) += pcigame.o gameport.o + +obj-$(CONFIG_INPUT_WARRIOR) += warrior.o serio.o +obj-$(CONFIG_INPUT_MAGELLAN) += magellan.o serio.o +obj-$(CONFIG_INPUT_SPACEORB) += spaceorb.o serio.o +obj-$(CONFIG_INPUT_SPACEBALL) += spaceball.o serio.o +obj-$(CONFIG_INPUT_IFORCE_232) += serio.o + +obj-$(CONFIG_INPUT_ANALOG) += analog.o gameport.o +obj-$(CONFIG_INPUT_A3D) += a3d.o gameport.o +obj-$(CONFIG_INPUT_ADI) += adi.o gameport.o +obj-$(CONFIG_INPUT_COBRA) += cobra.o gameport.o +obj-$(CONFIG_INPUT_GF2K) += gf2k.o gameport.o +obj-$(CONFIG_INPUT_GRIP) += grip.o gameport.o +obj-$(CONFIG_INPUT_INTERACT) += interact.o gameport.o +obj-$(CONFIG_INPUT_TMDC) += tmdc.o gameport.o +obj-$(CONFIG_INPUT_SIDEWINDER) += sidewinder.o gameport.o + +obj-$(CONFIG_INPUT_DB9) += db9.o +obj-$(CONFIG_INPUT_GAMECON) += gamecon.o +obj-$(CONFIG_INPUT_TURBOGRAFX) += turbografx.o + +obj-$(CONFIG_INPUT_AMIJOY) += amijoy.o + +# Files that are both resident and modular: remove from modular. + +obj-m := $(filter-out $(obj-y), $(obj-m)) +int-m := $(filter-out $(int-y), $(int-m)) + +# Translate to Rules.make lists. + +O_OBJS := $(sort $(filter-out $(export-objs), $(obj-y))) +OX_OBJS := $(sort $(filter $(export-objs), $(obj-y))) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) + +# The global Rules.make. include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/a3d.c linux/drivers/char/joystick/a3d.c --- v2.4.0-test1/linux/drivers/char/joystick/a3d.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick/a3d.c Thu Jun 22 06:59:58 2000 @@ -0,0 +1,387 @@ +/* + * $Id: a3d.c,v 1.10 2000/05/29 11:19:50 vojtech Exp $ + * + * Copyright (c) 1998-2000 Vojtech Pavlik + * + * Sponsored by SuSE + */ + +/* + * FP-Gaming Assasin 3D joystick driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include + +#define A3D_MAX_START 400 /* 400 us */ +#define A3D_MAX_STROBE 60 /* 40 us */ +#define A3D_DELAY_READ 3 /* 3 ms */ +#define A3D_MAX_LENGTH 40 /* 40*3 bits */ +#define A3D_REFRESH_TIME HZ/50 /* 20 ms */ + +#define A3D_MODE_A3D 1 /* Assassin 3D */ +#define A3D_MODE_PAN 2 /* Panther */ +#define A3D_MODE_OEM 3 /* Panther OEM version */ +#define A3D_MODE_PXL 4 /* Panther XL */ + +char *a3d_names[] = { NULL, "FP-Gaming Assassin 3D", "MadCatz Panther", "OEM Panther", + "MadCatz Panther XL", "MadCatz Panther XL w/ rudder" }; + +struct a3d { + struct gameport *gameport; + struct gameport adc; + struct input_dev dev; + struct timer_list timer; + int axes[4]; + int buttons; + int mode; + int length; + int used; + int reads; + int bads; +}; + +/* + * a3d_read_packet() reads an Assassin 3D packet. + */ + +static int a3d_read_packet(struct gameport *gameport, int length, char *data) +{ + unsigned long flags; + unsigned char u, v; + unsigned int t, s; + int i; + + i = 0; + t = gameport_time(gameport, A3D_MAX_START); + s = gameport_time(gameport, A3D_MAX_STROBE); + + __save_flags(flags); + __cli(); + gameport_trigger(gameport); + v = gameport_read(gameport); + + while (t > 0 && i < length) { + t--; + u = v; v = gameport_read(gameport); + if (~v & u & 0x10) { + data[i++] = v >> 5; + t = s; + } + } + + __restore_flags(flags); + + return i; +} + +/* + * a3d_csum() computes checksum of triplet packet + */ + +static int a3d_csum(char *data, int count) +{ + int i, csum = 0; + for (i = 0; i < count - 2; i++) csum += data[i]; + return (csum & 0x3f) != ((data[count - 2] << 3) | data[count - 1]); +} + +static void a3d_read(struct a3d *a3d, unsigned char *data) +{ + struct input_dev *dev = &a3d->dev; + + switch (a3d->mode) { + + case A3D_MODE_A3D: + case A3D_MODE_OEM: + case A3D_MODE_PAN: + + input_report_rel(dev, REL_X, ((data[5] << 6) | (data[6] << 3) | data[ 7]) - ((data[5] & 4) << 7)); + input_report_rel(dev, REL_Y, ((data[8] << 6) | (data[9] << 3) | data[10]) - ((data[8] & 4) << 7)); + + input_report_key(dev, BTN_RIGHT, data[2] & 1); + input_report_key(dev, BTN_LEFT, data[3] & 2); + input_report_key(dev, BTN_MIDDLE, data[3] & 4); + + a3d->axes[0] = ((signed char)((data[11] << 6) | (data[12] << 3) | (data[13]))) + 128; + a3d->axes[1] = ((signed char)((data[14] << 6) | (data[15] << 3) | (data[16]))) + 128; + a3d->axes[2] = ((signed char)((data[17] << 6) | (data[18] << 3) | (data[19]))) + 128; + a3d->axes[3] = ((signed char)((data[20] << 6) | (data[21] << 3) | (data[22]))) + 128; + + a3d->buttons = ((data[3] << 3) | data[4]) & 0xf; + + return; + + case A3D_MODE_PXL: + + input_report_rel(dev, REL_X, ((data[ 9] << 6) | (data[10] << 3) | data[11]) - ((data[ 9] & 4) << 7)); + input_report_rel(dev, REL_Y, ((data[12] << 6) | (data[13] << 3) | data[14]) - ((data[12] & 4) << 7)); + + input_report_key(dev, BTN_RIGHT, data[2] & 1); + input_report_key(dev, BTN_LEFT, data[3] & 2); + input_report_key(dev, BTN_MIDDLE, data[3] & 4); + input_report_key(dev, BTN_SIDE, data[7] & 2); + input_report_key(dev, BTN_EXTRA, data[7] & 4); + + input_report_abs(dev, ABS_X, ((signed char)((data[15] << 6) | (data[16] << 3) | (data[17]))) + 128); + input_report_abs(dev, ABS_Y, ((signed char)((data[18] << 6) | (data[19] << 3) | (data[20]))) + 128); + input_report_abs(dev, ABS_RUDDER, ((signed char)((data[21] << 6) | (data[22] << 3) | (data[23]))) + 128); + input_report_abs(dev, ABS_THROTTLE, ((signed char)((data[24] << 6) | (data[25] << 3) | (data[26]))) + 128); + + input_report_abs(dev, ABS_HAT0X, ( data[5] & 1) - ((data[5] >> 2) & 1)); + input_report_abs(dev, ABS_HAT0Y, ((data[5] >> 1) & 1) - ((data[6] >> 2) & 1)); + input_report_abs(dev, ABS_HAT1X, ((data[4] >> 1) & 1) - ( data[3] & 1)); + input_report_abs(dev, ABS_HAT1Y, ((data[4] >> 2) & 1) - ( data[4] & 1)); + + input_report_key(dev, BTN_TRIGGER, data[8] & 1); + input_report_key(dev, BTN_THUMB, data[8] & 2); + input_report_key(dev, BTN_TOP, data[8] & 4); + input_report_key(dev, BTN_PINKIE, data[7] & 1); + + return; + } +} + + +/* + * a3d_timer() reads and analyzes A3D joystick data. + */ + +static void a3d_timer(unsigned long private) +{ + struct a3d *a3d = (void *) private; + unsigned char data[A3D_MAX_LENGTH]; + a3d->reads++; + if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length + || data[0] != a3d->mode || a3d_csum(data, a3d->length)) + a3d->bads++; else a3d_read(a3d, data); + mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME); +} + +/* + * a3d_adc_cooked_read() copies the acis and button data to the + * callers arrays. It could do the read itself, but the caller could + * call this more than 50 times a second, which would use too much CPU. + */ + +int a3d_adc_cooked_read(struct gameport *gameport, int *axes, int *buttons) +{ + struct a3d *a3d = gameport->driver; + int i; + for (i = 0; i < 4; i++) + axes[i] = (a3d->axes[i] < 254) ? a3d->axes[i] : -1; + *buttons = a3d->buttons; + return 0; +} + +/* + * a3d_adc_open() is the gameport open routine. It refuses to serve + * any but cooked data. + */ + +int a3d_adc_open(struct gameport *gameport, int mode) +{ + struct a3d *a3d = gameport->driver; + if (mode != GAMEPORT_MODE_COOKED) + return -1; + if (!a3d->used++) + mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME); + return 0; +} + +/* + * a3d_adc_close() is a callback from the input close routine. + */ + +static void a3d_adc_close(struct gameport *gameport) +{ + struct a3d *a3d = gameport->driver; + if (!--a3d->used) + del_timer(&a3d->timer); +} + +/* + * a3d_open() is a callback from the input open routine. + */ + +static int a3d_open(struct input_dev *dev) +{ + struct a3d *a3d = dev->private; + if (!a3d->used++) + mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME); + return 0; +} + +/* + * a3d_close() is a callback from the input close routine. + */ + +static void a3d_close(struct input_dev *dev) +{ + struct a3d *a3d = dev->private; + if (!--a3d->used) + del_timer(&a3d->timer); +} + +/* + * a3d_connect() probes for A3D joysticks. + */ + +static void a3d_connect(struct gameport *gameport, struct gameport_dev *dev) +{ + struct a3d *a3d; + unsigned char data[A3D_MAX_LENGTH]; + int i; + + if (!(a3d = kmalloc(sizeof(struct a3d), GFP_KERNEL))) + return; + memset(a3d, 0, sizeof(struct a3d)); + + gameport->private = a3d; + + a3d->gameport = gameport; + init_timer(&a3d->timer); + a3d->timer.data = (long) a3d; + a3d->timer.function = a3d_timer; + + if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) + goto fail1; + + i = a3d_read_packet(gameport, A3D_MAX_LENGTH, data); + + if (!i || a3d_csum(data, i)) + goto fail2; + + a3d->mode = data[0]; + + if (!a3d->mode || a3d->mode > 5) { + printk(KERN_WARNING "a3d.c: Unknown A3D device detected " + "(gameport%d, id=%d), contact \n", gameport->number, a3d->mode); + goto fail2; + } + + + if (a3d->mode == A3D_MODE_PXL) { + + int axes[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER }; + + a3d->length = 33; + + a3d->dev.evbit[0] |= BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL); + a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y); + a3d->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_RUDDER) + | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y) | BIT(ABS_HAT1X) | BIT(ABS_HAT1Y); + + a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE) + | BIT(BTN_SIDE) | BIT(BTN_EXTRA); + + a3d->dev.keybit[LONG(BTN_JOYSTICK)] |= BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_PINKIE); + + a3d_read(a3d, data); + + for (i = 0; i < 4; i++) { + if (i < 2) { + a3d->dev.absmin[axes[i]] = 48; + a3d->dev.absmax[axes[i]] = a3d->dev.abs[axes[i]] * 2 - 48; + a3d->dev.absflat[axes[i]] = 8; + } else { + a3d->dev.absmin[axes[i]] = 2; + a3d->dev.absmax[axes[i]] = 253; + } + a3d->dev.absmin[ABS_HAT0X + i] = -1; + a3d->dev.absmax[ABS_HAT0X + i] = 1; + } + + } else { + a3d->length = 29; + + a3d->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_REL); + a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y); + a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE); + + a3d->adc.driver = a3d; + a3d->adc.open = a3d_adc_open; + a3d->adc.close = a3d_adc_close; + a3d->adc.cooked_read = a3d_adc_cooked_read; + a3d->adc.fuzz = 1; + a3d->adc.type = GAMEPORT_EXT; + + a3d_read(a3d, data); + + gameport_register_port(&a3d->adc); + printk(KERN_INFO "gameport%d: %s on gameport%d.0\n", + a3d->adc.number, a3d_names[a3d->mode], gameport->number); + } + + a3d->dev.private = a3d; + a3d->dev.open = a3d_open; + a3d->dev.close = a3d_close; + + a3d->dev.name = a3d_names[a3d->mode]; + a3d->dev.idbus = BUS_GAMEPORT; + a3d->dev.idvendor = GAMEPORT_ID_VENDOR_MADCATZ; + a3d->dev.idproduct = a3d->mode; + a3d->dev.idversion = 0x0100; + + input_register_device(&a3d->dev); + printk(KERN_INFO "input%d: %s on gameport%d.0\n", + a3d->dev.number, a3d_names[a3d->mode], gameport->number); + + return; +fail2: gameport_close(gameport); +fail1: kfree(a3d); +} + +static void a3d_disconnect(struct gameport *gameport) +{ + + struct a3d *a3d = gameport->private; + input_unregister_device(&a3d->dev); + if (a3d->mode < A3D_MODE_PXL) + gameport_unregister_port(&a3d->adc); + gameport_close(gameport); + kfree(a3d); +} + +static struct gameport_dev a3d_dev = { + connect: a3d_connect, + disconnect: a3d_disconnect, +}; + +int __init a3d_init(void) +{ + gameport_register_device(&a3d_dev); + return 0; +} + +void __exit a3d_exit(void) +{ + gameport_unregister_device(&a3d_dev); +} + +module_init(a3d_init); +module_exit(a3d_exit); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/adi.c linux/drivers/char/joystick/adi.c --- v2.4.0-test1/linux/drivers/char/joystick/adi.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick/adi.c Thu Jun 22 06:59:58 2000 @@ -0,0 +1,554 @@ +/* + * $Id: adi.c,v 1.12 2000/06/03 20:18:52 vojtech Exp $ + * + * Copyright (c) 1998-2000 Vojtech Pavlik + * + * Sponsored by SuSE + */ + +/* + * Logitech ADI joystick family driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Times, array sizes, flags, ids. + */ + +#define ADI_MAX_START 200 /* Trigger to packet timeout [200us] */ +#define ADI_MAX_STROBE 40 /* Single bit timeout [40us] */ +#define ADI_REFRESH_TIME HZ/50 /* How often to poll the joystick [20 ms] */ +#define ADI_INIT_DELAY 10 /* Delay after init packet [10ms] */ +#define ADI_DATA_DELAY 4 /* Delay after data packet [4ms] */ + +#define ADI_MAX_LENGTH 256 +#define ADI_MIN_LENGTH 8 +#define ADI_MIN_LEN_LENGTH 10 +#define ADI_MIN_ID_LENGTH 66 +#define ADI_MAX_NAME_LENGTH 48 +#define ADI_MAX_CNAME_LENGTH 16 + +#define ADI_FLAG_HAT 0x04 +#define ADI_FLAG_10BIT 0x08 + +#define ADI_ID_TPD 0x01 +#define ADI_ID_WGP 0x06 +#define ADI_ID_WGPE 0x08 +#define ADI_ID_MAX 0x0a + +/* + * Names, buttons, axes ... + */ + +static char *adi_names[] = { "WingMan Extreme Digital", "ThunderPad Digital", "SideCar", "CyberMan 2", + "WingMan Interceptor", "WingMan Formula", "WingMan GamePad", + "WingMan Extreme Digital 3D", "WingMan GamePad Extreme", + "WingMan GamePad USB", "Unknown Device %#x" }; + +static char adi_wmgpe_abs[] = { ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y }; +static char adi_wmi_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y }; +static char adi_wmed3d_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RZ, ABS_HAT0X, ABS_HAT0Y }; +static char adi_cm2_abs[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ }; +static char adi_wmf_abs[] = { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y }; + +static short adi_wmgpe_key[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT }; +static short adi_wmi_key[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA }; +static short adi_wmed3d_key[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2 }; +static short adi_cm2_key[] = { BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 }; + +static char* adi_abs[] = { adi_wmi_abs, adi_wmgpe_abs, adi_wmf_abs, adi_cm2_abs, adi_wmi_abs, adi_wmf_abs, + adi_wmgpe_abs, adi_wmed3d_abs, adi_wmgpe_abs, adi_wmgpe_abs, adi_wmi_abs }; + +static short* adi_key[] = { adi_wmi_key, adi_wmgpe_key, adi_cm2_key, adi_cm2_key, adi_wmi_key, adi_cm2_key, + adi_wmgpe_key, adi_wmed3d_key, adi_wmgpe_key, adi_wmgpe_key, adi_wmi_key }; + +/* + * Hat to axis conversion arrays. + */ + +static struct { + int x; + int y; +} adi_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; + +/* + * Per-port information. + */ + +struct adi { + struct input_dev dev; + int length; + int ret; + int idx; + unsigned char id; + char buttons; + char axes10; + char axes8; + signed char pad; + char hats; + char *abs; + short *key; + char name[ADI_MAX_NAME_LENGTH]; + char cname[ADI_MAX_CNAME_LENGTH]; + unsigned char data[ADI_MAX_LENGTH]; +}; + +struct adi_port { + struct gameport *gameport; + struct timer_list timer; + struct adi adi[2]; + int bad; + int reads; + int used; +}; + +/* + * adi_read_packet() reads a Logitech ADI packet. + */ + +static void adi_read_packet(struct adi_port *port) +{ + struct adi *adi = port->adi; + struct gameport *gameport = port->gameport; + unsigned char u, v, w, x, z; + int t[2], s[2], i; + unsigned long flags; + + for (i = 0; i < 2; i++) { + adi[i].ret = -1; + t[i] = gameport_time(gameport, ADI_MAX_START); + s[i] = 0; + } + + __save_flags(flags); + __cli(); + + gameport_trigger(gameport); + v = z = gameport_read(gameport); + + do { + u = v; + w = u ^ (v = x = gameport_read(gameport)); + for (i = 0; i < 2; i++, w >>= 2, x >>= 2) { + t[i]--; + if ((w & 0x30) && s[i]) { + if ((w & 0x30) < 0x30 && adi[i].ret < ADI_MAX_LENGTH && t[i] > 0) { + adi[i].data[++adi[i].ret] = w; + t[i] = gameport_time(gameport, ADI_MAX_STROBE); + } else t[i] = 0; + } else if (!(x & 0x30)) s[i] = 1; + } + } while (t[0] > 0 || t[1] > 0); + + __restore_flags(flags); + + return; +} + +/* + * adi_move_bits() detects a possible 2-stream mode, and moves + * the bits accordingly. + */ + +static void adi_move_bits(struct adi_port *port, int length) +{ + int i; + struct adi *adi = port->adi; + + adi[0].idx = adi[1].idx = 0; + + if (adi[0].ret <= 0 || adi[1].ret <= 0) return; + if (adi[0].data[0] & 0x20 || ~adi[1].data[0] & 0x20) return; + + for (i = 1; i <= adi[1].ret; i++) + adi[0].data[((length - 1) >> 1) + i + 1] = adi[1].data[i]; + + adi[0].ret += adi[1].ret; + adi[1].ret = -1; +} + +/* + * adi_get_bits() gathers bits from the data packet. + */ + +static inline int adi_get_bits(struct adi *adi, int count) +{ + int bits = 0; + int i; + if ((adi->idx += count) > adi->ret) return 0; + for (i = 0; i < count; i++) + bits |= ((adi->data[adi->idx - i] >> 5) & 1) << i; + return bits; +} + +/* + * adi_decode() decodes Logitech joystick data into input events. + */ + +static int adi_decode(struct adi *adi) +{ + struct input_dev *dev = &adi->dev; + char *abs = adi->abs; + short *key = adi->key; + int i, t; + + if (adi->ret < adi->length || adi->id != (adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4))) + return -1; + + for (i = 0; i < adi->axes10; i++) + input_report_abs(dev, *abs++, adi_get_bits(adi, 10)); + + for (i = 0; i < adi->axes8; i++) + input_report_abs(dev, *abs++, adi_get_bits(adi, 8)); + + for (i = 0; i < adi->buttons && i < 63; i++) { + if (i == adi->pad) { + t = adi_get_bits(adi, 4); + input_report_abs(dev, *abs++, ((t >> 2) & 1) - ( t & 1)); + input_report_abs(dev, *abs++, ((t >> 1) & 1) - ((t >> 3) & 1)); + } + input_report_key(dev, *key++, adi_get_bits(adi, 1)); + } + + for (i = 0; i < adi->hats; i++) { + if ((t = adi_get_bits(adi, 4)) > 8) t = 0; + input_report_abs(dev, *abs++, adi_hat_to_axis[t].x); + input_report_abs(dev, *abs++, adi_hat_to_axis[t].y); + } + + for (i = 63; i < adi->buttons; i++) + input_report_key(dev, *key++, adi_get_bits(adi, 1)); + + return 0; +} + +/* + * adi_read() reads the data packet and decodes it. + */ + +static int adi_read(struct adi_port *port) +{ + int i; + int result = 0; + + adi_read_packet(port); + adi_move_bits(port, port->adi[0].length); + + for (i = 0; i < 2; i++) + if (port->adi[i].length) + result |= adi_decode(port->adi + i); + + return result; +} + +/* + * adi_timer() repeatedly polls the Logitech joysticks. + */ + +static void adi_timer(unsigned long data) +{ + struct adi_port *port = (void *) data; + port->bad -= adi_read(port); + port->reads++; + mod_timer(&port->timer, jiffies + ADI_REFRESH_TIME); +} + +/* + * adi_open() is a callback from the input open routine. + */ + +static int adi_open(struct input_dev *dev) +{ + struct adi_port *port = dev->private; + if (!port->used++) + mod_timer(&port->timer, jiffies + ADI_REFRESH_TIME); + return 0; +} + +/* + * adi_close() is a callback from the input close routine. + */ + +static void adi_close(struct input_dev *dev) +{ + struct adi_port *port = dev->private; + if (!--port->used) + del_timer(&port->timer); +} + +/* + * adi_init_digital() sends a trigger & delay sequence + * to reset and initialize a Logitech joystick into digital mode. + */ + +static void adi_init_digital(struct gameport *gameport) +{ + int seq[] = { 3, -2, -3, 10, -6, -11, -7, -9, 11, 0 }; + int i; + + for (i = 0; seq[i]; i++) { + gameport_trigger(gameport); + if (seq[i] > 0) wait_ms(seq[i]); + if (seq[i] < 0) mdelay(-seq[i]); + } +} + +static void adi_id_decode(struct adi *adi, struct adi_port *port) +{ + int i, t; + + if (adi->ret < ADI_MIN_ID_LENGTH) /* Minimum ID packet length */ + return; + + if (adi->ret < (t = adi_get_bits(adi, 10))) { + printk(KERN_WARNING "adi: Short ID packet: reported: %d != read: %d\n", t, adi->ret); + return; + } + + adi->id = adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4); + + if ((t = adi_get_bits(adi, 4)) & ADI_FLAG_HAT) adi->hats++; + + adi->length = adi_get_bits(adi, 10); + + if (adi->length >= ADI_MAX_LENGTH || adi->length < ADI_MIN_LENGTH) { + printk(KERN_WARNING "adi: Bad data packet length (%d).\n", adi->length); + adi->length = 0; + return; + } + + adi->axes8 = adi_get_bits(adi, 4); + adi->buttons = adi_get_bits(adi, 6); + + if (adi_get_bits(adi, 6) != 8 && adi->hats) { + printk(KERN_WARNING "adi: Other than 8-dir POVs not supported yet.\n"); + adi->length = 0; + return; + } + + adi->buttons += adi_get_bits(adi, 6); + adi->hats += adi_get_bits(adi, 4); + + i = adi_get_bits(adi, 4); + + if (t & ADI_FLAG_10BIT) { + adi->axes10 = adi->axes8 - i; + adi->axes8 = i; + } + + t = adi_get_bits(adi, 4); + + for (i = 0; i < t; i++) + adi->cname[i] = adi_get_bits(adi, 8); + adi->cname[i] = 0; + + if (adi->length != (t = 8 + adi->buttons + adi->axes10 * 10 + adi->axes8 * 8 + adi->hats * 4)) { + printk(KERN_WARNING "adi: Expected length %d != data length %d\n", t, adi->length); + adi->length = 0; + return; + } + + switch (adi->id) { + case ADI_ID_TPD: + adi->pad = 4; + adi->buttons -= 4; + break; + case ADI_ID_WGP: + adi->pad = 0; + adi->buttons -= 4; + break; + default: + adi->pad = -1; + break; + } +} + +static void adi_init_input(struct adi *adi, struct adi_port *port) +{ + int i, t; + char buf[ADI_MAX_NAME_LENGTH]; + + if (!adi->length) return; + + t = adi->id < ADI_ID_MAX ? adi->id : ADI_ID_MAX; + + sprintf(buf, adi_names[t], adi->id); + sprintf(adi->name, "Logitech %s", buf); + + adi->abs = adi_abs[t]; + adi->key = adi_key[t]; + + adi->dev.open = adi_open; + adi->dev.close = adi_close; + + adi->dev.name = adi->name; + adi->dev.idbus = BUS_GAMEPORT; + adi->dev.idvendor = GAMEPORT_ID_VENDOR_LOGITECH; + adi->dev.idproduct = adi->id; + adi->dev.idversion = 0x0100; + + adi->dev.private = port; + adi->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + + for (i = 0; i < adi->axes10 + adi->axes8 + adi->hats * 2; i++) + set_bit(adi->abs[i], &adi->dev.absbit); + + for (i = 0; i < adi->buttons; i++) + set_bit(adi->key[i], &adi->dev.keybit); +} + +static void adi_init_center(struct adi *adi) +{ + int i, t, x; + + if (!adi->length) return; + + for (i = 0; i < adi->axes10 + adi->axes8 + adi->hats * 2; i++) { + + t = adi->abs[i]; + x = adi->dev.abs[t]; + + if (t == ABS_THROTTLE || t == ABS_RUDDER || adi->id == ADI_ID_WGPE) { + if (i < adi->axes10) x = 512; else x = 128; + } + + if (i < adi->axes10) { + adi->dev.absmax[t] = x * 2 - 64; + adi->dev.absmin[t] = 64; + adi->dev.absfuzz[t] = 2; + adi->dev.absflat[t] = 16; + continue; + } + + if (i < adi->axes10 + adi->axes8) { + adi->dev.absmax[t] = x * 2 - 48; + adi->dev.absmin[t] = 48; + adi->dev.absfuzz[t] = 1; + adi->dev.absflat[t] = 16; + continue; + } + + adi->dev.absmax[t] = 1; + adi->dev.absmin[t] = -1; + } +} + +/* + * adi_connect() probes for Logitech ADI joysticks. + */ + +static void adi_connect(struct gameport *gameport, struct gameport_dev *dev) +{ + struct adi_port *port; + int i; + + if (!(port = kmalloc(sizeof(struct adi_port), GFP_KERNEL))) + return; + memset(port, 0, sizeof(struct adi_port)); + + gameport->private = port; + + port->gameport = gameport; + init_timer(&port->timer); + port->timer.data = (long) port; + port->timer.function = adi_timer; + + if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) { + kfree(port); + return; + } + + adi_init_digital(gameport); + adi_read_packet(port); + + if (port->adi[0].ret >= ADI_MIN_LEN_LENGTH) + adi_move_bits(port, adi_get_bits(port->adi, 10)); + + for (i = 0; i < 2; i++) { + adi_id_decode(port->adi + i, port); + adi_init_input(port->adi + i, port); + } + + if (!port->adi[0].length && !port->adi[1].length) { + gameport_close(gameport); + kfree(port); + return; + } + + wait_ms(ADI_INIT_DELAY); + if (adi_read(port)) { + wait_ms(ADI_DATA_DELAY); + adi_read(port); + } + + for (i = 0; i < 2; i++) + if (port->adi[i].length > 0) { + adi_init_center(port->adi + i); + input_register_device(&port->adi[i].dev); + printk(KERN_INFO "input%d: %s [%s] on gameport%d.%d\n", + port->adi[i].dev.number, port->adi[i].name, port->adi[i].cname, gameport->number, i); + } +} + +static void adi_disconnect(struct gameport *gameport) +{ + int i; + + struct adi_port *port = gameport->private; + for (i = 0; i < 2; i++) + if (port->adi[i].length > 0) + input_unregister_device(&port->adi[i].dev); + gameport_close(gameport); + kfree(port); +} + +/* + * The gameport device structure. + */ + +static struct gameport_dev adi_dev = { + connect: adi_connect, + disconnect: adi_disconnect, +}; + +int __init adi_init(void) +{ + gameport_register_device(&adi_dev); + return 0; +} + +void __exit adi_exit(void) +{ + gameport_unregister_device(&adi_dev); +} + +module_init(adi_init); +module_exit(adi_exit); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/amijoy.c linux/drivers/char/joystick/amijoy.c --- v2.4.0-test1/linux/drivers/char/joystick/amijoy.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick/amijoy.c Wed Jun 21 08:22:21 2000 @@ -0,0 +1,149 @@ +/* + * $Id: amijoy.c,v 1.4 2000/05/29 10:39:54 vojtech Exp $ + * + * Copyright (c) 1998-2000 Vojtech Pavlik + * + * Sponsored by SuSE + */ + +/* + * Driver for Amiga joysticks for Linux/m68k + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_PARM(amijoy, "1-2i"); + +static int amijoy[2] = { 0, 1 }; +static int amijoy_used[2] = { 0, 0 }; +static struct input_dev amijoy_dev[2]; + +static char *amijoy_name = "Amiga joystick"; + +static void amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp) +{ + int i, data = 0, button = 0; + + for (i = 0; i < 2; i++) + if (amijoy[i]) { + + switch (i) { + case 0: data = ~custom.joy0dat; button = (~ciaa.pra >> 6) & 1; break; + case 1: data = ~custom.joy1dat; button = (~ciaa.pra >> 7) & 1; break; + } + + input_report_key(amijoy_dev + i, BTN_TRIGGER, button); + + input_report_abs(amijoy_dev + i, ABS_X, ((data >> 1) & 1) - ((data >> 9) & 1); + data = ~(data ^ (data << 1)); + input_report_abs(amijoy_dev + i, ABS_Y, ((data >> 1) & 1) - ((data >> 9) & 1); + } +} + +static int amijoy_open(struct input_dev *dev) +{ + int *used = dev->private; + + if ((*used)++) + return 0; + + if (request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", NULL)) { + amijoy_used--; + printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", amijoy_irq); + return -EBUSY; + } + + return 0; +} + +static void amijoy_close(struct input_dev *dev) +{ + int *used = dev->private; + + if (!--(*port->used)) + free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt); +} + +static int __init amijoy_setup(char *str) +{ + int i; + int ints[4] + str = get_options(str, ARRAY_SIZE(ints), ints); + for (i = 0; i <= ints[0] && i < 2; i++) amijoy[i] = ints[i+1]; + return 1; +} +__setup("amijoy=", amijoy_setup); + +static int __init amijoy_init(void) +{ + int i, j; + + init_timer(amijoy_timer); + port->timer.function = amijoy_timer; + + for (i = 0; i < 2; i++) + if (amijoy[i]) { + + amijoy_dev[i].open = amijoy_open; + amijoy_dev[i].close = amijoy_close; + amijoy_dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + amijoy_dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + amijoy_dev[i].keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + for (j = 0; j < 2; j++) + amijoy_dev[i].absmin[ABS_X + j] = -1; + amijoy_dev[i].absmax[ABS_X + j] = 1; + } + + amijoy->dev[i].name = amijoy_name; + amijoy->dev[i].idbus = BUS_AMIGA; + amijoy->dev[i].idvendor = 0x0001; + amijoy->dev[i].idproduct = 0x0003; + amijoy->dev[i].version = 0x0100; + + amijoy_dev[i].private = amijoy_used + i; + + input_register_device(amijoy_dev + i); + printk(KERN_INFO "input%d: %s at joy%ddat\n", amijoy_dev[i].number, amijoy_name, i); + } +} + +static void _exit amijoy_exit(void) +{ + int i; + + for (i = 0; i < 2; i++) + if (amijoy[i]) + input_unregister_device(amijoy_dev + i); +} + +module_init(amijoy_init); +module_exit(amijoy_exit); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/analog.c linux/drivers/char/joystick/analog.c --- v2.4.0-test1/linux/drivers/char/joystick/analog.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick/analog.c Thu Jun 22 06:59:58 2000 @@ -0,0 +1,758 @@ +/* + * $Id: analog.c,v 1.52 2000/06/07 13:07:06 vojtech Exp $ + * + * Copyright (c) 1996-2000 Vojtech Pavlik + * + * Sponsored by SuSE + */ + +/* + * Analog joystick and gamepad driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); + +/* + * Option parsing. + */ + +MODULE_PARM(js,"1-16s"); + +#define ANALOG_PORTS 16 + +static char *js[ANALOG_PORTS]; +static int analog_options[ANALOG_PORTS]; + +/* + * Times, feature definitions. + */ + +#define ANALOG_RUDDER 0x00004 +#define ANALOG_THROTTLE 0x00008 +#define ANALOG_AXES_STD 0x0000f +#define ANALOG_BTNS_STD 0x000f0 + +#define ANALOG_BTNS_CHF 0x00100 +#define ANALOG_HAT1_CHF 0x00200 +#define ANALOG_HAT2_CHF 0x00400 +#define ANALOG_HAT_FCS 0x00800 +#define ANALOG_HATS_ALL 0x00e00 +#define ANALOG_BTN_TL 0x01000 +#define ANALOG_BTN_TR 0x02000 +#define ANALOG_BTN_TL2 0x04000 +#define ANALOG_BTN_TR2 0x08000 +#define ANALOG_BTNS_TLR 0x03000 +#define ANALOG_BTNS_TLR2 0x0c000 +#define ANALOG_BTNS_GAMEPAD 0x0f000 + +#define ANALOG_HBTN_CHF 0x10000 +#define ANALOG_ANY_CHF 0x10700 +#define ANALOG_SAITEK 0x20000 +#define ANALOG_EXTENSIONS 0x7ff00 +#define ANALOG_GAMEPAD 0x80000 + +#define ANALOG_MAX_TIME 3 /* 3 ms */ +#define ANALOG_LOOP_TIME 2000 /* 2 * loop */ +#define ANALOG_REFRESH_TIME HZ/100 /* 10 ms */ +#define ANALOG_SAITEK_DELAY 200 /* 200 us */ +#define ANALOG_SAITEK_TIME 2000 /* 2000 us */ +#define ANALOG_AXIS_TIME 2 /* 2 * refresh */ +#define ANALOG_INIT_RETRIES 8 /* 8 times */ +#define ANALOG_FUZZ_BITS 2 /* 2 bit more */ +#define ANALOG_FUZZ_MAGIC 36 /* 36 u*ms/loop */ + +#define ANALOG_MAX_NAME_LENGTH 128 + +static short analog_axes[] = { ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE }; +static short analog_hats[] = { ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y }; +static short analog_pads[] = { BTN_Y, BTN_Z, BTN_TL, BTN_TR }; +static short analog_exts[] = { ANALOG_HAT1_CHF, ANALOG_HAT2_CHF, ANALOG_HAT_FCS }; +static short analog_pad_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_TL2, BTN_TR2, BTN_SELECT, BTN_START, BTN_MODE, BTN_BASE }; +static short analog_joy_btn[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, + BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_BASE6 }; + +static unsigned char analog_chf[] = { 0xf, 0x0, 0x1, 0x9, 0x2, 0x4, 0xc, 0x8, 0x3, 0x5, 0xb, 0x7, 0xd, 0xe, 0xa, 0x6 }; + +struct analog { + struct input_dev dev; + int mask; + short *buttons; + char name[ANALOG_MAX_NAME_LENGTH]; +}; + +struct analog_port { + struct gameport *gameport; + struct timer_list timer; + struct analog analog[2]; + unsigned char mask; + char saitek; + char cooked; + int bads; + int reads; + int speed; + int loop; + int fuzz; + int axes[4]; + int buttons; + int initial[4]; + int used; + int axtime; +}; + +/* + * Time macros. + */ + +#ifdef __i386__ +#ifdef CONFIG_X86_TSC +#define GET_TIME(x) __asm__ __volatile__ ( "rdtsc" : "=a" (x) : : "dx" ) +#define DELTA(x,y) ((y)-(x)) +#define TIME_NAME "TSC" +#else +#define GET_TIME(x) do { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0) +#define DELTA(x,y) ((x)-(y)+((x)<(y)?1193180L/HZ:0)) +#define TIME_NAME "PIT" +#endif +#elif __alpha__ +#define GET_TIME(x) __asm__ __volatile__ ( "rpcc %0" : "=r" (x) ) +#define DELTA(x,y) ((y)-(x)) +#define TIME_NAME "PCC" +#endif + +#ifndef GET_TIME +#define FAKE_TIME +static unsigned long analog_faketime = 0; +#define GET_TIME(x) do { x = analog_faketime++; } while(0) +#define DELTA(x,y) ((y)-(x)) +#define TIME_NAME "Unreliable" +#endif + +/* + * analog_decode() decodes analog joystick data and reports input events. + */ + +static void analog_decode(struct analog *analog, int *axes, int *initial, int buttons) +{ + struct input_dev *dev = &analog->dev; + int i, j; + + if (analog->mask & ANALOG_HAT_FCS) + for (i = 0; i < 4; i++) + if (axes[3] < ((initial[3] * ((i << 1) + 1)) >> 3)) { + buttons |= 1 << (i + 14); + break; + } + + for (i = j = 0; i < 6; i++) + if (analog->mask & (0x10 << i)) + input_report_key(dev, analog->buttons[j++], (buttons >> i) & 1); + + if (analog->mask & ANALOG_HBTN_CHF) + for (i = 0; i < 4; i++) + input_report_key(dev, analog->buttons[j++], (buttons >> (i + 10)) & 1); + + if (analog->mask & ANALOG_BTN_TL) + input_report_key(dev, analog_pads[0], axes[2] < (initial[2] >> 1)); + if (analog->mask & ANALOG_BTN_TR) + input_report_key(dev, analog_pads[1], axes[3] < (initial[3] >> 1)); + if (analog->mask & ANALOG_BTN_TL2) + input_report_key(dev, analog_pads[2], axes[2] > (initial[2] + (initial[2] >> 1))); + if (analog->mask & ANALOG_BTN_TR2) + input_report_key(dev, analog_pads[3], axes[3] > (initial[3] + (initial[3] >> 1))); + + for (i = j = 0; i < 4; i++) + if (analog->mask & (1 << i)) + input_report_abs(dev, analog_axes[j++], axes[i]); + + for (i = j = 0; i < 3; i++) + if (analog->mask & analog_exts[i]) { + input_report_abs(dev, analog_hats[j++], + ((buttons >> ((i << 2) + 7)) & 1) - ((buttons >> ((i << 2) + 9)) & 1)); + input_report_abs(dev, analog_hats[j++], + ((buttons >> ((i << 2) + 8)) & 1) - ((buttons >> ((i << 2) + 6)) & 1)); + } +} + +/* + * analog_cooked_read() reads analog joystick data. + */ + +static int analog_cooked_read(struct analog_port *port) +{ + struct gameport *gameport = port->gameport; + unsigned int time[4], start, loop, now, loopout, timeout; + unsigned char data[4], this, last; + unsigned long flags; + int i, j; + + loopout = (ANALOG_LOOP_TIME * port->loop) / 1000; + timeout = ANALOG_MAX_TIME * port->speed; + + __save_flags(flags); + __cli(); + gameport_trigger(gameport); + GET_TIME(now); + __restore_flags(flags); + + start = now; + this = port->mask; + i = 0; + + do { + loop = now; + last = this; + + __cli(); + this = gameport_read(gameport) & port->mask; + GET_TIME(now); + __restore_flags(flags); + + if ((last ^ this) && (DELTA(loop, now) < loopout)) { + data[i] = last ^ this; + time[i] = now; + i++; + } + + } while (this && (i < 4) && (DELTA(start, now) < timeout)); + + this <<= 4; + + for (--i; i >= 0; i--) { + this |= data[i]; + for (j = 0; j < 4; j++) + if (data[i] & (1 << j)) + port->axes[j] = (DELTA(start, time[i]) << ANALOG_FUZZ_BITS) / port->loop; + } + + return -(this != port->mask); +} + +static int analog_button_read(struct analog_port *port, char saitek, char chf) +{ + unsigned char u; + int t = 1, i = 0; + int strobe = gameport_time(port->gameport, ANALOG_SAITEK_TIME); + + u = gameport_read(port->gameport); + + if (!chf) { + port->buttons = (~u >> 4) & 0xf; + return 0; + } + + port->buttons = 0; + + while ((~u & 0xf0) && (i < 16) && t) { + port->buttons |= 1 << analog_chf[(~u >> 4) & 0xf]; + if (!saitek) return 0; + udelay(ANALOG_SAITEK_DELAY); + t = strobe; + gameport_trigger(port->gameport); + while (((u = gameport_read(port->gameport)) & port->mask) && t) t--; + i++; + } + + return -(!t || (i == 16)); +} + +/* + * analog_timer() repeatedly polls the Analog joysticks. + */ + +static void analog_timer(unsigned long data) +{ + struct analog_port *port = (void *) data; + int i; + + char saitek = !!(port->analog[0].mask & ANALOG_SAITEK); + char chf = !!(port->analog[0].mask & ANALOG_ANY_CHF); + + if (port->cooked) { + port->bads -= gameport_cooked_read(port->gameport, port->axes, &port->buttons); + if (chf) + port->buttons = port->buttons ? (1 << analog_chf[port->buttons]) : 0; + port->reads++; + } else { + if (!port->axtime--) { + port->bads -= analog_cooked_read(port); + port->bads -= analog_button_read(port, saitek, chf); + port->reads++; + port->axtime = ANALOG_AXIS_TIME - 1; + } else { + if (!saitek) + analog_button_read(port, saitek, chf); + } + } + + for (i = 0; i < 2; i++) + if (port->analog[i].mask) + analog_decode(port->analog + i, port->axes, port->initial, port->buttons); + + mod_timer(&port->timer, jiffies + ANALOG_REFRESH_TIME); +} + +/* + * analog_open() is a callback from the input open routine. + */ + +static int analog_open(struct input_dev *dev) +{ + struct analog_port *port = dev->private; + if (!port->used++) + mod_timer(&port->timer, jiffies + ANALOG_REFRESH_TIME); + return 0; +} + +/* + * analog_close() is a callback from the input close routine. + */ + +static void analog_close(struct input_dev *dev) +{ + struct analog_port *port = dev->private; + if (!--port->used) + del_timer(&port->timer); +} + +/* + * analog_calibrate_timer() calibrates the timer and computes loop + * and timeout values for a joystick port. + */ + +static void analog_calibrate_timer(struct analog_port *port) +{ + struct gameport *gameport = port->gameport; + unsigned int i, t, tx, t1, t2, t3; + unsigned long flags; + + save_flags(flags); + cli(); + GET_TIME(t1); +#ifdef FAKE_TIME + analog_faketime += 830; +#endif + udelay(1000); + GET_TIME(t2); + GET_TIME(t3); + restore_flags(flags); + + port->speed = DELTA(t1, t2) - DELTA(t2, t3); + + tx = ~0; + + for (i = 0; i < 50; i++) { + save_flags(flags); + cli(); + GET_TIME(t1); + for (t = 0; t < 50; t++) { gameport_read(gameport); GET_TIME(t2); } + GET_TIME(t3); + restore_flags(flags); + udelay(i); + t = DELTA(t1, t2) - DELTA(t2, t3); + if (t < tx) tx = t; + } + + port->loop = tx / 50; +} + +/* + * analog_name() constructs a name for an analog joystick. + */ + +static void analog_name(struct analog *analog) +{ + sprintf(analog->name, "Analog %d-axis %d-button", + hweight8(analog->mask & ANALOG_AXES_STD), + hweight8(analog->mask & ANALOG_BTNS_STD) + !!(analog->mask & ANALOG_BTNS_CHF) * 2 + + hweight16(analog->mask & ANALOG_BTNS_GAMEPAD) + !!(analog->mask & ANALOG_HBTN_CHF) * 4); + + if (analog->mask & ANALOG_HATS_ALL) + sprintf(analog->name, "%s %d-hat", + analog->name, hweight16(analog->mask & ANALOG_HATS_ALL)); + + if (analog->mask & ANALOG_HAT_FCS) + strcat(analog->name, " FCS"); + if (analog->mask & ANALOG_ANY_CHF) + strcat(analog->name, (analog->mask & ANALOG_SAITEK) ? " Saitek" : " CHF"); + + strcat(analog->name, (analog->mask & ANALOG_GAMEPAD) ? " gamepad": " joystick"); +} + +/* + * analog_init_device() + */ + +static void analog_init_device(struct analog_port *port, struct analog *analog, int index) +{ + int i, j, t, v, w, x, y, z; + + analog_name(analog); + + analog->buttons = (analog->mask & ANALOG_GAMEPAD) ? analog_pad_btn : analog_joy_btn; + + analog->dev.name = analog->name; + analog->dev.idbus = BUS_GAMEPORT; + analog->dev.idvendor = GAMEPORT_ID_VENDOR_ANALOG; + analog->dev.idproduct = analog->mask >> 4; + analog->dev.idversion = 0x0100; + + analog->dev.open = analog_open; + analog->dev.close = analog_close; + analog->dev.private = port; + analog->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + + for (i = j = 0; i < 4; i++) + if (analog->mask & (1 << i)) { + + t = analog_axes[j]; + x = port->axes[i]; + y = (port->axes[0] + port->axes[1]) >> 1; + z = y - port->axes[i]; + z = z > 0 ? z : -z; + v = (x >> 3); + w = (x >> 3); + + set_bit(t, analog->dev.absbit); + + if ((i == 2 || i == 3) && (j == 2 || j == 3) && (z > (y >> 3))) + x = y; + + if (analog->mask & ANALOG_SAITEK) { + if (i == 2) x = port->axes[i]; + v = x - (x >> 2); + w = (x >> 4); + } + + analog->dev.absmax[t] = (x << 1) - v; + analog->dev.absmin[t] = v; + analog->dev.absfuzz[t] = port->fuzz; + analog->dev.absflat[t] = w; + + j++; + } + + for (i = j = 0; i < 3; i++) + if (analog->mask & analog_exts[i]) + for (x = 0; x < 2; x++) { + t = analog_hats[j++]; + set_bit(t, analog->dev.absbit); + analog->dev.absmax[t] = 1; + analog->dev.absmin[t] = -1; + } + + for (i = j = 0; i < 4; i++) + if (analog->mask & (0x10 << i)) + set_bit(analog->buttons[j++], analog->dev.keybit); + + if (analog->mask & ANALOG_BTNS_CHF) + for (i = 0; i < 2; i++) + set_bit(analog->buttons[j++], analog->dev.keybit); + + if (analog->mask & ANALOG_HBTN_CHF) + for (i = 0; i < 4; i++) + set_bit(analog->buttons[j++], analog->dev.keybit); + + for (i = 0; i < 4; i++) + if (analog->mask & (ANALOG_BTN_TL << i)) + set_bit(analog_pads[i], analog->dev.keybit); + + analog_decode(analog, port->axes, port->initial, port->buttons); + + input_register_device(&analog->dev); + + printk(KERN_INFO "input%d: %s at gameport%d.%d", + analog->dev.number, analog->name, port->gameport->number, index); + + if (port->cooked) + printk(" [ADC port]\n"); + else + printk(" ["TIME_NAME" timer, %d %sHz clock, %d ns res]\n", + port->speed > 10000 ? (port->speed + 800) / 1000 : port->speed, + port->speed > 10000 ? "M" : "k", (port->loop * 1000000) / port->speed); +} + +/* + * analog_init_devices() sets up device-specific values and registers the input devices. + */ + +static int analog_init_masks(struct analog_port *port) +{ + int i; + struct analog *analog = port->analog; + int max[4]; + + if (!port->mask) + return -1; + + if ((port->mask & 3) != 3 && port->mask != 0xc) { + printk(KERN_WARNING "analog.c: Unknown joystick device found " + "(data=%#x, gameport%d), probably not analog joystick.\n", + port->mask, port->gameport->number); + return -1; + } + + i = port->gameport->number < ANALOG_PORTS ? analog_options[port->gameport->number] : 0xff; + + analog[0].mask = i & 0xfffff; + + analog[0].mask &= ~(ANALOG_AXES_STD | ANALOG_HAT_FCS | ANALOG_BTNS_GAMEPAD) + | port->mask | ((port->mask << 8) & ANALOG_HAT_FCS) + | ((port->mask << 10) & ANALOG_BTNS_TLR) | ((port->mask << 12) & ANALOG_BTNS_TLR2); + + analog[0].mask &= ~(ANALOG_HAT2_CHF) + | ((analog[0].mask & ANALOG_HBTN_CHF) ? 0 : ANALOG_HAT2_CHF); + + analog[0].mask &= ~(ANALOG_THROTTLE | ANALOG_BTN_TR | ANALOG_BTN_TR2) + | ((~analog[0].mask & ANALOG_HAT_FCS) >> 8) + | ((~analog[0].mask & ANALOG_HAT_FCS) << 2) + | ((~analog[0].mask & ANALOG_HAT_FCS) << 4); + + analog[0].mask &= ~(ANALOG_THROTTLE | ANALOG_RUDDER) + | (((~analog[0].mask & ANALOG_BTNS_TLR ) >> 10) + & ((~analog[0].mask & ANALOG_BTNS_TLR2) >> 12)); + + analog[1].mask = ((i >> 20) & 0xff) | ((i >> 12) & 0xf0000); + + analog[1].mask &= (analog[0].mask & ANALOG_EXTENSIONS) ? ANALOG_GAMEPAD + : (((ANALOG_BTNS_STD | port->mask) & ~analog[0].mask) | ANALOG_GAMEPAD); + + if (port->cooked) { + + for (i = 0; i < 4; i++) max[i] = port->axes[i] << 1; + + if ((analog[0].mask & 0x7) == 0x7) max[2] = (max[0] + max[1]) >> 1; + if ((analog[0].mask & 0xb) == 0xb) max[3] = (max[0] + max[1]) >> 1; + if ((analog[0].mask & ANALOG_BTN_TL) && !(analog[0].mask & ANALOG_BTN_TL2)) max[2] >>= 1; + if ((analog[0].mask & ANALOG_BTN_TR) && !(analog[0].mask & ANALOG_BTN_TR2)) max[3] >>= 1; + if ((analog[0].mask & ANALOG_HAT_FCS)) max[3] >>= 1; + + gameport_calibrate(port->gameport, port->axes, max); + } + + for (i = 0; i < 4; i++) + port->initial[i] = port->axes[i]; + + return -!(analog[0].mask || analog[1].mask); +} + +static int analog_init_port(struct gameport *gameport, struct gameport_dev *dev, struct analog_port *port) +{ + int i, t, u, v; + + gameport->private = port; + port->gameport = gameport; + init_timer(&port->timer); + port->timer.data = (long) port; + port->timer.function = analog_timer; + + if (!gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) { + + analog_calibrate_timer(port); + + gameport_trigger(gameport); + t = gameport_read(gameport); + wait_ms(ANALOG_MAX_TIME); + port->mask = (gameport_read(gameport) ^ t) & t & 0xf; + port->fuzz = (port->speed * ANALOG_FUZZ_MAGIC) / port->loop / 1000 + ANALOG_FUZZ_BITS; + + for (i = 0; i < ANALOG_INIT_RETRIES; i++) { + if (!analog_cooked_read(port)) break; + wait_ms(ANALOG_MAX_TIME); + } + + u = v = 0; + + wait_ms(ANALOG_MAX_TIME); + t = gameport_time(gameport, ANALOG_MAX_TIME * 1000); + gameport_trigger(gameport); + while ((gameport_read(port->gameport) & port->mask) && (u < t)) u++; + udelay(ANALOG_SAITEK_DELAY); + t = gameport_time(gameport, ANALOG_SAITEK_TIME); + gameport_trigger(gameport); + while ((gameport_read(port->gameport) & port->mask) && (v < t)) v++; + + if (v < (u >> 1) && port->gameport->number < ANALOG_PORTS) { + analog_options[port->gameport->number] |= + ANALOG_SAITEK | ANALOG_BTNS_CHF | ANALOG_HBTN_CHF | ANALOG_HAT1_CHF; + return 0; + } + + gameport_close(gameport); + } + + if (!gameport_open(gameport, dev, GAMEPORT_MODE_COOKED)) { + + for (i = 0; i < ANALOG_INIT_RETRIES; i++) + if (!gameport_cooked_read(gameport, port->axes, &port->buttons)) + break; + for (i = 0; i < 4; i++) + if (port->axes[i] != -1) port->mask |= 1 << i; + + port->fuzz = gameport->fuzz; + port->cooked = 1; + return 0; + } + + if (!gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) + return 0; + + return -1; +} + +static void analog_connect(struct gameport *gameport, struct gameport_dev *dev) +{ + struct analog_port *port; + int i; + + if (!(port = kmalloc(sizeof(struct analog_port), GFP_KERNEL))) + return; + memset(port, 0, sizeof(struct analog_port)); + + if (analog_init_port(gameport, dev, port)) { + kfree(port); + return; + } + + if (analog_init_masks(port)) { + gameport_close(gameport); + kfree(port); + return; + } + + for (i = 0; i < 2; i++) + if (port->analog[i].mask) + analog_init_device(port, port->analog + i, i); +} + +static void analog_disconnect(struct gameport *gameport) +{ + int i; + + struct analog_port *port = gameport->private; + for (i = 0; i < 2; i++) + if (port->analog[i].mask) + input_unregister_device(&port->analog[i].dev); + gameport_close(gameport); + printk(KERN_INFO "analog.c: %d out of %d reads (%d%%) on gameport%d failed\n", + port->bads, port->reads, port->reads ? (port->bads * 100 / port->reads) : 0, + port->gameport->number); + kfree(port); +} + +struct analog_types { + char *name; + int value; +}; + +struct analog_types analog_types[] = { + { "none", 0x00000000 }, + { "auto", 0x000000ff }, + { "2btn", 0x0000003f }, + { "y-joy", 0x0cc00033 }, + { "y-pad", 0x8cc80033 }, + { "fcs", 0x000008f7 }, + { "chf", 0x000002ff }, + { "fullchf", 0x000007ff }, + { "gamepad", 0x000830f3 }, + { "gamepad8", 0x0008f0f3 }, + { NULL, 0 } +}; + +static void analog_parse_options(void) +{ + int i, j; + char *end; + + for (i = 0; i < ANALOG_PORTS && js[i]; i++) { + + for (j = 0; analog_types[j].name; j++) + if (!strcmp(analog_types[j].name, js[i])) { + analog_options[i] = analog_types[j].value; + break; + } + if (analog_types[j].name) continue; + + analog_options[i] = simple_strtoul(js[i], &end, 0); + if (end != js[i]) continue; + + analog_options[i] = 0xff; + if (!strlen(js[i])) continue; + + printk(KERN_WARNING "analog.c: Bad config for port %d - \"%s\"\n", i, js[i]); + } + + for (; i < ANALOG_PORTS; i++) + analog_options[i] = 0xff; +} + +/* + * The gameport device structure. + */ + +static struct gameport_dev analog_dev = { + connect: analog_connect, + disconnect: analog_disconnect, +}; + +#ifndef MODULE +static int __init analog_setup(char *str) +{ + char *s = str; + int i = 0; + + if (!str || !*str) return 0; + + while ((str = s) && (i < ANALOG_PORTS)) { + if ((s = strchr(str,','))) *s++ = 0; + js[i++] = str; + } + + return 1; +} +__setup("js=", analog_setup); +#endif + +int __init analog_init(void) +{ + analog_parse_options(); + gameport_register_device(&analog_dev); + return 0; +} + +void __exit analog_exit(void) +{ + gameport_unregister_device(&analog_dev); +} + +module_init(analog_init); +module_exit(analog_exit); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/cobra.c linux/drivers/char/joystick/cobra.c --- v2.4.0-test1/linux/drivers/char/joystick/cobra.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick/cobra.c Wed Jun 21 08:22:21 2000 @@ -0,0 +1,250 @@ +/* + * $Id: cobra.c,v 1.10 2000/06/08 10:23:45 vojtech Exp $ + * + * Copyright (c) 1999-2000 Vojtech Pavlik + * + * Sponsored by SuSE + */ + +/* + * Creative Labd Blaster GamePad Cobra driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include + +#define COBRA_MAX_STROBE 45 /* 45 us max wait for first strobe */ +#define COBRA_REFRESH_TIME HZ/50 /* 20 ms between reads */ +#define COBRA_LENGTH 36 + +static char* cobra_name = "Creative Labs Blaster GamePad Cobra"; + +static int cobra_btn[] = { BTN_START, BTN_SELECT, BTN_TL, BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL2, BTN_TR2, 0 }; + +struct cobra { + struct gameport *gameport; + struct timer_list timer; + struct input_dev dev[2]; + int used; + int reads; + int bads; + unsigned char exists; +}; + +static unsigned char cobra_read_packet(struct gameport *gameport, unsigned int *data) +{ + unsigned long flags; + unsigned char u, v, w; + __u64 buf[2]; + int r[2], t[2]; + int i, j, ret; + + int strobe = gameport_time(gameport, COBRA_MAX_STROBE); + + for (i = 0; i < 2; i++) { + r[i] = buf[i] = 0; + t[i] = COBRA_MAX_STROBE; + } + + __save_flags(flags); + __cli(); + + u = gameport_read(gameport); + + do { + t[0]--; t[1]--; + v = gameport_read(gameport); + for (i = 0, w = u ^ v; i < 2 && w; i++, w >>= 2) + if (w & 0x30) { + if ((w & 0x30) < 0x30 && r[i] < COBRA_LENGTH && t[i] > 0) { + buf[i] |= (__u64)((w >> 5) & 1) << r[i]++; + t[i] = strobe; + u = v; + } else t[i] = 0; + } + } while (t[0] > 0 || t[1] > 0); + + __restore_flags(flags); + + ret = 0; + + for (i = 0; i < 2; i++) { + + if (r[i] != COBRA_LENGTH) continue; + + for (j = 0; j < COBRA_LENGTH && (buf[i] & 0x04104107f) ^ 0x041041040; j++) + buf[i] = (buf[i] >> 1) | ((__u64)(buf[i] & 1) << (COBRA_LENGTH - 1)); + + if (j < COBRA_LENGTH) ret |= (1 << i); + + data[i] = ((buf[i] >> 7) & 0x000001f) | ((buf[i] >> 8) & 0x00003e0) + | ((buf[i] >> 9) & 0x0007c00) | ((buf[i] >> 10) & 0x00f8000) + | ((buf[i] >> 11) & 0x1f00000); + + } + + return ret; +} + +static void cobra_timer(unsigned long private) +{ + struct cobra *cobra = (void *) private; + struct input_dev *dev; + unsigned int data[2]; + int i, j, r; + + cobra->reads++; + + if ((r = cobra_read_packet(cobra->gameport, data)) != cobra->exists) + cobra->bads++; + + for (i = 0; i < 2; i++) + if (cobra->exists & r & (1 << i)) { + + dev = cobra->dev + i; + + input_report_abs(dev, ABS_X, ((data[i] >> 4) & 1) - ((data[i] >> 3) & 1)); + input_report_abs(dev, ABS_Y, ((data[i] >> 2) & 1) - ((data[i] >> 1) & 1)); + + for (j = 0; cobra_btn[j]; j++) + input_report_key(dev, cobra_btn[j], data[i] & (0x20 << i)); + + } + + mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME); +} + +static int cobra_open(struct input_dev *dev) +{ + struct cobra *cobra = dev->private; + if (!cobra->used++) + mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME); + return 0; +} + +static void cobra_close(struct input_dev *dev) +{ + struct cobra *cobra = dev->private; + if (!--cobra->used) + del_timer(&cobra->timer); +} + +static void cobra_connect(struct gameport *gameport, struct gameport_dev *dev) +{ + struct cobra *cobra; + unsigned int data[2]; + int i, j; + + if (!(cobra = kmalloc(sizeof(struct cobra), GFP_KERNEL))) + return; + memset(cobra, 0, sizeof(struct cobra)); + + gameport->private = cobra; + + cobra->gameport = gameport; + init_timer(&cobra->timer); + cobra->timer.data = (long) cobra; + cobra->timer.function = cobra_timer; + + if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) + goto fail1; + + cobra->exists = cobra_read_packet(gameport, data); + + for (i = 0; i < 2; i++) + if ((cobra->exists >> i) & data[i] & 1) { + printk(KERN_WARNING "cobra.c: Device on gameport%d.%d has the Ext bit set. ID is: %d" + " Contact vojtech@suse.cz\n", gameport->number, i, (data[i] >> 2) & 7); + cobra->exists &= ~(1 << i); + } + + if (!cobra->exists) + goto fail2; + + for (i = 0; i < 2; i++) + if ((cobra->exists >> i) & 1) { + + cobra->dev[i].private = cobra; + cobra->dev[i].open = cobra_open; + cobra->dev[i].close = cobra_close; + + cobra->dev[i].name = cobra_name; + cobra->dev[i].idbus = BUS_GAMEPORT; + cobra->dev[i].idvendor = GAMEPORT_ID_VENDOR_CREATIVE; + cobra->dev[i].idproduct = 0x0008; + cobra->dev[i].idversion = 0x0100; + + cobra->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + cobra->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + + for (j = 0; cobra_btn[j]; j++) + set_bit(cobra_btn[j], cobra->dev[i].keybit); + + cobra->dev[i].absmin[ABS_X] = -1; cobra->dev[i].absmax[ABS_X] = 1; + cobra->dev[i].absmin[ABS_Y] = -1; cobra->dev[i].absmax[ABS_Y] = 1; + + input_register_device(cobra->dev + i); + printk(KERN_INFO "input%d: %s on gameport%d.%d\n", + cobra->dev[i].number, cobra_name, gameport->number, i); + } + + + return; +fail2: gameport_close(gameport); +fail1: kfree(cobra); +} + +static void cobra_disconnect(struct gameport *gameport) +{ + int i; + + struct cobra *cobra = gameport->private; + for (i = 0; i < 2; i++) + if ((cobra->exists >> i) & 1) + input_unregister_device(cobra->dev + i); + gameport_close(gameport); + kfree(cobra); +} + +static struct gameport_dev cobra_dev = { + connect: cobra_connect, + disconnect: cobra_disconnect, +}; + +int __init cobra_init(void) +{ + gameport_register_device(&cobra_dev); + return 0; +} + +void __exit cobra_exit(void) +{ + gameport_unregister_device(&cobra_dev); +} + +module_init(cobra_init); +module_exit(cobra_exit); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/db9.c linux/drivers/char/joystick/db9.c --- v2.4.0-test1/linux/drivers/char/joystick/db9.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick/db9.c Wed Jun 21 08:22:21 2000 @@ -0,0 +1,423 @@ +/* + * $Id: db9.c,v 1.5 2000/05/29 20:39:38 vojtech Exp $ + * + * Copyright (c) 1999 Vojtech Pavlik + * + * Based on the work of: + * Andree Borrmann Mats Sjövall + * + * Sponsored by SuSE + */ + +/* + * Atari, Amstrad, Commodore, Amiga, Sega, etc. joystick driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_PARM(db9, "2i"); +MODULE_PARM(db9_2, "2i"); +MODULE_PARM(db9_3, "2i"); + +#define DB9_MULTI_STICK 0x01 +#define DB9_MULTI2_STICK 0x02 +#define DB9_GENESIS_PAD 0x03 +#define DB9_GENESIS5_PAD 0x05 +#define DB9_GENESIS6_PAD 0x06 +#define DB9_SATURN_PAD 0x07 +#define DB9_MULTI_0802 0x08 +#define DB9_MULTI_0802_2 0x09 +#define DB9_CD32_PAD 0x0A +#define DB9_MAX_PAD 0x0B + +#define DB9_UP 0x01 +#define DB9_DOWN 0x02 +#define DB9_LEFT 0x04 +#define DB9_RIGHT 0x08 +#define DB9_FIRE1 0x10 +#define DB9_FIRE2 0x20 +#define DB9_FIRE3 0x40 +#define DB9_FIRE4 0x80 + +#define DB9_NORMAL 0x0a +#define DB9_NOSELECT 0x08 + +#define DB9_SATURN0 0x00 +#define DB9_SATURN1 0x02 +#define DB9_SATURN2 0x04 +#define DB9_SATURN3 0x06 + +#define DB9_GENESIS6_DELAY 14 +#define DB9_REFRESH_TIME HZ/100 + +static int db9[] __initdata = { -1, 0 }; +static int db9_2[] __initdata = { -1, 0 }; +static int db9_3[] __initdata = { -1, 0 }; + +struct db9 { + struct input_dev dev[2]; + struct timer_list timer; + struct pardevice *pd; + int mode; + int used; +}; + +static struct db9 *db9_base[3]; + +static short db9_multi_btn[] = { BTN_TRIGGER, BTN_THUMB }; +static short db9_genesis_btn[] = { BTN_START, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_MODE }; +static short db9_cd32_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START }; + +static char db9_buttons[DB9_MAX_PAD] = { 0, 1, 2, 4, 0, 6, 8, 8, 1, 1, 7 }; +static short *db9_btn[DB9_MAX_PAD] = { db9_multi_btn, db9_multi_btn, db9_genesis_btn, NULL, db9_genesis_btn, + db9_genesis_btn, db9_cd32_btn, db9_multi_btn, db9_multi_btn, db9_cd32_btn }; +static char *db9_name[DB9_MAX_PAD] = { NULL, "Multisystem joystick", "Multisystem joystick (2 fire)", "Genesis pad", + NULL, "Genesis 5 pad", "Genesis 6 pad", "Saturn pad", "Multisystem (0.8.0.2) joystick", + "Multisystem (0.8.0.2-dual) joystick", "Amiga CD-32 pad" }; + +static void db9_timer(unsigned long private) +{ + struct db9 *db9 = (void *) private; + struct parport *port = db9->pd->port; + struct input_dev *dev = db9->dev; + int data, i; + + switch(db9->mode) { + case DB9_MULTI_0802_2: + + data = parport_read_data(port) >> 3; + + input_report_abs(dev + 1, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); + input_report_abs(dev + 1, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); + input_report_key(dev + 1, BTN_TRIGGER, ~data&DB9_FIRE1); + + case DB9_MULTI_0802: + + data = parport_read_status(port) >> 3; + + input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); + input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); + input_report_key(dev, BTN_TRIGGER, data&DB9_FIRE1); + break; + + case DB9_MULTI_STICK: + + data = parport_read_data(port); + + input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); + input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); + input_report_key(dev, BTN_TRIGGER, ~data&DB9_FIRE1); + break; + + case DB9_MULTI2_STICK: + + data = parport_read_data(port); + + input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); + input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); + input_report_key(dev, BTN_TRIGGER, ~data&DB9_FIRE1); + input_report_key(dev, BTN_THUMB, ~data&DB9_FIRE2); + break; + + case DB9_GENESIS_PAD: + + parport_write_control(port, DB9_NOSELECT); + data = parport_read_data(port); + + input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); + input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); + input_report_key(dev, BTN_B, ~data&DB9_FIRE1); + input_report_key(dev, BTN_C, ~data&DB9_FIRE2); + + parport_write_control(port, DB9_NORMAL); + data=parport_read_data(port); + + input_report_key(dev, BTN_A, ~data&DB9_FIRE1); + input_report_key(dev, BTN_START, ~data&DB9_FIRE2); + break; + + case DB9_GENESIS5_PAD: + + parport_write_control(port, DB9_NOSELECT); + data=parport_read_data(port); + + input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); + input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); + input_report_key(dev, BTN_B, ~data&DB9_FIRE1); + input_report_key(dev, BTN_C, ~data&DB9_FIRE2); + + parport_write_control(port, DB9_NORMAL); + data=parport_read_data(port); + + input_report_key(dev, BTN_A, ~data&DB9_FIRE1); + input_report_key(dev, BTN_X, ~data&DB9_FIRE2); + input_report_key(dev, BTN_Y, ~data&DB9_LEFT); + input_report_key(dev, BTN_START, ~data&DB9_RIGHT); + break; + + case DB9_GENESIS6_PAD: + + parport_write_control(port, DB9_NOSELECT); /* 1 */ + udelay(DB9_GENESIS6_DELAY); + data=parport_read_data(port); + + input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); + input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); + input_report_key(dev, BTN_B, ~data&DB9_FIRE1); + input_report_key(dev, BTN_C, ~data&DB9_FIRE2); + + parport_write_control(port, DB9_NORMAL); + udelay(DB9_GENESIS6_DELAY); + data=parport_read_data(port); + + input_report_key(dev, BTN_A, ~data&DB9_FIRE1); + input_report_key(dev, BTN_X, ~data&DB9_FIRE2); + + parport_write_control(port, DB9_NOSELECT); /* 2 */ + udelay(DB9_GENESIS6_DELAY); + parport_write_control(port, DB9_NORMAL); + udelay(DB9_GENESIS6_DELAY); + parport_write_control(port, DB9_NOSELECT); /* 3 */ + udelay(DB9_GENESIS6_DELAY); + data=parport_read_data(port); + + input_report_key(dev, BTN_Y, ~data&DB9_LEFT); + input_report_key(dev, BTN_Z, ~data&DB9_DOWN); + input_report_key(dev, BTN_MODE, ~data&DB9_UP); + input_report_key(dev, BTN_START, ~data&DB9_RIGHT); + + parport_write_control(port, DB9_NORMAL); + udelay(DB9_GENESIS6_DELAY); + parport_write_control(port, DB9_NOSELECT); /* 4 */ + udelay(DB9_GENESIS6_DELAY); + parport_write_control(port, DB9_NORMAL); + break; + + case DB9_SATURN_PAD: + + parport_write_control(port, DB9_SATURN0); + data = parport_read_data(port); + + input_report_key(dev, BTN_Y, ~data&DB9_LEFT); + input_report_key(dev, BTN_Z, ~data&DB9_DOWN); + input_report_key(dev, BTN_TL,~data&DB9_UP); + input_report_key(dev, BTN_TR,~data&DB9_RIGHT); + + parport_write_control(port, DB9_SATURN2); + data = parport_read_data(port); + + input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); + input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); + + parport_write_control(port, DB9_NORMAL); + data = parport_read_data(port); + + input_report_key(dev, BTN_A, ~data&DB9_LEFT); + input_report_key(dev, BTN_B, ~data&DB9_UP); + input_report_key(dev, BTN_C, ~data&DB9_DOWN); + input_report_key(dev, BTN_X, ~data&DB9_RIGHT); + break; + + case DB9_CD32_PAD: + + data=parport_read_data(port); + + input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); + input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); + + parport_write_control(port, 0x0a); + + for (i = 0; i < 7; i++) { + data = parport_read_data(port); + parport_write_control(port, 0x02); + parport_write_control(port, 0x0a); + input_report_key(dev, db9_cd32_btn[i], ~data&DB9_FIRE2); + } + + parport_write_control(port, 0x00); + break; + } + + mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME); +} + +static int db9_open(struct input_dev *dev) +{ + struct db9 *db9 = dev->private; + struct parport *port = db9->pd->port; + + if (!db9->used++) { + parport_claim(db9->pd); + parport_write_data(port, 0xff); + parport_data_reverse(port); + parport_write_control(port, DB9_NORMAL); + mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME); + } + + return 0; +} + +static void db9_close(struct input_dev *dev) +{ + struct db9 *db9 = dev->private; + struct parport *port = db9->pd->port; + + if (!--db9->used) { + del_timer(&db9->timer); + parport_write_control(port, 0x00); + parport_data_forward(port); + parport_release(db9->pd); + } +} + +static struct db9 __init *db9_probe(int *config) +{ + struct db9 *db9; + struct parport *pp; + int i, j; + + if (config[0] < 0) + return NULL; + if (config[1] < 1 || config[1] >= DB9_MAX_PAD || !db9_buttons[config[1]]) { + printk(KERN_ERR "db9.c: bad config\n"); + return NULL; + } + + for (pp = parport_enumerate(); pp && (config[0] > 0); pp = pp->next) + config[0]--; + + if (!pp) { + printk(KERN_ERR "db9.c: no such parport\n"); + return NULL; + } + + if (!(pp->modes & PARPORT_MODE_TRISTATE) && config[1] != DB9_MULTI_0802) { + printk(KERN_ERR "db9.c: specified parport is not bidirectional\n"); + return NULL; + } + + if (!(db9 = kmalloc(sizeof(struct db9), GFP_KERNEL))) + return NULL; + memset(db9, 0, sizeof(struct db9)); + + db9->mode = config[1]; + init_timer(&db9->timer); + db9->timer.data = (long) db9; + db9->timer.function = db9_timer; + + db9->pd = parport_register_device(pp, "db9", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); + + if (!db9->pd) { + printk(KERN_ERR "db9.c: parport busy already - lp.o loaded?\n"); + kfree(db9); + return NULL; + } + + for (i = 0; i < 1 + (db9->mode == DB9_MULTI_0802_2); i++) { + + db9->dev[i].private = db9; + db9->dev[i].open = db9_open; + db9->dev[i].close = db9_close; + + db9->dev[i].name = db9_name[db9->mode]; + db9->dev[i].idbus = BUS_PARPORT; + db9->dev[i].idvendor = 0x0002; + db9->dev[i].idproduct = config[1]; + db9->dev[i].idversion = 0x0100; + + db9->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + db9->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + + for (j = 0; j < db9_buttons[db9->mode]; j++) + set_bit(db9_btn[db9->mode][j], db9->dev[i].keybit); + + db9->dev[i].absmin[ABS_X] = -1; db9->dev[i].absmax[ABS_X] = 1; + db9->dev[i].absmin[ABS_Y] = -1; db9->dev[i].absmax[ABS_Y] = 1; + + input_register_device(db9->dev + i); + printk(KERN_INFO "input%d: %s on %s\n", + db9->dev[i].number, db9_name[db9->mode], db9->pd->port->name); + } + + return db9; +} + +#ifndef MODULE +int __init db9_setup(char *str) +{ + int i, ints[3]; + get_options(str, ARRAY_SIZE(ints), ints); + for (i = 0; i <= ints[0] && i < 2; i++) db9[i] = ints[i + 1]; + return 1; +} +int __init db9_setup_2(char *str) +{ + int i, ints[3]; + get_options(str, ARRAY_SIZE(ints), ints); + for (i = 0; i <= ints[0] && i < 2; i++) db9_2[i] = ints[i + 1]; + return 1; +} +int __init db9_setup_3(char *str) +{ + int i, ints[3]; + get_options(str, ARRAY_SIZE(ints), ints); + for (i = 0; i <= ints[0] && i < 2; i++) db9_3[i] = ints[i + 1]; + return 1; +} +__setup("db9=", db9_setup); +__setup("db9_2=", db9_setup_2); +__setup("db9_3=", db9_setup_3); +#endif + +int __init db9_init(void) +{ + db9_base[0] = db9_probe(db9); + db9_base[1] = db9_probe(db9_2); + db9_base[2] = db9_probe(db9_3); + + if (db9_base[0] || db9_base[1] || db9_base[2]) + return 0; + + return -ENODEV; +} + +void __exit db9_exit(void) +{ + int i, j; + + for (i = 0; i < 3; i++) + if (db9_base[i]) { + for (j = 0; j < 1 + (db9_base[i]->mode == DB9_MULTI_0802_2); j++) + input_unregister_device(db9_base[i]->dev + j); + parport_unregister_device(db9_base[i]->pd); + } +} + +module_init(db9_init); +module_exit(db9_exit); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/gamecon.c linux/drivers/char/joystick/gamecon.c --- v2.4.0-test1/linux/drivers/char/joystick/gamecon.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick/gamecon.c Wed Jun 21 08:22:21 2000 @@ -0,0 +1,668 @@ +/* + * $Id: gamecon.c,v 1.4 2000/05/29 21:08:45 vojtech Exp $ + * + * Copyright (c) 1999-2000 Vojtech Pavlik + * + * Based on the work of: + * Andree Borrmann John Dahlstrom + * David Kuder + * + * Sponsored by SuSE + */ + +/* + * NES, SNES, N64, Multi1, Multi2, PSX gamepad driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_PARM(gc, "2-6i"); +MODULE_PARM(gc_2,"2-6i"); +MODULE_PARM(gc_3,"2-6i"); + +#define GC_SNES 1 +#define GC_NES 2 +#define GC_NES4 3 +#define GC_MULTI 4 +#define GC_MULTI2 5 +#define GC_N64 6 +#define GC_PSX 7 + +#define GC_MAX 7 + +#define GC_REFRESH_TIME HZ/100 + +struct gc { + struct pardevice *pd; + struct input_dev dev[5]; + struct timer_list timer; + unsigned char pads[GC_PSX + 1]; + int used; +}; + +static struct gc *gc_base[3]; + +static int gc[] __initdata = { -1, 0, 0, 0, 0, 0 }; +static int gc_2[] __initdata = { -1, 0, 0, 0, 0, 0 }; +static int gc_3[] __initdata = { -1, 0, 0, 0, 0, 0 }; + +static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 }; + +static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick", + "Multisystem 2-button joystick", "N64 controller", "PSX pad", + "PSX NegCon", "PSX Analog contoller" }; +/* + * N64 support. + */ + +static unsigned char gc_n64_bytes[] = { 0, 1, 13, 15, 14, 12, 10, 11, 2, 3 }; +static short gc_n64_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TRIGGER, BTN_START }; + +#define GC_N64_LENGTH 32 /* N64 bit length, not including stop bit */ +#define GC_N64_REQUEST_LENGTH 37 /* transmit request sequence is 9 bits long */ +#define GC_N64_DELAY 133 /* delay between transmit request, and response ready (us) */ +#define GC_N64_REQUEST 0x1dd1111111ULL /* the request data command (encoded for 000000011) */ +#define GC_N64_DWS 3 /* delay between write segments (required for sound playback because of ISA DMA) */ + /* GC_N64_DWS > 24 is known to fail */ +#define GC_N64_POWER_W 0xe2 /* power during write (transmit request) */ +#define GC_N64_POWER_R 0xfd /* power during read */ +#define GC_N64_OUT 0x1d /* output bits to the 4 pads */ + /* Reading the main axes of any N64 pad is known to fail if the corresponding bit */ + /* in GC_N64_OUT is pulled low on the output port (by any routine) for more */ + /* than 123 us */ +#define GC_N64_CLOCK 0x02 /* clock bits for read */ + +/* + * gc_n64_read_packet() reads an N64 packet. + * Each pad uses one bit per byte. So all pads connected to this port are read in parallel. + */ + +static void gc_n64_read_packet(struct gc *gc, unsigned char *data) +{ + int i; + unsigned long flags; + +/* + * Request the pad to transmit data + */ + + __save_flags(flags); + __cli(); + for (i = 0; i < GC_N64_REQUEST_LENGTH; i++) { + parport_write_data(gc->pd->port, GC_N64_POWER_W | ((GC_N64_REQUEST >> i) & 1 ? GC_N64_OUT : 0)); + udelay(GC_N64_DWS); + } + __restore_flags(flags); + +/* + * Wait for the pad response to be loaded into the 33-bit register of the adapter + */ + + udelay(GC_N64_DELAY); + +/* + * Grab data (ignoring the last bit, which is a stop bit) + */ + + for (i = 0; i < GC_N64_LENGTH; i++) { + parport_write_data(gc->pd->port, GC_N64_POWER_R); + data[i] = parport_read_status(gc->pd->port); + parport_write_data(gc->pd->port, GC_N64_POWER_R | GC_N64_CLOCK); + } + +/* + * We must wait 200 ms here for the controller to reinitialize before the next read request. + * No worries as long as gc_read is polled less frequently than this. + */ + +} + +/* + * NES/SNES support. + */ + +#define GC_NES_DELAY 6 /* Delay between bits - 6us */ +#define GC_NES_LENGTH 8 /* The NES pads use 8 bits of data */ +#define GC_SNES_LENGTH 12 /* The SNES true length is 16, but the last 4 bits are unused */ + +#define GC_NES_POWER 0xfc +#define GC_NES_CLOCK 0x01 +#define GC_NES_LATCH 0x02 + +static unsigned char gc_nes_bytes[] = { 0, 1, 2, 3 }; +static unsigned char gc_snes_bytes[] = { 8, 0, 2, 3, 9, 1, 10, 11 }; +static short gc_snes_btn[] = { BTN_A, BTN_B, BTN_START, BTN_SELECT, BTN_X, BTN_Y, BTN_TL, BTN_TR }; + +/* + * gc_nes_read_packet() reads a NES/SNES packet. + * Each pad uses one bit per byte. So all pads connected to + * this port are read in parallel. + */ + +static void gc_nes_read_packet(struct gc *gc, int length, unsigned char *data) +{ + int i; + + parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK | GC_NES_LATCH); + udelay(GC_NES_DELAY * 2); + parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK); + + for (i = 0; i < length; i++) { + udelay(GC_NES_DELAY); + parport_write_data(gc->pd->port, GC_NES_POWER); + data[i] = parport_read_status(gc->pd->port) ^ 0x7f; + udelay(GC_NES_DELAY); + parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK); + } +} + +/* + * Multisystem joystick support + */ + +#define GC_MULTI_LENGTH 5 /* Multi system joystick packet length is 5 */ +#define GC_MULTI2_LENGTH 6 /* One more bit for one more button */ + +/* + * gc_multi_read_packet() reads a Multisystem joystick packet. + */ + +static void gc_multi_read_packet(struct gc *gc, int length, unsigned char *data) +{ + int i; + + for (i = 0; i < length; i++) { + parport_write_data(gc->pd->port, ~(1 << i)); + data[i] = parport_read_status(gc->pd->port) ^ 0x7f; + } +} + +/* + * PSX support + */ + +#define GC_PSX_DELAY 10 +#define GC_PSX_LENGTH 8 /* talk to the controller in bytes */ + +#define GC_PSX_MOUSE 0x12 /* PSX Mouse */ +#define GC_PSX_NEGCON 0x23 /* NegCon pad */ +#define GC_PSX_NORMAL 0x41 /* Standard Digital controller */ +#define GC_PSX_ANALOGR 0x73 /* Analog controller in Red mode */ +#define GC_PSX_ANALOGG 0x53 /* Analog controller in Green mode */ + +#define GC_PSX_CLOCK 0x04 /* Pin 3 */ +#define GC_PSX_COMMAND 0x01 /* Pin 1 */ +#define GC_PSX_POWER 0xf8 /* Pins 5-9 */ +#define GC_PSX_SELECT 0x02 /* Pin 2 */ +#define GC_PSX_NOPOWER 0x04 + +static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y }; +static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y, + BTN_START, BTN_SELECT, BTN_THUMB, BTN_THUMB2 }; + +/* + * gc_psx_command() writes 8bit command and reads 8bit data from + * the psx pad. + */ + +static int gc_psx_command(struct gc *gc, int b) +{ + int i, cmd, ret = 0; + + cmd = (b & 1) ? GC_PSX_COMMAND : 0; + for (i = 0; i < 8; i++) { + parport_write_data(gc->pd->port, cmd | GC_PSX_POWER); + udelay(GC_PSX_DELAY); + ret |= ((parport_read_status(gc->pd->port) ^ 0x80) & gc->pads[GC_PSX]) ? (1 << i) : 0; + cmd = (b & 1) ? GC_PSX_COMMAND : 0; + parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER); + udelay(GC_PSX_DELAY); + b >>= 1; + } + return ret; +} + +/* + * gc_psx_read_packet() reads a whole psx packet and returns + * device identifier code. + */ + +static int gc_psx_read_packet(struct gc *gc, int length, unsigned char *data) +{ + int i, ret; + unsigned long flags; + + __save_flags(flags); + __cli(); + + parport_write_data(gc->pd->port, GC_PSX_POWER); + + parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); /* Select pad */ + udelay(GC_PSX_DELAY * 2); + gc_psx_command(gc, 0x01); /* Access pad */ + ret = gc_psx_command(gc, 0x42); /* Get device id */ + if (gc_psx_command(gc, 0) == 'Z') /* okay? */ + for (i = 0; i < length; i++) + data[i] = gc_psx_command(gc, 0); + else ret = -1; + + parport_write_data(gc->pd->port, GC_PSX_SELECT | GC_PSX_CLOCK | GC_PSX_POWER); + __restore_flags(flags); + + return ret; +} + +/* + * gc_timer() reads and analyzes console pads data. + */ + +#define GC_MAX_LENGTH GC_N64_LENGTH + +static void gc_timer(unsigned long private) +{ + struct gc *gc = (void *) private; + struct input_dev *dev = gc->dev; + unsigned char data[GC_MAX_LENGTH]; + int i, j, s; + +/* + * N64 pads - must be read first, any read confuses them for 200 us + */ + + if (gc->pads[GC_N64]) { + + gc_n64_read_packet(gc, data); + + for (i = 0; i < 5; i++) { + + s = gc_status_bit[i]; + + if (s & gc->pads[GC_N64] & ~(data[8] | data[9])) { + + signed char axes[2]; + axes[0] = axes[1] = 0; + + for (j = 0; j < 8; j++) { + if (data[23 - j] & s) axes[0] |= 1 << j; + if (data[31 - j] & s) axes[1] |= 1 << j; + } + + input_report_abs(dev + i, ABS_X, axes[0]); + input_report_abs(dev + i, ABS_Y, -axes[1]); + + input_report_abs(dev + i, ABS_HAT0X, !!(s & data[7]) - !!(s & data[6])); + input_report_abs(dev + i, ABS_HAT0Y, !!(s & data[5]) - !!(s & data[4])); + + for (j = 0; j < 10; j++) + input_report_key(dev + i, gc_n64_btn[j], s & data[gc_n64_bytes[j]]); + } + } + } + +/* + * NES and SNES pads + */ + + if (gc->pads[GC_NES] || gc->pads[GC_SNES]) { + + gc_nes_read_packet(gc, gc->pads[GC_SNES] ? GC_SNES_LENGTH : GC_NES_LENGTH, data); + + for (i = 0; i < 5; i++) { + + s = gc_status_bit[i]; + + if (s & (gc->pads[GC_NES] | gc->pads[GC_SNES])) { + input_report_abs(dev + i, ABS_X, !!(s & data[7]) - !!(s & data[6])); + input_report_abs(dev + i, ABS_Y, !!(s & data[5]) - !!(s & data[4])); + } + + if (s & gc->pads[GC_NES]) + for (j = 0; j < 4; j++) + input_report_key(dev + i, gc_snes_btn[j], s & data[gc_nes_bytes[j]]); + + if (s & gc->pads[GC_SNES]) + for (j = 0; j < 8; j++) + input_report_key(dev + i, gc_snes_btn[j], s & data[gc_snes_bytes[j]]); + } + } + +/* + * Multi and Multi2 joysticks + */ + + if (gc->pads[GC_MULTI] || gc->pads[GC_MULTI2]) { + + gc_multi_read_packet(gc, gc->pads[GC_MULTI2] ? GC_MULTI2_LENGTH : GC_MULTI_LENGTH, data); + + for (i = 0; i < 5; i++) { + + s = gc_status_bit[i]; + + if (s & (gc->pads[GC_MULTI] | gc->pads[GC_MULTI2])) { + input_report_abs(dev + i, ABS_X, !!(s & data[3]) - !!(s & data[2])); + input_report_abs(dev + i, ABS_Y, !!(s & data[1]) - !!(s & data[0])); + input_report_key(dev + i, BTN_TRIGGER, s & data[4]); + } + + if (s & gc->pads[GC_MULTI2]) + input_report_key(dev + i, BTN_THUMB, s & data[5]); + } + } + +/* + * PSX controllers + */ + + if (gc->pads[GC_PSX]) { + + for (i = 0; i < 5; i++) + if (gc->pads[GC_PSX] & gc_status_bit[i]) + break; + + switch (gc_psx_read_packet(gc, 6, data)) { + + case GC_PSX_ANALOGG: + + for (j = 0; j < 4; j++) + input_report_abs(dev + i, gc_psx_abs[j], data[j + 2]); + + input_report_abs(dev + i, ABS_HAT0X, !!(data[0]&0x20) - !!(data[0]&0x80)); + input_report_abs(dev + i, ABS_HAT0Y, !!(data[0]&0x40) - !!(data[0]&0x10)); + + for (j = 0; j < 8; j++) + input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << i)); + + input_report_key(dev + i, BTN_START, ~data[0] & 0x08); + input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01); + + break; + + case GC_PSX_ANALOGR: + + input_report_key(dev + i, BTN_THUMB, ~data[0] & 0x04); + input_report_key(dev + i, BTN_THUMB2, ~data[0] & 0x02); + + case GC_PSX_NORMAL: + case GC_PSX_NEGCON: + + input_report_abs(dev + i, ABS_X, 128 + !!(data[0] & 0x20) * 127 - !!(data[0] & 0x80) * 128); + input_report_abs(dev + i, ABS_Y, 128 + !!(data[0] & 0x40) * 127 - !!(data[0] & 0x10) * 128); + + for (j = 0; j < 8; j++) + input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << i)); + + input_report_key(dev + i, BTN_START, ~data[0] & 0x08); + input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01); + + break; + } + } + + mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME); +} + +static int gc_open(struct input_dev *dev) +{ + struct gc *gc = dev->private; + if (!gc->used++) { + parport_claim(gc->pd); + parport_write_control(gc->pd->port, 0x04); + mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME); + } + return 0; +} + +static void gc_close(struct input_dev *dev) +{ + struct gc *gc = dev->private; + if (!--gc->used) { + del_timer(&gc->timer); + parport_write_control(gc->pd->port, 0x00); + parport_release(gc->pd); + } +} + + + +static struct gc __init *gc_probe(int *config) +{ + struct gc *gc; + struct parport *pp; + int i, j, psx, pbtn; + unsigned char data[2]; + + if (config[0] < 0) + return NULL; + + for (pp = parport_enumerate(); pp && (config[0] > 0); pp = pp->next) + config[0]--; + + if (!pp) { + printk(KERN_ERR "gamecon.c: no such parport\n"); + return NULL; + } + + if (!(gc = kmalloc(sizeof(struct gc), GFP_KERNEL))) + return NULL; + memset(gc, 0, sizeof(struct gc)); + + gc->pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); + + if (!gc->pd) { + printk(KERN_ERR "gamecon.c: parport busy already - lp.o loaded?\n"); + kfree(gc); + return NULL; + } + + parport_claim(gc->pd); + + init_timer(&gc->timer); + gc->timer.data = (long) gc; + gc->timer.function = gc_timer; + + for (i = 0; i < 5; i++) { + + if (!config[i + 1]) + continue; + + if (config[i + 1] < 1 || config[i + 1] > GC_MAX) { + printk(KERN_WARNING "gamecon.c: Pad type %d unknown\n", config[i + 1]); + continue; + } + + gc->dev[i].private = gc; + gc->dev[i].open = gc_open; + gc->dev[i].close = gc_close; + + gc->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + + for (j = 0; j < 2; j++) { + set_bit(ABS_X + j, gc->dev[i].absbit); + gc->dev[i].absmin[ABS_X + j] = -1; + gc->dev[i].absmax[ABS_X + j] = 1; + } + + gc->pads[0] |= gc_status_bit[i]; + gc->pads[config[i + 1]] |= gc_status_bit[i]; + + switch(config[i + 1]) { + + case GC_N64: + for (j = 0; j < 10; j++) + set_bit(gc_n64_btn[j], gc->dev[j].keybit); + + for (j = 0; j < 2; j++) { + set_bit(ABS_X + j, gc->dev[i].absbit); + gc->dev[i].absmin[ABS_X + j] = -127; + gc->dev[i].absmax[ABS_X + j] = 126; + gc->dev[i].absflat[ABS_X + j] = 2; + set_bit(ABS_HAT0X + j, gc->dev[i].absbit); + gc->dev[i].absmin[ABS_HAT0X + j] = -1; + gc->dev[i].absmax[ABS_HAT0X + j] = 1; + } + + break; + + case GC_SNES: + for (j = 0; j < 8; j++) + set_bit(gc_snes_btn[j], gc->dev[j].keybit); + break; + + case GC_NES: + for (j = 0; j < 4; j++) + set_bit(gc_snes_btn[j], gc->dev[j].keybit); + break; + + case GC_MULTI2: + set_bit(BTN_THUMB, gc->dev[i].keybit); + + case GC_MULTI: + set_bit(BTN_TRIGGER, gc->dev[i].keybit); + break; + + case GC_PSX: + + psx = gc_psx_read_packet(gc, 2, data); + + switch(psx) { + case GC_PSX_NEGCON: + config[i + 1] += 1; + case GC_PSX_NORMAL: + pbtn = 10; + break; + + case GC_PSX_ANALOGG: + case GC_PSX_ANALOGR: + config[i + 1] += 2; + pbtn = 12; + for (j = 0; j < 6; j++) { + psx = gc_psx_abs[j]; + set_bit(psx, gc->dev[i].absbit); + gc->dev[i].absmin[psx] = 4; + gc->dev[i].absmax[psx] = 252; + gc->dev[i].absflat[psx] = 2; + } + break; + + case -1: + gc->pads[GC_PSX] &= ~gc_status_bit[i]; + pbtn = 0; + printk(KERN_ERR "gamecon.c: No PSX controller found.\n"); + break; + + default: + gc->pads[GC_PSX] &= ~gc_status_bit[i]; + pbtn = 0; + printk(KERN_WARNING "gamecon.c: Unsupported PSX controller %#x," + " please report to .\n", psx); + } + + for (j = 0; j < pbtn; j++) + set_bit(gc_psx_btn[j], gc->dev[i].keybit); + + break; + } + + gc->dev[i].name = gc_names[config[i + 1]]; + gc->dev[i].idbus = BUS_PARPORT; + gc->dev[i].idvendor = 0x0001; + gc->dev[i].idproduct = config[i + 1]; + gc->dev[i].idversion = 0x0100; + } + + parport_release(gc->pd); + + if (!gc->pads[0]) { + parport_unregister_device(gc->pd); + kfree(gc); + return NULL; + } + + for (i = 0; i < 5; i++) + if (gc->pads[0] & gc_status_bit[i]) { + input_register_device(gc->dev + i); + printk(KERN_INFO "input%d: %s on %s\n", gc->dev[i].number, gc->dev[i].name, gc->pd->port->name); + } + + return gc; +} + +#ifndef MODULE +int __init gc_setup(char *str) +{ + int i, ints[7]; + get_options(str, ARRAY_SIZE(ints), ints); + for (i = 0; i <= ints[0] && i < 6; i++) gc[i] = ints[i + 1]; + return 1; +} +int __init gc_setup_2(char *str) +{ + int i, ints[7]; + get_options(str, ARRAY_SIZE(ints), ints); + for (i = 0; i <= ints[0] && i < 6; i++) gc_2[i] = ints[i + 1]; + return 1; +} +int __init gc_setup_3(char *str) +{ + int i, ints[7]; + get_options(str, ARRAY_SIZE(ints), ints); + for (i = 0; i <= ints[0] && i < 6; i++) gc_3[i] = ints[i + 1]; + return 1; +} +__setup("gc=", gc_setup); +__setup("gc_2=", gc_setup_2); +__setup("gc_3=", gc_setup_3); +#endif + +int __init gc_init(void) +{ + gc_base[0] = gc_probe(gc); + gc_base[1] = gc_probe(gc_2); + gc_base[2] = gc_probe(gc_3); + + if (gc_base[0] || gc_base[1] || gc_base[2]) + return 0; + + return -ENODEV; +} + +void __exit gc_exit(void) +{ + int i, j; + + for (i = 0; i < 3; i++) { + for (j = 0; j < 5; j++) + if (gc_base[i]->pads[0] & gc_status_bit[j]) + input_unregister_device(gc_base[i]->dev + j); + parport_unregister_device(gc_base[i]->pd); + } +} + +module_init(gc_init); +module_exit(gc_exit); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/gameport.c linux/drivers/char/joystick/gameport.c --- v2.4.0-test1/linux/drivers/char/joystick/gameport.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick/gameport.c Thu Jun 22 06:59:53 2000 @@ -0,0 +1,198 @@ +/* + * $Id: gameport.c,v 1.5 2000/05/29 10:54:53 vojtech Exp $ + * + * Copyright (c) 1999-2000 Vojtech Pavlik + * + * Sponsored by SuSE + */ + +/* + * Generic gameport layer + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); + +EXPORT_SYMBOL(gameport_register_port); +EXPORT_SYMBOL(gameport_unregister_port); +EXPORT_SYMBOL(gameport_register_device); +EXPORT_SYMBOL(gameport_unregister_device); +EXPORT_SYMBOL(gameport_open); +EXPORT_SYMBOL(gameport_close); +EXPORT_SYMBOL(gameport_rescan); +EXPORT_SYMBOL(gameport_cooked_read); + +static struct gameport *gameport_list = NULL; +static struct gameport_dev *gameport_dev = NULL; +static int gameport_number = 0; + +/* + * gameport_measure_speed() measures the gameport i/o speed. + */ + +static int gameport_measure_speed(struct gameport *gameport) +{ +#ifdef __i386__ + +#define GET_TIME(x) do { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0) +#define DELTA(x,y) ((y)-(x)+((y)<(x)?1193180L/HZ:0)) + + unsigned int i, t, t1, t2, t3, tx; + unsigned long flags; + + if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW)) + return 0; + + tx = 1 << 30; + + for(i = 0; i < 50; i++) { + save_flags(flags); /* Yes, all CPUs */ + cli(); + GET_TIME(t1); + for(t = 0; t < 50; t++) gameport_read(gameport); + GET_TIME(t2); + GET_TIME(t3); + restore_flags(flags); + udelay(i * 10); + if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t; + } + + return 59659 / (tx < 1 ? 1 : tx); + +#else + + unsigned int j, t = 0; + + j = jiffies; while (j == jiffies); + j = jiffies; while (j == jiffies) { t++; gameport_read(gameport); } + + return t * HZ / 1000; + +#endif + + gameport_close(gameport); +} + +static void gameport_find_dev(struct gameport *gameport) +{ + struct gameport_dev *dev = gameport_dev; + + while (dev && !gameport->dev) { + if (dev->connect) + dev->connect(gameport, dev); + dev = dev->next; + } +} + +void gameport_rescan(struct gameport *gameport) +{ + gameport_close(gameport); + gameport_find_dev(gameport); +} + +void gameport_register_port(struct gameport *gameport) +{ + gameport->number = gameport_number++; + gameport->next = gameport_list; + gameport_list = gameport; + + gameport->speed = gameport_measure_speed(gameport); + + gameport_find_dev(gameport); +} + +void gameport_unregister_port(struct gameport *gameport) +{ + struct gameport **gameportptr = &gameport_list; + + while (*gameportptr && (*gameportptr != gameport)) gameportptr = &((*gameportptr)->next); + *gameportptr = (*gameportptr)->next; + + if (gameport->dev && gameport->dev->disconnect) + gameport->dev->disconnect(gameport); + + gameport_number--; +} + +void gameport_register_device(struct gameport_dev *dev) +{ + struct gameport *gameport = gameport_list; + + dev->next = gameport_dev; + gameport_dev = dev; + + while (gameport) { + if (!gameport->dev && dev->connect) + dev->connect(gameport, dev); + gameport = gameport->next; + } +} + +void gameport_unregister_device(struct gameport_dev *dev) +{ + struct gameport_dev **devptr = &gameport_dev; + struct gameport *gameport = gameport_list; + + while (*devptr && (*devptr != dev)) devptr = &((*devptr)->next); + *devptr = (*devptr)->next; + + while (gameport) { + if (gameport->dev == dev && dev->disconnect) + dev->disconnect(gameport); + gameport_find_dev(gameport); + gameport = gameport->next; + } +} + +int gameport_open(struct gameport *gameport, struct gameport_dev *dev, int mode) +{ + if (gameport->open) { + if (gameport->open(gameport, mode)) + return -1; + } else { + if (mode != GAMEPORT_MODE_RAW) + return -1; + } + + if (gameport->dev) + return -1; + + gameport->dev = dev; + + return 0; +} + +void gameport_close(struct gameport *gameport) +{ + gameport->dev = NULL; + if (gameport->close) gameport->close(gameport); +} diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/gf2k.c linux/drivers/char/joystick/gf2k.c --- v2.4.0-test1/linux/drivers/char/joystick/gf2k.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick/gf2k.c Wed Jun 21 08:22:21 2000 @@ -0,0 +1,359 @@ +/* + * $Id: gf2k.c,v 1.12 2000/06/04 14:53:44 vojtech Exp $ + * + * Copyright (c) 1998-2000 Vojtech Pavlik + * + * Sponsored by SuSE + */ + +/* + * Genius Flight 2000 joystick driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include + +#define GF2K_START 400 /* The time we wait for the first bit [400 us] */ +#define GF2K_STROBE 40 /* The time we wait for the first bit [40 us] */ +#define GF2K_TIMEOUT 4 /* Wait for everything to settle [4 ms] */ +#define GF2K_LENGTH 80 /* Max number of triplets in a packet */ +#define GF2K_REFRESH HZ/50 /* Time between joystick polls [20 ms] */ + +/* + * Genius joystick ids ... + */ + +#define GF2K_ID_G09 1 +#define GF2K_ID_F30D 2 +#define GF2K_ID_F30 3 +#define GF2K_ID_F31D 4 +#define GF2K_ID_F305 5 +#define GF2K_ID_F23P 6 +#define GF2K_ID_F31 7 +#define GF2K_ID_MAX 7 + +static char gf2k_length[] = { 40, 40, 40, 40, 40, 40, 40, 40 }; +static char gf2k_hat_to_axis[][2] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; + +static char *gf2k_names[] = {"", "Genius G-09D", "Genius F-30D", "Genius F-30", "Genius MaxFighter F-31D", + "Genius F-30-5", "Genius Flight2000 F-23", "Genius F-31"}; +static unsigned char gf2k_hats[] = { 0, 2, 0, 0, 2, 0, 2, 0 }; +static unsigned char gf2k_axes[] = { 0, 2, 0, 0, 4, 0, 4, 0 }; +static unsigned char gf2k_joys[] = { 0, 0, 0, 0,10, 0, 8, 0 }; +static unsigned char gf2k_pads[] = { 0, 6, 0, 0, 0, 0, 0, 0 }; +static unsigned char gf2k_lens[] = { 0,18, 0, 0,18, 0,18, 0 }; + +static unsigned char gf2k_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, ABS_GAS, ABS_BRAKE }; +static short gf2k_btn_joy[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4 }; +static short gf2k_btn_pad[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_START, BTN_SELECT }; + + +static short gf2k_seq_reset[] = { 240, 340, 0 }; +static short gf2k_seq_digital[] = { 590, 320, 860, 0 }; + +struct gf2k { + struct gameport *gameport; + struct timer_list timer; + struct input_dev dev; + int reads; + int bads; + int used; + unsigned char id; + unsigned char length; +}; + +/* + * gf2k_read_packet() reads a Genius Flight2000 packet. + */ + +static int gf2k_read_packet(struct gameport *gameport, int length, char *data) +{ + unsigned char u, v; + int i; + unsigned int t, p; + unsigned long flags; + + t = gameport_time(gameport, GF2K_START); + p = gameport_time(gameport, GF2K_STROBE); + + i = 0; + + __save_flags(flags); + __cli(); + + gameport_trigger(gameport); + v = gameport_read(gameport);; + + while (t > 0 && i < length) { + t--; u = v; + v = gameport_read(gameport); + if (v & ~u & 0x10) { + data[i++] = v >> 5; + t = p; + } + } + + __restore_flags(flags); + + return i; +} + +/* + * gf2k_trigger_seq() initializes a Genius Flight2000 joystick + * into digital mode. + */ + +static void gf2k_trigger_seq(struct gameport *gameport, short *seq) +{ + + unsigned long flags; + int i, t; + + __save_flags(flags); + __cli(); + + i = 0; + do { + gameport_trigger(gameport); + t = gameport_time(gameport, GF2K_TIMEOUT * 1000); + while ((gameport_read(gameport) & 1) && t) t--; + udelay(seq[i]); + } while (seq[++i]); + + gameport_trigger(gameport); + + __restore_flags(flags); +} + +/* + * js_sw_get_bits() composes bits from the triplet buffer into a __u64. + * Parameter 'pos' is bit number inside packet where to start at, 'num' is number + * of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits + * is number of bits per triplet. + */ + +#define GB(p,n,s) gf2k_get_bits(data, p, n, s) + +static int gf2k_get_bits(unsigned char *buf, int pos, int num, int shift) +{ + __u64 data = 0; + int i; + + for (i = 0; i < num / 3 + 2; i++) + data |= buf[pos / 3 + i] << (i * 3); + data >>= pos % 3; + data &= (1 << num) - 1; + data <<= shift; + + return data; +} + +static void gf2k_read(struct gf2k *gf2k, unsigned char *data) +{ + struct input_dev *dev = &gf2k->dev; + int i, t; + + for (i = 0; i < 4 && i < gf2k_axes[gf2k->id]; i++) + input_report_abs(dev, gf2k_abs[i], GB(i<<3,8,0) | GB(i+46,1,8) | GB(i+50,1,9)); + + for (i = 0; i < 2 && i < gf2k_axes[gf2k->id] - 4; i++) + input_report_abs(dev, gf2k_abs[i], GB(i*9+60,8,0) | GB(i+54,1,9)); + + t = GB(40,4,0); + + for (i = 0; i < gf2k_hats[gf2k->id]; i++) + input_report_abs(dev, ABS_HAT0X + i, gf2k_hat_to_axis[t][i]); + + t = GB(44,2,0) | GB(32,8,2) | GB(78,2,10); + + for (i = 0; i < gf2k_joys[gf2k->id]; i++) + input_report_key(dev, gf2k_btn_joy[i], (t >> i) & 1); + + for (i = 0; i < gf2k_pads[gf2k->id]; i++) + input_report_key(dev, gf2k_btn_pad[i], (t >> i) & 1); +} + +/* + * gf2k_timer() reads and analyzes Genius joystick data. + */ + +static void gf2k_timer(unsigned long private) +{ + struct gf2k *gf2k = (void *) private; + unsigned char data[GF2K_LENGTH]; + + gf2k->reads++; + + if (gf2k_read_packet(gf2k->gameport, gf2k_length[gf2k->id], data) < gf2k_length[gf2k->id]) { + gf2k->bads++; + } else gf2k_read(gf2k, data); + + mod_timer(&gf2k->timer, jiffies + GF2K_REFRESH); +} + +static int gf2k_open(struct input_dev *dev) +{ + struct gf2k *gf2k = dev->private; + if (!gf2k->used++) + mod_timer(&gf2k->timer, jiffies + GF2K_REFRESH); + return 0; +} + +static void gf2k_close(struct input_dev *dev) +{ + struct gf2k *gf2k = dev->private; + if (!--gf2k->used) + del_timer(&gf2k->timer); +} + +/* + * gf2k_connect() probes for Genius id joysticks. + */ + +static void gf2k_connect(struct gameport *gameport, struct gameport_dev *dev) +{ + struct gf2k *gf2k; + unsigned char data[GF2K_LENGTH]; + int i; + + if (!(gf2k = kmalloc(sizeof(struct gf2k), GFP_KERNEL))) + return; + memset(gf2k, 0, sizeof(struct gf2k)); + + gameport->private = gf2k; + + gf2k->gameport = gameport; + init_timer(&gf2k->timer); + gf2k->timer.data = (long) gf2k; + gf2k->timer.function = gf2k_timer; + + if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) + goto fail1; + + gf2k_trigger_seq(gameport, gf2k_seq_reset); + + wait_ms(GF2K_TIMEOUT); + + gf2k_trigger_seq(gameport, gf2k_seq_digital); + + wait_ms(GF2K_TIMEOUT); + + if (gf2k_read_packet(gameport, GF2K_LENGTH, data) < 12) + goto fail2; + + if (!(gf2k->id = GB(7,2,0) | GB(3,3,2) | GB(0,3,5))) + goto fail2; + +#ifdef RESET_WORKS + if ((gf2k->id != (GB(19,2,0) | GB(15,3,2) | GB(12,3,5))) || + (gf2k->id != (GB(31,2,0) | GB(27,3,2) | GB(24,3,5)))) + goto fail2; +#else + gf2k->id = 6; +#endif + + if (gf2k->id > GF2K_ID_MAX || !gf2k_axes[gf2k->id]) { + printk(KERN_WARNING "gf2k.c: Not yet supported joystick on gameport%d. [id: %d type:%s]\n", + gameport->number, gf2k->id, gf2k->id > GF2K_ID_MAX ? "Unknown" : gf2k_names[gf2k->id]); + goto fail2; + } + + gf2k->length = gf2k_lens[gf2k->id]; + + gf2k->dev.private = gf2k; + gf2k->dev.open = gf2k_open; + gf2k->dev.close = gf2k_close; + gf2k->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + + gf2k->dev.name = gf2k_names[gf2k->id]; + gf2k->dev.idbus = BUS_GAMEPORT; + gf2k->dev.idvendor = GAMEPORT_ID_VENDOR_GENIUS; + gf2k->dev.idproduct = gf2k->id; + gf2k->dev.idversion = 0x0100; + + for (i = 0; i < gf2k_axes[gf2k->id]; i++) + set_bit(gf2k_abs[i], gf2k->dev.absbit); + + for (i = 0; i < gf2k_hats[gf2k->id]; i++) { + set_bit(ABS_HAT0X + i, gf2k->dev.absbit); + gf2k->dev.absmin[ABS_HAT0X + i] = -1; + gf2k->dev.absmax[ABS_HAT0X + i] = 1; + } + + for (i = 0; i < gf2k_joys[gf2k->id]; i++) + set_bit(gf2k_btn_joy[i], gf2k->dev.keybit); + + for (i = 0; i < gf2k_pads[gf2k->id]; i++) + set_bit(gf2k_btn_pad[i], gf2k->dev.keybit); + + gf2k_read_packet(gameport, gf2k->length, data); + gf2k_read(gf2k, data); + + for (i = 0; i < gf2k_axes[gf2k->id]; i++) { + gf2k->dev.absmax[gf2k_abs[i]] = (i < 2) ? gf2k->dev.abs[gf2k_abs[i]] * 2 - 32 : + gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32; + gf2k->dev.absmin[gf2k_abs[i]] = 32; + gf2k->dev.absfuzz[gf2k_abs[i]] = 8; + gf2k->dev.absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0; + } + + input_register_device(&gf2k->dev); + printk(KERN_INFO "input%d: %s on gameport%d.0\n", + gf2k->dev.number, gf2k_names[gf2k->id], gameport->number); + + return; +fail2: gameport_close(gameport); +fail1: kfree(gf2k); +} + +static void gf2k_disconnect(struct gameport *gameport) +{ + struct gf2k *gf2k = gameport->private; + input_unregister_device(&gf2k->dev); + gameport_close(gameport); + kfree(gf2k); +} + +static struct gameport_dev gf2k_dev = { + connect: gf2k_connect, + disconnect: gf2k_disconnect, +}; + +int __init gf2k_init(void) +{ + gameport_register_device(&gf2k_dev); + return 0; +} + +void __exit gf2k_exit(void) +{ + gameport_unregister_device(&gf2k_dev); +} + +module_init(gf2k_init); +module_exit(gf2k_exit); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/grip.c linux/drivers/char/joystick/grip.c --- v2.4.0-test1/linux/drivers/char/joystick/grip.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick/grip.c Wed Jun 21 08:22:21 2000 @@ -0,0 +1,423 @@ +/* + * $Id: grip.c,v 1.14 2000/06/06 21:13:36 vojtech Exp $ + * + * Copyright (c) 1998-2000 Vojtech Pavlik + * + * Sponsored by SuSE + */ + +/* + * Gravis/Kensington GrIP protocol joystick and gamepad driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include + +#define GRIP_MODE_GPP 1 +#define GRIP_MODE_BD 2 +#define GRIP_MODE_XT 3 +#define GRIP_MODE_DC 4 + +#define GRIP_LENGTH_GPP 24 +#define GRIP_STROBE_GPP 200 /* 200 us */ +#define GRIP_LENGTH_XT 4 +#define GRIP_STROBE_XT 64 /* 64 us */ +#define GRIP_MAX_CHUNKS_XT 10 +#define GRIP_MAX_BITS_XT 30 + +#define GRIP_REFRESH_TIME HZ/50 /* 20 ms */ + +struct grip { + struct gameport *gameport; + struct timer_list timer; + struct input_dev dev[2]; + unsigned char mode[2]; + int used; + int reads; + int bads; +}; + +static int grip_btn_gpp[] = { BTN_START, BTN_SELECT, BTN_TR2, BTN_Y, 0, BTN_TL2, BTN_A, BTN_B, BTN_X, 0, BTN_TL, BTN_TR, -1 }; +static int grip_btn_bd[] = { BTN_THUMB, BTN_THUMB2, BTN_TRIGGER, BTN_TOP, BTN_BASE, -1 }; +static int grip_btn_xt[] = { BTN_TRIGGER, BTN_THUMB, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_SELECT, BTN_START, BTN_MODE, -1 }; +static int grip_btn_dc[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, -1 }; + +static int grip_abs_gpp[] = { ABS_X, ABS_Y, -1 }; +static int grip_abs_bd[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 }; +static int grip_abs_xt[] = { ABS_X, ABS_Y, ABS_BRAKE, ABS_GAS, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, -1 }; +static int grip_abs_dc[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 }; + +static char *grip_name[] = { NULL, "Gravis GamePad Pro", "Gravis Blackhawk Digital", + "Gravis Xterminator Digital", "Gravis Xterminator DualControl" }; +static int *grip_abs[] = { 0, grip_abs_gpp, grip_abs_bd, grip_abs_xt, grip_abs_dc }; +static int *grip_btn[] = { 0, grip_btn_gpp, grip_btn_bd, grip_btn_xt, grip_btn_dc }; +static char grip_anx[] = { 0, 0, 3, 5, 5 }; +static char grip_cen[] = { 0, 0, 2, 2, 4 }; + +/* + * grip_gpp_read_packet() reads a Gravis GamePad Pro packet. + */ + +static int grip_gpp_read_packet(struct gameport *gameport, int shift, unsigned int *data) +{ + unsigned long flags; + unsigned char u, v; + unsigned int t; + int i; + + int strobe = gameport_time(gameport, GRIP_STROBE_GPP); + + data[0] = 0; + t = strobe; + i = 0; + + __save_flags(flags); + __cli(); + + v = gameport_read(gameport) >> shift; + + do { + t--; + u = v; v = (gameport_read(gameport) >> shift) & 3; + if (~v & u & 1) { + data[0] |= (v >> 1) << i++; + t = strobe; + } + } while (i < GRIP_LENGTH_GPP && t > 0); + + __restore_flags(flags); + + if (i < GRIP_LENGTH_GPP) return -1; + + for (i = 0; i < GRIP_LENGTH_GPP && (data[0] & 0xfe4210) ^ 0x7c0000; i++) + data[0] = data[0] >> 1 | (data[0] & 1) << (GRIP_LENGTH_GPP - 1); + + return -(i == GRIP_LENGTH_GPP); +} + +/* + * grip_xt_read_packet() reads a Gravis Xterminator packet. + */ + +static int grip_xt_read_packet(struct gameport *gameport, int shift, unsigned int *data) +{ + unsigned int i, j, buf, crc; + unsigned char u, v, w; + unsigned long flags; + unsigned int t; + char status; + + int strobe = gameport_time(gameport, GRIP_STROBE_XT); + + data[0] = data[1] = data[2] = data[3] = 0; + status = buf = i = j = 0; + t = strobe; + + __save_flags(flags); + __cli(); + + v = w = (gameport_read(gameport) >> shift) & 3; + + do { + t--; + u = (gameport_read(gameport) >> shift) & 3; + + if (u ^ v) { + + if ((u ^ v) & 1) { + buf = (buf << 1) | (u >> 1); + t = strobe; + i++; + } else + + if ((((u ^ v) & (v ^ w)) >> 1) & ~(u | v | w) & 1) { + if (i == 20) { + crc = buf ^ (buf >> 7) ^ (buf >> 14); + if (!((crc ^ (0x25cb9e70 >> ((crc >> 2) & 0x1c))) & 0xf)) { + data[buf >> 18] = buf >> 4; + status |= 1 << (buf >> 18); + } + j++; + } + t = strobe; + buf = 0; + i = 0; + } + w = v; + v = u; + } + + } while (status != 0xf && i < GRIP_MAX_BITS_XT && j < GRIP_MAX_CHUNKS_XT && t > 0); + + __restore_flags(flags); + + return -(status != 0xf); +} + +/* + * grip_timer() repeatedly polls the joysticks and generates events. + */ + +static void grip_timer(unsigned long private) +{ + struct grip *grip = (void*) private; + unsigned int data[GRIP_LENGTH_XT]; + struct input_dev *dev; + int i, j; + + for (i = 0; i < 2; i++) { + + dev = grip->dev + i; + grip->reads++; + + switch (grip->mode[i]) { + + case GRIP_MODE_GPP: + + if (grip_gpp_read_packet(grip->gameport, (i << 1) + 4, data)) { + grip->bads++; + break; + } + + input_report_abs(dev, ABS_X, ((*data >> 15) & 1) - ((*data >> 16) & 1)); + input_report_abs(dev, ABS_Y, ((*data >> 13) & 1) - ((*data >> 12) & 1)); + + for (j = 0; j < 12; j++) + if (grip_btn_gpp[j]) + input_report_key(dev, grip_btn_gpp[j], (*data >> j) & 1); + + break; + + case GRIP_MODE_BD: + + if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) { + grip->bads++; + break; + } + + input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f); + input_report_abs(dev, ABS_Y, 63 - ((data[0] >> 8) & 0x3f)); + input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f); + + input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1)); + input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1)); + + for (j = 0; j < 5; j++) + input_report_key(dev, grip_btn_bd[j], (data[3] >> (j + 4)) & 1); + + break; + + case GRIP_MODE_XT: + + if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) { + grip->bads++; + break; + } + + input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f); + input_report_abs(dev, ABS_Y, 63 - ((data[0] >> 8) & 0x3f)); + input_report_abs(dev, ABS_BRAKE, (data[1] >> 2) & 0x3f); + input_report_abs(dev, ABS_GAS, (data[1] >> 8) & 0x3f); + input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f); + + input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1)); + input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1)); + input_report_abs(dev, ABS_HAT1X, ((data[2] >> 5) & 1) - ((data[2] >> 4) & 1)); + input_report_abs(dev, ABS_HAT1Y, ((data[2] >> 6) & 1) - ((data[2] >> 7) & 1)); + + for (j = 0; j < 11; j++) + input_report_key(dev, grip_btn_xt[j], (data[3] >> (j + 3)) & 1); + break; + + case GRIP_MODE_DC: + + if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) { + grip->bads++; + break; + } + + input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f); + input_report_abs(dev, ABS_Y, (data[0] >> 8) & 0x3f); + input_report_abs(dev, ABS_RX, (data[1] >> 2) & 0x3f); + input_report_abs(dev, ABS_RY, (data[1] >> 8) & 0x3f); + input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f); + + input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1)); + input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1)); + + for (j = 0; j < 9; j++) + input_report_key(dev, grip_btn_dc[j], (data[3] >> (j + 3)) & 1); + break; + + + } + } + + mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME); +} + +static int grip_open(struct input_dev *dev) +{ + struct grip *grip = dev->private; + if (!grip->used++) + mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME); + return 0; +} + +static void grip_close(struct input_dev *dev) +{ + struct grip *grip = dev->private; + if (!--grip->used) + del_timer(&grip->timer); +} + +static void grip_connect(struct gameport *gameport, struct gameport_dev *dev) +{ + struct grip *grip; + unsigned int data[GRIP_LENGTH_XT]; + int i, j, t; + + if (!(grip = kmalloc(sizeof(struct grip), GFP_KERNEL))) + return; + memset(grip, 0, sizeof(struct grip)); + + gameport->private = grip; + + grip->gameport = gameport; + init_timer(&grip->timer); + grip->timer.data = (long) grip; + grip->timer.function = grip_timer; + + if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) + goto fail1; + + for (i = 0; i < 2; i++) { + if (!grip_gpp_read_packet(gameport, (i << 1) + 4, data)) { + grip->mode[i] = GRIP_MODE_GPP; + continue; + } + if (!grip_xt_read_packet(gameport, (i << 1) + 4, data)) { + if (!(data[3] & 7)) { + grip->mode[i] = GRIP_MODE_BD; + continue; + } + if (!(data[2] & 0xf0)) { + grip->mode[i] = GRIP_MODE_XT; + continue; + } + grip->mode[i] = GRIP_MODE_DC; + continue; + } + } + + if (!grip->mode[0] && !grip->mode[1]) + goto fail2; + + for (i = 0; i < 2; i++) + if (grip->mode[i]) { + + grip->dev[i].private = grip; + + grip->dev[i].open = grip_open; + grip->dev[i].close = grip_close; + + grip->dev[i].name = grip_name[grip->mode[i]]; + grip->dev[i].idbus = BUS_GAMEPORT; + grip->dev[i].idvendor = GAMEPORT_ID_VENDOR_GRAVIS; + grip->dev[i].idproduct = grip->mode[i]; + grip->dev[i].idversion = 0x0100; + + grip->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + + for (j = 0; (t = grip_abs[grip->mode[i]][j]) >= 0; j++) { + + set_bit(t, grip->dev[i].absbit); + + if (j < grip_cen[grip->mode[i]]) { + grip->dev[i].absmin[t] = 14; + grip->dev[i].absmax[t] = 52; + grip->dev[i].absfuzz[t] = 1; + grip->dev[i].absflat[t] = 2; + continue; + } + + if (j < grip_anx[grip->mode[i]]) { + grip->dev[i].absmin[t] = 3; + grip->dev[i].absmax[t] = 57; + grip->dev[i].absfuzz[t] = 1; + continue; + } + + grip->dev[i].absmin[t] = -1; + grip->dev[i].absmax[t] = 1; + } + + for (j = 0; (t = grip_btn[grip->mode[i]][j]) >= 0; j++) + if (t > 0) + set_bit(t, grip->dev[i].keybit); + + input_register_device(grip->dev + i); + + printk(KERN_INFO "input%d: %s on gameport%d.%d\n", + grip->dev[i].number, grip_name[grip->mode[i]], gameport->number, i); + } + + return; +fail2: gameport_close(gameport); +fail1: kfree(grip); +} + +static void grip_disconnect(struct gameport *gameport) +{ + int i; + + struct grip *grip = gameport->private; + for (i = 0; i < 2; i++) + if (grip->mode[i]) + input_unregister_device(grip->dev + i); + gameport_close(gameport); + kfree(grip); +} + +static struct gameport_dev grip_dev = { + connect: grip_connect, + disconnect: grip_disconnect, +}; + +int __init grip_init(void) +{ + gameport_register_device(&grip_dev); + return 0; +} + +void __exit grip_exit(void) +{ + gameport_unregister_device(&grip_dev); +} + +module_init(grip_init); +module_exit(grip_exit); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/interact.c linux/drivers/char/joystick/interact.c --- v2.4.0-test1/linux/drivers/char/joystick/interact.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick/interact.c Wed Jun 21 08:22:21 2000 @@ -0,0 +1,306 @@ +/* + * $Id: interact.c,v 1.8 2000/05/29 11:19:51 vojtech Exp $ + * + * Copyright (c) 2000 Vojtech Pavlik + * + * Based on the work of: + * Toby Deshane + * + * Sponsored by SuSE + */ + +/* + * InterAct digital gamepad/joystick driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include + +#define INTERACT_MAX_START 400 /* 400 us */ +#define INTERACT_MAX_STROBE 40 /* 40 us */ +#define INTERACT_MAX_LENGTH 32 /* 32 bits */ +#define INTERACT_REFRESH_TIME HZ/50 /* 20 ms */ + +#define INTERACT_TYPE_HHFX 0 /* HammerHead/FX */ +#define INTERACT_TYPE_PP8D 1 /* ProPad 8 */ + +struct interact { + struct gameport *gameport; + struct input_dev dev; + struct timer_list timer; + int used; + int bads; + int reads; + unsigned char type; + unsigned char length; +}; + +static short interact_abs_hhfx[] = + { ABS_RX, ABS_RY, ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y, -1 }; +static short interact_abs_pp8d[] = + { ABS_X, ABS_Y, -1 }; + +static short interact_btn_hhfx[] = + { BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL, BTN_TL2, BTN_TR2, BTN_MODE, BTN_SELECT, -1 }; +static short interact_btn_pp8d[] = + { BTN_C, BTN_TL, BTN_TR, BTN_A, BTN_B, BTN_Y, BTN_Z, BTN_X, -1 }; + +struct interact_type { + int id; + short *abs; + short *btn; + char *name; + unsigned char length; + unsigned char b8; +}; + +static struct interact_type interact_type[] = { + { 0x6202, interact_abs_hhfx, interact_btn_hhfx, "InterAct HammerHead/FX", 32, 4 }, + { 0x53f8, interact_abs_pp8d, interact_btn_pp8d, "InterAct ProPad 8 Digital", 16, 0 }, + { 0 }}; + +/* + * interact_read_packet() reads and InterAct joystick data. + */ + +static int interact_read_packet(struct gameport *gameport, int length, u32 *data) +{ + unsigned long flags; + unsigned char u, v; + unsigned int t, s; + int i; + + i = 0; + data[0] = data[1] = data[2] = 0; + t = gameport_time(gameport, INTERACT_MAX_START); + s = gameport_time(gameport, INTERACT_MAX_STROBE); + + __save_flags(flags); + __cli(); + gameport_trigger(gameport); + v = gameport_read(gameport); + + while (t > 0 && i < length) { + t--; + u = v; v = gameport_read(gameport); + if (v & ~u & 0x40) { + data[0] = (data[0] << 1) | ((v >> 4) & 1); + data[1] = (data[1] << 1) | ((v >> 5) & 1); + data[2] = (data[2] << 1) | ((v >> 7) & 1); + i++; + t = s; + } + } + + __restore_flags(flags); + + return i; +} + +/* + * interact_timer() reads and analyzes InterAct joystick data. + */ + +static void interact_timer(unsigned long private) +{ + struct interact *interact = (struct interact *) private; + struct input_dev *dev = &interact->dev; + u32 data[3]; + int i; + + interact->reads++; + + if (interact_read_packet(interact->gameport, interact->length, data) < interact->length) { + interact->bads++; + } else + + for (i = 0; i < 3; i++) + data[i] <<= INTERACT_MAX_LENGTH - interact->length; + + switch (interact->type) { + + case INTERACT_TYPE_HHFX: + + for (i = 0; i < 4; i++) + input_report_abs(dev, interact_abs_hhfx[i], (data[i & 1] >> ((i >> 1) << 3)) & 0xff); + + for (i = 0; i < 2; i++) + input_report_abs(dev, ABS_HAT0Y - i, + ((data[1] >> ((i << 1) + 17)) & 1) - ((data[1] >> ((i << 1) + 16)) & 1)); + + for (i = 0; i < 8; i++) + input_report_key(dev, interact_btn_hhfx[i], (data[0] >> (i + 16)) & 1); + + for (i = 0; i < 4; i++) + input_report_key(dev, interact_btn_hhfx[i + 8], (data[1] >> (i + 20)) & 1); + + break; + + case INTERACT_TYPE_PP8D: + + for (i = 0; i < 2; i++) + input_report_abs(dev, interact_abs_pp8d[i], + ((data[0] >> ((i << 1) + 20)) & 1) - ((data[0] >> ((i << 1) + 21)) & 1)); + + for (i = 0; i < 8; i++) + input_report_key(dev, interact_btn_pp8d[i], (data[1] >> (i + 16)) & 1); + + break; + } + + mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME); + +} + +/* + * interact_open() is a callback from the input open routine. + */ + +static int interact_open(struct input_dev *dev) +{ + struct interact *interact = dev->private; + if (!interact->used++) + mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME); + return 0; +} + +/* + * interact_close() is a callback from the input close routine. + */ + +static void interact_close(struct input_dev *dev) +{ + struct interact *interact = dev->private; + if (!--interact->used) + del_timer(&interact->timer); +} + +/* + * interact_connect() probes for InterAct joysticks. + */ + +static void interact_connect(struct gameport *gameport, struct gameport_dev *dev) +{ + struct interact *interact; + __u32 data[3]; + int i, t; + + if (!(interact = kmalloc(sizeof(struct interact), GFP_KERNEL))) + return; + memset(interact, 0, sizeof(struct interact)); + + gameport->private = interact; + + interact->gameport = gameport; + init_timer(&interact->timer); + interact->timer.data = (long) interact; + interact->timer.function = interact_timer; + + if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) + goto fail1; + + i = interact_read_packet(gameport, INTERACT_MAX_LENGTH * 2, data); + + if (i != 32 || (data[0] >> 24) != 0x0c || (data[1] >> 24) != 0x02) { + goto fail2; + } + + for (i = 0; interact_type[i].length; i++) + if (interact_type[i].id == (data[2] >> 16)) + break; + + if (!interact_type[i].length) { + printk(KERN_WARNING "interact.c: Unknown joystick on gameport%d. [len %d d0 %08x d1 %08x i2 %08x]\n", + gameport->number, i, data[0], data[1], data[2]); + goto fail2; + } + + interact->type = i; + interact->length = interact_type[i].length; + + interact->dev.private = interact; + interact->dev.open = interact_open; + interact->dev.close = interact_close; + + interact->dev.name = interact_type[i].name; + interact->dev.idbus = BUS_GAMEPORT; + interact->dev.idvendor = GAMEPORT_ID_VENDOR_INTERACT; + interact->dev.idproduct = interact_type[i].id; + interact->dev.idversion = 0x0100; + + interact->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + + for (i = 0; (t = interact_type[interact->type].abs[i]) >= 0; i++) { + set_bit(t, interact->dev.absbit); + if (i < interact_type[interact->type].b8) { + interact->dev.absmin[t] = 0; + interact->dev.absmax[t] = 255; + } else { + interact->dev.absmin[t] = -1; + interact->dev.absmax[t] = 1; + } + } + + for (i = 0; (t = interact_type[interact->type].btn[i]) >= 0; i++) + set_bit(t, interact->dev.keybit); + + input_register_device(&interact->dev); + printk(KERN_INFO "input%d: %s on gameport%d.0\n", + interact->dev.number, interact_type[interact->type].name, gameport->number); + + return; +fail2: gameport_close(gameport); +fail1: kfree(interact); +} + +static void interact_disconnect(struct gameport *gameport) +{ + struct interact *interact = gameport->private; + input_unregister_device(&interact->dev); + gameport_close(gameport); + kfree(interact); +} + +static struct gameport_dev interact_dev = { + connect: interact_connect, + disconnect: interact_disconnect, +}; + +int __init interact_init(void) +{ + gameport_register_device(&interact_dev); + return 0; +} + +void __exit interact_exit(void) +{ + gameport_unregister_device(&interact_dev); +} + +module_init(interact_init); +module_exit(interact_exit); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/joy-amiga.c linux/drivers/char/joystick/joy-amiga.c --- v2.4.0-test1/linux/drivers/char/joystick/joy-amiga.c Wed Dec 8 14:11:26 1999 +++ linux/drivers/char/joystick/joy-amiga.c Wed Dec 31 16:00:00 1969 @@ -1,163 +0,0 @@ -/* - * joy-amiga.c Version 1.2 - * - * Copyright (c) 1998-1999 Vojtech Pavlik - * - * Sponsored by SuSE - */ - -/* - * This is a module for the Linux joystick driver, supporting - * microswitch based joystick connected to Amiga joystick port. - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static struct js_port* js_am_port __initdata = NULL; - -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_PARM(js_am, "1-2i"); - -static int __initdata js_am[] = { 0, 0 }; - -/* - * js_am_read() reads and Amiga joystick data. - */ - -static int js_am_read(void *info, int **axes, int **buttons) -{ - int data = 0; - - switch (*(int*)info) { - case 0: - data = ~custom.joy0dat; - buttons[0][0] = (~ciaa.pra >> 6) & 1; - break; - - case 1: - data = ~custom.joy1dat; - buttons[0][0] = (~ciaa.pra >> 7) & 1; - break; - - default: - return -1; - } - - axes[0][0] = ((data >> 1) & 1) - ((data >> 9) & 1); - data = ~(data ^ (data << 1)); - axes[0][1] = ((data >> 1) & 1) - ((data >> 9) & 1); - - return 0; -} - -/* - * js_am_open() is a callback from the file open routine. - */ - -static int js_am_open(struct js_dev *jd) -{ - MOD_INC_USE_COUNT; - return 0; -} - -/* - * js_am_close() is a callback from the file release routine. - */ - -static int js_am_close(struct js_dev *jd) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -/* - * js_am_init_corr() initializes correction values of - * Amiga joysticks. - */ - -static void __init js_am_init_corr(struct js_corr **corr) -{ - int i; - - for (i = 0; i < 2; i++) { - corr[0][i].type = JS_CORR_BROKEN; - corr[0][i].prec = 0; - corr[0][i].coef[0] = 0; - corr[0][i].coef[1] = 0; - corr[0][i].coef[2] = (1 << 29); - corr[0][i].coef[3] = (1 << 29); - } -} - -#ifndef MODULE -int __init js_am_setup(SETUP_PARAM) -{ - int i; - SETUP_PARSE(2); - for (i = 0; i <= ints[0] && i < 2; i++) js_am[i] = ints[i+1]; - return 1; -} -__setup("js_am=", js_am_setup); -#endif - -#ifdef MODULE -int init_module(void) -#else -int __init js_am_init(void) -#endif -{ - int i; - - for (i = 0; i < 2; i++) - if (js_am[i]) { - js_am_port = js_register_port(js_am_port, &i, 1, sizeof(int), js_am_read); - printk(KERN_INFO "js%d: Amiga joystick at joy%ddat\n", - js_register_device(js_am_port, 0, 2, 1, "Amiga joystick", js_am_open, js_am_close), i); - js_am_init_corr(js_am_port->corr); - } - if (js_am_port) return 0; - -#ifdef MODULE - printk(KERN_WARNING "joy-amiga: no joysticks specified\n"); -#endif - - return -ENODEV; -} - -#ifdef MODULE -void cleanup_module(void) -{ - while (js_am_port) { - if (js_am_port->devs[0]) - js_unregister_device(js_am_port->devs[0]); - js_am_port = js_unregister_port(js_am_port); - } -} -#endif diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/joy-analog.c linux/drivers/char/joystick/joy-analog.c --- v2.4.0-test1/linux/drivers/char/joystick/joy-analog.c Wed Dec 8 14:11:26 1999 +++ linux/drivers/char/joystick/joy-analog.c Wed Dec 31 16:00:00 1969 @@ -1,315 +0,0 @@ -/* - * joy-analog.c Version 1.2 - * - * Copyright (c) 1996-1999 Vojtech Pavlik - * - * Sponsored by SuSE - */ - -/* - * This is a module for the Linux joystick driver, supporting - * up to two analog (or CHF/FCS) joysticks on a single joystick port. - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define JS_AN_MAX_TIME 3000 /* 3 ms */ -#define JS_AN_LOOP_TIME 2000 /* 2 t */ - -static int js_an_port_list[] __initdata = {0x201, 0}; -static struct js_port* js_an_port __initdata = NULL; - -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_PARM(js_an, "2-24i"); - -static int __initdata js_an[] = { -1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 }; - -#include "joy-analog.h" - -struct js_ax_info { - int io; - int speed; - int loop; - int timeout; - struct js_an_info an; -}; - -/* - * Time macros. - */ - -#ifdef __i386__ -#ifdef CONFIG_X86_TSC -#define GET_TIME(x) __asm__ __volatile__ ( "rdtsc" : "=a" (x) : : "dx" ) -#define DELTA(x,y) ((x)-(y)) -#define TIME_NAME "TSC" -#else -#define GET_TIME(x) do { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0) -#define DELTA(x,y) ((y)-(x)+((y)<(x)?1193180L/HZ:0)) -#define TIME_NAME "PIT" -#endif -#elif __alpha__ -#define GET_TIME(x) __asm__ __volatile__ ( "rpcc %0" : "=r" (x) ) -#define DELTA(x,y) ((x)-(y)) -#define TIME_NAME "PCC" -#endif - -#ifndef GET_TIME -#define FAKE_TIME -static unsigned long js_an_faketime = 0; -#define GET_TIME(x) do { x = js_an_faketime++; } while(0) -#define DELTA(x,y) ((x)-(y)) -#define TIME_NAME "Unreliable" -#endif - -/* - * js_an_read() reads analog joystick data. - */ - -static int js_an_read(void *xinfo, int **axes, int **buttons) -{ - struct js_ax_info *info = xinfo; - struct js_an_info *an = &info->an; - int io = info->io; - unsigned long flags; - unsigned char buf[4]; - unsigned int time[4]; - unsigned char u, v, w; - unsigned int p, q, r, s, t; - int i, j; - - an->buttons = ~inb(io) >> 4; - - i = 0; - w = ((an->mask[0] | an->mask[1]) & JS_AN_AXES_STD) | (an->extensions & JS_AN_HAT_FCS) - | ((an->extensions & JS_AN_BUTTONS_PXY_XY) >> 2) | ((an->extensions & JS_AN_BUTTONS_PXY_UV) >> 4); - p = info->loop; - q = info->timeout; - - __save_flags(flags); - __cli(); - outb(0xff,io); - GET_TIME(r); - __restore_flags(flags); - t = r; - v = w; - do { - s = t; - u = v; - __cli(); - v = inb(io) & w; - GET_TIME(t); - __restore_flags(flags); - if ((u ^ v) && (DELTA(t,s) < p)) { - time[i] = t; - buf[i] = u ^ v; - i++; - } - } while (v && (i < 4) && (DELTA(t,r) < q)); - - v <<= 4; - - for (--i; i >= 0; i--) { - v |= buf[i]; - for (j = 0; j < 4; j++) - if (buf[i] & (1 << j)) an->axes[j] = (DELTA(time[i],r) << 10) / info->speed; - } - - js_an_decode(an, axes, buttons); - - return -(v != w); -} - -/* - * js_an_open() is a callback from the file open routine. - */ - -static int js_an_open(struct js_dev *jd) -{ - MOD_INC_USE_COUNT; - return 0; -} - -/* - * js_an_close() is a callback from the file release routine. - */ - -static int js_an_close(struct js_dev *jd) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -/* - * js_an_calibrate_timer() calibrates the timer and computes loop - * and timeout values for a joystick port. - */ - -static void __init js_an_calibrate_timer(struct js_ax_info *info) -{ - unsigned int i, t, tx, t1, t2, t3; - unsigned long flags; - int io = info->io; - - save_flags(flags); - cli(); - GET_TIME(t1); -#ifdef FAKE_TIME - js_an_faketime += 830; -#endif - udelay(1000); - GET_TIME(t2); - GET_TIME(t3); - restore_flags(flags); - - info->speed = DELTA(t2, t1) - DELTA(t3, t2); - - tx = 1 << 30; - - for(i = 0; i < 50; i++) { - save_flags(flags); - cli(); - GET_TIME(t1); - for(t = 0; t < 50; t++) { inb(io); GET_TIME(t2); } - GET_TIME(t3); - restore_flags(flags); - udelay(i); - if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t; - } - - info->loop = (JS_AN_LOOP_TIME * t) / 50000; - info->timeout = (JS_AN_MAX_TIME * info->speed) / 1000; -} - -/* - * js_an_probe() probes for analog joysticks. - */ - -static struct js_port __init *js_an_probe(int io, int mask0, int mask1, struct js_port *port) -{ - struct js_ax_info info, *ax; - int i, numdev; - unsigned char u; - - if (io < 0) return port; - - if (check_region(io, 1)) return port; - - outb(0xff,io); - u = inb(io); - udelay(JS_AN_MAX_TIME); - u = (inb(io) ^ u) & u; - - if (!u) return port; - if (u & 0xf0) return port; - - if ((numdev = js_an_probe_devs(&info.an, u, mask0, mask1, port)) <= 0) - return port; - - info.io = io; - js_an_calibrate_timer(&info); - - request_region(info.io, 1, "joystick (analog)"); - port = js_register_port(port, &info, numdev, sizeof(struct js_ax_info), js_an_read); - ax = port->info; - - for (i = 0; i < numdev; i++) - printk(KERN_INFO "js%d: %s at %#x ["TIME_NAME" timer, %d %sHz clock, %d ns res]\n", - js_register_device(port, i, js_an_axes(i, &ax->an), js_an_buttons(i, &ax->an), - js_an_name(i, &ax->an), js_an_open, js_an_close), - js_an_name(i, &ax->an), - ax->io, - ax->speed > 10000 ? (ax->speed + 800) / 1000 : ax->speed, - ax->speed > 10000 ? "M" : "k", - ax->loop * 1000000000 / JS_AN_LOOP_TIME / ax->speed); - - js_an_read(ax, port->axes, port->buttons); - js_an_init_corr(&ax->an, port->axes, port->corr, 8); - - return port; -} - -#ifndef MODULE -int __init js_an_setup(SETUP_PARAM) -{ - int i; - SETUP_PARSE(24); - for (i = 0; i <= ints[0] && i < 24; i++) js_an[i] = ints[i+1]; - return 1; -} -__setup("js_an=", js_an_setup); -#endif - -#ifdef MODULE -int init_module(void) -#else -int __init js_an_init(void) -#endif -{ - int i; - - if (js_an[0] >= 0) { - for (i = 0; (js_an[i*3] >= 0) && i < 8; i++) - js_an_port = js_an_probe(js_an[i*3], js_an[i*3+1], js_an[i*3+2], js_an_port); - } else { - for (i = 0; js_an_port_list[i]; i++) - js_an_port = js_an_probe(js_an_port_list[i], 0, 0, js_an_port); - } - if (js_an_port) return 0; - -#ifdef MODULE - printk(KERN_WARNING "joy-analog: no joysticks found\n"); -#endif - - return -ENODEV; -} - -#ifdef MODULE -void cleanup_module(void) -{ - int i; - struct js_ax_info *info; - - while (js_an_port) { - for (i = 0; i < js_an_port->ndevs; i++) - if (js_an_port->devs[i]) - js_unregister_device(js_an_port->devs[i]); - info = js_an_port->info; - release_region(info->io, 1); - js_an_port = js_unregister_port(js_an_port); - } - -} -#endif diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/joy-analog.h linux/drivers/char/joystick/joy-analog.h --- v2.4.0-test1/linux/drivers/char/joystick/joy-analog.h Wed Dec 8 14:11:26 1999 +++ linux/drivers/char/joystick/joy-analog.h Wed Dec 31 16:00:00 1969 @@ -1,287 +0,0 @@ -/* - * joy-analog.h Version 1.2 - * - * Copyright (c) 1996-1999 Vojtech Pavlik - * - * Sponsored by SuSE - */ - -/* - * This file is designed to be included in any joystick driver - * that communicates with standard analog joysticks. This currently - * is: joy-analog.c, joy-assassin.c, and joy-lightning.c - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include - -#define JS_AN_AXES_STD 0x0f -#define JS_AN_BUTTONS_STD 0xf0 - -#define JS_AN_BUTTONS_CHF 0x01 -#define JS_AN_HAT1_CHF 0x02 -#define JS_AN_HAT2_CHF 0x04 -#define JS_AN_ANY_CHF 0x07 -#define JS_AN_HAT_FCS 0x08 -#define JS_AN_HATS_ALL 0x0e -#define JS_AN_BUTTON_PXY_X 0x10 -#define JS_AN_BUTTON_PXY_Y 0x20 -#define JS_AN_BUTTON_PXY_U 0x40 -#define JS_AN_BUTTON_PXY_V 0x80 -#define JS_AN_BUTTONS_PXY_XY 0x30 -#define JS_AN_BUTTONS_PXY_UV 0xc0 -#define JS_AN_BUTTONS_PXY 0xf0 - -static struct { - int x; - int y; -} js_an_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1, 0}, { 0, 1}, {-1, 0}}; - -struct js_an_info { - unsigned char mask[2]; - unsigned int extensions; - int axes[4]; - int initial[4]; - unsigned char buttons; -}; - -/* - * js_an_decode() decodes analog joystick data. - */ - -static void js_an_decode(struct js_an_info *info, int **axes, int **buttons) -{ - int i, j, k; - int hat1, hat2, hat3; - - hat1 = hat2 = hat3 = 0; - if (info->mask[0] & JS_AN_BUTTONS_STD) buttons[0][0] = 0; - if (info->mask[1] & JS_AN_BUTTONS_STD) buttons[1][0] = 0; - - if (info->extensions & JS_AN_ANY_CHF) { - switch (info->buttons & 0xf) { - case 0x1: buttons[0][0] = 0x01; break; - case 0x2: buttons[0][0] = 0x02; break; - case 0x4: buttons[0][0] = 0x04; break; - case 0x8: buttons[0][0] = 0x08; break; - case 0x5: buttons[0][0] = 0x10; break; - case 0x9: buttons[0][0] = 0x20; break; - case 0xf: hat1 = 1; break; - case 0xb: hat1 = 2; break; - case 0x7: hat1 = 3; break; - case 0x3: hat1 = 4; break; - case 0xe: hat2 = 1; break; - case 0xa: hat2 = 2; break; - case 0x6: hat2 = 3; break; - case 0xc: hat2 = 4; break; - } - k = info->extensions & JS_AN_BUTTONS_CHF ? 6 : 4; - } else { - for (i = 1; i >= 0; i--) - for (j = k = 0; j < 4; j++) - if (info->mask[i] & (0x10 << j)) - buttons[i][0] |= ((info->buttons >> j) & 1) << k++; - } - - if (info->extensions & JS_AN_BUTTON_PXY_X) - buttons[0][0] |= (info->axes[2] < (info->initial[2] >> 1)) << k++; - if (info->extensions & JS_AN_BUTTON_PXY_Y) - buttons[0][0] |= (info->axes[3] < (info->initial[3] >> 1)) << k++; - if (info->extensions & JS_AN_BUTTON_PXY_U) - buttons[0][0] |= (info->axes[2] > (info->initial[2] + (info->initial[2] >> 1))) << k++; - if (info->extensions & JS_AN_BUTTON_PXY_V) - buttons[0][0] |= (info->axes[3] > (info->initial[3] + (info->initial[3] >> 1))) << k++; - - if (info->extensions & JS_AN_HAT_FCS) - for (j = 0; j < 4; j++) - if (info->axes[3] < ((info->initial[3] * ((j << 1) + 1)) >> 3)) { - hat3 = j + 1; - break; - } - - for (i = 1; i >= 0; i--) - for (j = k = 0; j < 4; j++) - if (info->mask[i] & (1 << j)) - axes[i][k++] = info->axes[j]; - - if (info->extensions & JS_AN_HAT1_CHF) { - axes[0][k++] = js_an_hat_to_axis[hat1].x; - axes[0][k++] = js_an_hat_to_axis[hat1].y; - } - if (info->extensions & JS_AN_HAT2_CHF) { - axes[0][k++] = js_an_hat_to_axis[hat2].x; - axes[0][k++] = js_an_hat_to_axis[hat2].y; - } - if (info->extensions & JS_AN_HAT_FCS) { - axes[0][k++] = js_an_hat_to_axis[hat3].x; - axes[0][k++] = js_an_hat_to_axis[hat3].y; - } -} - - -/* - * js_an_init_corr() initializes the correction values for - * analog joysticks. - */ - -static void __init js_an_init_corr(struct js_an_info *info, int **axes, struct js_corr **corr, int prec) -{ - int i, j, t; - - for (i = 0; i < 2; i++) - for (j = 0; j < hweight8(info->mask[i] & 0xf); j++) { - - if ((j == 2 && (info->mask[i] & 0xb) == 0xb) || - (j == 3 && (info->mask[i] & 0xf) == 0xf)) { - t = (axes[i][0] + axes[i][1]) >> 1; - } else { - t = axes[i][j]; - } - - corr[i][j].type = JS_CORR_BROKEN; - corr[i][j].prec = prec; - corr[i][j].coef[0] = t - (t >> 3); - corr[i][j].coef[1] = t + (t >> 3); - corr[i][j].coef[2] = (1 << 29) / (t - (t >> 2) + 1); - corr[i][j].coef[3] = (1 << 29) / (t - (t >> 2) + 1); - } - - i = hweight8(info->mask[0] & 0xf); - - for (j = i; j < i + (hweight8(info->extensions & JS_AN_HATS_ALL) << 1); j++) { - corr[0][j].type = JS_CORR_BROKEN; - corr[0][j].prec = 0; - corr[0][j].coef[0] = 0; - corr[0][j].coef[1] = 0; - corr[0][j].coef[2] = (1 << 29); - corr[0][j].coef[3] = (1 << 29); - } - - for (i = 0; i < 4; i++) - info->initial[i] = info->axes[i]; -} - - -/* - * js_an_probe_devs() probes for analog joysticks. - */ - -static int __init js_an_probe_devs(struct js_an_info *info, int exist, int mask0, int mask1, struct js_port *port) -{ - info->mask[0] = info->mask[1] = info->extensions = 0; - - if (mask0 || mask1) { - info->mask[0] = mask0 & (exist | 0xf0); - info->mask[1] = mask1 & (exist | 0xf0) & ~info->mask[0]; - info->extensions = (mask0 >> 8) & ((exist & JS_AN_HAT_FCS) | ((exist << 2) & JS_AN_BUTTONS_PXY_XY) | - ((exist << 4) & JS_AN_BUTTONS_PXY_UV) | JS_AN_ANY_CHF); - - if (info->extensions & JS_AN_BUTTONS_PXY) { - info->mask[0] &= ~((info->extensions & JS_AN_BUTTONS_PXY_XY) >> 2); - info->mask[0] &= ~((info->extensions & JS_AN_BUTTONS_PXY_UV) >> 4); - info->mask[1] = 0; - } - if (info->extensions & JS_AN_HAT_FCS) { - info->mask[0] &= ~JS_AN_HAT_FCS; - info->mask[1] = 0; - info->extensions &= ~(JS_AN_BUTTON_PXY_Y | JS_AN_BUTTON_PXY_V); - } - if (info->extensions & JS_AN_ANY_CHF) { - info->mask[0] |= 0xf0; - info->mask[1] = 0; - } - if (!(info->mask[0] | info->mask[1])) return -1; - } else { - switch (exist) { - case 0x0: - return -1; - case 0x3: - info->mask[0] = 0xf3; /* joystick 0, assuming 4-button */ - break; - case 0xb: - info->mask[0] = 0xfb; /* 3-axis, 4-button joystick */ - break; - case 0xc: - info->mask[0] = 0xcc; /* joystick 1 */ - break; - case 0xf: - info->mask[0] = 0xff; /* 4-axis 4-button joystick */ - break; - default: - printk(KERN_WARNING "joy-analog: Unknown joystick device detected " - "(data=%#x), contact \n", exist); - return -1; - } - } - - return !!info->mask[0] + !!info->mask[1]; -} - -/* - * js_an_axes() returns the number of axes for an analog joystick. - */ - -static inline int js_an_axes(int i, struct js_an_info *info) -{ - return hweight8(info->mask[i] & 0x0f) + hweight8(info->extensions & JS_AN_HATS_ALL) * 2; -} - -/* - * js_an_buttons() returns the number of buttons for an analog joystick. - */ - -static inline int js_an_buttons(int i, struct js_an_info *info) -{ - return hweight8(info->mask[i] & 0xf0) + - (info->extensions & JS_AN_BUTTONS_CHF) * 2 + - hweight8(info->extensions & JS_AN_BUTTONS_PXY); -} - -/* - * js_an_name() constructs a name for an analog joystick. - */ - -static char js_an_name_buf[128] __initdata = ""; - -static char __init *js_an_name(int i, struct js_an_info *info) -{ - - sprintf(js_an_name_buf, "Analog %d-axis %d-button", - hweight8(info->mask[i] & 0x0f), - js_an_buttons(i, info)); - - if (info->extensions & JS_AN_HATS_ALL) - sprintf(js_an_name_buf, "%s %d-hat", - js_an_name_buf, - hweight8(info->extensions & JS_AN_HATS_ALL)); - - strcat(js_an_name_buf, " joystick"); - - if (info->extensions) - sprintf(js_an_name_buf, "%s with%s%s%s extensions", - js_an_name_buf, - info->extensions & JS_AN_ANY_CHF ? " CHF" : "", - info->extensions & JS_AN_HAT_FCS ? " FCS" : "", - info->extensions & JS_AN_BUTTONS_PXY ? " XY/UV" : ""); - - return js_an_name_buf; -} diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/joy-assassin.c linux/drivers/char/joystick/joy-assassin.c --- v2.4.0-test1/linux/drivers/char/joystick/joy-assassin.c Wed Dec 8 14:11:26 1999 +++ linux/drivers/char/joystick/joy-assassin.c Wed Dec 31 16:00:00 1969 @@ -1,416 +0,0 @@ -/* - * joy-assassin.c Version 1.2 - * - * Copyright (c) 1998-1999 Vojtech Pavlik - * - * Sponsored by SuSE - */ - -/* - * This is a module for the Linux joystick driver, supporting - * joysticks using FP-Gaming's Assassin 3D protocol. - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define JS_AS_MAX_START 1000 -#define JS_AS_DELAY_READ 3000 -#define JS_AS_MAX_LENGTH 40 - -#define JS_AS_MODE_A3D 1 /* Assassin 3D */ -#define JS_AS_MODE_PAN 2 /* Panther */ -#define JS_AS_MODE_OEM 3 /* Panther OEM version */ -#define JS_AS_MODE_PXL 4 /* Panther XL */ - -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_PARM(js_as, "2-24i"); - -static int __initdata js_as[] = { -1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 }; - -static int js_as_port_list[] __initdata = {0x201, 0}; -static struct js_port* js_as_port __initdata = NULL; - -#include "joy-analog.h" - -struct js_as_info { - int io; - char mode; - char rudder; - struct js_an_info an; -}; - -/* - * js_as_read_packet() reads an Assassin 3D packet. - */ - -static int js_as_read_packet(int io, int length, char *data) -{ - unsigned char u, v; - int i; - unsigned int t, p; - unsigned long flags; - - i = 0; - - __save_flags(flags); - __cli(); - - outb(0xff,io); - v = inb(io); - t = p = JS_AS_MAX_START; - - while (t > 0 && i < length) { - t--; - u = v; v = inb(io); - if (~v & u & 0x10) { - data[i++] = v >> 5; - p = t = (p - t) << 3; - } - } - - __restore_flags(flags); - - return i; -} - -/* - * js_as_csum() computes checksum of triplet packet - */ - -static int js_as_csum(char *data, int count) -{ - int i, csum = 0; - for (i = 0; i < count - 2; i++) csum += data[i]; - return (csum & 0x3f) != ((data[count - 2] << 3) | data[count - 1]); -} - -/* - * js_as_read() reads and analyzes A3D joystick data. - */ - -static int js_as_read(void *xinfo, int **axes, int **buttons) -{ - struct js_as_info *info = xinfo; - char data[JS_AS_MAX_LENGTH]; - - switch (info->mode) { - - case JS_AS_MODE_A3D: - case JS_AS_MODE_OEM: - case JS_AS_MODE_PAN: - - if (js_as_read_packet(info->io, 29, data) != 29) return -1; - if (data[0] != info->mode) return -1; - if (js_as_csum(data, 29)) return -1; - - axes[0][0] = ((data[5] << 6) | (data[6] << 3) | data[ 7]) - ((data[5] & 4) << 7); - axes[0][1] = ((data[8] << 6) | (data[9] << 3) | data[10]) - ((data[8] & 4) << 7); - - buttons[0][0] = (data[2] << 2) | (data[3] >> 1); - - info->an.axes[0] = ((char)((data[11] << 6) | (data[12] << 3) | (data[13]))) + 128; - info->an.axes[1] = ((char)((data[14] << 6) | (data[15] << 3) | (data[16]))) + 128; - info->an.axes[2] = ((char)((data[17] << 6) | (data[18] << 3) | (data[19]))) + 128; - info->an.axes[3] = ((char)((data[20] << 6) | (data[21] << 3) | (data[22]))) + 128; - - info->an.buttons = ((data[3] << 3) | data[4]) & 0xf; - - js_an_decode(&info->an, axes + 1, buttons + 1); - - return 0; - - case JS_AS_MODE_PXL: - - if (js_as_read_packet(info->io, 33, data) != 33) return -1; - if (data[0] != info->mode) return -1; - if (js_as_csum(data, 33)) return -1; - - axes[0][0] = ((char)((data[15] << 6) | (data[16] << 3) | (data[17]))) + 128; - axes[0][1] = ((char)((data[18] << 6) | (data[19] << 3) | (data[20]))) + 128; - info->an.axes[0] = ((char)((data[21] << 6) | (data[22] << 3) | (data[23]))) + 128; - axes[0][2] = ((char)((data[24] << 6) | (data[25] << 3) | (data[26]))) + 128; - - axes[0][3] = ( data[5] & 1) - ((data[5] >> 2) & 1); - axes[0][4] = ((data[5] >> 1) & 1) - ((data[6] >> 2) & 1); - axes[0][5] = ((data[4] >> 1) & 1) - ( data[3] & 1); - axes[0][6] = ((data[4] >> 2) & 1) - ( data[4] & 1); - - axes[0][7] = ((data[ 9] << 6) | (data[10] << 3) | data[11]) - ((data[ 9] & 4) << 7); - axes[0][8] = ((data[12] << 6) | (data[13] << 3) | data[14]) - ((data[12] & 4) << 7); - - buttons[0][0] = (data[2] << 8) | ((data[3] & 6) << 5) | (data[7] << 3) | data[8]; - - if (info->rudder) axes[1][0] = info->an.axes[0]; - - return 0; - } - return -1; -} - -/* - * js_as_open() is a callback from the file open routine. - */ - -static int js_as_open(struct js_dev *jd) -{ - MOD_INC_USE_COUNT; - return 0; -} - -/* - * js_as_close() is a callback from the file release routine. - */ - -static int js_as_close(struct js_dev *jd) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -/* - * js_as_pxl_init_corr() initializes the correction values for - * the Panther XL. - */ - -static void __init js_as_pxl_init_corr(struct js_corr **corr, int **axes) -{ - int i; - - for (i = 0; i < 2; i++) { - corr[0][i].type = JS_CORR_BROKEN; - corr[0][i].prec = 0; - corr[0][i].coef[0] = axes[0][i] - 4; - corr[0][i].coef[1] = axes[0][i] + 4; - corr[0][i].coef[2] = (1 << 29) / (127 - 32); - corr[0][i].coef[3] = (1 << 29) / (127 - 32); - } - - corr[0][2].type = JS_CORR_BROKEN; - corr[0][2].prec = 0; - corr[0][2].coef[0] = 127 - 4; - corr[0][2].coef[1] = 128 + 4; - corr[0][2].coef[2] = (1 << 29) / (127 - 6); - corr[0][2].coef[3] = (1 << 29) / (127 - 6); - - for (i = 3; i < 7; i++) { - corr[0][i].type = JS_CORR_BROKEN; - corr[0][i].prec = 0; - corr[0][i].coef[0] = 0; - corr[0][i].coef[1] = 0; - corr[0][i].coef[2] = (1 << 29); - corr[0][i].coef[3] = (1 << 29); - } - - for (i = 7; i < 9; i++) { - corr[0][i].type = JS_CORR_BROKEN; - corr[0][i].prec = -1; - corr[0][i].coef[0] = 0; - corr[0][i].coef[1] = 0; - corr[0][i].coef[2] = (104 << 14); - corr[0][i].coef[3] = (104 << 14); - } -} - -/* - * js_as_as_init_corr() initializes the correction values for - * the Panther and Assassin. - */ - -static void __init js_as_as_init_corr(struct js_corr **corr) -{ - int i; - - for (i = 0; i < 2; i++) { - corr[0][i].type = JS_CORR_BROKEN; - corr[0][i].prec = -1; - corr[0][i].coef[0] = 0; - corr[0][i].coef[1] = 0; - corr[0][i].coef[2] = (104 << 14); - corr[0][i].coef[3] = (104 << 14); - } -} - -/* - * js_as_rudder_init_corr() initializes the correction values for - * the Panther XL connected rudder. - */ - -static void __init js_as_rudder_init_corr(struct js_corr **corr, int **axes) -{ - corr[1][0].type = JS_CORR_BROKEN; - corr[1][0].prec = 0; - corr[1][0].coef[0] = axes[1][0] - (axes[1][0] >> 3); - corr[1][0].coef[1] = axes[1][0] + (axes[1][0] >> 3); - corr[1][0].coef[2] = (1 << 29) / (axes[1][0] - (axes[1][0] >> 2) + 1); - corr[1][0].coef[3] = (1 << 29) / (axes[1][0] - (axes[1][0] >> 2) + 1); -} - -/* - * js_as_probe() probes for A3D joysticks. - */ - -static struct js_port __init *js_as_probe(int io, int mask0, int mask1, struct js_port *port) -{ - struct js_as_info iniinfo; - struct js_as_info *info = &iniinfo; - char *name; - char data[JS_AS_MAX_LENGTH]; - unsigned char u; - int i; - int numdev; - - memset(info, 0, sizeof(struct js_as_info)); - - if (io < 0) return port; - - if (check_region(io, 1)) return port; - - i = js_as_read_packet(io, JS_AS_MAX_LENGTH, data); - - printk("%d\n", i); - - if (!i) return port; - if (js_as_csum(data, i)) return port; - - if (data[0] && data[0] <= 4) { - info->mode = data[0]; - info->io = io; - request_region(io, 1, "joystick (assassin)"); - port = js_register_port(port, info, 3, sizeof(struct js_as_info), js_as_read); - info = port->info; - } else { - printk(KERN_WARNING "joy-assassin: unknown joystick device detected " - "(io=%#x, id=%d), contact \n", io, data[0]); - return port; - } - - udelay(JS_AS_DELAY_READ); - - if (info->mode == JS_AS_MODE_PXL) { - printk(KERN_INFO "js%d: MadCatz Panther XL at %#x\n", - js_register_device(port, 0, 9, 9, "MadCatz Panther XL", js_as_open, js_as_close), - info->io); - js_as_read(port->info, port->axes, port->buttons); - js_as_pxl_init_corr(port->corr, port->axes); - if (info->an.axes[0] < 254) { - printk(KERN_INFO "js%d: Analog rudder on MadCatz Panther XL\n", - js_register_device(port, 1, 1, 0, "Analog rudder", js_as_open, js_as_close)); - info->rudder = 1; - port->axes[1][0] = info->an.axes[0]; - js_as_rudder_init_corr(port->corr, port->axes); - } - return port; - } - - switch (info->mode) { - case JS_AS_MODE_A3D: name = "FP-Gaming Assassin 3D"; break; - case JS_AS_MODE_PAN: name = "MadCatz Panther"; break; - case JS_AS_MODE_OEM: name = "OEM Assassin 3D"; break; - default: name = "This cannot happen"; break; - } - - printk(KERN_INFO "js%d: %s at %#x\n", - js_register_device(port, 0, 2, 3, name, js_as_open, js_as_close), - name, info->io); - - js_as_as_init_corr(port->corr); - - js_as_read(port->info, port->axes, port->buttons); - - for (i = u = 0; i < 4; i++) if (info->an.axes[i] < 254) u |= 1 << i; - - if ((numdev = js_an_probe_devs(&info->an, u, mask0, mask1, port)) <= 0) - return port; - - for (i = 0; i < numdev; i++) - printk(KERN_INFO "js%d: %s on %s\n", - js_register_device(port, i + 1, js_an_axes(i, &info->an), js_an_buttons(i, &info->an), - js_an_name(i, &info->an), js_as_open, js_as_close), - js_an_name(i, &info->an), name); - - js_an_decode(&info->an, port->axes + 1, port->buttons + 1); - js_an_init_corr(&info->an, port->axes + 1, port->corr + 1, 0); - - return port; -} - -#ifndef MODULE -int __init js_as_setup(SETUP_PARAM) -{ - int i; - SETUP_PARSE(24); - for (i = 0; i <= ints[0] && i < 24; i++) js_as[i] = ints[i+1]; - return 1; -} -__setup("js_as=", js_as_setup); -#endif - -#ifdef MODULE -int init_module(void) -#else -int __init js_as_init(void) -#endif -{ - int i; - - if (js_as[0] >= 0) { - for (i = 0; (js_as[i*3] >= 0) && i < 8; i++) - js_as_port = js_as_probe(js_as[i*3], js_as[i*3+1], js_as[i*3+2], js_as_port); - } else { - for (i = 0; js_as_port_list[i]; i++) js_as_port = js_as_probe(js_as_port_list[i], 0, 0, js_as_port); - } - if (js_as_port) return 0; - -#ifdef MODULE - printk(KERN_WARNING "joy-assassin: no joysticks found\n"); -#endif - - return -ENODEV; -} - -#ifdef MODULE -void cleanup_module(void) -{ - int i; - struct js_as_info *info; - - while (js_as_port) { - for (i = 0; i < js_as_port->ndevs; i++) - if (js_as_port->devs[i]) - js_unregister_device(js_as_port->devs[i]); - info = js_as_port->info; - release_region(info->io, 1); - js_as_port = js_unregister_port(js_as_port); - } - -} -#endif diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/joy-console.c linux/drivers/char/joystick/joy-console.c --- v2.4.0-test1/linux/drivers/char/joystick/joy-console.c Wed Dec 8 14:11:26 1999 +++ linux/drivers/char/joystick/joy-console.c Wed Dec 31 16:00:00 1969 @@ -1,810 +0,0 @@ -/* - * joy-console.c Version 0.14V - * - * Copyright (c) 1998 Andree Borrmann - * Copyright (c) 1999 John Dahlstrom - * Copyright (c) 1999 David Kuder - * Copyright (c) 1999 Vojtech Pavlik - * - * Sponsored by SuSE - */ - -/* - * This is a module for the Linux joystick driver, supporting - * console (NES, SNES, N64, Multi1, Multi2, PSX) gamepads - * connected via parallel port. Up to five such controllers - * can be connected to one parallel port. - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_PARM(js_console, "2-6i"); -MODULE_PARM(js_console_2,"2-6i"); -MODULE_PARM(js_console_3,"2-6i"); - - -#define JS_NO_PAD 0 -#define JS_SNES_PAD 1 -#define JS_NES_PAD 2 -#define JS_NES4_PAD 3 -#define JS_MULTI_STICK 4 -#define JS_MULTI2_STICK 5 -#define JS_PSX_PAD 6 -#define JS_N64_PAD 7 -#define JS_N64_PAD_DPP 8 /* DirectPad Pro compatible layout */ - -#define JS_MAX_PAD JS_N64_PAD_DPP - -struct js_console_info { - struct pardevice *port; /* parport device */ - int pads; /* total number of pads */ - int pad_to_device[5]; /* pad to js device mapping (js0, js1, etc.) */ - int snes; /* SNES pads */ - int nes; /* NES pads */ - int n64; /* N64 pads */ - int n64_dpp; /* bits indicate N64 pads treated 14 button, 2 axis */ - int multi; /* Multi joysticks */ - int multi2; /* Multi joysticks with 2 buttons */ - int psx; /* PSX controllers */ -}; - -static struct js_port* js_console_port = NULL; - -static int js_console[] __initdata = { -1, 0, 0, 0, 0, 0 }; -static int js_console_2[] __initdata = { -1, 0, 0, 0, 0, 0 }; -static int js_console_3[] __initdata = { -1, 0, 0, 0, 0, 0 }; - -static int status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 }; - -/* - * NES/SNES support. - */ - -#define JS_NES_DELAY 6 /* Delay between bits - 6us */ - -#define JS_NES_LENGTH 8 /* The NES pads use 8 bits of data */ - -#define JS_NES_A 0 -#define JS_NES_B 1 -#define JS_NES_START 2 -#define JS_NES_SELECT 3 -#define JS_NES_UP 4 -#define JS_NES_DOWN 5 -#define JS_NES_LEFT 6 -#define JS_NES_RIGHT 7 - -#define JS_SNES_LENGTH 12 /* The SNES true length is 16, but the last 4 bits are unused */ - -#define JS_SNES_B 0 -#define JS_SNES_Y 1 -#define JS_SNES_START 2 -#define JS_SNES_SELECT 3 -#define JS_SNES_UP 4 -#define JS_SNES_DOWN 5 -#define JS_SNES_LEFT 6 -#define JS_SNES_RIGHT 7 -#define JS_SNES_A 8 -#define JS_SNES_X 9 -#define JS_SNES_L 10 -#define JS_SNES_R 11 - -#define JS_NES_POWER 0xfc -#define JS_NES_CLOCK 0x01 -#define JS_NES_LATCH 0x02 - -/* - * js_nes_read_packet() reads a NES/SNES packet. - * Each pad uses one bit per byte. So all pads connected to - * this port are read in parallel. - */ - -static void js_nes_read_packet(struct js_console_info *info, int length, unsigned char *data) -{ - int i; - - JS_PAR_DATA_OUT(JS_NES_POWER | JS_NES_CLOCK | JS_NES_LATCH, info->port); - udelay(JS_NES_DELAY * 2); - JS_PAR_DATA_OUT(JS_NES_POWER | JS_NES_CLOCK, info->port); - - for (i = 0; i < length; i++) { - udelay(JS_NES_DELAY); - JS_PAR_DATA_OUT(JS_NES_POWER, info->port); - data[i] = JS_PAR_STATUS(info->port) ^ ~JS_PAR_STATUS_INVERT; - udelay(JS_NES_DELAY); - JS_PAR_DATA_OUT(JS_NES_POWER | JS_NES_CLOCK, info->port); - } -} - -/* - * N64 support. - */ - -#define JS_N64_A 0 -#define JS_N64_B 1 -#define JS_N64_Z 2 -#define JS_N64_START 3 -#define JS_N64_UP 4 -#define JS_N64_DOWN 5 -#define JS_N64_LEFT 6 -#define JS_N64_RIGHT 7 -#define JS_N64_UNUSED1 8 -#define JS_N64_UNUSED2 9 -#define JS_N64_L 10 -#define JS_N64_R 11 -#define JS_N64_CU 12 -#define JS_N64_CD 13 -#define JS_N64_CL 14 -#define JS_N64_CR 15 -#define JS_N64_X 23 /* 16 - 23, signed 8-bit int */ -#define JS_N64_Y 31 /* 24 - 31, signed 8-bit int */ - -#define JS_N64_LENGTH 32 /* N64 bit length, not including stop bit */ -#define JS_N64_REQUEST_LENGTH 37 /* transmit request sequence is 9 bits long */ -#define JS_N64_DELAY 133 /* delay between transmit request, and response ready (us) */ -#define JS_N64_REQUEST 0x1dd1111111ULL /* the request data command (encoded for 000000011) */ -#define JS_N64_DWS 3 /* delay between write segments (required for sound playback because of ISA DMA) */ - /* JS_N64_DWS > 24 is known to fail */ -#define JS_N64_POWER_W 0xe2 /* power during write (transmit request) */ -#define JS_N64_POWER_R 0xfd /* power during read */ -#define JS_N64_OUT 0x1d /* output bits to the 4 pads */ - /* Reading the main axes of any N64 pad is known to fail if the corresponding bit */ - /* in JS_N64_OUT is pulled low on the output port (by any routine) for more */ - /* than 0.123 consecutive ms */ -#define JS_N64_CLOCK 0x02 /* clock bits for read */ - -/* - * js_n64_read_packet() reads an N64 packet. - * Each pad uses one bit per byte. So all pads connected to this port are read in parallel. - */ - -static void js_n64_read_packet(struct js_console_info *info, unsigned char *data) -{ - int i; - unsigned long flags; - -/* - * Request the pad to transmit data - */ - - save_flags(flags); - cli(); - for (i = 0; i < JS_N64_REQUEST_LENGTH; i++) { - JS_PAR_DATA_OUT(JS_N64_POWER_W | ((JS_N64_REQUEST >> i) & 1 ? JS_N64_OUT : 0), info->port); - udelay(JS_N64_DWS); - } - restore_flags(flags); - -/* - * Wait for the pad response to be loaded into the 33-bit register of the adapter - */ - - udelay(JS_N64_DELAY); - -/* - * Grab data (ignoring the last bit, which is a stop bit) - */ - - for (i = 0; i < JS_N64_LENGTH; i++) { - JS_PAR_DATA_OUT(JS_N64_POWER_R, info->port); - data[i] = JS_PAR_STATUS(info->port); - JS_PAR_DATA_OUT(JS_N64_POWER_R | JS_N64_CLOCK, info->port); - } - -/* - * We must wait ~0.2 ms here for the controller to reinitialize before the next read request. - * No worries as long as js_console_read is polled less frequently than this. - */ - -} - -/* - * Multisystem joystick support - */ - -#define JS_MULTI_LENGTH 5 /* Multi system joystick packet lenght is 5 */ -#define JS_MULTI2_LENGTH 6 /* One more bit for one more button */ - -#define JS_MULTI_UP 0 -#define JS_MULTI_DOWN 1 -#define JS_MULTI_LEFT 2 -#define JS_MULTI_RIGHT 3 -#define JS_MULTI_BUTTON 4 -#define JS_MULTI_BUTTON2 5 - -/* - * js_multi_read_packet() reads a Multisystem joystick packet. - */ - -static void js_multi_read_packet(struct js_console_info *info, int length, unsigned char *data) -{ - int i; - - for (i = 0; i < length; i++) { - JS_PAR_DATA_OUT(~(1 << i), info->port); - data[i] = JS_PAR_STATUS(info->port) ^ ~JS_PAR_STATUS_INVERT; - printk(" %d", data[i]); - } - printk("\n"); -} - -/* - * PSX support - */ - -#define JS_PSX_DELAY 10 -#define JS_PSX_LENGTH 8 /* talk to the controller in bytes */ - -#define JS_PSX_NORMAL 0x41 /* Standard Digital controller */ -#define JS_PSX_NEGCON 0x23 /* NegCon pad */ -#define JS_PSX_MOUSE 0x12 /* PSX Mouse */ -#define JS_PSX_ANALOGR 0x73 /* Analog controller in Red mode */ -#define JS_PSX_ANALOGG 0x53 /* Analog controller in Green mode */ - -#define JS_PSX_JOYR 0x02 /* These are for the Analog/Dual Shock controller in RED mode */ -#define JS_PSX_JOYL 0x04 /* I'm not sure the exact purpose of these but its in the docs */ -#define JS_PSX_SELBUT 0x01 /* Standard buttons on almost all PSX controllers. */ -#define JS_PSX_START 0x08 -#define JS_PSX_UP 0x10 /* Digital direction pad */ -#define JS_PSX_RIGHT 0x20 -#define JS_PSX_DOWN 0x40 -#define JS_PSX_LEFT 0x80 - -#define JS_PSX_CLOCK 0x04 /* Pin 3 */ -#define JS_PSX_COMMAND 0x01 /* Pin 1 */ -#define JS_PSX_POWER 0xf8 /* Pins 5-9 */ -#define JS_PSX_SELECT 0x02 /* Pin 2 */ -#define JS_PSX_NOPOWER 0x04 - -/* - * js_psx_command() writes 8bit command and reads 8bit data from - * the psx pad. - */ - -static int js_psx_command(struct js_console_info *info, int b) -{ - int i, cmd, ret=0; - - cmd = (b&1)?JS_PSX_COMMAND:0; - for (i=0; i<8; i++) { - JS_PAR_DATA_OUT(cmd | JS_PSX_POWER, info->port); - udelay(JS_PSX_DELAY); - ret |= ((JS_PAR_STATUS(info->port) ^ JS_PAR_STATUS_INVERT ) & info->psx) ? (1<port); - udelay(JS_PSX_DELAY); - b >>= 1; - } - return ret; -} - -/* - * js_psx_read_packet() reads a whole psx packet and returns - * device identifier code. - */ - -static int js_psx_read_packet(struct js_console_info *info, int length, unsigned char *data) -{ - int i, ret; - unsigned long flags; - - __save_flags(flags); - __cli(); - - JS_PAR_DATA_OUT(JS_PSX_POWER, info->port); - - JS_PAR_DATA_OUT(JS_PSX_CLOCK | JS_PSX_SELECT | JS_PSX_POWER, info->port); /* Select pad */ - udelay(JS_PSX_DELAY*2); - js_psx_command(info, 0x01); /* Access pad */ - ret = js_psx_command(info, 0x42); /* Get device id */ - if (js_psx_command(info, 0)=='Z') /* okay? */ - for (i=0; iport); - __restore_flags(flags); - - return ret; -} - - -/* - * js_console_read() reads and analyzes console pads data. - */ - -#define JS_MAX_LENGTH JS_N64_LENGTH - -static int js_console_read(void *xinfo, int **axes, int **buttons) -{ - struct js_console_info *info = xinfo; - unsigned char data[JS_MAX_LENGTH]; - - int i, j, s; - int n = 0; - -/* - * NES and SNES pads - */ - - if (info->nes || info->snes) { - - js_nes_read_packet(info, info->snes ? JS_SNES_LENGTH : JS_NES_LENGTH, data); - - for (i = 0; i < 5; i++) { - s = status_bit[i]; - n = info->pad_to_device[i]; - if (info->nes & s) { - axes[n][0] = (data[JS_SNES_RIGHT]&s?1:0) - (data[JS_SNES_LEFT]&s?1:0); - axes[n][1] = (data[JS_SNES_DOWN] &s?1:0) - (data[JS_SNES_UP] &s?1:0); - - buttons[n][0] = (data[JS_NES_A] &s?1:0) | (data[JS_NES_B] &s?2:0) - | (data[JS_NES_START]&s?4:0) | (data[JS_NES_SELECT]&s?8:0); - } else - if (info->snes & s) { - axes[n][0] = (data[JS_SNES_RIGHT]&s?1:0) - (data[JS_SNES_LEFT]&s?1:0); - axes[n][1] = (data[JS_SNES_DOWN] &s?1:0) - (data[JS_SNES_UP] &s?1:0); - - buttons[n][0] = (data[JS_SNES_A] &s?0x01:0) | (data[JS_SNES_B] &s?0x02:0) - | (data[JS_SNES_X] &s?0x04:0) | (data[JS_SNES_Y] &s?0x08:0) - | (data[JS_SNES_L] &s?0x10:0) | (data[JS_SNES_R] &s?0x20:0) - | (data[JS_SNES_START]&s?0x40:0) | (data[JS_SNES_SELECT]&s?0x80:0); - } - } - } - -/* - * N64 pads - */ - - if (info->n64) { - if ( (info->nes || info->snes) && (info->n64 & status_bit[0]) ) { - /* SNES/NES compatibility */ - udelay(240); /* 200 us delay + 20% tolerance */ - } - - js_n64_read_packet(info, data); - - for (i = 0; i < 5; i++) { - s = status_bit[i]; - n = info->pad_to_device[i]; - if (info->n64 & s & ~(data[JS_N64_UNUSED1] | data[JS_N64_UNUSED2])) { - - buttons[n][0] = ( ((data[JS_N64_A]&s) ? 0x01:0) | ((data[JS_N64_B] & s ) ? 0x02:0) - | ((data[JS_N64_Z]&s) ? 0x04:0) | ((data[JS_N64_L] & s ) ? 0x08:0) - | ((data[JS_N64_R]&s) ? 0x10:0) | ((data[JS_N64_START]&s)? 0x20:0) - | ((data[JS_N64_CU]&s)? 0x40:0) | ((data[JS_N64_CR]&s) ? 0x80:0) - | ((data[JS_N64_CD]&s)?0x100:0) | ((data[JS_N64_CL]&s) ?0x200:0) ); - - if (info->n64_dpp & s) { - buttons[n][0] |= ((data[JS_N64_LEFT]&s) ? 0x400:0) | ((data[JS_N64_UP] & s)? 0x800:0) - |((data[JS_N64_RIGHT]&s)?0x1000:0) | ((data[JS_N64_DOWN]&s)?0x2000:0); - } else { - axes[n][2] = (data[JS_N64_RIGHT]&s?1:0) - (data[JS_N64_LEFT]&s?1:0); - axes[n][3] = (data[JS_N64_DOWN] &s?1:0) - (data[JS_N64_UP] &s?1:0); - } - - /* build int from bits of signed 8-bit int's */ - j = 7; - axes[n][0] = (data[JS_N64_X - j] & s) ? ~0x7f : 0; - axes[n][1] = (data[JS_N64_Y - j] & s) ? ~0x7f : 0; - while ( j-- > 0 ) { - axes[n][0] |= (data[JS_N64_X - j] & s) ? (1 << j) : 0; - axes[n][1] |= (data[JS_N64_Y - j] & s) ? (1 << j) : 0; - } - /* flip Y-axis for conformity */ - axes[n][1] = -axes[n][1]; - - } - } - } - -/* - * Multi and Multi2 joysticks - */ - - if (info->multi || info->multi2) { - - js_multi_read_packet(info, info->multi2 ? JS_MULTI2_LENGTH : JS_MULTI_LENGTH, data); - - for (i = 0; i < 5; i++) { - s = status_bit[i]; - n = info->pad_to_device[i]; - if (info->multi & s) { - axes[n][0] = (data[JS_MULTI_RIGHT]&s?1:0) - (data[JS_MULTI_LEFT]&s?1:0); - axes[n][1] = (data[JS_MULTI_DOWN] &s?1:0) - (data[JS_MULTI_UP] &s?1:0); - - buttons[n][0] = (data[JS_MULTI_BUTTON]&s)?1:0; - } else - if (info->multi2 & s) { - axes[n][0] = (data[JS_MULTI_RIGHT]&s?1:0) - (data[JS_MULTI_LEFT]&s?1:0); - axes[n][1] = (data[JS_MULTI_DOWN] &s?1:0) - (data[JS_MULTI_UP] &s?1:0); - - buttons[n][0] = (data[JS_MULTI_BUTTON]&s)?1:0 | (data[JS_MULTI_BUTTON2]&s)?2:0; - } - } - } - -/* - * PSX controllers - */ - - if (info->psx) { - - for ( i = 0; i < 5; i++ ) - if ( info->psx & status_bit[i] ) { - n = info->pad_to_device[i]; - break; - } - - buttons[n][0] = 0; - - switch (js_psx_read_packet(info, 6, data)) { - - case JS_PSX_ANALOGR: - - buttons[n][0] |= (data[0]&JS_PSX_JOYL?0:0x800) | (data[0]&JS_PSX_JOYR?0:0x400); - - case JS_PSX_ANALOGG: - - axes[n][2] = data[2]; - axes[n][3] = data[3]; - axes[n][4] = data[4]; - axes[n][5] = data[5]; - - case JS_PSX_NORMAL: - case JS_PSX_NEGCON: - - axes[n][0] = (data[0]&JS_PSX_RIGHT?0:1) - (data[0]&JS_PSX_LEFT?0:1); - axes[n][1] = (data[0]&JS_PSX_DOWN ?0:1) - (data[0]&JS_PSX_UP ?0:1); - - buttons[n][0] |= ((~data[1]&0xf)<<4) | ((~data[1]&0xf0)>>4) | - (data[0]&JS_PSX_START?0:0x200) | (data[0]&JS_PSX_SELBUT?0:0x100); - - break; - - } - } - - return 0; -} - -/* - * open callback: claim parport. - */ - -int js_console_open(struct js_dev *dev) -{ - struct js_console_info *info = dev->port->info; - if (!MOD_IN_USE && parport_claim(info->port)) return -EBUSY; - MOD_INC_USE_COUNT; - return 0; -} - -/* - * close callback: release parport - */ - -int js_console_close(struct js_dev *dev) -{ - struct js_console_info *info = dev->port->info; - MOD_DEC_USE_COUNT; - if (!MOD_IN_USE) parport_release(info->port); - return 0; -} - -#ifdef MODULE -void cleanup_module(void) -{ - struct js_console_info *info; - int i; - - while (js_console_port) { - for (i = 0; i < js_console_port->ndevs; i++) - if (js_console_port->devs[i]) - js_unregister_device(js_console_port->devs[i]); - info = js_console_port->info; - parport_unregister_device(info->port); - js_console_port = js_unregister_port(js_console_port); - } -} -#endif - -/* - * js_console_init_corr() initializes correction values of - * console gamepads. - */ - -static void __init js_console_init_corr(int num_axes, int type, struct js_corr *corr) -{ - int i; - - for (i = 0; i < num_axes; i++) { - corr[i].type = JS_CORR_BROKEN; - corr[i].prec = 0; - corr[i].coef[0] = 0; - corr[i].coef[1] = 0; - corr[i].coef[2] = (1 << 29); - corr[i].coef[3] = (1 << 29); - } - - if (type == JS_N64_PAD || type == JS_N64_PAD_DPP) { - for (i = 0; i < 2; i++) { - corr[i].type = JS_CORR_BROKEN; - corr[i].prec = 0; - corr[i].coef[0] = 0; - corr[i].coef[1] = 0; - corr[i].coef[2] = (1 << 22); - corr[i].coef[3] = (1 << 22); - } - } - - if (type == JS_PSX_ANALOGG || type == JS_PSX_ANALOGR) { - for (i = 2; i < 6; i++) { - corr[i].type = JS_CORR_BROKEN; - corr[i].prec = 0; - corr[i].coef[0] = 127 - 2; - corr[i].coef[1] = 128 + 2; - corr[i].coef[2] = (1 << 29) / (127 - 4); - corr[i].coef[3] = (1 << 29) / (127 - 4); - } - } -} - -/* - * js_console_probe() probes for console gamepads. - * Only PSX pads can really be probed for. - */ - -static struct js_port __init *js_console_probe(int *config, struct js_port *port) -{ - char *name[5]; - int i, psx, axes[5], buttons[5], type[5]; - unsigned char data[2]; /* used for PSX probe */ - struct js_console_info info; - struct parport *pp; - - memset(&info, 0, sizeof(struct js_console_info)); - - if (config[0] < 0) return port; - - if (config[0] > 0x10) - for (pp=parport_enumerate(); pp && (pp->base!=config[0]); pp=pp->next); - else - for (pp=parport_enumerate(); pp && (config[0]>0); pp=pp->next) config[0]--; - - if (!pp) { - printk(KERN_ERR "joy-console: no such parport\n"); - return port; - } - - info.port = parport_register_device(pp, "joystick (console)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); - if (!info.port) - return port; - - if (parport_claim(info.port)) - { - parport_unregister_device(info.port); /* port currently not available ... */ - return port; - } - - for (i = 0; i < 5; i++) { - - type[info.pads] = config[i+1]; - info.pad_to_device[i] = info.pads; - - switch(config[i+1]) { - - case JS_NO_PAD: - - break; - - case JS_SNES_PAD: - - axes[info.pads] = 2; - buttons[info.pads] = 8; - name[info.pads] = "SNES pad"; - info.snes |= status_bit[i]; - info.pads++; - break; - - case JS_NES_PAD: - - axes[info.pads] = 2; - buttons[info.pads] = 4; - name[info.pads] = "NES pad"; - info.nes |= status_bit[i]; - info.pads++; - break; - - case JS_N64_PAD: - axes[info.pads] = 4; - buttons[info.pads] = 10; - name[info.pads] = "N64 pad"; - info.n64 |= status_bit[i]; - info.pads++; - break; - - case JS_N64_PAD_DPP: - axes[info.pads] = 2; - buttons[info.pads] = 14; - name[info.pads] = "N64 pad (DPP mode)"; - info.n64 |= status_bit[i]; - info.n64_dpp |= status_bit[i]; - info.pads++; - break; - - case JS_MULTI_STICK: - - axes[info.pads] = 2; - buttons[info.pads] = 1; - name[info.pads] = "Multisystem joystick"; - info.multi |= status_bit[i]; - info.pads++; - break; - - case JS_MULTI2_STICK: - - axes[info.pads] = 2; - buttons[info.pads] = 2; - name[info.pads] = "Multisystem joystick (2 fire)"; - info.multi |= status_bit[i]; - info.pads++; - break; - - case JS_PSX_PAD: - - info.psx |= status_bit[i]; - psx = js_psx_read_packet(&info, 2, data); - psx = js_psx_read_packet(&info, 2, data); - info.psx &= ~status_bit[i]; - - type[i] = psx; - - switch(psx) { - case JS_PSX_NORMAL: - axes[info.pads] = 2; - buttons[info.pads] = 10; - name[info.pads] = "PSX pad"; - info.psx |= status_bit[i]; - info.pads++; - break; - - case JS_PSX_ANALOGR: - axes[info.pads] = 6; - buttons[info.pads] = 12; - name[info.pads] = "Analog Red PSX pad"; - info.psx |= status_bit[i]; - info.pads++; - break; - - case JS_PSX_ANALOGG: - axes[info.pads] = 6; - buttons[info.pads] = 10; - name[info.pads] = "Analog Green PSX pad"; - info.psx |= status_bit[i]; - info.pads++; - break; - - case JS_PSX_NEGCON: - axes[info.pads] = 2; - buttons[info.pads] = 10; - name[info.pads] = "NegCon PSX pad"; - info.psx |= status_bit[i]; - info.pads++; - break; - - case JS_PSX_MOUSE: - printk(KERN_WARNING "joy-psx: PSX mouse not supported...\n"); - break; - - case -1: - printk(KERN_ERR "joy-psx: no PSX controller found...\n"); - break; - - default: - printk(KERN_WARNING "joy-psx: PSX controller unknown: 0x%x," - " please report to .\n", psx); - } - break; - - default: - - printk(KERN_WARNING "joy-console: pad type %d unknown\n", config[i+1]); - } - } - - if (!info.pads) { - parport_release(info.port); - parport_unregister_device(info.port); - return port; - } - - port = js_register_port(port, &info, info.pads, sizeof(struct js_console_info), js_console_read); - - for (i = 0; i < info.pads; i++) { - printk(KERN_INFO "js%d: %s on %s\n", - js_register_device(port, i, axes[i], buttons[i], name[i], js_console_open, js_console_close), - name[i], info.port->port->name); - - js_console_init_corr(axes[i], type[i], port->corr[i]); - } - - parport_release(info.port); - return port; -} - -#ifndef MODULE -int __init js_console_setup(SETUP_PARAM) -{ - int i; - SETUP_PARSE(6); - for (i = 0; i <= ints[0] && i < 6; i++) js_console[i] = ints[i+1]; - return 1; -} -int __init js_console_setup_2(SETUP_PARAM) -{ - int i; - SETUP_PARSE(6); - for (i = 0; i <= ints[0] && i < 6; i++) js_console_2[i] = ints[i+1]; - return 1; -} -int __init js_console_setup_3(SETUP_PARAM) -{ - int i; - SETUP_PARSE(6); - for (i = 0; i <= ints[0] && i < 6; i++) js_console_3[i] = ints[i+1]; - return 1; -} -__setup("js_console=", js_console_setup); -__setup("js_console_2=", js_console_setup_2); -__setup("js_console_3=", js_console_setup_3); -#endif - -#ifdef MODULE -int init_module(void) -#else -int __init js_console_init(void) -#endif -{ - js_console_port = js_console_probe(js_console, js_console_port); - js_console_port = js_console_probe(js_console_2, js_console_port); - js_console_port = js_console_probe(js_console_3, js_console_port); - - if (js_console_port) return 0; - -#ifdef MODULE - printk(KERN_WARNING "joy-console: no joysticks specified\n"); -#endif - return -ENODEV; -} diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/joy-creative.c linux/drivers/char/joystick/joy-creative.c --- v2.4.0-test1/linux/drivers/char/joystick/joy-creative.c Tue Feb 1 01:35:43 2000 +++ linux/drivers/char/joystick/joy-creative.c Wed Dec 31 16:00:00 1969 @@ -1,287 +0,0 @@ -/* - * joy-creative.c Version 1.2 - * - * Copyright (c) 1999 Vojtech Pavlik - * - * Sponsored by SuSE - */ - -/* - * This is a module for the Linux joystick driver, supporting - * Creative Labs Blaster gamepad family. - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define JS_CR_MAX_STROBE 100 /* 100 us max wait for first strobe */ -#define JS_CR_LENGTH 36 - -#define JS_CR_MODE_BGPC 8 - -static int js_cr_port_list[] __initdata = {0x201, 0}; -static struct js_port* js_cr_port __initdata = NULL; - -struct js_cr_info { - int io; - unsigned char mode[2]; -}; - -/* - * js_cr_read_packet() reads a Blaster gamepad packet. - */ - -static int js_cr_read_packet(int io, unsigned int *data) -{ - unsigned long flags; - unsigned char u, v, w; - __u64 buf[2]; - int r[2], t[2], p[2]; - int i, j, ret; - - for (i = 0; i < 2; i++) { - r[i] = buf[i] = 0; - p[i] = t[i] = JS_CR_MAX_STROBE; - p[i] += JS_CR_MAX_STROBE; - } - - __save_flags(flags); - __cli(); - - u = inb(io); - - do { - t[0]--; t[1]--; - v = inb(io); - for (i = 0, w = u ^ v; i < 2 && w; i++, w >>= 2) - if (w & 0x30) { - if ((w & 0x30) < 0x30 && r[i] < JS_CR_LENGTH && t[i] > 0) { - buf[i] |= (__u64)((w >> 5) & 1) << r[i]++; - p[i] = t[i] = (p[i] - t[i]) << 1; - u = v; - } else t[i] = 0; - } - } while (t[0] > 0 || t[1] > 0); - - __restore_flags(flags); - - - ret = 0; - - for (i = 0; i < 2; i++) { - - if (r[i] != JS_CR_LENGTH) continue; - - for (j = 0; j < JS_CR_LENGTH && (buf[i] & 0x04104107f) ^ 0x041041040; j++) - buf[i] = (buf[i] >> 1) | ((__u64)(buf[i] & 1) << (JS_CR_LENGTH - 1)); - - if (j < JS_CR_LENGTH) ret |= (1 << i); - - data[i] = ((buf[i] >> 7) & 0x000001f) | ((buf[i] >> 8) & 0x00003e0) - | ((buf[i] >> 9) & 0x0007c00) | ((buf[i] >> 10) & 0x00f8000) - | ((buf[i] >> 11) & 0x1f00000); - - } - - return ret; -} - -/* - * js_cr_read() reads and analyzes Blaster gamepad data. - */ - -static int js_cr_read(void *xinfo, int **axes, int **buttons) -{ - struct js_cr_info *info = xinfo; - unsigned int data[2]; - int i, r; - - if (!(r = js_cr_read_packet(info->io, data))) - return -1; - - for (i = 0; i < 2; i++) - if (r & (1 << i)) { - switch (info->mode[i]) { - - case JS_CR_MODE_BGPC: - - axes[i][0] = ((data[i] >> 4) & 1) - ((data[i] >> 3) & 1); - axes[i][1] = ((data[i] >> 2) & 1) - ((data[i] >> 1) & 1); - - buttons[i][0] = ((data[i] >> 12) & 0x007) | ((data[i] >> 6) & 0x038) - | ((data[i] >> 1) & 0x0c0) | ((data[i] >> 7) & 0x300) - | ((data[i] << 5) & 0xc00); - - break; - - default: - break; - - } - } - - return 0; -} - -/* - * js_cr_open() is a callback from the file open routine. - */ - -static int js_cr_open(struct js_dev *jd) -{ - MOD_INC_USE_COUNT; - return 0; -} - -/* - * js_cr_close() is a callback from the file release routine. - */ - -static int js_cr_close(struct js_dev *jd) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -/* - * js_cr_init_corr() initializes correction values of - * Blaster gamepads. - */ - -static void __init js_cr_init_corr(int mode, struct js_corr *corr) -{ - int i; - - switch (mode) { - - case JS_CR_MODE_BGPC: - - for (i = 0; i < 2; i++) { - corr[i].type = JS_CORR_BROKEN; - corr[i].prec = 0; - corr[i].coef[0] = 0; - corr[i].coef[1] = 0; - corr[i].coef[2] = (1 << 29); - corr[i].coef[3] = (1 << 29); - } - - break; - - } -} - -/* - * js_cr_probe() probes for Blaster gamepads. - */ - -static struct js_port __init *js_cr_probe(int io, struct js_port *port) -{ - struct js_cr_info info; - char *names[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Blaster GamePad Cobra" }; - char axes[] = { 0, 0, 0, 0, 0, 0, 0, 0, 2 }; - char buttons[] = { 0, 0, 0, 0, 0, 0, 0, 0, 12 }; - unsigned int data[2]; - int i, r; - - if (check_region(io, 1)) return port; - - info.mode[0] = info.mode[1] = 0; - - if (!(r = js_cr_read_packet(io, data))) - return port; - - for (i = 0; i < 2; i++) { - if (r & (1 << i)) { - if (~data[i] & 1) { - info.mode[i] = JS_CR_MODE_BGPC; - } else { - info.mode[i] = (data[i] >> 2) & 7; - } - if (!names[info.mode[i]]) { - printk(KERN_WARNING "joy-creative: Unknown Creative device %d at %#x\n", - info.mode[i], io); - info.mode[i] = 0; - } - } - } - - if (!info.mode[0] && !info.mode[1]) return port; - - info.io = io; - - request_region(io, 1, "joystick (creative)"); - port = js_register_port(port, &info, 2, sizeof(struct js_cr_info), js_cr_read); - - for (i = 0; i < 2; i++) - if (info.mode[i]) { - printk(KERN_INFO "js%d: %s at %#x\n", - js_register_device(port, i, axes[info.mode[i]], buttons[info.mode[i]], - names[info.mode[i]], js_cr_open, js_cr_close), - names[info.mode[i]], io); - js_cr_init_corr(info.mode[i], port->corr[i]); - } - - return port; -} - -#ifdef MODULE -int init_module(void) -#else -int __init js_cr_init(void) -#endif -{ - int *p; - - for (p = js_cr_port_list; *p; p++) js_cr_port = js_cr_probe(*p, js_cr_port); - if (js_cr_port) return 0; - -#ifdef MODULE - printk(KERN_WARNING "joy-creative: no joysticks found\n"); -#endif - - return -ENODEV; -} - -#ifdef MODULE -void cleanup_module(void) -{ - int i; - struct js_cr_info *info; - - while (js_cr_port) { - for (i = 0; i < js_cr_port->ndevs; i++) - if (js_cr_port->devs[i]) - js_unregister_device(js_cr_port->devs[i]); - info = js_cr_port->info; - release_region(info->io, 1); - js_cr_port = js_unregister_port(js_cr_port); - } -} -#endif diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/joy-db9.c linux/drivers/char/joystick/joy-db9.c --- v2.4.0-test1/linux/drivers/char/joystick/joy-db9.c Wed Dec 8 14:11:26 1999 +++ linux/drivers/char/joystick/joy-db9.c Wed Dec 31 16:00:00 1969 @@ -1,420 +0,0 @@ -/* - * joy-db9.c Version 0.6V - * - * Copyright (c) 1998 Andree Borrmann - * Copyright (c) 1999 Vojtech Pavlik - * - * Sponsored by SuSE - */ - -/* - * This is a module for the Linux joystick driver, supporting - * console (Atari, Amstrad, Commodore, Amiga, Sega) joysticks - * and gamepads connected to the parallel port. - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_PARM(js_db9, "2i"); -MODULE_PARM(js_db9_2, "2i"); -MODULE_PARM(js_db9_3, "2i"); - -#define JS_MULTI_STICK 0x01 -#define JS_MULTI2_STICK 0x02 -#define JS_GENESIS_PAD 0x03 -#define JS_GENESIS5_PAD 0x05 -#define JS_GENESIS6_PAD 0x06 -#define JS_SATURN_PAD 0x07 -#define JS_MULTI_0802 0x08 -#define JS_MULTI_0802_2 0x09 -#define JS_MAX_PAD 0x0A - -#define JS_DB9_UP 0x01 -#define JS_DB9_DOWN 0x02 -#define JS_DB9_LEFT 0x04 -#define JS_DB9_RIGHT 0x08 -#define JS_DB9_FIRE1 0x10 -#define JS_DB9_FIRE2 0x20 -#define JS_DB9_FIRE3 0x40 -#define JS_DB9_FIRE4 0x80 - -#define JS_DB9_NORMAL 0x2a -#define JS_DB9_NOSELECT 0x28 - -#define JS_DB9_SATURN0 0x20 -#define JS_DB9_SATURN1 0x22 -#define JS_DB9_SATURN2 0x24 -#define JS_DB9_SATURN3 0x26 - -#define JS_GENESIS6_DELAY 14 - -static struct js_port* js_db9_port = NULL; - -static int js_db9[] __initdata = { -1, 0 }; -static int js_db9_2[] __initdata = { -1, 0 }; -static int js_db9_3[] __initdata = { -1, 0 }; - -struct js_db9_info { - struct pardevice *port; /* parport device */ - int mode; /* pad mode */ -}; - -/* - * js_db9_read() reads and analyzes db9 joystick data. - */ - -static int js_db9_read(void *xinfo, int **axes, int **buttons) -{ - struct js_db9_info *info = xinfo; - int data; - - switch(info->mode) - { - case JS_MULTI_0802_2: - - data = JS_PAR_DATA_IN(info->port) >> 3; - - axes[1][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP ?0:1); - axes[1][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1); - - buttons[1][0] = (data&JS_DB9_FIRE1?0:1); - - case JS_MULTI_0802: - - data = JS_PAR_STATUS(info->port) >> 3; - - axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP ?0:1); - axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1); - - buttons[0][0] = (data&JS_DB9_FIRE1?1:0); - - break; - - case JS_MULTI_STICK: - - data = JS_PAR_DATA_IN(info->port); - - axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP ?0:1); - axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1); - - buttons[0][0] = (data&JS_DB9_FIRE1?0:1); - - break; - - case JS_MULTI2_STICK: - - data=JS_PAR_DATA_IN(info->port); - - axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP ?0:1); - axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1); - - buttons[0][0] = (data&JS_DB9_FIRE1?0:1) | (data&JS_DB9_FIRE2?0:2); - - break; - - case JS_GENESIS_PAD: - - JS_PAR_CTRL_OUT(JS_DB9_NOSELECT, info->port); - data = JS_PAR_DATA_IN(info->port); - - axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP ?0:1); - axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1); - - buttons[0][0] = (data&JS_DB9_FIRE1?0:2) | (data&JS_DB9_FIRE2?0:4); - - JS_PAR_CTRL_OUT(JS_DB9_NORMAL,info->port); - data=JS_PAR_DATA_IN(info->port); - - buttons[0][0] |= (data&JS_DB9_FIRE1?0:1) | (data&JS_DB9_FIRE2?0:8); - - break; - - case JS_GENESIS5_PAD: - - JS_PAR_CTRL_OUT(JS_DB9_NOSELECT,info->port); - data=JS_PAR_DATA_IN(info->port); - - axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP ?0:1); - axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1); - - buttons[0][0] = (data&JS_DB9_FIRE1?0:0x02) | (data&JS_DB9_FIRE2?0:0x04); - - JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port); - data=JS_PAR_DATA_IN(info->port); - - buttons[0][0] |= (data&JS_DB9_FIRE1?0:0x01) | (data&JS_DB9_FIRE2?0:0x08) | - (data&JS_DB9_LEFT ?0:0x10) | (data&JS_DB9_RIGHT?0:0x20); - break; - - case JS_GENESIS6_PAD: - - JS_PAR_CTRL_OUT(JS_DB9_NOSELECT,info->port); /* 1 */ - udelay(JS_GENESIS6_DELAY); - data=JS_PAR_DATA_IN(info->port); - - axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP ?0:1); - axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1); - - buttons[0][0] = (data&JS_DB9_FIRE1?0:0x02) | (data&JS_DB9_FIRE2?0:0x04); - - JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port); - udelay(JS_GENESIS6_DELAY); - data=JS_PAR_DATA_IN(info->port); - - buttons[0][0] |= (data&JS_DB9_FIRE1?0:0x01) | (data&JS_DB9_FIRE2?0:0x08); - - JS_PAR_CTRL_OUT(JS_DB9_NOSELECT, info->port); /* 2 */ - udelay(JS_GENESIS6_DELAY); - JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port); - udelay(JS_GENESIS6_DELAY); - JS_PAR_CTRL_OUT(JS_DB9_NOSELECT, info->port); /* 3 */ - udelay(JS_GENESIS6_DELAY); - data=JS_PAR_DATA_IN(info->port); - - buttons[0][0] |= (data&JS_DB9_LEFT?0:0x10) | (data&JS_DB9_DOWN ?0:0x20) | - (data&JS_DB9_UP ?0:0x40) | (data&JS_DB9_RIGHT?0:0x80); - - JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port); - udelay(JS_GENESIS6_DELAY); - JS_PAR_CTRL_OUT(JS_DB9_NOSELECT, info->port); /* 4 */ - udelay(JS_GENESIS6_DELAY); - JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port); - - break; - - case JS_SATURN_PAD: - - JS_PAR_CTRL_OUT(JS_DB9_SATURN0, info->port); - data = JS_PAR_DATA_IN(info->port); - - buttons[0][0] = (data&JS_DB9_UP ?0:0x20) | (data&JS_DB9_DOWN ?0:0x10) | - (data&JS_DB9_LEFT?0:0x08) | (data&JS_DB9_RIGHT?0:0x40); - - JS_PAR_CTRL_OUT(JS_DB9_SATURN2, info->port); - data = JS_PAR_DATA_IN(info->port); - - axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP ?0:1); - axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1); - - JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port); - data = JS_PAR_DATA_IN(info->port); - - buttons[0][0] |= (data&JS_DB9_UP ?0:0x02) | (data&JS_DB9_DOWN ?0:0x04) | - (data&JS_DB9_LEFT?0:0x01) | (data&JS_DB9_RIGHT?0:0x80); - - - break; - - default: - return -1; - } - - return 0; -} - -/* - * open callback: claim parport. - */ - -int js_db9_open(struct js_dev *dev) -{ - struct js_db9_info *info = dev->port->info; - - if (!MOD_IN_USE) { - if (parport_claim(info->port)) return -EBUSY; - - JS_PAR_DATA_OUT(0xff, info->port); - if (info->mode != JS_MULTI_0802) - JS_PAR_ECTRL_OUT(0x35,info->port); /* enable PS/2 mode: */ - JS_PAR_CTRL_OUT(JS_DB9_NORMAL,info->port); /* reverse direction, enable Select signal */ - } - - MOD_INC_USE_COUNT; - return 0; -} - -/* - * close callback: release parport - */ - -int js_db9_close(struct js_dev *dev) -{ - struct js_db9_info *info = dev->port->info; - - MOD_DEC_USE_COUNT; - - if (!MOD_IN_USE) { - - JS_PAR_CTRL_OUT(0x00,info->port); /* normal direction */ - if (info->mode != JS_MULTI_0802) - JS_PAR_ECTRL_OUT(0x15,info->port); /* enable normal mode */ - - parport_release(info->port); - } - return 0; -} - -#ifdef MODULE -void cleanup_module(void) -{ - struct js_db9_info *info; - int i; - - while (js_db9_port) { - info = js_db9_port->info; - - for (i = 0; i < js_db9_port->ndevs; i++) - if (js_db9_port->devs[i]) - js_unregister_device(js_db9_port->devs[i]); - parport_unregister_device(info->port); - js_db9_port = js_unregister_port(js_db9_port); - } - -} -#endif - -/* - * js_db9_init_corr() initializes correction values of - * db9 gamepads. - */ - -static void __init js_db9_init_corr(struct js_corr *corr) -{ - int i; - - for (i = 0; i < 2; i++) { - corr[i].type = JS_CORR_BROKEN; - corr[i].prec = 0; - corr[i].coef[0] = 0; - corr[i].coef[1] = 0; - corr[i].coef[2] = (1 << 29); - corr[i].coef[3] = (1 << 29); - } -} - -/* - * js_db9_probe() probes for db9 gamepads. - */ - -static struct js_port __init *js_db9_probe(int *config, struct js_port *port) -{ - struct js_db9_info info; - struct parport *pp; - int i; - char buttons[JS_MAX_PAD] = {0,1,2,4,0,6,8,8,1,1}; - char *name[JS_MAX_PAD] = {NULL, "Multisystem joystick", "Multisystem joystick (2 fire)", "Genesis pad", - NULL, "Genesis 5 pad", "Genesis 6 pad", "Saturn pad", "Multisystem (0.8.0.2) joystick", - "Multisystem (0.8.0.2-dual) joystick"}; - - if (config[0] < 0) return port; - if (config[1] < 0 || config[1] >= JS_MAX_PAD || !name[config[1]]) return port; - - info.mode = config[1]; - - if (config[0] > 0x10) - for (pp=parport_enumerate(); pp && (pp->base!=config[0]); pp=pp->next); - else - for (pp=parport_enumerate(); pp && (config[0]>0); pp=pp->next) config[0]--; - - if (!pp) { - printk(KERN_ERR "joy-db9: no such parport\n"); - return port; - } - - if (!(pp->modes & (PARPORT_MODE_PCPS2 | PARPORT_MODE_PCECPPS2)) && info.mode != JS_MULTI_0802) { - printk(KERN_ERR "js-db9: specified parport is not bidirectional\n"); - return port; - } - - info.port = parport_register_device(pp, "joystick (db9)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); - if (!info.port) - return port; - - port = js_register_port(port, &info, 1 + (info.mode == JS_MULTI_0802_2), sizeof(struct js_db9_info), js_db9_read); - - for (i = 0; i < 1 + (info.mode == JS_MULTI_0802_2); i++) { - printk(KERN_INFO "js%d: %s on %s\n", - js_register_device(port, i, 2, buttons[info.mode], name[info.mode], js_db9_open, js_db9_close), - name[info.mode], info.port->port->name); - - js_db9_init_corr(port->corr[i]); - } - - - return port; -} - -#ifndef MODULE -int __init js_db9_setup(SETUP_PARAM) -{ - int i; - SETUP_PARSE(2); - for (i = 0; i <= ints[0] && i < 2; i++) js_db9[i] = ints[i+1]; - return 1; -} -int __init js_db9_setup_2(SETUP_PARAM) -{ - int i; - SETUP_PARSE(2); - for (i = 0; i <= ints[0] && i < 2; i++) js_db9_2[i] = ints[i+1]; - return 1; -} -int __init js_db9_setup_3(SETUP_PARAM) -{ - int i; - SETUP_PARSE(2); - for (i = 0; i <= ints[0] && i < 2; i++) js_db9_3[i] = ints[i+1]; - return 1; -} -__setup("js_db9=", js_db9_setup); -__setup("js_db9_2=", js_db9_setup_2); -__setup("js_db9_3=", js_db9_setup_3); -#endif - -#ifdef MODULE -int init_module(void) -#else -int __init js_db9_init(void) -#endif -{ - js_db9_port = js_db9_probe(js_db9, js_db9_port); - js_db9_port = js_db9_probe(js_db9_2, js_db9_port); - js_db9_port = js_db9_probe(js_db9_3, js_db9_port); - - if (js_db9_port) return 0; - -#ifdef MODULE - printk(KERN_WARNING "joy-db9: no joysticks specified\n"); -#endif - return -ENODEV; -} diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/joy-gravis.c linux/drivers/char/joystick/joy-gravis.c --- v2.4.0-test1/linux/drivers/char/joystick/joy-gravis.c Wed Dec 8 14:11:26 1999 +++ linux/drivers/char/joystick/joy-gravis.c Wed Dec 31 16:00:00 1969 @@ -1,403 +0,0 @@ -/* - * joy-gravis.c Version 1.2 - * - * Copyright (c) 1998-1999 Vojtech Pavlik - * - * Sponsored by SuSE - */ - -/* - * This is a module for the Linux joystick driver, supporting - * Gravis GrIP digital joystick family. - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define JS_GR_MODE_GPP 1 -#define JS_GR_LENGTH_GPP 24 -#define JS_GR_STROBE_GPP 400 - -#define JS_GR_MODE_XT 2 -#define JS_GR_MODE_BD 3 -#define JS_GR_LENGTH_XT 4 -#define JS_GR_STROBE_XT 200 -#define JS_GR_MAX_CHUNKS_XT 10 -#define JS_GR_MAX_BITS_XT 30 - -static int js_gr_port_list[] __initdata = {0x201, 0}; -static struct js_port* js_gr_port __initdata = NULL; - -struct js_gr_info { - int io; - unsigned char mode[2]; -}; - -/* - * js_gr_gpp_read_packet() reads a Gravis GamePad Pro packet. - */ - -static int js_gr_gpp_read_packet(int io, int shift, unsigned int *data) -{ - unsigned long flags; - unsigned char u, v; - unsigned int t, p; - int i; - - i = 0; - data[0] = 0; - p = t = JS_GR_STROBE_GPP; - p += JS_GR_STROBE_GPP; - - __save_flags(flags); - __cli(); - - v = inb(io) >> shift; - - do { - t--; - u = v; v = (inb(io) >> shift) & 3; - if (~v & u & 1) { - data[0] |= (v >> 1) << i++; - p = t = (p - t) << 1; - } - } while (i < JS_GR_LENGTH_GPP && t > 0); - - __restore_flags(flags); - - if (i < JS_GR_LENGTH_GPP) return -1; - - for (i = 0; i < JS_GR_LENGTH_GPP && (data[0] & 0xfe4210) ^ 0x7c0000; i++) - data[0] = data[0] >> 1 | (data[0] & 1) << (JS_GR_LENGTH_GPP - 1); - - return -(i == JS_GR_LENGTH_GPP); -} - -/* - * js_gr_xt_read_packet() reads a Gravis Xterminator packet. - */ - -static int js_gr_xt_read_packet(int io, int shift, unsigned int *data) -{ - unsigned int i, j, buf, crc; - unsigned char u, v, w; - unsigned long flags; - unsigned int t, p; - char status; - - data[0] = data[1] = data[2] = data[3] = 0; - status = buf = i = j = 0; - p = t = JS_GR_STROBE_XT; - p += JS_GR_STROBE_XT; - - __save_flags(flags); - __cli(); - - v = w = (inb(io) >> shift) & 3; - - do { - t--; - u = (inb(io) >> shift) & 3; - - if (u ^ v) { - - if ((u ^ v) & 1) { - p = t = (p - t) << 2; - buf = (buf << 1) | (u >> 1); - i++; - } else - - if ((((u ^ v) & (v ^ w)) >> 1) & ~(u | v | w) & 1) { - p = t = (p - t) << 2; - if (i == 20) { - crc = buf ^ (buf >> 7) ^ (buf >> 14); - if (!((crc ^ (0x25cb9e70 >> ((crc >> 2) & 0x1c))) & 0xf)) { - data[buf >> 18] = buf >> 4; - status |= 1 << (buf >> 18); - } - j++; - } - buf = 0; - i = 0; - } - - w = v; - v = u; - } - - } while (status != 0xf && i < JS_GR_MAX_BITS_XT && j < JS_GR_MAX_CHUNKS_XT && t > 0); - - __restore_flags(flags); - - return -(status != 0xf); -} - -/* - * js_gr_read() reads and analyzes GrIP joystick data. - */ - -static int js_gr_read(void *xinfo, int **axes, int **buttons) -{ - struct js_gr_info *info = xinfo; - unsigned int data[JS_GR_LENGTH_XT]; - int i; - - for (i = 0; i < 2; i++) - switch (info->mode[i]) { - - case JS_GR_MODE_GPP: - - if (js_gr_gpp_read_packet(info->io, (i << 1) + 4, data)) return -1; - - axes[i][0] = ((data[0] >> 15) & 1) - ((data[0] >> 16) & 1); - axes[i][1] = ((data[0] >> 13) & 1) - ((data[0] >> 12) & 1); - - data[0] = ((data[0] >> 6) & 0x37) | (data[0] & 0x08) | ((data[0] << 1) & 0x40) | - ((data[0] << 5) & 0x80) | ((data[0] << 8) & 0x300); - - buttons[i][0] = (data[0] & 0xfc) | ((data[0] >> 1) & 0x101) | ((data[0] << 1) & 0x202); - - break; - - case JS_GR_MODE_XT: - - if (js_gr_xt_read_packet(info->io, (i << 1) + 4, data)) return -1; - - axes[i][0] = (data[0] >> 2) & 0x3f; - axes[i][1] = 63 - ((data[0] >> 8) & 0x3f); - axes[i][2] = (data[1] >> 2) & 0x3f; - axes[i][3] = (data[1] >> 8) & 0x3f; - axes[i][4] = (data[2] >> 8) & 0x3f; - - axes[i][5] = ((data[2] >> 1) & 1) - ( data[2] & 1); - axes[i][6] = ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1); - axes[i][7] = ((data[2] >> 5) & 1) - ((data[2] >> 4) & 1); - axes[i][8] = ((data[2] >> 6) & 1) - ((data[2] >> 7) & 1); - - buttons[i][0] = (data[3] >> 3) & 0x7ff; - - break; - - case JS_GR_MODE_BD: - - if (js_gr_xt_read_packet(info->io, (i << 1) + 4, data)) return -1; - - axes[i][0] = (data[0] >> 2) & 0x3f; - axes[i][1] = 63 - ((data[0] >> 8) & 0x3f); - axes[i][2] = (data[2] >> 8) & 0x3f; - - axes[i][3] = ((data[2] >> 1) & 1) - ( data[2] & 1); - axes[i][4] = ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1); - - buttons[i][0] = ((data[3] >> 6) & 0x01) | ((data[3] >> 3) & 0x06) - | ((data[3] >> 4) & 0x18); - - break; - - default: - break; - - } - - - return 0; -} - -/* - * js_gr_open() is a callback from the file open routine. - */ - -static int js_gr_open(struct js_dev *jd) -{ - MOD_INC_USE_COUNT; - return 0; -} - -/* - * js_gr_close() is a callback from the file release routine. - */ - -static int js_gr_close(struct js_dev *jd) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -/* - * js_gr_init_corr() initializes correction values of - * GrIP joysticks. - */ - -static void __init js_gr_init_corr(int mode, struct js_corr *corr) -{ - int i; - - switch (mode) { - - case JS_GR_MODE_GPP: - - for (i = 0; i < 2; i++) { - corr[i].type = JS_CORR_BROKEN; - corr[i].prec = 0; - corr[i].coef[0] = 0; - corr[i].coef[1] = 0; - corr[i].coef[2] = (1 << 29); - corr[i].coef[3] = (1 << 29); - } - - break; - - case JS_GR_MODE_XT: - - for (i = 0; i < 5; i++) { - corr[i].type = JS_CORR_BROKEN; - corr[i].prec = 0; - corr[i].coef[0] = 31 - 4; - corr[i].coef[1] = 32 + 4; - corr[i].coef[2] = (1 << 29) / (32 - 14); - corr[i].coef[3] = (1 << 29) / (32 - 14); - } - - for (i = 5; i < 9; i++) { - corr[i].type = JS_CORR_BROKEN; - corr[i].prec = 0; - corr[i].coef[0] = 0; - corr[i].coef[1] = 0; - corr[i].coef[2] = (1 << 29); - corr[i].coef[3] = (1 << 29); - } - - break; - - case JS_GR_MODE_BD: - - for (i = 0; i < 3; i++) { - corr[i].type = JS_CORR_BROKEN; - corr[i].prec = 0; - corr[i].coef[0] = 31 - 4; - corr[i].coef[1] = 32 + 4; - corr[i].coef[2] = (1 << 29) / (32 - 14); - corr[i].coef[3] = (1 << 29) / (32 - 14); - } - - for (i = 3; i < 5; i++) { - corr[i].type = JS_CORR_BROKEN; - corr[i].prec = 0; - corr[i].coef[0] = 0; - corr[i].coef[1] = 0; - corr[i].coef[2] = (1 << 29); - corr[i].coef[3] = (1 << 29); - } - - break; - - } -} - -/* - * js_gr_probe() probes for GrIP joysticks. - */ - -static struct js_port __init *js_gr_probe(int io, struct js_port *port) -{ - struct js_gr_info info; - char *names[] = { NULL, "Gravis GamePad Pro", "Gravis Xterminator", "Gravis Blackhawk Digital"}; - char axes[] = { 0, 2, 9, 5}; - char buttons[] = { 0, 10, 11, 5}; - unsigned int data[JS_GR_LENGTH_XT]; - int i; - - if (check_region(io, 1)) return port; - - info.mode[0] = info.mode[1] = 0; - - for (i = 0; i < 2; i++) { - if (!js_gr_gpp_read_packet(io, (i << 1) + 4, data)) info.mode[i] = JS_GR_MODE_GPP; - if (!js_gr_xt_read_packet(io, (i << 1) + 4, data)) { - if ((data[3] & 7) == 7) - info.mode[i] = JS_GR_MODE_XT; - if ((data[3] & 7) == 0) - info.mode[i] = JS_GR_MODE_BD; - } - } - - if (!info.mode[0] && !info.mode[1]) return port; - - info.io = io; - - request_region(io, 1, "joystick (gravis)"); - port = js_register_port(port, &info, 2, sizeof(struct js_gr_info), js_gr_read); - - for (i = 0; i < 2; i++) - if (info.mode[i]) { - printk(KERN_INFO "js%d: %s at %#x\n", - js_register_device(port, i, axes[info.mode[i]], buttons[info.mode[i]], - names[info.mode[i]], js_gr_open, js_gr_close), - names[info.mode[i]], io); - js_gr_init_corr(info.mode[i], port->corr[i]); - } - - return port; -} - -#ifdef MODULE -int init_module(void) -#else -int __init js_gr_init(void) -#endif -{ - int *p; - - for (p = js_gr_port_list; *p; p++) js_gr_port = js_gr_probe(*p, js_gr_port); - if (js_gr_port) return 0; - -#ifdef MODULE - printk(KERN_WARNING "joy-gravis: no joysticks found\n"); -#endif - - return -ENODEV; -} - -#ifdef MODULE -void cleanup_module(void) -{ - int i; - struct js_gr_info *info; - - while (js_gr_port) { - for (i = 0; i < js_gr_port->ndevs; i++) - if (js_gr_port->devs[i]) - js_unregister_device(js_gr_port->devs[i]); - info = js_gr_port->info; - release_region(info->io, 1); - js_gr_port = js_unregister_port(js_gr_port); - } -} -#endif diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/joy-lightning.c linux/drivers/char/joystick/joy-lightning.c --- v2.4.0-test1/linux/drivers/char/joystick/joy-lightning.c Wed Dec 8 14:11:26 1999 +++ linux/drivers/char/joystick/joy-lightning.c Wed Dec 31 16:00:00 1969 @@ -1,371 +0,0 @@ -/* - * joy-lightning.c Version 1.2 - * - * Copyright (c) 1998-1999 Vojtech Pavlik - * - * Sponsored by SuSE - */ - -/* - * This is a module for the Linux joystick driver, supporting - * PDPI Lightning 4 gamecards and analog joysticks connected - * to them. - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define JS_L4_PORT 0x201 -#define JS_L4_SELECT_ANALOG 0xa4 -#define JS_L4_SELECT_DIGITAL 0xa5 -#define JS_L4_SELECT_SECONDARY 0xa6 -#define JS_L4_CMD_ID 0x80 -#define JS_L4_CMD_GETCAL 0x92 -#define JS_L4_CMD_SETCAL 0x93 -#define JS_L4_ID 0x04 -#define JS_L4_BUSY 0x01 -#define JS_L4_TIMEOUT 80 /* 80 us */ - -static struct js_port* __initdata js_l4_port = NULL; - -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_PARM(js_l4, "2-24i"); - -static int __initdata js_l4[] = { -1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 }; - -#include "joy-analog.h" - -struct js_l4_info { - int port; - struct js_an_info an; -}; - -/* - * js_l4_wait_ready() waits for the L4 to become ready. - */ - -static int js_l4_wait_ready(void) -{ - unsigned int t; - t = JS_L4_TIMEOUT; - while ((inb(JS_L4_PORT) & JS_L4_BUSY) && t > 0) t--; - return -(t<=0); -} - -/* - * js_l4_read() reads data from the Lightning 4. - */ - -static int js_l4_read(void *xinfo, int **axes, int **buttons) -{ - struct js_l4_info *info = xinfo; - int i; - unsigned char status; - - outb(JS_L4_SELECT_ANALOG, JS_L4_PORT); - outb(JS_L4_SELECT_DIGITAL + (info->port >> 2), JS_L4_PORT); - - if (inb(JS_L4_PORT) & JS_L4_BUSY) return -1; - outb(info->port & 3, JS_L4_PORT); - - if (js_l4_wait_ready()) return -1; - status = inb(JS_L4_PORT); - - for (i = 0; i < 4; i++) - if (status & (1 << i)) { - if (js_l4_wait_ready()) return -1; - info->an.axes[i] = inb(JS_L4_PORT); - } - - if (status & 0x10) { - if (js_l4_wait_ready()) return -1; - info->an.buttons = inb(JS_L4_PORT); - } - - js_an_decode(&info->an, axes, buttons); - - return 0; -} - -/* - * js_l4_getcal() reads the L4 with calibration values. - */ - -static int js_l4_getcal(int port, int *cal) -{ - int i; - - outb(JS_L4_SELECT_ANALOG, JS_L4_PORT); - outb(JS_L4_SELECT_DIGITAL + (port >> 2), JS_L4_PORT); - - if (inb(JS_L4_PORT) & JS_L4_BUSY) return -1; - outb(JS_L4_CMD_GETCAL, JS_L4_PORT); - - if (js_l4_wait_ready()) return -1; - if (inb(JS_L4_PORT) != JS_L4_SELECT_DIGITAL + (port >> 2)) return -1; - - if (js_l4_wait_ready()) return -1; - outb(port & 3, JS_L4_PORT); - - for (i = 0; i < 4; i++) { - if (js_l4_wait_ready()) return -1; - cal[i] = inb(JS_L4_PORT); - } - - return 0; -} - -/* - * js_l4_setcal() programs the L4 with calibration values. - */ - -static int js_l4_setcal(int port, int *cal) -{ - int i; - - outb(JS_L4_SELECT_ANALOG, JS_L4_PORT); - outb(JS_L4_SELECT_DIGITAL + (port >> 2), JS_L4_PORT); - - if (inb(JS_L4_PORT) & JS_L4_BUSY) return -1; - outb(JS_L4_CMD_SETCAL, JS_L4_PORT); - - if (js_l4_wait_ready()) return -1; - if (inb(JS_L4_PORT) != JS_L4_SELECT_DIGITAL + (port >> 2)) return -1; - - if (js_l4_wait_ready()) return -1; - outb(port & 3, JS_L4_PORT); - - for (i = 0; i < 4; i++) { - if (js_l4_wait_ready()) return -1; - outb(cal[i], JS_L4_PORT); - } - - return 0; -} - -/* - * js_l4_calibrate() calibrates the L4 for the attached device, so - * that the device's resistance fits into the L4's 8-bit range. - */ - -static void js_l4_calibrate(struct js_l4_info *info) -{ - int i; - int cal[4]; - int axes[4]; - int t; - - js_l4_getcal(info->port, cal); - - for (i = 0; i < 4; i++) - axes[i] = info->an.axes[i]; - - if ((info->an.extensions & JS_AN_BUTTON_PXY_X) && !(info->an.extensions & JS_AN_BUTTON_PXY_U)) - axes[2] >>= 1; /* Pad button X */ - - if ((info->an.extensions & JS_AN_BUTTON_PXY_Y) && !(info->an.extensions & JS_AN_BUTTON_PXY_V)) - axes[3] >>= 1; /* Pad button Y */ - - if (info->an.extensions & JS_AN_HAT_FCS) - axes[3] >>= 1; /* FCS hat */ - - if (((info->an.mask[0] & 0xb) == 0xb) || ((info->an.mask[1] & 0xb) == 0xb)) - axes[3] = (axes[0] + axes[1]) >> 1; /* Throttle */ - - for (i = 0; i < 4; i++) { - t = (axes[i] * cal[i]) / 100; - if (t > 255) t = 255; - info->an.axes[i] = (info->an.axes[i] * cal[i]) / t; - cal[i] = t; - } - - js_l4_setcal(info->port, cal); -} - -/* - * js_l4_open() is a callback from the file open routine. - */ - -static int js_l4_open(struct js_dev *jd) -{ - MOD_INC_USE_COUNT; - return 0; -} - -/* - * js_l4_close() is a callback from the file release routine. - */ - -static int js_l4_close(struct js_dev *jd) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -/* - * js_l4_probe() probes for joysticks on the L4 cards. - */ - -static struct js_port __init *js_l4_probe(unsigned char *cards, int l4port, int mask0, int mask1, struct js_port *port) -{ - struct js_l4_info iniinfo; - struct js_l4_info *info = &iniinfo; - int cal[4] = {255,255,255,255}; - int i, numdev; - unsigned char u; - - if (l4port < 0) return port; - if (!cards[(l4port >> 2)]) return port; - - memset(info, 0, sizeof(struct js_l4_info)); - info->port = l4port; - - if (cards[l4port >> 2] > 0x28) js_l4_setcal(info->port, cal); - if (js_l4_read(info, NULL, NULL)) return port; - - for (i = u = 0; i < 4; i++) if (info->an.axes[i] < 253) u |= 1 << i; - - if ((numdev = js_an_probe_devs(&info->an, u, mask0, mask1, port)) <= 0) - return port; - - port = js_register_port(port, info, numdev, sizeof(struct js_l4_info), js_l4_read); - - info = port->info; - - for (i = 0; i < numdev; i++) - printk(KERN_INFO "js%d: %s on L4 port %d\n", - js_register_device(port, i, js_an_axes(i, &info->an), js_an_buttons(i, &info->an), - js_an_name(i, &info->an), js_l4_open, js_l4_close), - js_an_name(i, &info->an), info->port); - - js_l4_calibrate(info); - js_l4_read(info, port->axes, port->buttons); - js_an_init_corr(&info->an, port->axes, port->corr, 0); - - return port; -} - -/* - * js_l4_card_probe() probes for presence of the L4 card(s). - */ - -static void __init js_l4_card_probe(unsigned char *cards) -{ - int i; - unsigned char rev = 0; - - if (check_region(JS_L4_PORT, 1)) return; - - for (i = 0; i < 2; i++) { - - outb(JS_L4_SELECT_ANALOG, JS_L4_PORT); - outb(JS_L4_SELECT_DIGITAL + i, JS_L4_PORT); /* Select card 0-1 */ - - if (inb(JS_L4_PORT) & JS_L4_BUSY) continue; - outb(JS_L4_CMD_ID, JS_L4_PORT); /* Get card ID & rev */ - - if (js_l4_wait_ready()) continue; - if (inb(JS_L4_PORT) != JS_L4_SELECT_DIGITAL + i) continue; - - if (js_l4_wait_ready()) continue; - if (inb(JS_L4_PORT) != JS_L4_ID) continue; - - if (js_l4_wait_ready()) continue; - rev = inb(JS_L4_PORT); - - cards[i] = rev; - - printk(KERN_INFO "js: PDPI Lightning 4 %s card (ports %d-%d) firmware v%d.%d at %#x\n", - i ? "secondary" : "primary", (i << 2), (i << 2) + 3, rev >> 4, rev & 0xf, JS_L4_PORT); - } - -} - -#ifndef MODULE -int __init js_l4_setup(SETUP_PARAM) -{ - int i; - SETUP_PARSE(24); - for (i = 0; i <= ints[0] && i < 24; i++) js_l4[i] = ints[i+1]; - return 1; -} -__setup("js_l4=", js_l4_setup); -#endif - -#ifdef MODULE -int init_module(void) -#else -int __init js_l4_init(void) -#endif -{ - int i; - unsigned char cards[2] = {0, 0}; - - js_l4_card_probe(cards); - - if (js_l4[0] >= 0) { - for (i = 0; (js_l4[i*3] >= 0) && i < 8; i++) - js_l4_port = js_l4_probe(cards, js_l4[i*3], js_l4[i*3+1], js_l4[i*3+2], js_l4_port); - } else { - for (i = 0; i < 8; i++) - js_l4_port = js_l4_probe(cards, i, 0, 0, js_l4_port); - } - - if (!js_l4_port) { -#ifdef MODULE - printk(KERN_WARNING "joy-lightning: no joysticks found\n"); -#endif - return -ENODEV; - } - - request_region(JS_L4_PORT, 1, "joystick (lightning)"); - - return 0; -} - -#ifdef MODULE -void cleanup_module(void) -{ - int i; - int cal[4] = {59, 59, 59, 59}; - struct js_l4_info *info; - - while (js_l4_port) { - for (i = 0; i < js_l4_port->ndevs; i++) - if (js_l4_port->devs[i]) - js_unregister_device(js_l4_port->devs[i]); - info = js_l4_port->info; - js_l4_setcal(info->port, cal); - js_l4_port = js_unregister_port(js_l4_port); - } - outb(JS_L4_SELECT_ANALOG, JS_L4_PORT); - release_region(JS_L4_PORT, 1); -} -#endif diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/joy-logitech.c linux/drivers/char/joystick/joy-logitech.c --- v2.4.0-test1/linux/drivers/char/joystick/joy-logitech.c Wed Dec 8 14:11:26 1999 +++ linux/drivers/char/joystick/joy-logitech.c Wed Dec 31 16:00:00 1969 @@ -1,554 +0,0 @@ -/* - * joy-logitech.c Version 1.2 - * - * Copyright (c) 1998-1999 Vojtech Pavlik - * - * Sponsored by SuSE - */ - -/* - * This is a module for the Linux joystick driver, supporting - * Logitech ADI joystick family. - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Times array sizes, flags, ids. - */ - -#undef JS_LT_DEBUG - -#define JS_LT_MAX_START 400 /* Trigger to packet timeout [400us] */ - -#define JS_LT_MAX_LENGTH 256 -#define JS_LT_MIN_LENGTH 8 -#define JS_LT_MIN_LEN_LENGTH 10 -#define JS_LT_MIN_ID_LENGTH 66 -#define JS_LT_MAX_NAME_LENGTH 16 - -#define JS_LT_INIT_DELAY 10 /* Delay after init packet [10ms] */ -#define JS_LT_DATA_DELAY 4 /* Delay after data packet [4ms] */ - -#define JS_LT_FLAG_HAT 0x04 -#define JS_LT_FLAG_10BIT 0x08 - -#define JS_LT_ID_WMED 0x00 -#define JS_LT_ID_TPD 0x01 -#define JS_LT_ID_WMI 0x04 -#define JS_LT_ID_WGP 0x06 -#define JS_LT_ID_WM3D 0x07 -#define JS_LT_ID_WGPE 0x08 - -#define JS_LT_BUG_BUTTONS 0x01 -#define JS_LT_BUG_LONGID 0x02 -#define JS_LT_BUG_LONGDATA 0x04 -#define JS_LT_BUG_IGNTRIG 0x08 - -/* - * Port probing variables. - */ - -static int js_lt_port_list[] __initdata = { 0x201, 0 }; -static struct js_port* js_lt_port __initdata = NULL; - -/* - * Device names. - */ - -#define JS_LT_MAX_ID 10 - -static char *js_lt_names[] = { "WingMan Extreme Digital", "ThunderPad Digital", "SideCar", "CyberMan 2", - "WingMan Interceptor", "WingMan Formula", "WingMan GamePad", - "WingMan Extreme Digital 3D", "WingMan GamePad Extreme", - "WingMan GamePad USB", "Unknown Device %#x"}; - -/* - * Hat to axis conversion arrays. - */ - -static struct { - int x; - int y; -} js_lt_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; - -/* - * Per-port information. - */ - -struct js_lt_info { - int io; - int length[2]; - int ret[2]; - int idx[2]; - unsigned char id[2]; - char buttons[2]; - char axes10[2]; - char axes8[2]; - char pad[2]; - char hats[2]; - char name[2][JS_LT_MAX_NAME_LENGTH]; - unsigned char data[2][JS_LT_MAX_LENGTH]; - char bugs[2]; -}; - -/* - * js_lt_read_packet() reads a Logitech ADI packet. - */ - -static void js_lt_read_packet(struct js_lt_info *info) -{ - unsigned char u, v, w, x, z; - int t[2], s[2], p[2], i; - unsigned long flags; - - for (i = 0; i < 2; i++) { - info->ret[i] = -1; - p[i] = t[i] = JS_LT_MAX_START; - s[i] = 0; - } - - __save_flags(flags); - __cli(); - - outb(0xff, info->io); - v = z = inb(info->io); - - do { - u = v; - w = u ^ (v = x = inb(info->io)); - for (i = 0; i < 2; i++, w >>= 2, x >>= 2) { - t[i]--; - if ((w & 0x30) && s[i]) { - if ((w & 0x30) < 0x30 && info->ret[i] < JS_LT_MAX_LENGTH && t[i] > 0) { - info->data[i][++info->ret[i]] = w; - p[i] = t[i] = (p[i] - t[i]) << 1; - } else t[i] = 0; - } else if (!(x & 0x30)) s[i] = 1; - } - } while (t[0] > 0 || t[1] > 0); - - __restore_flags(flags); - - for (i = 0; i < 2; i++, z >>= 2) - if ((z & 0x30) && info->ret[i] > 0) - info->bugs[i] |= JS_LT_BUG_BUTTONS; - -#ifdef JS_LT_DEBUG - printk(KERN_DEBUG "joy-logitech: read %d %d bits\n", info->ret[0], info->ret[1]); - printk(KERN_DEBUG "joy-logitech: stream0:"); - for (i = 0; i <= info->ret[0]; i++) printk("%d", (info->data[0][i] >> 5) & 1); - printk("\n"); - printk(KERN_DEBUG "joy-logitech: stream1:"); - for (i = 0; i <= info->ret[1]; i++) printk("%d", (info->data[1][i] >> 5) & 1); - printk("\n"); -#endif - - return; -} - -/* - * js_lt_move_bits() detects a possible 2-stream mode, and moves - * the bits accordingly. - */ - -static void js_lt_move_bits(struct js_lt_info *info, int length) -{ - int i; - - info->idx[0] = info->idx[1] = 0; - - if (info->ret[0] <= 0 || info->ret[1] <= 0) return; - if (info->data[0][0] & 0x20 || ~info->data[1][0] & 0x20) return; - - for (i = 1; i <= info->ret[1]; i++) - info->data[0][((length - 1) >> 1) + i + 1] = info->data[1][i]; - - info->ret[0] += info->ret[1]; - info->ret[1] = -1; -} - -/* - * js_lt_get_bits() gathers bits from the data packet. - */ - -static inline int js_lt_get_bits(struct js_lt_info *info, int device, int count) -{ - int bits = 0; - int i; - if ((info->idx[device] += count) > info->ret[device]) return 0; - for (i = 0; i < count; i++) bits |= ((info->data[device][info->idx[device] - i] >> 5) & 1) << i; - return bits; -} - -/* - * js_lt_read() reads and analyzes Logitech joystick data. - */ - -static int js_lt_read(void *xinfo, int **axes, int **buttons) -{ - struct js_lt_info *info = xinfo; - int i, j, k, l, t; - int ret = 0; - - js_lt_read_packet(info); - js_lt_move_bits(info, info->length[0]); - - for (i = 0; i < 2; i++) { - - if (!info->length[i]) continue; - - if (info->length[i] > info->ret[i] || - info->id[i] != (js_lt_get_bits(info, i, 4) | (js_lt_get_bits(info, i, 4) << 4))) { - ret = -1; - continue; - } - - if (info->length[i] < info->ret[i]) - info->bugs[i] |= JS_LT_BUG_LONGDATA; - - k = l = 0; - - for (j = 0; j < info->axes10[i]; j++) - axes[i][k++] = js_lt_get_bits(info, i, 10); - - for (j = 0; j < info->axes8[i]; j++) - axes[i][k++] = js_lt_get_bits(info, i, 8); - - for (j = 0; j <= (info->buttons[i] - 1) >> 5; j++) buttons[i][j] = 0; - - for (j = 0; j < info->buttons[i] && j < 63; j++) { - if (j == info->pad[i]) { - t = js_lt_get_bits(info, i, 4); - axes[i][k++] = ((t >> 2) & 1) - ( t & 1); - axes[i][k++] = ((t >> 1) & 1) - ((t >> 3) & 1); - } - buttons[i][l >> 5] |= js_lt_get_bits(info, i, 1) << (l & 0x1f); - l++; - } - - for (j = 0; j < info->hats[i]; j++) { - if((t = js_lt_get_bits(info, i, 4)) > 8) { - if (t != 15) ret = -1; /* Hat press */ - t = 0; - } - axes[i][k++] = js_lt_hat_to_axis[t].x; - axes[i][k++] = js_lt_hat_to_axis[t].y; - } - - for (j = 63; j < info->buttons[i]; j++) { - buttons[i][l >> 5] |= js_lt_get_bits(info, i, 1) << (l & 0x1f); - l++; - } - } - - return ret; -} - -/* - * js_lt_open() is a callback from the file open routine. - */ - -static int js_lt_open(struct js_dev *jd) -{ - MOD_INC_USE_COUNT; - return 0; -} - -/* - * js_lt_close() is a callback from the file release routine. - */ - -static int js_lt_close(struct js_dev *jd) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -/* - * js_lt_init_digital() sends a trigger & delay sequence - * to reset and initialize a Logitech joystick into digital mode. - */ - -static void __init js_lt_init_digital(int io) -{ - int seq[] = { 3, 2, 3, 10, 6, 11, 7, 9, 11, 0 }; - int i; - - for (i = 0; seq[i]; i++) { - outb(0xff,io); - mdelay(seq[i]); - } -} - -/* - * js_lt_init_corr() initializes the correction values for - * Logitech joysticks. - */ - -static void __init js_lt_init_corr(int id, int naxes10, int naxes8, int naxes1, int *axes, struct js_corr *corr) -{ - int j; - - if (id == JS_LT_ID_WMED) axes[2] = 128; /* Throttle fixup */ - if (id == JS_LT_ID_WMI) axes[2] = 512; - if (id == JS_LT_ID_WM3D) axes[3] = 128; - - if (id == JS_LT_ID_WGPE) { /* Tilt fixup */ - axes[0] = 512; - axes[1] = 512; - } - - for (j = 0; j < naxes10; j++) { - corr[j].type = JS_CORR_BROKEN; - corr[j].prec = 2; - corr[j].coef[0] = axes[j] - 16; - corr[j].coef[1] = axes[j] + 16; - corr[j].coef[2] = (1 << 29) / (256 - 32); - corr[j].coef[3] = (1 << 29) / (256 - 32); - } - - for (; j < naxes8 + naxes10; j++) { - corr[j].type = JS_CORR_BROKEN; - corr[j].prec = 1; - corr[j].coef[0] = axes[j] - 2; - corr[j].coef[1] = axes[j] + 2; - corr[j].coef[2] = (1 << 29) / (64 - 16); - corr[j].coef[3] = (1 << 29) / (64 - 16); - } - - for (; j < naxes1 + naxes8 + naxes10; j++) { - corr[j].type = JS_CORR_BROKEN; - corr[j].prec = 0; - corr[j].coef[0] = 0; - corr[j].coef[1] = 0; - corr[j].coef[2] = (1 << 29); - corr[j].coef[3] = (1 << 29); - } -} - -/* - * js_lt_probe() probes for Logitech type joysticks. - */ - -static struct js_port __init *js_lt_probe(int io, struct js_port *port) -{ - struct js_lt_info iniinfo; - struct js_lt_info *info = &iniinfo; - char name[32]; - int i, j, t; - - if (check_region(io, 1)) return port; - - js_lt_init_digital(io); - - memset(info, 0, sizeof(struct js_lt_info)); - - info->length[0] = info->length[1] = JS_LT_MAX_LENGTH; - - info->io = io; - js_lt_read_packet(info); - - if (info->ret[0] >= JS_LT_MIN_LEN_LENGTH) - js_lt_move_bits(info, js_lt_get_bits(info, 0, 10)); - - info->length[0] = info->length[1] = 0; - - for (i = 0; i < 2; i++) { - - if (info->ret[i] < JS_LT_MIN_ID_LENGTH) continue; /* Minimum ID packet length */ - - if (info->ret[i] < (t = js_lt_get_bits(info, i, 10))) { - printk(KERN_WARNING "joy-logitech: Short ID packet: reported: %d != read: %d\n", - t, info->ret[i]); - continue; - } - - if (info->ret[i] > t) - info->bugs[i] |= JS_LT_BUG_LONGID; - -#ifdef JS_LT_DEBUG - printk(KERN_DEBUG "joy-logitech: id %d length %d", i, t); -#endif - - info->id[i] = js_lt_get_bits(info, i, 4) | (js_lt_get_bits(info, i, 4) << 4); - - if ((t = js_lt_get_bits(info, i, 4)) & JS_LT_FLAG_HAT) info->hats[i]++; - -#ifdef JS_LT_DEBUG - printk(KERN_DEBUG "joy-logitech: id %d flags %d", i, t); -#endif - - if ((info->length[i] = js_lt_get_bits(info, i, 10)) >= JS_LT_MAX_LENGTH) { - printk(KERN_WARNING "joy-logitech: Expected packet length too long (%d).\n", - info->length[i]); - continue; - } - - if (info->length[i] < JS_LT_MIN_LENGTH) { - printk(KERN_WARNING "joy-logitech: Expected packet length too short (%d).\n", - info->length[i]); - continue; - } - - info->axes8[i] = js_lt_get_bits(info, i, 4); - info->buttons[i] = js_lt_get_bits(info, i, 6); - - if (js_lt_get_bits(info, i, 6) != 8 && info->hats[i]) { - printk(KERN_WARNING "joy-logitech: Other than 8-dir POVs not supported yet.\n"); - continue; - } - - info->buttons[i] += js_lt_get_bits(info, i, 6); - info->hats[i] += js_lt_get_bits(info, i, 4); - - j = js_lt_get_bits(info, i, 4); - - if (t & JS_LT_FLAG_10BIT) { - info->axes10[i] = info->axes8[i] - j; - info->axes8[i] = j; - } - - t = js_lt_get_bits(info, i, 4); - - for (j = 0; j < t; j++) - info->name[i][j] = js_lt_get_bits(info, i, 8); - info->name[i][j] = 0; - - switch (info->id[i]) { - case JS_LT_ID_TPD: - info->pad[i] = 4; - info->buttons[i] -= 4; - break; - case JS_LT_ID_WGP: - info->pad[i] = 0; - info->buttons[i] -= 4; - break; - default: - info->pad[i] = -1; - break; - } - - if (info->length[i] != - (t = 8 + info->buttons[i] + info->axes10[i] * 10 + info->axes8[i] * 8 + - info->hats[i] * 4 + (info->pad[i] != -1) * 4)) { - printk(KERN_WARNING "js%d: Expected lenght %d != data length %d\n", i, t, info->length[i]); - } - - } - - if (!info->length[0] && !info->length[1]) - return port; - - request_region(io, 1, "joystick (logitech)"); - - port = js_register_port(port, info, 2, sizeof(struct js_lt_info), js_lt_read); - info = port->info; - - for (i = 0; i < 2; i++) - if (info->length[i] > 0) { - sprintf(name, info->id[i] < JS_LT_MAX_ID ? - js_lt_names[info->id[i]] : js_lt_names[JS_LT_MAX_ID], info->id[i]); - printk(KERN_INFO "js%d: %s [%s] at %#x\n", - js_register_device(port, i, - info->axes10[i] + info->axes8[i] + ((info->hats[i] + (info->pad[i] >= 0)) << 1), - info->buttons[i], name, js_lt_open, js_lt_close), name, info->name[i], io); - } - - mdelay(JS_LT_INIT_DELAY); - if (js_lt_read(info, port->axes, port->buttons)) { - if (info->ret[0] < 1) info->bugs[0] |= JS_LT_BUG_IGNTRIG; - if (info->ret[1] < 1) info->bugs[1] |= JS_LT_BUG_IGNTRIG; - mdelay(JS_LT_DATA_DELAY); - js_lt_read(info, port->axes, port->buttons); - } - - for (i = 0; i < 2; i++) - if (info->length[i] > 0) { -#ifdef JS_LT_DEBUG - printk(KERN_DEBUG "js%d: length %d ret %d id %d buttons %d axes10 %d axes8 %d " - "pad %d hats %d name %s explen %d\n", - i, info->length[i], info->ret[i], info->id[i], - info->buttons[i], info->axes10[i], info->axes8[i], - info->pad[i], info->hats[i], info->name[i], - 8 + info->buttons[i] + info->axes10[i] * 10 + info->axes8[i] * 8 + - info->hats[i] * 4 + (info->pad[i] != -1) * 4); -#endif - if (info->bugs[i]) { - printk(KERN_WARNING "js%d: Firmware bugs detected:%s%s%s%s\n", i, - info->bugs[i] & JS_LT_BUG_BUTTONS ? " init_buttons" : "", - info->bugs[i] & JS_LT_BUG_LONGID ? " long_id" : "", - info->bugs[i] & JS_LT_BUG_LONGDATA ? " long_data" : "", - info->bugs[i] & JS_LT_BUG_IGNTRIG ? " ignore_trigger" : ""); - } - js_lt_init_corr(info->id[i], info->axes10[i], info->axes8[i], - ((info->pad[i] >= 0) + info->hats[i]) << 1, port->axes[i], port->corr[i]); - } - - return port; -} - -#ifdef MODULE -int init_module(void) -#else -int __init js_lt_init(void) -#endif -{ - int *p; - - for (p = js_lt_port_list; *p; p++) js_lt_port = js_lt_probe(*p, js_lt_port); - if (js_lt_port) return 0; - -#ifdef MODULE - printk(KERN_WARNING "joy-logitech: no joysticks found\n"); -#endif - - return -ENODEV; -} - -#ifdef MODULE -void cleanup_module(void) -{ - int i; - struct js_lt_info *info; - - while (js_lt_port) { - for (i = 0; i < js_lt_port->ndevs; i++) - if (js_lt_port->devs[i]) - js_unregister_device(js_lt_port->devs[i]); - info = js_lt_port->info; - release_region(info->io, 1); - js_lt_port = js_unregister_port(js_lt_port); - } -} -#endif diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/joy-magellan.c linux/drivers/char/joystick/joy-magellan.c --- v2.4.0-test1/linux/drivers/char/joystick/joy-magellan.c Wed Dec 8 14:11:26 1999 +++ linux/drivers/char/joystick/joy-magellan.c Wed Dec 31 16:00:00 1969 @@ -1,397 +0,0 @@ -/* - * joy-magellan.c Version 0.1 - * - * Copyright (c) 1999 Vojtech Pavlik - * - * Sponsored by SuSE - */ - -/* - * This is a module for the Linux joystick driver, supporting - * the Magellan and Space Mouse 6dof controllers. - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Constants. - */ - -#define N_JOYSTICK_MAG 14 -#define JS_MAG_MAX_LENGTH 64 - -/* - * List of Magellans. - */ - -static struct js_port* js_mag_port = NULL; - -/* - * Per-Magellan data. - */ - -struct js_mag_info { - struct tty_struct* tty; - struct js_port* port; - int idx; - unsigned char data[JS_MAG_MAX_LENGTH]; - unsigned char name[JS_MAG_MAX_LENGTH]; - char ack; - char used; -}; - -/* - * js_mag_crunch_nibbles() verifies that the bytes sent from the Magellan - * have correct upper nibbles for the lower ones, if not, the packet will - * be thrown away. It also strips these upper halves to simplify further - * processing. - */ - -static int js_mag_crunch_nibbles(unsigned char *data, int count) -{ - static unsigned char nibbles[16] = "0AB3D56GH9:Kidx) return; - - switch (info->data[0]) { - - case 'd': /* Axis data */ - if (info->idx != 25) return; - if (js_mag_crunch_nibbles(info->data, 24)) return; - if (!info->port->devs[0]) return; - for (i = 0; i < 6; i++) { - info->port->axes[0][i] = - ( info->data[(i << 2) + 1] << 12 | info->data[(i << 2) + 2] << 8 | - info->data[(i << 2) + 3] << 4 | info->data[(i << 2) + 4] ) - - 32768; - } - break; - - case 'e': /* Error packet */ - if (info->idx != 4) return; - if (js_mag_crunch_nibbles(info->data, 3)) return; - switch (info->data[1]) { - case 1: - printk(KERN_ERR "joy-magellan: Received command error packet. Failing command byte: %c\n", - info->data[2] | (info->data[3] << 4)); - break; - case 2: - printk(KERN_ERR "joy-magellan: Received framing error packet.\n"); - break; - default: - printk(KERN_ERR "joy-magellan: Received unknown error packet.\n"); - } - break; - - case 'k': /* Button data */ - if (info->idx != 4) return; - if (js_mag_crunch_nibbles(info->data, 3)) return; - if (!info->port->devs[0]) return; - info->port->buttons[0][0] = (info->data[1] << 1) | (info->data[2] << 5) | info->data[3]; - break; - - case 'm': /* Mode */ - if (info->idx != 2) return; - if (js_mag_crunch_nibbles(info->data, 1)) return; - break; - - case 'n': /* Null radius */ - if (info->idx != 2) return; - if (js_mag_crunch_nibbles(info->data, 1)) return; - break; - - case 'p': /* Data rate */ - if (info->idx != 3) return; - if (js_mag_crunch_nibbles(info->data, 2)) return; - break; - - case 'q': /* Sensitivity */ - if (info->idx != 3) return; - if (js_mag_crunch_nibbles(info->data, 2)) return; - break; - - case 'v': /* Version string */ - info->data[info->idx] = 0; - for (i = 1; i < info->idx && info->data[i] == ' '; i++); - memcpy(info->name, info->data + i, info->idx - i); - break; - - case 'z': /* Zero position */ - break; - - default: - printk("joy-magellan: Unknown packet %d length %d:", info->data[0], info->idx); - for (i = 0; i < info->idx; i++) printk(" %02x", info->data[i]); - printk("\n"); - return; - } - - info->ack = info->data[0]; -} - -/* - * js_mag_command() sends a command to the Magellan, and waits for - * acknowledge. - */ - -static int js_mag_command(struct js_mag_info *info, char *command, int timeout) -{ - info->ack = 0; - if (info->tty->driver.write(info->tty, 0, command, strlen(command)) != strlen(command)) return -1; - while (!info->ack && timeout--) mdelay(1); - return -(info->ack != command[0]); -} - -/* - * js_mag_setup() initializes the Magellan to sane state. Also works as - * a probe for Magellan existence. - */ - -static int js_mag_setup(struct js_mag_info *info) -{ - - if (js_mag_command(info, "vQ\r", 800)) /* Read version */ - return -1; - if (js_mag_command(info, "m3\r", 50)) /* Set full 3d mode */ - return -1; - if (js_mag_command(info, "pBB\r", 50)) /* Set 16 reports/second (max) */ - return -1; - if (js_mag_command(info, "z\r", 50)) /* Set zero position */ - return -1; - - return 0; -} - -/* - * js_mag_read() updates the axis and button data upon startup. - */ - -static int js_mag_read(struct js_mag_info *info) -{ - memset(info->port->axes[0],0, sizeof(int) * 6); /* Axes are 0 after zero postition cmd */ - - if (js_mag_command(info, "kQ\r", 50)) /* Read buttons */ - return -1; - - return 0; -} - -/* - * js_mag_open() is a callback from the joystick device open routine. - */ - -static int js_mag_open(struct js_dev *jd) -{ - struct js_mag_info *info = jd->port->info; - info->used++; - MOD_INC_USE_COUNT; - return 0; -} - -/* - * js_mag_close() is a callback from the joystick device release routine. - */ - -static int js_mag_close(struct js_dev *jd) -{ - struct js_mag_info *info = jd->port->info; - if (!--info->used) { - js_unregister_device(jd->port->devs[0]); - js_mag_port = js_unregister_port(jd->port); - } - MOD_DEC_USE_COUNT; - return 0; -} - -/* - * js_mag_init_corr() initializes the correction values for the Magellan. - * It asumes gain setting of 0, question is, what we should do for higher - * gain settings ... - */ - -static void js_mag_init_corr(struct js_corr **corr) -{ - int i; - - for (i = 0; i < 6; i++) { - corr[0][i].type = JS_CORR_BROKEN; - corr[0][i].prec = 0; - corr[0][i].coef[0] = 0; - corr[0][i].coef[1] = 0; - corr[0][i].coef[2] = (1 << 29) / 256; - corr[0][i].coef[3] = (1 << 29) / 256; - } -} - -/* - * js_mag_ldisc_open() is the routine that is called upon setting our line - * discipline on a tty. It looks for the Magellan, and if found, registers - * it as a joystick device. - */ - -static int js_mag_ldisc_open(struct tty_struct *tty) -{ - struct js_mag_info iniinfo; - struct js_mag_info *info = &iniinfo; - - info->tty = tty; - info->idx = 0; - info->used = 1; - - js_mag_port = js_register_port(js_mag_port, info, 1, sizeof(struct js_mag_info), NULL); - - info = js_mag_port->info; - info->port = js_mag_port; - tty->disc_data = info; - - if (js_mag_setup(info)) { - js_mag_port = js_unregister_port(info->port); - return -ENODEV; - } - - printk(KERN_INFO "js%d: Magellan [%s] on %s%d\n", - js_register_device(js_mag_port, 0, 6, 9, "Magellan", js_mag_open, js_mag_close), - info->name, tty->driver.name, MINOR(tty->device) - tty->driver.minor_start); - - - js_mag_read(info); - js_mag_init_corr(js_mag_port->corr); - - MOD_INC_USE_COUNT; - - return 0; -} - -/* - * js_mag_ldisc_close() is the opposite of js_mag_ldisc_open() - */ - -static void js_mag_ldisc_close(struct tty_struct *tty) -{ - struct js_mag_info* info = (struct js_mag_info*) tty->disc_data; - if (!--info->used) { - js_unregister_device(info->port->devs[0]); - js_mag_port = js_unregister_port(info->port); - } - MOD_DEC_USE_COUNT; -} - -/* - * js_mag_ldisc_receive() is called by the low level driver when characters - * are ready for us. We then buffer them for further processing, or call the - * packet processing routine. - */ - -static void js_mag_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) -{ - struct js_mag_info* info = (struct js_mag_info*) tty->disc_data; - int i; - - for (i = 0; i < count; i++) - if (cp[i] == '\r') { - js_mag_process_packet(info); - info->idx = 0; - } else { - if (info->idx < JS_MAG_MAX_LENGTH) - info->data[info->idx++] = cp[i]; - } -} - -/* - * js_mag_ldisc_room() reports how much room we do have for receiving data. - * Although we in fact have infinite room, we need to specify some value - * here, so why not the size of our packet buffer. It's big anyway. - */ - -static int js_mag_ldisc_room(struct tty_struct *tty) -{ - return JS_MAG_MAX_LENGTH; -} - -/* - * The line discipline structure. - */ - -static struct tty_ldisc js_mag_ldisc = { - magic: TTY_LDISC_MAGIC, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) - name: "magellan", -#endif - open: js_mag_ldisc_open, - close: js_mag_ldisc_close, - receive_buf: js_mag_ldisc_receive, - receive_room: js_mag_ldisc_room, -}; - -/* - * The functions for inserting/removing us as a module. - */ - -#ifdef MODULE -int init_module(void) -#else -int __init js_mag_init(void) -#endif -{ - if (tty_register_ldisc(N_JOYSTICK_MAG, &js_mag_ldisc)) { - printk(KERN_ERR "joy-magellan: Error registering line discipline.\n"); - return -ENODEV; - } - - return 0; -} - -#ifdef MODULE -void cleanup_module(void) -{ - tty_register_ldisc(N_JOYSTICK_MAG, NULL); -} -#endif diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/joy-pci.c linux/drivers/char/joystick/joy-pci.c --- v2.4.0-test1/linux/drivers/char/joystick/joy-pci.c Wed Dec 8 14:11:26 1999 +++ linux/drivers/char/joystick/joy-pci.c Wed Dec 31 16:00:00 1969 @@ -1,273 +0,0 @@ -/* - * joy-pci.c Version 0.4.0 - * - * Copyright (c) 1999 Raymond Ingles - * Copyright (c) 1999 Vojtech Pavlik - * - * Sponsored by SuSE - */ - -/* - * This is a module for the Linux joystick driver, supporting the - * gameports on Trident 4DWave and Aureal Vortex soundcards, and - * analog joysticks connected to them. - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_AUTHOR("Raymond Ingles "); -MODULE_PARM(js_pci, "3-32i"); - -#define NUM_CARDS 8 -static int js_pci[NUM_CARDS * 4] __initdata = { -1,0,0,0,-1,0,0,0,-1,0,0,0,-1,0,0,0, - -1,0,0,0,-1,0,0,0,-1,0,0,0,-1,0,0,0 }; - -static struct js_port * js_pci_port __initdata = NULL; - -#include "joy-analog.h" - -struct js_pci_info; -typedef void (*js_pci_func)(struct js_pci_info *); - -struct js_pci_data { - int vendor; /* PCI Vendor ID */ - int model; /* PCI Model ID */ - int size; /* Memory / IO region size */ - int lcr; /* Aureal Legacy Control Register */ - int gcr; /* Gameport control register */ - int buttons; /* Buttons location */ - int axes; /* Axes start */ - int axsize; /* Axis field size */ - int axmax; /* Axis field max value */ - js_pci_func init; - js_pci_func cleanup; - char *name; -}; - -struct js_pci_info { - unsigned char *base; - struct pci_dev *pci_p; - __u32 lcr; - struct js_pci_data *data; - struct js_an_info an; -}; - -/* - * js_pci_*_init() sets the info->base field, disables legacy gameports, - * and enables the enhanced ones. - */ - -static void js_pci_4dwave_init(struct js_pci_info *info) -{ - info->base = ioremap(BASE_ADDRESS(info->pci_p, 1), info->data->size); - pci_read_config_word(info->pci_p, info->data->lcr, (unsigned short *)&info->lcr); - pci_write_config_word(info->pci_p, info->data->lcr, info->lcr & ~0x20); - writeb(0x80, info->base + info->data->gcr); -} - -static void js_pci_vortex_init(struct js_pci_info *info) -{ - info->base = ioremap(BASE_ADDRESS(info->pci_p, 0), info->data->size); - info->lcr = readl(info->base + info->data->lcr); - writel(info->lcr & ~0x8, info->base + info->data->lcr); - writel(0x40, info->base + info->data->gcr); -} - -/* - * js_pci_*_cleanup does the opposite of the above functions. - */ - -static void js_pci_4dwave_cleanup(struct js_pci_info *info) -{ - pci_write_config_word(info->pci_p, info->data->lcr, info->lcr); - writeb(0x00, info->base + info->data->gcr); - iounmap(info->base); -} - -static void js_pci_vortex_cleanup(struct js_pci_info *info) -{ - writel(info->lcr, info->base + info->data->lcr); - writel(0x00, info->base + info->data->gcr); - iounmap(info->base); -} - -static struct js_pci_data js_pci_data[] = -{{ PCI_VENDOR_ID_TRIDENT, 0x2000, 0x10000, 0x00044 ,0x00030, 0x00031, 0x00034, 2, 0xffff, - js_pci_4dwave_init, js_pci_4dwave_cleanup, "Trident 4DWave DX" }, - { PCI_VENDOR_ID_TRIDENT, 0x2001, 0x10000, 0x00044, 0x00030, 0x00031, 0x00034, 2, 0xffff, - js_pci_4dwave_init, js_pci_4dwave_cleanup, "Trident 4DWave NX" }, - { PCI_VENDOR_ID_AUREAL, 0x0001, 0x40000, 0x1280c, 0x1100c, 0x11008, 0x11010, 4, 0x1fff, - js_pci_vortex_init, js_pci_vortex_cleanup, "Aureal Vortex1" }, - { PCI_VENDOR_ID_AUREAL, 0x0002, 0x40000, 0x2a00c, 0x2880c, 0x28808, 0x28810, 4, 0x1fff, - js_pci_vortex_init, js_pci_vortex_cleanup, "Aureal Vortex2" }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL }}; - -/* - * js_pci_read() reads data from a PCI gameport. - */ - -static int js_pci_read(void *xinfo, int **axes, int **buttons) -{ - struct js_pci_info *info = xinfo; - int i; - - info->an.buttons = ~readb(info->base + info->data->buttons) >> 4; - - for (i = 0; i < 4; i++) - info->an.axes[i] = readw(info->base + info->data->axes + i * info->data->axsize); - - js_an_decode(&info->an, axes, buttons); - - return 0; -} - -/* - * js_pci_open() is a callback from the file open routine. - */ - -static int js_pci_open(struct js_dev *jd) -{ - MOD_INC_USE_COUNT; - return 0; -} - -/* - * js_pci_close() is a callback from the file release routine. - */ - -static int js_pci_close(struct js_dev *jd) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -static struct js_port * __init js_pci_probe(struct js_port *port, int type, int number, - struct pci_dev *pci_p, struct js_pci_data *data) -{ - int i; - unsigned char u; - int mask0, mask1, numdev; - struct js_pci_info iniinfo; - struct js_pci_info *info = &iniinfo; - - mask0 = mask1 = 0; - - for (i = 0; i < NUM_CARDS; i++) - if (js_pci[i * 4] == type && js_pci[i * 4 + 1] == number) { - mask0 = js_pci[i * 4 + 2]; - mask1 = js_pci[i * 4 + 3]; - if (!mask0 && !mask1) return port; - break; - } - - memset(info, 0, sizeof(struct js_pci_info)); - - info->data = data; - info->pci_p = pci_p; - data->init(info); - - mdelay(10); - js_pci_read(info, NULL, NULL); - - for (i = u = 0; i < 4; i++) - if (info->an.axes[i] < info->data->axmax) u |= 1 << i; - - if ((numdev = js_an_probe_devs(&info->an, u, mask0, mask1, port)) <= 0) - return port; - - port = js_register_port(port, info, numdev, sizeof(struct js_pci_info), js_pci_read); - - info = port->info; - - for (i = 0; i < numdev; i++) - printk(KERN_WARNING "js%d: %s on %s #%d\n", - js_register_device(port, i, js_an_axes(i, &info->an), js_an_buttons(i, &info->an), - js_an_name(i, &info->an), js_pci_open, js_pci_close), js_an_name(i, &info->an), data->name, number); - - js_pci_read(info, port->axes, port->buttons); - js_an_init_corr(&info->an, port->axes, port->corr, 32); - - return port; -} - -#ifndef MODULE -int __init js_pci_setup(SETUP_PARAM) -{ - int i; - SETUP_PARSE(NUM_CARDS*4); - for (i = 0; i <= ints[0] && i < NUM_CARDS*4; i++) - js_pci[i] = ints[i+1]; - return 1; -} -__setup("js_pci=", js_pci_setup); -#endif - -#ifdef MODULE -int init_module(void) -#else -int __init js_pci_init(void) -#endif -{ - struct pci_dev *pci_p = NULL; - int i, j; - - for (i = 0; js_pci_data[i].vendor; i++) - for (j = 0; (pci_p = pci_find_device(js_pci_data[i].vendor, js_pci_data[i].model, pci_p)); j++) - js_pci_port = js_pci_probe(js_pci_port, i, j, pci_p, js_pci_data + i); - - if (!js_pci_port) { -#ifdef MODULE - printk(KERN_WARNING "joy-pci: no joysticks found\n"); -#endif - return -ENODEV; - } - - return 0; -} - -#ifdef MODULE -void cleanup_module(void) -{ - int i; - struct js_pci_info *info; - - while (js_pci_port) { - for (i = 0; i < js_pci_port->ndevs; i++) - if (js_pci_port->devs[i]) - js_unregister_device(js_pci_port->devs[i]); - info = js_pci_port->info; - info->data->cleanup(info); - js_pci_port = js_unregister_port(js_pci_port); - } -} -#endif diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/joy-sidewinder.c linux/drivers/char/joystick/joy-sidewinder.c --- v2.4.0-test1/linux/drivers/char/joystick/joy-sidewinder.c Wed Dec 8 14:11:26 1999 +++ linux/drivers/char/joystick/joy-sidewinder.c Wed Dec 31 16:00:00 1969 @@ -1,855 +0,0 @@ -/* - * joy-sidewinder.c Version 1.2 - * - * Copyright (c) 1998-1999 Vojtech Pavlik - * - * Sponsored by SuSE - */ - -/* - * This is a module for the Linux joystick driver, supporting - * Microsoft SideWinder digital joystick family. - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * These are really magic values. Changing them can make a problem go away, - * as well as break everything. - */ - -#undef JS_SW_DEBUG - -#define JS_SW_START 400 /* The time we wait for the first bit [400 us] */ -#define JS_SW_STROBE 45 /* Max time per bit [45 us] */ -#define JS_SW_TIMEOUT 4000 /* Wait for everything to settle [4 ms] */ -#define JS_SW_KICK 45 /* Wait after A0 fall till kick [45 us] */ -#define JS_SW_END 8 /* Number of bits before end of packet to kick */ -#define JS_SW_FAIL 16 /* Number of packet read errors to fail and reinitialize */ -#define JS_SW_BAD 2 /* Number of packet read errors to switch off 3d Pro optimization */ -#define JS_SW_OK 64 /* Number of packet read successes to switch optimization back on */ -#define JS_SW_LENGTH 512 /* Max number of bits in a packet */ - -/* - * SideWinder joystick types ... - */ - -#define JS_SW_TYPE_3DP 1 -#define JS_SW_TYPE_F23 2 -#define JS_SW_TYPE_GP 3 -#define JS_SW_TYPE_PP 4 -#define JS_SW_TYPE_FFP 5 -#define JS_SW_TYPE_FSP 6 -#define JS_SW_TYPE_FFW 7 - -static int js_sw_port_list[] __initdata = {0x201, 0}; -static struct js_port* js_sw_port __initdata = NULL; - -static struct { - int x; - int y; -} js_sw_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; - -struct js_sw_info { - int io; - int length; - int speed; - unsigned char type; - unsigned char bits; - unsigned char number; - unsigned char fail; - unsigned char ok; -}; - -/* - * Gameport speed. - */ - -unsigned int js_sw_io_speed = 0; - -/* - * js_sw_measure_speed() measures the gameport i/o speed. - */ - -static int __init js_sw_measure_speed(int io) -{ -#ifdef __i386__ - -#define GET_TIME(x) do { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0) -#define DELTA(x,y) ((y)-(x)+((y)<(x)?1193180L/HZ:0)) - - unsigned int i, t, t1, t2, t3, tx; - unsigned long flags; - - tx = 1 << 30; - - for(i = 0; i < 50; i++) { - save_flags(flags); /* Yes, all CPUs */ - cli(); - GET_TIME(t1); - for(t = 0; t < 50; t++) inb(io); - GET_TIME(t2); - GET_TIME(t3); - restore_flags(flags); - udelay(i * 10); - if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t; - } - - return 59659 / t; - -#else - - unsigned int j, t = 0; - - j = jiffies; while (j == jiffies); - j = jiffies; while (j == jiffies) { t++; inb(0x201); } - - return t * HZ / 1000; - -#endif -} - -/* - * js_sw_read_packet() is a function which reads either a data packet, or an - * identification packet from a SideWinder joystick. Better don't try to - * understand this, since all the ugliness of the Microsoft Digital - * Overdrive protocol is concentrated in this function. If you really want - * to know how this works, first go watch a couple horror movies, so that - * you are well prepared, read US patent #5628686 and then e-mail me, - * and I'll send you an explanation. - * Vojtech - */ - -static int js_sw_read_packet(int io, int speed, unsigned char *buf, int length, int id) -{ - unsigned long flags; - int timeout, bitout, sched, i, kick, start, strobe; - unsigned char pending, u, v; - - i = -id; /* Don't care about data, only want ID */ - timeout = id ? (JS_SW_TIMEOUT * speed) >> 10 : 0; /* Set up global timeout for ID packet */ - kick = id ? (JS_SW_KICK * speed) >> 10 : 0; /* Set up kick timeout for ID packet */ - start = (JS_SW_START * speed) >> 10; - strobe = (JS_SW_STROBE * speed) >> 10; - bitout = start; - pending = 0; - sched = 0; - - __save_flags(flags); /* Quiet, please */ - __cli(); - - outb(0xff, io); /* Trigger */ - v = inb(io); - - do { - bitout--; - u = v; - v = inb(io); - } while (!(~v & u & 0x10) && (bitout > 0)); /* Wait for first falling edge on clock */ - - if (bitout > 0) bitout = strobe; /* Extend time if not timed out */ - - while ((timeout > 0 || bitout > 0) && (i < length)) { - - timeout--; - bitout--; /* Decrement timers */ - sched--; - - u = v; - v = inb(io); - - if ((~u & v & 0x10) && (bitout > 0)) { /* Rising edge on clock - data bit */ - if (i >= 0) /* Want this data */ - buf[i] = v >> 5; /* Store it */ - i++; /* Advance index */ - bitout = strobe; /* Extend timeout for next bit */ - } - - if (kick && (~v & u & 0x01)) { /* Falling edge on axis 0 */ - sched = kick; /* Schedule second trigger */ - kick = 0; /* Don't schedule next time on falling edge */ - pending = 1; /* Mark schedule */ - } - - if (pending && sched < 0 && (i > -JS_SW_END)) { /* Second trigger time */ - outb(0xff, io); /* Trigger */ - bitout = start; /* Long bit timeout */ - pending = 0; /* Unmark schedule */ - timeout = 0; /* Switch from global to bit timeouts */ - } - } - - __restore_flags(flags); /* Done - relax */ - -#ifdef JS_SW_DEBUG - { - int j; - printk(KERN_DEBUG "joy-sidewinder: Read %d triplets. [", i); - for (j = 0; j < i; j++) printk("%d", buf[j]); - printk("]\n"); - } -#endif - - return i; -} - -/* - * js_sw_get_bits() and GB() compose bits from the triplet buffer into a __u64. - * Parameter 'pos' is bit number inside packet where to start at, 'num' is number - * of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits - * is number of bits per triplet. - */ - -#define GB(pos,num,shift) js_sw_get_bits(buf, pos, num, shift, info->bits) - -static __u64 js_sw_get_bits(unsigned char *buf, int pos, int num, char shift, char bits) -{ - __u64 data = 0; - int tri = pos % bits; /* Start position */ - int i = pos / bits; - int bit = shift; - - while (num--) { - data |= (__u64)((buf[i] >> tri++) & 1) << bit++; /* Transfer bit */ - if (tri == bits) { - i++; /* Next triplet */ - tri = 0; - } - } - - return data; -} - -/* - * js_sw_init_digital() initializes a SideWinder 3D Pro joystick - * into digital mode. - */ - -static void js_sw_init_digital(int io, int speed) -{ - int seq[] = { 140, 140+725, 140+300, 0 }; - unsigned long flags; - int i, t; - - __save_flags(flags); - __cli(); - - i = 0; - do { - outb(0xff, io); /* Trigger */ - t = (JS_SW_TIMEOUT * speed) >> 10; - while ((inb(io) & 1) && t) t--; /* Wait for axis to fall back to 0 */ - udelay(seq[i]); /* Delay magic time */ - } while (seq[++i]); - - outb(0xff, io); /* Last trigger */ - - __restore_flags(flags); -} - -/* - * js_sw_parity() computes parity of __u64 - */ - -static int js_sw_parity(__u64 t) -{ - int x = t ^ (t >> 32); - x ^= x >> 16; - x ^= x >> 8; - x ^= x >> 4; - x ^= x >> 2; - x ^= x >> 1; - return x & 1; -} - -/* - * js_sw_ccheck() checks synchronization bits and computes checksum of nibbles. - */ - -static int js_sw_check(__u64 t) -{ - char sum = 0; - - if ((t & 0x8080808080808080ULL) ^ 0x80) /* Sync */ - return -1; - - while (t) { /* Sum */ - sum += t & 0xf; - t >>= 4; - } - - return sum & 0xf; -} - -/* - * js_sw_parse() analyzes SideWinder joystick data, and writes the results into - * the axes and buttons arrays. - */ - -static int js_sw_parse(unsigned char *buf, struct js_sw_info *info, int **axes, int **buttons) -{ - int hat, i; - - switch (info->type) { - - case JS_SW_TYPE_3DP: - case JS_SW_TYPE_F23: - - if (js_sw_check(GB(0,64,0)) || (hat = GB(6,1,3) | GB(60,3,0)) > 8) return -1; - - axes[0][0] = GB( 3,3,7) | GB(16,7,0); - axes[0][1] = GB( 0,3,7) | GB(24,7,0); - axes[0][2] = GB(35,2,7) | GB(40,7,0); - axes[0][3] = GB(32,3,7) | GB(48,7,0); - axes[0][4] = js_sw_hat_to_axis[hat].x; - axes[0][5] = js_sw_hat_to_axis[hat].y; - buttons[0][0] = ~(GB(37,1,8) | GB(38,1,7) | GB(8,7,0)); - - return 0; - - case JS_SW_TYPE_GP: - - for (i = 0; i < info->number * 15; i += 15) { - - if (js_sw_parity(GB(i,15,0))) return -1; - - axes[i][0] = GB(i+3,1,0) - GB(i+2,1,0); - axes[i][1] = GB(i+0,1,0) - GB(i+1,1,0); - buttons[i][0] = ~GB(i+4,10,0); - - } - - return 0; - - case JS_SW_TYPE_PP: - case JS_SW_TYPE_FFP: - - if (!js_sw_parity(GB(0,48,0)) || (hat = GB(42,4,0)) > 8) return -1; - - axes[0][0] = GB( 9,10,0); - axes[0][1] = GB(19,10,0); - axes[0][2] = GB(36, 6,0); - axes[0][3] = GB(29, 7,0); - axes[0][4] = js_sw_hat_to_axis[hat].x; - axes[0][5] = js_sw_hat_to_axis[hat].y; - buttons[0][0] = ~GB(0,9,0); - - return 0; - - case JS_SW_TYPE_FSP: - - if (!js_sw_parity(GB(0,43,0)) || (hat = GB(28,4,0)) > 8) return -1; - - axes[0][0] = GB( 0,10,0); - axes[0][1] = GB(16,10,0); - axes[0][2] = GB(32, 6,0); - axes[0][3] = js_sw_hat_to_axis[hat].x; - axes[0][4] = js_sw_hat_to_axis[hat].y; - buttons[0][0] = ~(GB(10,6,0) | GB(26,2,6) | GB(38,2,8)); - - return 0; - - case JS_SW_TYPE_FFW: - - if (!js_sw_parity(GB(0,33,0))) return -1; - - axes[0][0] = GB( 0,10,0); - axes[0][1] = GB(10, 6,0); - axes[0][2] = GB(16, 6,0); - buttons[0][0] = ~GB(22,8,0); - - return 0; - } - - return -1; -} - -/* - * js_sw_read() reads SideWinder joystick data, and reinitializes - * the joystick in case of persistent problems. This is the function that is - * called from the generic code to poll the joystick. - */ - -static int js_sw_read(void *xinfo, int **axes, int **buttons) -{ - struct js_sw_info *info = xinfo; - unsigned char buf[JS_SW_LENGTH]; - int i; - - i = js_sw_read_packet(info->io, info->speed, buf, info->length, 0); - - if (info->type <= JS_SW_TYPE_F23 && info->length == 66 && i != 66) { /* Broken packet, try to fix */ - - if (i == 64 && !js_sw_check(js_sw_get_bits(buf,0,64,0,1))) { /* Last init failed, 1 bit mode */ - printk(KERN_WARNING "joy-sidewinder: Joystick in wrong mode on %#x" - " - going to reinitialize.\n", info->io); - info->fail = JS_SW_FAIL; /* Reinitialize */ - i = 128; /* Bogus value */ - } - - if (i < 66 && GB(0,64,0) == GB(i*3-66,64,0)) /* 1 == 3 */ - i = 66; /* Everything is fine */ - - if (i < 66 && GB(0,64,0) == GB(66,64,0)) /* 1 == 2 */ - i = 66; /* Everything is fine */ - - if (i < 66 && GB(i*3-132,64,0) == GB(i*3-66,64,0)) { /* 2 == 3 */ - memmove(buf, buf + i - 22, 22); /* Move data */ - i = 66; /* Carry on */ - } - } - - if (i == info->length && !js_sw_parse(buf, info, axes, buttons)) { /* Parse data */ - - info->fail = 0; - info->ok++; - - if (info->type <= JS_SW_TYPE_F23 && info->length == 66 /* Many packets OK */ - && info->ok > JS_SW_OK) { - - printk(KERN_INFO "joy-sidewinder: No more trouble on %#x" - " - enabling optimization again.\n", info->io); - info->length = 22; - } - - return 0; - } - - info->ok = 0; - info->fail++; - - if (info->type <= JS_SW_TYPE_F23 && info->length == 22 /* Consecutive bad packets */ - && info->fail > JS_SW_BAD) { - - printk(KERN_INFO "joy-sidewinder: Many bit errors on %#x" - " - disabling optimization.\n", info->io); - info->length = 66; - } - - if (info->fail < JS_SW_FAIL) return -1; /* Not enough, don't reinitialize yet */ - - printk(KERN_WARNING "joy-sidewinder: Too many bit errors on %#x" - " - reinitializing joystick.\n", info->io); - - if (!i && info->type <= JS_SW_TYPE_F23) { /* 3D Pro can be in analog mode */ - udelay(3 * JS_SW_TIMEOUT); - js_sw_init_digital(info->io, info->speed); - } - - udelay(JS_SW_TIMEOUT); - i = js_sw_read_packet(info->io, info->speed, buf, JS_SW_LENGTH, 0); /* Read normal data packet */ - udelay(JS_SW_TIMEOUT); - js_sw_read_packet(info->io, info->speed, buf, JS_SW_LENGTH, i); /* Read ID packet, this initializes the stick */ - - info->fail = JS_SW_FAIL; - - return -1; -} - -/* - * js_sw_open() is a callback from the file open routine. - */ - -static int js_sw_open(struct js_dev *jd) -{ - MOD_INC_USE_COUNT; - return 0; -} - -/* - * js_sw_close() is a callback from the file release routine. - */ - -static int js_sw_close(struct js_dev *jd) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -/* - * js_sw_init_corr() initializes the correction values for - * SideWinders. - */ - -static void __init js_sw_init_corr(int num_axes, int type, int number, struct js_corr **corr) -{ - int i, j; - - for (i = 0; i < number; i++) { - - for (j = 0; j < num_axes; j++) { - corr[i][j].type = JS_CORR_BROKEN; - corr[i][j].prec = 8; - corr[i][j].coef[0] = 511 - 32; - corr[i][j].coef[1] = 512 + 32; - corr[i][j].coef[2] = (1 << 29) / (511 - 32); - corr[i][j].coef[3] = (1 << 29) / (511 - 32); - } - - switch (type) { - - case JS_SW_TYPE_3DP: - case JS_SW_TYPE_F23: - - corr[i][2].type = JS_CORR_BROKEN; - corr[i][2].prec = 4; - corr[i][2].coef[0] = 255 - 16; - corr[i][2].coef[1] = 256 + 16; - corr[i][2].coef[2] = (1 << 29) / (255 - 16); - corr[i][2].coef[3] = (1 << 29) / (255 - 16); - - j = 4; - - break; - - case JS_SW_TYPE_PP: - case JS_SW_TYPE_FFP: - - corr[i][2].type = JS_CORR_BROKEN; - corr[i][2].prec = 0; - corr[i][2].coef[0] = 31 - 2; - corr[i][2].coef[1] = 32 + 2; - corr[i][2].coef[2] = (1 << 29) / (31 - 2); - corr[i][2].coef[3] = (1 << 29) / (31 - 2); - - corr[i][3].type = JS_CORR_BROKEN; - corr[i][3].prec = 1; - corr[i][3].coef[0] = 63 - 4; - corr[i][3].coef[1] = 64 + 4; - corr[i][3].coef[2] = (1 << 29) / (63 - 4); - corr[i][3].coef[3] = (1 << 29) / (63 - 4); - - j = 4; - - break; - - case JS_SW_TYPE_FFW: - - corr[i][0].type = JS_CORR_BROKEN; - corr[i][0].prec = 2; - corr[i][0].coef[0] = 511 - 8; - corr[i][0].coef[1] = 512 + 8; - corr[i][0].coef[2] = (1 << 29) / (511 - 8); - corr[i][0].coef[3] = (1 << 29) / (511 - 8); - - corr[i][1].type = JS_CORR_BROKEN; - corr[i][1].prec = 1; - corr[i][1].coef[0] = 63; - corr[i][1].coef[1] = 63; - corr[i][1].coef[2] = (1 << 29) / -63; - corr[i][1].coef[3] = (1 << 29) / -63; - - corr[i][2].type = JS_CORR_BROKEN; - corr[i][2].prec = 1; - corr[i][2].coef[0] = 63; - corr[i][2].coef[1] = 63; - corr[i][2].coef[2] = (1 << 29) / -63; - corr[i][2].coef[3] = (1 << 29) / -63; - - j = 3; - - break; - - case JS_SW_TYPE_FSP: - - corr[i][2].type = JS_CORR_BROKEN; - corr[i][2].prec = 0; - corr[i][2].coef[0] = 31 - 2; - corr[i][2].coef[1] = 32 + 2; - corr[i][2].coef[2] = (1 << 29) / (31 - 2); - corr[i][2].coef[3] = (1 << 29) / (31 - 2); - - j = 3; - - break; - - default: - - j = 0; - } - - for (; j < num_axes; j++) { /* Hats & other binary axes */ - corr[i][j].type = JS_CORR_BROKEN; - corr[i][j].prec = 0; - corr[i][j].coef[0] = 0; - corr[i][j].coef[1] = 0; - corr[i][j].coef[2] = (1 << 29); - corr[i][j].coef[3] = (1 << 29); - } - } -} - -/* - * js_sw_print_packet() prints the contents of a SideWinder packet. - */ - -static void js_sw_print_packet(char *name, int length, unsigned char *buf, char bits) -{ - int i; - - printk("joy-sidewinder: %s packet, %d bits. [", name, length); - for (i = (((length + 3) >> 2) - 1); i >= 0; i--) - printk("%x", (int)js_sw_get_bits(buf, i << 2, 4, 0, bits)); - printk("]\n"); -} - -/* - * js_sw_3dp_id() translates the 3DP id into a human legible string. - * Unfortunately I don't know how to do this for the other SW types. - */ - -static void js_sw_3dp_id(unsigned char *buf, char *comment) -{ - int i; - char pnp[8], rev[9]; - - for (i = 0; i < 7; i++) /* ASCII PnP ID */ - pnp[i] = js_sw_get_bits(buf, 24+8*i, 8, 0, 1); - - for (i = 0; i < 8; i++) /* ASCII firmware revision */ - rev[i] = js_sw_get_bits(buf, 88+8*i, 8, 0, 1); - - pnp[7] = rev[8] = 0; - - sprintf(comment, " [PnP %d.%02d id %s rev %s]", - (int) (js_sw_get_bits(buf, 8, 6, 6, 1) | /* Two 6-bit values */ - js_sw_get_bits(buf, 16, 6, 0, 1)) / 100, - (int) (js_sw_get_bits(buf, 8, 6, 6, 1) | - js_sw_get_bits(buf, 16, 6, 0, 1)) % 100, - pnp, rev); -} - -/* - * js_sw_guess_mode() checks the upper two button bits for toggling - - * indication of that the joystick is in 3-bit mode. This is documented - * behavior for 3DP ID packet, and for example the FSP does this in - * normal packets instead. Fun ... - */ - -static int js_sw_guess_mode(unsigned char *buf, int len) -{ - int i; - unsigned char xor = 0; - for (i = 1; i < len; i++) xor |= (buf[i - 1] ^ buf[i]) & 6; - return !!xor * 2 + 1; -} - -/* - * js_sw_probe() probes for SideWinder type joysticks. - */ - -static struct js_port __init *js_sw_probe(int io, struct js_port *port) -{ - struct js_sw_info info; - char *names[] = {NULL, "SideWinder 3D Pro", "Flight2000 F-23", "SideWinder GamePad", "SideWinder Precision Pro", - "SideWinder Force Feedback Pro", "SideWinder FreeStyle Pro", "SideWinder Force Feedback Wheel" }; - char axes[] = { 0, 6, 6, 2, 6, 6, 5, 3 }; - char buttons[] = { 0, 9, 9, 10, 9, 9, 10, 8 }; - int i, j, k, l, speed; - unsigned char buf[JS_SW_LENGTH]; - unsigned char idbuf[JS_SW_LENGTH]; - unsigned char m = 1; - char comment[40]; - - comment[0] = 0; - - if (check_region(io, 1)) return port; - - speed = js_sw_measure_speed(io); - - i = js_sw_read_packet(io, speed, buf, JS_SW_LENGTH, 0); /* Read normal packet */ - m |= js_sw_guess_mode(buf, i); /* Data packet (1-bit) can carry mode info [FSP] */ - udelay(JS_SW_TIMEOUT); - -#ifdef JS_SW_DEBUG - printk(KERN_DEBUG "joy-sidewinder: Init 1: Mode %d. Length %d.\n", m , i); -#endif - - if (!i) { /* No data. 3d Pro analog mode? */ - js_sw_init_digital(io, speed); /* Switch to digital */ - udelay(JS_SW_TIMEOUT); - i = js_sw_read_packet(io, speed, buf, JS_SW_LENGTH, 0); /* Retry reading packet */ - udelay(JS_SW_TIMEOUT); -#ifdef JS_SW_DEBUG - printk(KERN_DEBUG "joy-sidewinder: Init 1b: Length %d.\n", i); -#endif - if (!i) return port; /* No data -> FAIL */ - } - - j = js_sw_read_packet(io, speed, idbuf, JS_SW_LENGTH, i); /* Read ID. This initializes the stick */ - m |= js_sw_guess_mode(idbuf, j); /* ID packet should carry mode info [3DP] */ - -#ifdef JS_SW_DEBUG - printk(KERN_DEBUG "joy-sidewinder: Init 2: Mode %d. ID Length %d.\n", m , j); -#endif - - if (!j) { /* Read ID failed. Happens in 1-bit mode on PP */ - udelay(JS_SW_TIMEOUT); - i = js_sw_read_packet(io, speed, buf, JS_SW_LENGTH, 0); /* Retry reading packet */ -#ifdef JS_SW_DEBUG - printk(KERN_DEBUG "joy-sidewinder: Init 2b: Mode %d. Length %d.\n", m , i); -#endif - if (!i) return port; - udelay(JS_SW_TIMEOUT); - j = js_sw_read_packet(io, speed, idbuf, JS_SW_LENGTH, i);/* Retry reading ID */ -#ifdef JS_SW_DEBUG - printk(KERN_DEBUG "joy-sidewinder: Init 2c: ID Length %d.\n", j); -#endif - - } - - k = JS_SW_FAIL; /* Try JS_SW_FAIL times */ - l = 0; - - do { - k--; - udelay(JS_SW_TIMEOUT); - i = js_sw_read_packet(io, speed, buf, JS_SW_LENGTH, 0); /* Read data packet */ -#ifdef JS_SW_DEBUG - printk(KERN_DEBUG "joy-sidewinder: Init 3: Length %d.\n", i); -#endif - - if (i > l) { /* Longer? As we can only lose bits, it makes */ - /* no sense to try detection for a packet shorter */ - l = i; /* than the previous one */ - - info.number = 1; - info.io = io; - info.speed = speed; - info.length = i; - info.bits = m; - info.fail = 0; - info.ok = 0; - info.type = 0; - - switch (i * m) { - case 60: - info.number++; - case 45: /* Ambiguous packet length */ - if (j <= 40) { /* ID length less or eq 40 -> FSP */ - case 43: - info.type = JS_SW_TYPE_FSP; - break; - } - info.number++; - case 30: - info.number++; - case 15: - info.type = JS_SW_TYPE_GP; - break; - case 33: - case 31: - info.type = JS_SW_TYPE_FFW; - break; - case 48: /* Ambiguous */ - if (j == 14) { /* ID lenght 14*3 -> FFP */ - info.type = JS_SW_TYPE_FFP; - sprintf(comment, " [AC %s]", js_sw_get_bits(idbuf,38,1,0,3) ? "off" : "on"); - } else - info.type = JS_SW_TYPE_PP; - break; - case 198: - info.length = 22; - case 64: - info.type = JS_SW_TYPE_3DP; - if (j == 160) js_sw_3dp_id(idbuf, comment); - break; - } - } - - } while (k && !info.type); - - if (!info.type) { - printk(KERN_WARNING "joy-sidewinder: unknown joystick device detected " - "(io=%#x), contact \n", io); - js_sw_print_packet("ID", j * 3, idbuf, 3); - js_sw_print_packet("Data", i * m, buf, m); - return port; - } - -#ifdef JS_SW_DEBUG - js_sw_print_packet("ID", j * 3, idbuf, 3); - js_sw_print_packet("Data", i * m, buf, m); -#endif - - k = i; - - request_region(io, 1, "joystick (sidewinder)"); - - port = js_register_port(port, &info, info.number, sizeof(struct js_sw_info), js_sw_read); - - for (i = 0; i < info.number; i++) - printk(KERN_INFO "js%d: %s%s at %#x [%d ns res %d-bit id %d data %d]\n", - js_register_device(port, i, axes[info.type], buttons[info.type], - names[info.type], js_sw_open, js_sw_close), names[info.type], comment, io, - 1000000 / speed, m, j, k); - - js_sw_init_corr(axes[info.type], info.type, info.number, port->corr); - - return port; -} - -#ifdef MODULE -int init_module(void) -#else -int __init js_sw_init(void) -#endif -{ - int *p; - - for (p = js_sw_port_list; *p; p++) js_sw_port = js_sw_probe(*p, js_sw_port); - if (js_sw_port) return 0; - -#ifdef MODULE - printk(KERN_WARNING "joy-sidewinder: no joysticks found\n"); -#endif - - return -ENODEV; -} - -#ifdef MODULE -void cleanup_module(void) -{ - int i; - struct js_sw_info *info; - - while (js_sw_port) { - for (i = 0; i < js_sw_port->ndevs; i++) - if (js_sw_port->devs[i]) - js_unregister_device(js_sw_port->devs[i]); - info = js_sw_port->info; - release_region(info->io, 1); - js_sw_port = js_unregister_port(js_sw_port); - } - -} -#endif diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/joy-spaceball.c linux/drivers/char/joystick/joy-spaceball.c --- v2.4.0-test1/linux/drivers/char/joystick/joy-spaceball.c Tue Apr 11 15:09:16 2000 +++ linux/drivers/char/joystick/joy-spaceball.c Wed Dec 31 16:00:00 1969 @@ -1,345 +0,0 @@ -/* - * joy-spaceball.c Version 0.1 - * - * Copyright (c) 1998 David Thompson - * Copyright (c) 1999 Vojtech Pavlik - * Copyright (c) 1999 Joseph Krahn - * - * Sponsored by SuSE - */ - -/* - * This is a module for the Linux joystick driver, supporting - * the SpaceTec SpaceBall 4000 FLX. - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Constants. - */ - -#define N_JOYSTICK_SBALL 12 -#define JS_SBALL_MAX_LENGTH 128 - -/* - * List of SpaceBalls. - */ - -static struct js_port* js_sball_port = NULL; - -/* - * Per-Ball data. - */ - -struct js_sball_info { - struct tty_struct* tty; - struct js_port* port; - int idx; - unsigned char data[JS_SBALL_MAX_LENGTH]; - int js; - char used; -}; - -/* - * js_sball_process_packet() decodes packets the driver receives from the - * SpaceBall. - */ - -static void js_sball_process_packet(struct js_sball_info* info) -{ - int i,b; - int **axes = info->port->axes; - int **buttons = info->port->buttons; - unsigned char *data = info->data; - - if (info->idx < 2) return; - - switch (info->data[0]) { - - case '@': /* Reset packet */ - info->data[info->idx - 1] = 0; - for (i = 1; i < info->idx && info->data[i] == ' '; i++); - - printk(KERN_INFO "js%d: SpaceBall 4000FLX [%s] on %s%d\n", - info->js, info->data + i, info->tty->driver.name, - MINOR(info->tty->device) - info->tty->driver.minor_start); - - memset(axes[0], 0, sizeof(int) * 6); /* All axes, buttons should be zero */ - buttons[0][0] = 0; - break; - - case 'D': /* Ball data */ - if (info->idx != 16) return; - if (!info->port->devs[0]) return; - axes[0][0] = ((data[3] << 8) | data[4] ); - axes[0][1] = ((data[5] << 8) | data[6] ); - axes[0][2] = ((data[7] << 8) | data[8] ); - axes[0][3] = ((data[9] << 8) | data[10]); - axes[0][4] = ((data[11]<< 8) | data[12]); - axes[0][5] = ((data[13]<< 8) | data[14]); - for(i = 0; i < 6; i ++) if (axes[0][i] & 0x8000) axes[0][i] -= 0x10000; - break; - - case 'K': /* Button data, part1 */ - /* We can ignore this packet for the SB 4000FLX. */ - break; - - case '.': /* Button data, part2 */ - if (info->idx != 4) return; - if (!info->port->devs[0]) return; - b = (data[1] & 0xbf) << 8 | (data[2] & 0xbf); - buttons[0][0] = ((b & 0x1f80) >> 1 | (b & 0x3f)); - break; - - case '?': /* Error packet */ - info->data[info->idx - 1] = 0; - printk(KERN_ERR "joy-spaceball: Device error. [%s]\n",info->data+1); - break; - - case 'A': /* reply to A command (ID# report) */ - case 'B': /* reply to B command (beep) */ - case 'H': /* reply to H command (firmware report) */ - case 'S': /* reply to S command (single beep) */ - case 'Y': /* reply to Y command (scale flag) */ - case '"': /* reply to "n command (report info, part n) */ - break; - - case 'P': /* Pulse (update) speed */ - if (info->idx != 3) return; /* data[2],data[3] = hex digits for speed 00-FF */ - break; - - default: - printk("joy-spaceball: Unknown packet %d length %d:", data[0], info->idx); - for (i = 0; i < info->idx; i++) printk(" %02x", data[i]); - printk("\n"); - return; - } -} - -/* - * js_sball_open() is a callback from the joystick device open routine. - */ - -static int js_sball_open(struct js_dev *jd) -{ - struct js_sball_info *info = jd->port->info; - info->used++; - MOD_INC_USE_COUNT; - return 0; -} - -/* - * js_sball_close() is a callback from the joystick device release routine. - */ - -static int js_sball_close(struct js_dev *jd) -{ - struct js_sball_info *info = jd->port->info; - if (!--info->used) { - js_unregister_device(jd->port->devs[0]); - js_sball_port = js_unregister_port(jd->port); - } - MOD_DEC_USE_COUNT; - return 0; -} - -/* - * js_sball_init_corr() initializes the correction values for the SpaceBall. - */ - -static void __init js_sball_init_corr(struct js_corr **corr) -{ - int j; - - for (j = 0; j < 3; j++) { - corr[0][j].type = JS_CORR_BROKEN; - corr[0][j].prec = 0; - corr[0][j].coef[0] = 0; - corr[0][j].coef[1] = 0; - corr[0][j].coef[2] = 50000; - corr[0][j].coef[3] = 50000; - } - for (j = 3; j < 6; j++) { - corr[0][j].type = JS_CORR_BROKEN; - corr[0][j].prec = 0; - corr[0][j].coef[0] = 0; - corr[0][j].coef[1] = 0; - corr[0][j].coef[2] = 300000; - corr[0][j].coef[3] = 300000; - } -} - -/* - * js_sball_ldisc_open() is the routine that is called upon setting our line - * discipline on a tty. - */ - -static int js_sball_ldisc_open(struct tty_struct *tty) -{ - struct js_sball_info iniinfo; - struct js_sball_info *info = &iniinfo; - - MOD_INC_USE_COUNT; - - info->tty = tty; - info->idx = 0; - info->used = 1; - - js_sball_port = js_register_port(js_sball_port, info, 1, sizeof(struct js_sball_info), NULL); - - info = js_sball_port->info; - info->port = js_sball_port; - tty->disc_data = info; - - info->js = js_register_device(js_sball_port, 0, 6, 12, "SpaceBall 4000 FLX", js_sball_open, js_sball_close); - - js_sball_init_corr(js_sball_port->corr); - - return 0; -} - -/* - * js_sball_ldisc_close() is the opposite of js_sball_ldisc_open() - */ - -static void js_sball_ldisc_close(struct tty_struct *tty) -{ - struct js_sball_info* info = (struct js_sball_info*) tty->disc_data; - if (!--info->used) { - js_unregister_device(info->port->devs[0]); - js_sball_port = js_unregister_port(info->port); - } - MOD_DEC_USE_COUNT; -} - -/* - * js_sball_ldisc_receive() is called by the low level driver when characters - * are ready for us. We then buffer them for further processing, or call the - * packet processing routine. - */ - -static void js_sball_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) -{ - struct js_sball_info* info = (struct js_sball_info*) tty->disc_data; - int i; - int esc_flag = 0; - -/* - * Spaceball 4000 FLX packets all start with a one letter packet-type decriptor, - * and end in 0x0d. It uses '^' as an escape for 0x0d characters which can - * occur in the axis values. ^M, ^Q and ^S all mean 0x0d, depending (I think) - * on whether the axis value is increasing, decreasing, or same as before. - * (I don't see why this is useful). - * - * There may be a nicer whay to handle the escapes, but I wanted to be sure to - * allow for an escape at the end of the buffer. - */ - for (i = 0; i < count; i++) { - if (esc_flag) { /* If the last char was an escape, overwrite it with the escaped value */ - - switch (cp[i]){ - case 'M': - case 'Q': - case 'S': - info->data[info->idx]=0x0d; - break; - case '^': /* escaped escape; leave as is */ - break; - default: - printk("joy-spaceball: Unknown escape character: %02x\n", cp[i]); - } - - esc_flag = 0; - - } else { - - if (info->idx < JS_SBALL_MAX_LENGTH) - info->data[info->idx++] = cp[i]; - - if (cp[i] == 0x0D) { - if (info->idx) - js_sball_process_packet(info); - info->idx = 0; - } else - if (cp[i] == '^') esc_flag = 1; - - } - } -} - -/* - * js_sball_ldisc_room() reports how much room we do have for receiving data. - * Although we in fact have infinite room, we need to specify some value - * here, so why not the size of our packet buffer. It's big anyway. - */ - -static int js_sball_ldisc_room(struct tty_struct *tty) -{ - return JS_SBALL_MAX_LENGTH; -} - -/* - * The line discipline structure. - */ - -static struct tty_ldisc js_sball_ldisc = { - magic: TTY_LDISC_MAGIC, - name: "spaceball", - open: js_sball_ldisc_open, - close: js_sball_ldisc_close, - receive_buf: js_sball_ldisc_receive, - receive_room: js_sball_ldisc_room, -}; - -/* - * The functions for inserting/removing us as a module. - */ - -#ifdef MODULE -int init_module(void) -#else -int __init js_sball_init(void) -#endif -{ - if (tty_register_ldisc(N_JOYSTICK_SBALL, &js_sball_ldisc)) { - printk(KERN_ERR "joy-spaceball: Error registering line discipline.\n"); - return -ENODEV; - } - - return 0; -} - -#ifdef MODULE -void cleanup_module(void) -{ - tty_register_ldisc(N_JOYSTICK_SBALL, NULL); -} -#endif diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/joy-spaceorb.c linux/drivers/char/joystick/joy-spaceorb.c --- v2.4.0-test1/linux/drivers/char/joystick/joy-spaceorb.c Tue Apr 11 15:09:16 2000 +++ linux/drivers/char/joystick/joy-spaceorb.c Wed Dec 31 16:00:00 1969 @@ -1,303 +0,0 @@ -/* - * joy-spaceorb.c Version 0.1 - * - * Copyright (c) 1998 David Thompson - * Copyright (c) 1999 Vojtech Pavlik - * - * Sponsored by SuSE - */ - -/* - * This is a module for the Linux joystick driver, supporting - * the SpaceTec SpaceOrb 360 and SpaceBall Avenger 6dof controllers. - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Constants. - */ - -#define N_JOYSTICK_ORB 15 -#define JS_ORB_MAX_LENGTH 64 - -/* - * List of SpaceOrbs. - */ - -static struct js_port* js_orb_port = NULL; - -/* - * Per-Orb data. - */ - -struct js_orb_info { - struct tty_struct* tty; - struct js_port* port; - int idx; - unsigned char data[JS_ORB_MAX_LENGTH]; - int js; - char used; -}; - -static unsigned char js_orb_xor[] = "SpaceWare"; - -static unsigned char *js_orb_errors[] = { "EEPROM storing 0 failed", "Receive queue overflow", "Transmit queue timeout", - "Bad packet", "Power brown-out", "EEPROM checksum error", "Hardware fault" }; - -/* - * js_orb_process_packet() decodes packets the driver receives from the - * SpaceOrb. - */ - -static void js_orb_process_packet(struct js_orb_info* info) -{ - int i; - int **axes = info->port->axes; - int **buttons = info->port->buttons; - unsigned char *data = info->data; - unsigned char c = 0; - - if (info->idx < 2) return; - for (i = 0; i < info->idx; i++) c ^= data[i]; - if (c) return; - - switch (info->data[0]) { - - case 'R': /* Reset packet */ - info->data[info->idx - 1] = 0; - for (i = 1; i < info->idx && info->data[i] == ' '; i++); - printk(KERN_INFO "js%d: SpaceOrb 360 [%s] on %s%d\n", - info->js, info->data + i, info->tty->driver.name, - MINOR(info->tty->device) - info->tty->driver.minor_start); - break; - - case 'D': /* Ball + button data */ - if (info->idx != 12) return; - if (!info->port->devs[0]) return; - for (i = 0; i < 9; i++) info->data[i+2] ^= js_orb_xor[i]; - axes[0][0] = ( data[2] << 3) | (data[ 3] >> 4); - axes[0][1] = ((data[3] & 0x0f) << 6) | (data[ 4] >> 1); - axes[0][2] = ((data[4] & 0x01) << 9) | (data[ 5] << 2) | (data[4] >> 5); - axes[0][3] = ((data[6] & 0x1f) << 5) | (data[ 7] >> 2); - axes[0][4] = ((data[7] & 0x03) << 8) | (data[ 8] << 1) | (data[7] >> 6); - axes[0][5] = ((data[9] & 0x3f) << 4) | (data[10] >> 3); - for(i = 0; i < 6; i ++) if (axes[0][i] & 0x200) axes[0][i] -= 1024; - buttons[0][0] = data[1]; - break; - - case 'K': /* Button data */ - if (info->idx != 5) return; - if (!info->port->devs[0]) return; - buttons[0][0] = data[2]; - break; - - case 'E': /* Error packet */ - if (info->idx != 4) return; - printk(KERN_ERR "joy-spaceorb: Device error. [ "); - for (i = 0; i < 7; i++) - if (data[1] & (1 << i)) - printk("%s ", js_orb_errors[i]); - printk("]\n"); - break; - - case 'N': /* Null region */ - if (info->idx != 3) return; - break; - - case 'P': /* Pulse (update) speed */ - if (info->idx != 4) return; - break; - - default: - printk("joy-spaceorb: Unknown packet %d length %d:", data[0], info->idx); - for (i = 0; i < info->idx; i++) printk(" %02x", data[i]); - printk("\n"); - return; - } -} - -/* - * js_orb_open() is a callback from the joystick device open routine. - */ - -static int js_orb_open(struct js_dev *jd) -{ - struct js_orb_info *info = jd->port->info; - info->used++; - MOD_INC_USE_COUNT; - return 0; -} - -/* - * js_orb_close() is a callback from the joystick device release routine. - */ - -static int js_orb_close(struct js_dev *jd) -{ - struct js_orb_info *info = jd->port->info; - if (!--info->used) { - js_unregister_device(jd->port->devs[0]); - js_orb_port = js_unregister_port(jd->port); - } - MOD_DEC_USE_COUNT; - return 0; -} - -/* - * js_orb_init_corr() initializes the correction values for the SpaceOrb. - */ - -static void __init js_orb_init_corr(struct js_corr **corr) -{ - int j; - - for (j = 0; j < 6; j++) { - corr[0][j].type = JS_CORR_BROKEN; - corr[0][j].prec = 0; - corr[0][j].coef[0] = 0 ; - corr[0][j].coef[1] = 0 ; - corr[0][j].coef[2] = (1 << 29) / 511; - corr[0][j].coef[3] = (1 << 29) / 511; - } -} - -/* - * js_orb_ldisc_open() is the routine that is called upon setting our line - * discipline on a tty. - */ - -static int js_orb_ldisc_open(struct tty_struct *tty) -{ - struct js_orb_info iniinfo; - struct js_orb_info *info = &iniinfo; - - MOD_INC_USE_COUNT; - - info->tty = tty; - info->idx = 0; - info->used = 1; - - js_orb_port = js_register_port(js_orb_port, info, 1, sizeof(struct js_orb_info), NULL); - - info = js_orb_port->info; - info->port = js_orb_port; - tty->disc_data = info; - - info->js = js_register_device(js_orb_port, 0, 6, 7, "SpaceOrb 360", js_orb_open, js_orb_close); - - js_orb_init_corr(js_orb_port->corr); - - return 0; -} - -/* - * js_orb_ldisc_close() is the opposite of js_orb_ldisc_open() - */ - -static void js_orb_ldisc_close(struct tty_struct *tty) -{ - struct js_orb_info* info = (struct js_orb_info*) tty->disc_data; - if (!--info->used) { - js_unregister_device(info->port->devs[0]); - js_orb_port = js_unregister_port(info->port); - } - MOD_DEC_USE_COUNT; -} - -/* - * js_orb_ldisc_receive() is called by the low level driver when characters - * are ready for us. We then buffer them for further processing, or call the - * packet processing routine. - */ - -static void js_orb_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) -{ - struct js_orb_info* info = (struct js_orb_info*) tty->disc_data; - int i; - - for (i = 0; i < count; i++) { - if (~cp[i] & 0x80) { - if (info->idx) js_orb_process_packet(info); - info->idx = 0; - } - if (info->idx < JS_ORB_MAX_LENGTH) - info->data[info->idx++] = cp[i] & 0x7f; - } -} - -/* - * js_orb_ldisc_room() reports how much room we do have for receiving data. - * Although we in fact have infinite room, we need to specify some value - * here, so why not the size of our packet buffer. It's big anyway. - */ - -static int js_orb_ldisc_room(struct tty_struct *tty) -{ - return JS_ORB_MAX_LENGTH; -} - -/* - * The line discipline structure. - */ - -static struct tty_ldisc js_orb_ldisc = { - magic: TTY_LDISC_MAGIC, - name: "spaceorb", - open: js_orb_ldisc_open, - close: js_orb_ldisc_close, - receive_buf: js_orb_ldisc_receive, - receive_room: js_orb_ldisc_room, -}; - -/* - * The functions for inserting/removing us as a module. - */ - -#ifdef MODULE -int init_module(void) -#else -int __init js_orb_init(void) -#endif -{ - if (tty_register_ldisc(N_JOYSTICK_ORB, &js_orb_ldisc)) { - printk(KERN_ERR "joy-spaceorb: Error registering line discipline.\n"); - return -ENODEV; - } - - return 0; -} - -#ifdef MODULE -void cleanup_module(void) -{ - tty_register_ldisc(N_JOYSTICK_ORB, NULL); -} -#endif diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/joy-thrustmaster.c linux/drivers/char/joystick/joy-thrustmaster.c --- v2.4.0-test1/linux/drivers/char/joystick/joy-thrustmaster.c Wed Dec 8 14:11:26 1999 +++ linux/drivers/char/joystick/joy-thrustmaster.c Wed Dec 31 16:00:00 1969 @@ -1,300 +0,0 @@ -/* - * joy-thrustmaster.c Version 1.2 - * - * Copyright (c) 1998-1999 Vojtech Pavlik - * - * Sponsored by SuSE - */ - -/* - * This is a module for the Linux joystick driver, supporting - * ThrustMaster DirectConnect (BSP) joystick family. - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define JS_TM_MAX_START 400 -#define JS_TM_MAX_STROBE 45 -#define JS_TM_MAX_LENGTH 13 - -#define JS_TM_MODE_M3DI 1 -#define JS_TM_MODE_3DRP 3 -#define JS_TM_MODE_FGP 163 - -#define JS_TM_BYTE_ID 10 -#define JS_TM_BYTE_REV 11 -#define JS_TM_BYTE_DEF 12 - -static int js_tm_port_list[] __initdata = {0x201, 0}; -static struct js_port* js_tm_port __initdata = NULL; - -static unsigned char js_tm_byte_a[16] = { 0, 1, 3, 4, 6, 7 }; -static unsigned char js_tm_byte_d[16] = { 2, 5, 8, 9 }; - -struct js_tm_info { - int io; - unsigned char mode; -}; - -/* - * js_tm_read_packet() reads a ThrustMaster packet. - */ - -static int js_tm_read_packet(int io, unsigned char *data) -{ - unsigned int t, p; - unsigned char u, v, error; - int i, j; - unsigned long flags; - - error = 0; - i = j = 0; - p = t = JS_TM_MAX_START; - - __save_flags(flags); - __cli(); - outb(0xff,io); - - v = inb(io) >> 4; - - do { - t--; - u = v; v = inb(io) >> 4; - if (~v & u & 2) { - if (j) { - if (j < 9) { /* Data bit */ - data[i] |= (~v & 1) << (j - 1); - j++; - } else { /* Stop bit */ - error |= v & 1; - j = 0; - i++; - } - } else { /* Start bit */ - data[i] = 0; - error |= ~v & 1; - j++; - } - p = t = (p - t) << 1; - } - } while (!error && i < JS_TM_MAX_LENGTH && t > 0); - - __restore_flags(flags); - - return -(i != JS_TM_MAX_LENGTH); -} - -/* - * js_tm_read() reads and analyzes ThrustMaster joystick data. - */ - -static int js_tm_read(void *xinfo, int **axes, int **buttons) -{ - struct js_tm_info *info = xinfo; - unsigned char data[JS_TM_MAX_LENGTH]; - int i; - - if (js_tm_read_packet(info->io, data)) return -1; - if (data[JS_TM_BYTE_ID] != info->mode) return -1; - - for (i = 0; i < data[JS_TM_BYTE_DEF] >> 4; i++) axes[0][i] = data[js_tm_byte_a[i]]; - - switch (info->mode) { - - case JS_TM_MODE_M3DI: - - axes[0][4] = ((data[js_tm_byte_d[0]] >> 3) & 1) - ((data[js_tm_byte_d[0]] >> 1) & 1); - axes[0][5] = ((data[js_tm_byte_d[0]] >> 2) & 1) - ( data[js_tm_byte_d[0]] & 1); - - buttons[0][0] = ((data[js_tm_byte_d[0]] >> 6) & 0x01) | ((data[js_tm_byte_d[0]] >> 3) & 0x06) - | ((data[js_tm_byte_d[0]] >> 4) & 0x08) | ((data[js_tm_byte_d[1]] >> 2) & 0x30); - - return 0; - - case JS_TM_MODE_3DRP: - case JS_TM_MODE_FGP: - - buttons[0][0] = (data[js_tm_byte_d[0]] & 0x3f) | ((data[js_tm_byte_d[1]] << 6) & 0xc0) - | (( ((int) data[js_tm_byte_d[0]]) << 2) & 0x300); - - return 0; - - default: - - buttons[0][0] = 0; - - for (i = 0; i < (data[JS_TM_BYTE_DEF] & 0xf); i++) - buttons[0][0] |= ((int) data[js_tm_byte_d[i]]) << (i << 3); - - return 0; - - } - - return -1; -} - -/* - * js_tm_open() is a callback from the file open routine. - */ - -static int js_tm_open(struct js_dev *jd) -{ - MOD_INC_USE_COUNT; - return 0; -} - -/* - * js_tm_close() is a callback from the file release routine. - */ - -static int js_tm_close(struct js_dev *jd) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -/* - * js_tm_init_corr() initializes the correction values for - * ThrustMaster joysticks. - */ - -static void __init js_tm_init_corr(int num_axes, int mode, int **axes, struct js_corr **corr) -{ - int j = 0; - - for (; j < num_axes; j++) { - corr[0][j].type = JS_CORR_BROKEN; - corr[0][j].prec = 0; - corr[0][j].coef[0] = 127 - 2; - corr[0][j].coef[1] = 128 + 2; - corr[0][j].coef[2] = (1 << 29) / (127 - 4); - corr[0][j].coef[3] = (1 << 29) / (127 - 4); - } - - switch (mode) { - case JS_TM_MODE_M3DI: j = 4; break; - default: break; - } - - for (; j < num_axes; j++) { - corr[0][j].type = JS_CORR_BROKEN; - corr[0][j].prec = 0; - corr[0][j].coef[0] = 0; - corr[0][j].coef[1] = 0; - corr[0][j].coef[2] = (1 << 29); - corr[0][j].coef[3] = (1 << 29); - } - -} - -/* - * js_tm_probe() probes for ThrustMaster type joysticks. - */ - -static struct js_port __init *js_tm_probe(int io, struct js_port *port) -{ - struct js_tm_info info; - struct js_rm_models { - unsigned char id; - char *name; - char axes; - char buttons; - } models[] = { { 1, "ThrustMaster Millenium 3D Inceptor", 6, 6 }, - { 3, "ThrustMaster Rage 3D Gamepad", 2, 10 }, - { 163, "Thrustmaster Fusion GamePad", 2, 10 }, - { 0, NULL, 0, 0 }}; - char name[64]; - unsigned char data[JS_TM_MAX_LENGTH]; - unsigned char a, b; - int i; - - if (check_region(io, 1)) return port; - - if (js_tm_read_packet(io, data)) return port; - - info.io = io; - info.mode = data[JS_TM_BYTE_ID]; - - if (!info.mode) return port; - - for (i = 0; models[i].id && models[i].id != info.mode; i++); - - if (models[i].id != info.mode) { - a = data[JS_TM_BYTE_DEF] >> 4; - b = (data[JS_TM_BYTE_DEF] & 0xf) << 3; - sprintf(name, "Unknown %d-axis, %d-button TM device %d", a, b, info.mode); - } else { - sprintf(name, models[i].name); - a = models[i].axes; - b = models[i].buttons; - } - - request_region(io, 1, "joystick (thrustmaster)"); - port = js_register_port(port, &info, 1, sizeof(struct js_tm_info), js_tm_read); - printk(KERN_INFO "js%d: %s revision %d at %#x\n", - js_register_device(port, 0, a, b, name, js_tm_open, js_tm_close), name, data[JS_TM_BYTE_REV], io); - js_tm_init_corr(a, info.mode, port->axes, port->corr); - - return port; -} - -#ifdef MODULE -int init_module(void) -#else -int __init js_tm_init(void) -#endif -{ - int *p; - - for (p = js_tm_port_list; *p; p++) js_tm_port = js_tm_probe(*p, js_tm_port); - if (js_tm_port) return 0; - -#ifdef MODULE - printk(KERN_WARNING "joy-thrustmaster: no joysticks found\n"); -#endif - - return -ENODEV; -} - -#ifdef MODULE -void cleanup_module(void) -{ - struct js_tm_info *info; - - while (js_tm_port) { - js_unregister_device(js_tm_port->devs[0]); - info = js_tm_port->info; - release_region(info->io, 1); - js_tm_port = js_unregister_port(js_tm_port); - } -} -#endif diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/joy-turbografx.c linux/drivers/char/joystick/joy-turbografx.c --- v2.4.0-test1/linux/drivers/char/joystick/joy-turbografx.c Wed Dec 8 14:11:26 1999 +++ linux/drivers/char/joystick/joy-turbografx.c Wed Dec 31 16:00:00 1969 @@ -1,266 +0,0 @@ -/* - * joy-turbografx.c Version 1.2 - * - * Copyright (c) 1998-1999 Vojtech Pavlik - * - * Sponsored by SuSE - */ - -/* - * This is a module for the Linux joystick driver, supporting - * Steffen Schwenke's TurboGraFX parallel port - * interface. - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_PARM(js_tg, "2-8i"); -MODULE_PARM(js_tg_2, "2-8i"); -MODULE_PARM(js_tg_3, "2-8i"); - -#define JS_TG_BUTTON1 0x08 -#define JS_TG_UP 0x10 -#define JS_TG_DOWN 0x20 -#define JS_TG_LEFT 0x40 -#define JS_TG_RIGHT 0x80 - -#define JS_TG_BUTTON2 0x02 -#define JS_TG_BUTTON3 0x04 -#define JS_TG_BUTTON4 0x01 -#define JS_TG_BUTTON5 0x08 - -static struct js_port* js_tg_port __initdata = NULL; - -static int js_tg[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; -static int js_tg_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; -static int js_tg_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; - -struct js_tg_info { - struct pardevice *port; /* parport device */ - int sticks; /* joysticks connected */ -}; - -/* - * js_tg_read() reads and analyzes tg joystick data. - */ - -static int js_tg_read(void *xinfo, int **axes, int **buttons) -{ - struct js_tg_info *info = xinfo; - int data1, data2, i; - - for (i = 0; i < 7; i++) - if ((info->sticks >> i) & 1) { - - JS_PAR_DATA_OUT(~(1 << i), info->port); - data1 = JS_PAR_STATUS(info->port) ^ ~JS_PAR_STATUS_INVERT; - data2 = JS_PAR_CTRL_IN(info->port) ^ JS_PAR_CTRL_INVERT; - - axes[i][0] = ((data1 & JS_TG_RIGHT) ? 1 : 0) - ((data1 & JS_TG_LEFT) ? 1 : 0); - axes[i][1] = ((data1 & JS_TG_DOWN ) ? 1 : 0) - ((data1 & JS_TG_UP ) ? 1 : 0); - - buttons[i][0] = ((data1 & JS_TG_BUTTON1) ? 0x01 : 0) | ((data2 & JS_TG_BUTTON2) ? 0x02 : 0) - | ((data2 & JS_TG_BUTTON3) ? 0x04 : 0) | ((data2 & JS_TG_BUTTON4) ? 0x08 : 0) - | ((data2 & JS_TG_BUTTON5) ? 0x10 : 0); - - } - - return 0; -} - -/* - * open callback: claim parport. - */ - -int js_tg_open(struct js_dev *dev) -{ - struct js_tg_info *info = dev->port->info; - - if (!MOD_IN_USE) { - if (parport_claim(info->port)) return -EBUSY; - JS_PAR_CTRL_OUT(0x04, info->port); - } - MOD_INC_USE_COUNT; - return 0; -} - -/* - * close callback: release parport - */ - -int js_tg_close(struct js_dev *dev) -{ - struct js_tg_info *info = dev->port->info; - - MOD_DEC_USE_COUNT; - if (!MOD_IN_USE) { - JS_PAR_CTRL_OUT(0x00, info->port); - parport_release(info->port); - } - return 0; -} - -#ifdef MODULE -void cleanup_module(void) -{ - struct js_tg_info *info; - int i; - - while (js_tg_port) { - for (i = 0; i < js_tg_port->ndevs; i++) - if (js_tg_port->devs[i]) - js_unregister_device(js_tg_port->devs[i]); - info = js_tg_port->info; - parport_unregister_device(info->port); - js_tg_port = js_unregister_port(js_tg_port); - } -} -#endif - -/* - * js_tg_init_corr() initializes correction values of - * tg gamepads. - */ - -static void __init js_tg_init_corr(int sticks, struct js_corr **corr) -{ - int i, j; - - for (i = 0; i < 7; i++) - if ((sticks >> i) & 1) - for (j = 0; j < 2; j++) { - corr[i][j].type = JS_CORR_BROKEN; - corr[i][j].prec = 0; - corr[i][j].coef[0] = 0; - corr[i][j].coef[1] = 0; - corr[i][j].coef[2] = (1 << 29); - corr[i][j].coef[3] = (1 << 29); - } -} - -/* - * js_tg_probe() probes for tg gamepads. - */ - -static struct js_port __init *js_tg_probe(int *config, struct js_port *port) -{ - struct js_tg_info iniinfo; - struct js_tg_info *info = &iniinfo; - struct parport *pp; - int i; - - if (config[0] < 0) return port; - - - if (config[0] > 0x10) - for (pp=parport_enumerate(); pp && (pp->base!=config[0]); pp=pp->next); - else - for (pp=parport_enumerate(); pp && (config[0]>0); pp=pp->next) config[0]--; - - if (!pp) { - printk(KERN_ERR "joy-tg: no such parport\n"); - return port; - } - - info->port = parport_register_device(pp, "joystick (turbografx)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); - if (!info->port) - return port; - - port = js_register_port(port, info, 7, sizeof(struct js_tg_info), js_tg_read); - info = port->info; - - info->sticks = 0; - - for (i = 0; i < 7; i++) - if (config[i+1] > 0 && config[i+1] < 6) { - printk(KERN_INFO "js%d: Multisystem joystick on %s\n", - js_register_device(port, i, 2, config[i+1], "Multisystem joystick", js_tg_open, js_tg_close), - info->port->port->name); - info->sticks |= (1 << i); - } - - if (!info->sticks) { - parport_unregister_device(info->port); - return port; - } - - js_tg_init_corr(info->sticks, port->corr); - - return port; -} - -#ifndef MODULE -int __init js_tg_setup(SETUP_PARAM) -{ - int i; - SETUP_PARSE(2); - for (i = 0; i <= ints[0] && i < 2; i++) js_tg[i] = ints[i+1]; - return 1; -} -int __init js_tg_setup_2(SETUP_PARAM) -{ - int i; - SETUP_PARSE(2); - for (i = 0; i <= ints[0] && i < 2; i++) js_tg_2[i] = ints[i+1]; - return 1; -} -int __init js_tg_setup_3(SETUP_PARAM) -{ - int i; - SETUP_PARSE(2); - for (i = 0; i <= ints[0] && i < 2; i++) js_tg_3[i] = ints[i+1]; - return 1; -} -__setup("js_tg=", js_tg_setup); -__setup("js_tg_2=", js_tg_setup_2); -__setup("js_tg_3=", js_tg_setup_3); -#endif - -#ifdef MODULE -int init_module(void) -#else -int __init js_tg_init(void) -#endif -{ - js_tg_port = js_tg_probe(js_tg, js_tg_port); - js_tg_port = js_tg_probe(js_tg_2, js_tg_port); - js_tg_port = js_tg_probe(js_tg_3, js_tg_port); - - if (js_tg_port) return 0; - -#ifdef MODULE - printk(KERN_WARNING "joy-tg: no joysticks specified\n"); -#endif - return -ENODEV; -} diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/joy-warrior.c linux/drivers/char/joystick/joy-warrior.c --- v2.4.0-test1/linux/drivers/char/joystick/joy-warrior.c Tue Apr 11 15:09:16 2000 +++ linux/drivers/char/joystick/joy-warrior.c Wed Dec 31 16:00:00 1969 @@ -1,303 +0,0 @@ -/* - * joy-warrior.c Version 0.1 - * - * Copyright (c) 1998 David Thompson - * Copyright (c) 1999 Vojtech Pavlik - * - * Sponsored by SuSE - */ - -/* - * This is a module for the Linux joystick driver, supporting - * the Logitech WingMan Warrior joystick. - */ - -/* - * This program is free warftware; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Constants. - */ - -#define N_JOYSTICK_WAR 13 -#define JS_WAR_MAX_LENGTH 16 - -/* - * List of Warriors. - */ - -static struct js_port* js_war_port = NULL; - -static char js_war_lengths[] = { 0, 4, 12, 3, 4, 4, 0, 0 }; - -/* - * Per-Warrior data. - */ - -struct js_war_info { - struct tty_struct* tty; - struct js_port* port; - int idx; - int len; - unsigned char data[JS_WAR_MAX_LENGTH]; - char used; -}; - -/* - * js_war_process_packet() decodes packets the driver receives from the - * Warrior. It updates the data accordingly. - */ - -static void js_war_process_packet(struct js_war_info* info) -{ - int **axes = info->port->axes; - int **buttons = info->port->buttons; - unsigned char *data = info->data; - int i; - - if (!info->idx) return; - - switch ((data[0] >> 4) & 7) { - - case 1: /* Button data */ - if (!info->port->devs[0]) return; - buttons[0][0] = ((data[3] & 0xa) >> 1) | ((data[3] & 0x5) << 1); - return; - case 3: /* XY-axis info->data */ - if (!info->port->devs[0]) return; - axes[0][0] = ((data[0] & 8) << 5) - (data[2] | ((data[0] & 4) << 5)); - axes[0][1] = (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7); - return; - break; - case 5: /* Throttle, spinner, hat info->data */ - if (!info->port->devs[0]) return; - axes[0][2] = (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7); - axes[0][3] = (data[3] & 2 ? 1 : 0) - (info->data[3] & 1 ? 1 : 0); - axes[0][4] = (data[3] & 8 ? 1 : 0) - (info->data[3] & 4 ? 1 : 0); - axes[0][5] = (data[2] | ((data[0] & 4) << 5)) - ((data[0] & 8) << 5); - return; - case 2: /* Static status (Send !S to get one) */ - case 4: /* Dynamic status */ - return; - default: - printk("joy-warrior: Unknown packet %d length %d:", (data[0] >> 4) & 7, info->idx); - for (i = 0; i < info->idx; i++) - printk(" %02x", data[i]); - printk("\n"); - return; - } -} - -/* - * js_war_open() is a callback from the joystick device open routine. - */ - -static int js_war_open(struct js_dev *jd) -{ - struct js_war_info *info = jd->port->info; - info->used++; - MOD_INC_USE_COUNT; - return 0; -} - -/* - * js_war_close() is a callback from the joystick device release routine. - */ - -static int js_war_close(struct js_dev *jd) -{ - struct js_war_info *info = jd->port->info; - if (!--info->used) { - js_unregister_device(jd->port->devs[0]); - js_war_port = js_unregister_port(jd->port); - } - MOD_DEC_USE_COUNT; - return 0; -} - -/* - * js_war_init_corr() initializes the correction values for the Warrior. - */ - -static void __init js_war_init_corr(struct js_corr **corr) -{ - int i; - - for (i = 0; i < 6; i++) { - corr[0][i].type = JS_CORR_BROKEN; - corr[0][i].prec = 0; - corr[0][i].coef[0] = -8; - corr[0][i].coef[1] = 8; - corr[0][i].coef[2] = (1 << 29) / (128 - 64); - corr[0][i].coef[3] = (1 << 29) / (128 - 64); - } - - corr[0][2].coef[2] = (1 << 29) / (128 - 16); - corr[0][2].coef[3] = (1 << 29) / (128 - 16); - - for (i = 3; i < 5; i++) { - corr[0][i].coef[0] = 0; - corr[0][i].coef[1] = 0; - corr[0][i].coef[2] = (1 << 29); - corr[0][i].coef[3] = (1 << 29); - } - - corr[0][5].prec = -1; - corr[0][5].coef[0] = 0; - corr[0][5].coef[1] = 0; - corr[0][5].coef[2] = (1 << 29) / 128; - corr[0][5].coef[3] = (1 << 29) / 128; -} - -/* - * js_war_ldisc_open() is the routine that is called upon setting our line - * discipline on a tty. - */ - -static int js_war_ldisc_open(struct tty_struct *tty) -{ - struct js_war_info iniinfo; - struct js_war_info *info = &iniinfo; - - MOD_INC_USE_COUNT; - - info->tty = tty; - info->idx = 0; - info->len = 0; - info->used = 1; - - js_war_port = js_register_port(js_war_port, info, 1, sizeof(struct js_war_info), NULL); - - info = js_war_port->info; - info->port = js_war_port; - tty->disc_data = info; - - printk(KERN_INFO "js%d: WingMan Warrior on %s%d\n", - js_register_device(js_war_port, 0, 6, 4, "WingMan Warrior", js_war_open, js_war_close), - tty->driver.name, MINOR(tty->device) - tty->driver.minor_start); - - js_war_init_corr(js_war_port->corr); - - return 0; -} - -/* - * js_war_ldisc_close() is the opposite of js_war_ldisc_open() - */ - -static void js_war_ldisc_close(struct tty_struct *tty) -{ - struct js_war_info* info = (struct js_war_info*) tty->disc_data; - if (!--info->used) { - js_unregister_device(info->port->devs[0]); - js_war_port = js_unregister_port(info->port); - } - MOD_DEC_USE_COUNT; -} - -/* - * js_war_ldisc_receive() is called by the low level driver when characters - * are ready for us. We then buffer them for further processing, or call the - * packet processing routine. - */ - -static void js_war_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) -{ - struct js_war_info* info = (struct js_war_info*) tty->disc_data; - int i; - - for (i = 0; i < count; i++) { - if (cp[i] & 0x80) { - if (info->idx) - js_war_process_packet(info); - info->idx = 0; - info->len = js_war_lengths[(cp[i] >> 4) & 7]; - } - - if (info->idx < JS_WAR_MAX_LENGTH) - info->data[info->idx++] = cp[i]; - - if (info->idx == info->len) { - if (info->idx) - js_war_process_packet(info); - info->idx = 0; - info->len = 0; - } - } -} - -/* - * js_war_ldisc_room() reports how much room we do have for receiving data. - * Although we in fact have infinite room, we need to specify some value - * here, so why not the size of our packet buffer. It's big anyway. - */ - -static int js_war_ldisc_room(struct tty_struct *tty) -{ - return JS_WAR_MAX_LENGTH; -} - -/* - * The line discipline structure. - */ - -static struct tty_ldisc js_war_ldisc = { - magic: TTY_LDISC_MAGIC, - name: "warrior", - open: js_war_ldisc_open, - close: js_war_ldisc_close, - receive_buf: js_war_ldisc_receive, - receive_room: js_war_ldisc_room, -}; - -/* - * The functions for inserting/removing us as a module. - */ - -#ifdef MODULE -int init_module(void) -#else -int __init js_war_init(void) -#endif -{ - if (tty_register_ldisc(N_JOYSTICK_WAR, &js_war_ldisc)) { - printk(KERN_ERR "joy-warrior: Error registering line discipline.\n"); - return -ENODEV; - } - - return 0; -} - -#ifdef MODULE -void cleanup_module(void) -{ - tty_register_ldisc(N_JOYSTICK_WAR, NULL); -} -#endif diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/joystick.c linux/drivers/char/joystick/joystick.c --- v2.4.0-test1/linux/drivers/char/joystick/joystick.c Wed Apr 26 16:34:07 2000 +++ linux/drivers/char/joystick/joystick.c Wed Dec 31 16:00:00 1969 @@ -1,854 +0,0 @@ -/* - * joystick.c Version 1.2 - * - * Copyright (c) 1996-1999 Vojtech Pavlik - * - * Sponsored by SuSE - */ - -/* - * This is the main joystick driver for Linux. It doesn't support any - * devices directly, rather is lets you use sub-modules to do that job. See - * Documentation/joystick.txt for more info. - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Configurable parameters. - */ - -#define JS_REFRESH_TIME HZ/50 /* Time between two reads of joysticks (20ms) */ - -/* - * Exported symbols. - */ - -EXPORT_SYMBOL(js_register_port); -EXPORT_SYMBOL(js_unregister_port); -EXPORT_SYMBOL(js_register_device); -EXPORT_SYMBOL(js_unregister_device); - -/* - * Buffer macros. - */ - -#define ROT(A,B,C) ((((A)<(C))&&(((B)>(A))&&((B)<(C))))||(((A)>(C))&&(((B)>(A))||((B)<(C))))) -#define GOF(X) (((X)==JS_BUFF_SIZE-1)?0:(X)+1) -#define GOB(X) ((X)?(X)-1:JS_BUFF_SIZE-1) -#define DIFF(X,Y) ((X)>(Y)?(X)-(Y):(Y)-(X)) - -/* - * Global variables. - */ - -static struct JS_DATA_SAVE_TYPE js_comp_glue; -static struct js_port *js_port = NULL; -static struct js_dev *js_dev = NULL; -static struct timer_list js_timer; -spinlock_t js_lock = SPIN_LOCK_UNLOCKED; -static int js_use_count = 0; - -/* - * Module info. - */ - -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_SUPPORTED_DEVICE("js"); - -/* - * js_correct() performs correction of raw joystick data. - */ - -static int js_correct(int value, struct js_corr *corr) -{ - switch (corr->type) { - case JS_CORR_NONE: - break; - case JS_CORR_BROKEN: - value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 : - ((corr->coef[3] * (value - corr->coef[1])) >> 14)) : - ((corr->coef[2] * (value - corr->coef[0])) >> 14); - break; - - default: - return 0; - } - - if (value < -32767) return -32767; - if (value > 32767) return 32767; - - return value; -} - -/* - * js_button() returns value of button number i. - */ - -static inline int js_button(int *buttons, int i) -{ - return (buttons[i >> 5] >> (i & 0x1f)) & 1; -} - -/* - * js_add_event() adds an event to the buffer. This requires additional - * queue post-processing done by js_sync_buff. - */ - -static void js_add_event(struct js_dev *jd, __u32 time, __u8 type, __u8 number, __s16 value) -{ - jd->buff[jd->ahead].time = time; - jd->buff[jd->ahead].type = type; - jd->buff[jd->ahead].number = number; - jd->buff[jd->ahead].value = value; - if (++jd->ahead == JS_BUFF_SIZE) jd->ahead = 0; -} - -/* - * js_flush_data() does the same as js_process_data, except for that it doesn't - * generate any events - it just copies the data from new to cur. - */ - -static void js_flush_data(struct js_dev *jd) -{ - int i; - - for (i = 0; i < ((jd->num_buttons - 1) >> 5) + 1; i++) - jd->cur.buttons[i] = jd->new.buttons[i]; - for (i = 0; i < jd->num_axes; i++) - jd->cur.axes[i] = jd->new.axes[i]; -} - -/* - * js_process_data() finds changes in button states and axis positions and adds - * them as events to the buffer. - */ - -static void js_process_data(struct js_dev *jd) -{ - int i, t; - - for (i = 0; i < jd->num_buttons; i++) - if ((t = js_button(jd->new.buttons, i)) != js_button(jd->cur.buttons, i)) { - js_add_event(jd, jiffies, JS_EVENT_BUTTON, i, t); - jd->cur.buttons[i >> 5] ^= (1 << (i & 0x1f)); - } - - for (i = 0; i < jd->num_axes; i++) { - t = js_correct(jd->new.axes[i], &jd->corr[i]); - if (((jd->corr[i].prec == -1) && t) || - ((DIFF(jd->new.axes[i], jd->cur.axes[i]) > jd->corr[i].prec) && - (t != js_correct(jd->cur.axes[i], &jd->corr[i])))) { - js_add_event(jd, jiffies, JS_EVENT_AXIS, i, t); - jd->cur.axes[i] = jd->new.axes[i]; - } - } -} - -/* - * js_sync_buff() checks for all overflows caused by recent additions to the buffer. - * These happen only if some process is reading the data too slowly. It - * wakes up any process waiting for data. - */ - -static void js_sync_buff(struct js_dev *jd) -{ - struct js_list *curl = jd->list; - - if (jd->bhead != jd->ahead) { - if(ROT(jd->bhead, jd->tail, jd->ahead) || (jd->tail == jd->bhead)) { - while (curl) { - if (ROT(jd->bhead, curl->tail, jd->ahead) || (curl->tail == jd->bhead)) { - curl->tail = jd->ahead; - curl->startup = 0; - } - curl = curl->next; - } - jd->tail = jd->ahead; - } - jd->bhead = jd->ahead; - wake_up_interruptible(&jd->wait); - } -} - -/* - * js_do_timer() acts as an interrupt replacement. It reads the data - * from all ports and then generates events for all devices. - */ - -static void js_do_timer(unsigned long data) -{ - struct js_port *curp = js_port; - struct js_dev *curd = js_dev; - unsigned long flags; - - while (curp) { - if (curp->read) - if (curp->read(curp->info, curp->axes, curp->buttons)) - curp->fail++; - curp->total++; - curp = curp->next; - } - - spin_lock_irqsave(&js_lock, flags); - - while (curd) { - if (data) { - js_process_data(curd); - js_sync_buff(curd); - } else { - js_flush_data(curd); - } - curd = curd->next; - } - - spin_unlock_irqrestore(&js_lock, flags); - - js_timer.expires = jiffies + JS_REFRESH_TIME; - add_timer(&js_timer); -} - -/* - * js_read() copies one or more entries from jsd[].buff to user - * space. - */ - -static ssize_t js_read(struct file *file, char *buf, size_t count, loff_t *ppos) -{ - DECLARE_WAITQUEUE(wait, current); - struct js_event *buff = (void *) buf; - struct js_list *curl; - struct js_dev *jd; - unsigned long blocks = count / sizeof(struct js_event); - int written = 0; - int new_tail, orig_tail; - int retval = 0; - unsigned long flags; - - curl = file->private_data; - jd = curl->dev; - orig_tail = curl->tail; - -/* - * Check user data. - */ - - if (!blocks) - return -EINVAL; - -/* - * Lock it. - */ - - spin_lock_irqsave(&js_lock, flags); - -/* - * Handle (non)blocking i/o. - */ - if (count != sizeof(struct JS_DATA_TYPE)) { - - if (GOF(curl->tail) == jd->bhead && curl->startup == jd->num_axes + jd->num_buttons) { - - __set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&jd->wait, &wait); - - while (GOF(curl->tail) == jd->bhead) { - - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - break; - } - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - - spin_unlock_irqrestore(&js_lock, flags); - schedule(); - spin_lock_irqsave(&js_lock, flags); - - } - - current->state = TASK_RUNNING; - remove_wait_queue(&jd->wait, &wait); - } - - if (retval) { - spin_unlock_irqrestore(&js_lock, flags); - return retval; - } - -/* - * Initial state. - */ - - while (curl->startup < jd->num_axes + jd->num_buttons && written < blocks && !retval) { - - struct js_event tmpevent; - - if (curl->startup < jd->num_buttons) { - tmpevent.type = JS_EVENT_BUTTON | JS_EVENT_INIT; - tmpevent.value = js_button(jd->cur.buttons, curl->startup); - tmpevent.number = curl->startup; - } else { - tmpevent.type = JS_EVENT_AXIS | JS_EVENT_INIT; - tmpevent.value = js_correct(jd->cur.axes[curl->startup - jd->num_buttons], - &jd->corr[curl->startup - jd->num_buttons]); - tmpevent.number = curl->startup - jd->num_buttons; - } - - tmpevent.time = jiffies * (1000/HZ); - - if (copy_to_user(&buff[written], &tmpevent, sizeof(struct js_event))) - retval = -EFAULT; - - curl->startup++; - written++; - } - -/* - * Buffer data. - */ - - while ((jd->bhead != (new_tail = GOF(curl->tail))) && (written < blocks) && !retval) { - - if (copy_to_user(&buff[written], &jd->buff[new_tail], sizeof(struct js_event))) - retval = -EFAULT; - if (put_user((__u32)(jd->buff[new_tail].time * (1000/HZ)), &buff[written].time)) - retval = -EFAULT; - - curl->tail = new_tail; - written++; - } - } - - else - -/* - * Handle version 0.x compatibility. - */ - - { - struct JS_DATA_TYPE data; - - data.buttons = jd->new.buttons[0]; - data.x = jd->num_axes < 1 ? 0 : - ((js_correct(jd->new.axes[0], &jd->corr[0]) / 256) + 128) >> js_comp_glue.JS_CORR.x; - data.y = jd->num_axes < 2 ? 0 : - ((js_correct(jd->new.axes[1], &jd->corr[1]) / 256) + 128) >> js_comp_glue.JS_CORR.y; - - retval = copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0; - - curl->startup = jd->num_axes + jd->num_buttons; - curl->tail = GOB(jd->bhead); - if (!retval) retval = sizeof(struct JS_DATA_TYPE); - } - -/* - * Check main tail and move it. - */ - - if (orig_tail == jd->tail) { - new_tail = curl->tail; - curl = jd->list; - while (curl && curl->tail != jd->tail) { - if (ROT(jd->bhead, new_tail, curl->tail) || - (jd->bhead == curl->tail)) new_tail = curl->tail; - curl = curl->next; - } - if (!curl) jd->tail = new_tail; - } - - spin_unlock_irqrestore(&js_lock, flags); - - return retval ? retval : written * sizeof(struct js_event); -} - -/* - * js_poll() does select() support. - */ - -static unsigned int js_poll(struct file *file, poll_table *wait) -{ - struct js_list *curl = file->private_data; - unsigned long flags; - int retval = 0; - poll_wait(file, &curl->dev->wait, wait); - spin_lock_irqsave(&js_lock, flags); - if (GOF(curl->tail) != curl->dev->bhead || - curl->startup < curl->dev->num_axes + curl->dev->num_buttons) retval = POLLIN | POLLRDNORM; - spin_unlock_irqrestore(&js_lock, flags); - return retval; -} - -/* - * js_ioctl handles misc ioctl calls. - */ - -static int js_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct js_list *curl; - struct js_dev *jd; - int len; - - curl = file->private_data; - jd = curl->dev; - - switch (cmd) { - -/* - * 0.x compatibility - */ - - case JS_SET_CAL: - return copy_from_user(&js_comp_glue.JS_CORR, (struct JS_DATA_TYPE *) arg, - sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0; - case JS_GET_CAL: - return copy_to_user((struct JS_DATA_TYPE *) arg, &js_comp_glue.JS_CORR, - sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0; - case JS_SET_TIMEOUT: - return get_user(js_comp_glue.JS_TIMEOUT, (int *) arg); - case JS_GET_TIMEOUT: - return put_user(js_comp_glue.JS_TIMEOUT, (int *) arg); - case JS_SET_TIMELIMIT: - return get_user(js_comp_glue.JS_TIMELIMIT, (long *) arg); - case JS_GET_TIMELIMIT: - return put_user(js_comp_glue.JS_TIMELIMIT, (long *) arg); - case JS_SET_ALL: - return copy_from_user(&js_comp_glue, (struct JS_DATA_SAVE_TYPE *) arg, - sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0; - case JS_GET_ALL: - return copy_to_user((struct JS_DATA_SAVE_TYPE *) arg, &js_comp_glue, - sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0; - -/* - * 1.x ioctl calls - */ - - case JSIOCGVERSION: - return put_user(JS_VERSION, (__u32 *) arg); - case JSIOCGAXES: - return put_user(jd->num_axes, (__u8 *) arg); - case JSIOCGBUTTONS: - return put_user(jd->num_buttons, (__u8 *) arg); - case JSIOCSCORR: - return copy_from_user(jd->corr, (struct js_corr *) arg, - sizeof(struct js_corr) * jd->num_axes) ? -EFAULT : 0; - case JSIOCGCORR: - return copy_to_user((struct js_corr *) arg, jd->corr, - sizeof(struct js_corr) * jd->num_axes) ? -EFAULT : 0; - default: - if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) { - len = strlen(jd->name) + 1; - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - if (copy_to_user((char *) arg, jd->name, len)) return -EFAULT; - return len; - } - } - - return -EINVAL; -} - -/* - * js_open() performs necessary initialization and adds - * an entry to the linked list. - */ - -static int js_open(struct inode *inode, struct file *file) -{ - struct js_list *curl, *new; - struct js_dev *jd = js_dev; - int i = MINOR(inode->i_rdev); - unsigned long flags; - int result; - - if (MAJOR(inode->i_rdev) != JOYSTICK_MAJOR) - return -EINVAL; - - - spin_lock_irqsave(&js_lock, flags); - - while (i > 0 && jd) { - jd = jd->next; - i--; - } - - spin_unlock_irqrestore(&js_lock, flags); - - if (!jd) return -ENODEV; - - if ((result = jd->open(jd))) - return result; - - MOD_INC_USE_COUNT; - - new = kmalloc(sizeof(struct js_list), GFP_KERNEL); - if (!new) { - jd->close(jd); - MOD_DEC_USE_COUNT; - return -ENOMEM; - } - - spin_lock_irqsave(&js_lock, flags); - - curl = jd->list; - - jd->list = new; - jd->list->next = curl; - jd->list->dev = jd; - jd->list->startup = 0; - jd->list->tail = GOB(jd->bhead); - file->private_data = jd->list; - - spin_unlock_irqrestore(&js_lock, flags); - - if (!js_use_count++) js_do_timer(0); - - return 0; -} - -/* - * js_release() removes an entry from list and deallocates memory - * used by it. - */ - -static int js_release(struct inode *inode, struct file *file) -{ - struct js_list *curl = file->private_data; - struct js_dev *jd = curl->dev; - struct js_list **curp = &jd->list; - int new_tail; - unsigned long flags; - - spin_lock_irqsave(&js_lock, flags); - - while (*curp && (*curp != curl)) curp = &((*curp)->next); - *curp = (*curp)->next; - - if (jd->list) - if (curl->tail == jd->tail) { - curl = jd->list; - new_tail = curl->tail; - while (curl && curl->tail != jd->tail) { - if (ROT(jd->bhead, new_tail, curl->tail) || - (jd->bhead == curl->tail)) new_tail = curl->tail; - curl = curl->next; - } - if (!curl) jd->tail = new_tail; - } - - spin_unlock_irqrestore(&js_lock, flags); - - kfree(file->private_data); - - if (!--js_use_count) del_timer(&js_timer); - - jd->close(jd); - - MOD_DEC_USE_COUNT; - - return 0; -} - -/* - * js_dump_mem() dumps all data structures in memory. - * It's used for debugging only. - */ - -struct js_port *js_register_port(struct js_port *port, - void *info, int devs, int infos, js_read_func read) -{ - struct js_port **ptrp = &js_port; - struct js_port *curp; - void *all; - int i; - unsigned long flags; - - if (!(all = kmalloc(sizeof(struct js_port) + 4 * devs * sizeof(void*) + infos, GFP_KERNEL))) - return NULL; - - curp = all; - - curp->next = NULL; - curp->prev = port; - curp->read = read; - curp->ndevs = devs; - curp->fail = 0; - curp->total = 0; - - curp->devs = all += sizeof(struct js_port); - for (i = 0; i < devs; i++) curp->devs[i] = NULL; - - curp->axes = all += devs * sizeof(void*); - curp->buttons = (void*) all += devs * sizeof(void*); - curp->corr = all += devs * sizeof(void*); - - if (infos) { - curp->info = all += devs * sizeof(void*); - memcpy(curp->info, info, infos); - } else { - curp->info = NULL; - } - - spin_lock_irqsave(&js_lock, flags); - - while (*ptrp) ptrp=&((*ptrp)->next); - *ptrp = curp; - - spin_unlock_irqrestore(&js_lock, flags); - - return curp; -} - -struct js_port *js_unregister_port(struct js_port *port) -{ - struct js_port **curp = &js_port; - struct js_port *prev; - unsigned long flags; - - spin_lock_irqsave(&js_lock, flags); - - printk("js: There were %d failures out of %d read attempts.\n", port->fail, port->total); - - while (*curp && (*curp != port)) curp = &((*curp)->next); - *curp = (*curp)->next; - - spin_unlock_irqrestore(&js_lock, flags); - - prev = port->prev; - kfree(port); - - return prev; -} - -extern struct file_operations js_fops; - -static devfs_handle_t devfs_handle = NULL; - -int js_register_device(struct js_port *port, int number, int axes, int buttons, char *name, - js_ops_func open, js_ops_func close) -{ - struct js_dev **ptrd = &js_dev; - struct js_dev *curd; - void *all; - int i = 0; - unsigned long flags; - char devfs_name[8]; - - if (!(all = kmalloc(sizeof(struct js_dev) + 2 * axes * sizeof(int) + - 2 * (((buttons - 1) >> 5) + 1) * sizeof(int) + - axes * sizeof(struct js_corr) + strlen(name) + 1, GFP_KERNEL))) - return -1; - - curd = all; - - curd->next = NULL; - curd->list = NULL; - curd->port = port; - curd->open = open; - curd->close = close; - - init_waitqueue_head(&curd->wait); - - curd->ahead = 0; - curd->bhead = 0; - curd->tail = JS_BUFF_SIZE - 1; - curd->num_axes = axes; - curd->num_buttons = buttons; - - curd->cur.axes = all += sizeof(struct js_dev); - curd->cur.buttons = all += axes * sizeof(int); - curd->new.axes = all += (((buttons - 1) >> 5) + 1) * sizeof(int); - curd->new.buttons = all += axes * sizeof(int); - curd->corr = all += (((buttons -1 ) >> 5) + 1) * sizeof(int); - - curd->name = all += axes * sizeof(struct js_corr); - strcpy(curd->name, name); - - port->devs[number] = curd; - port->axes[number] = curd->new.axes; - port->buttons[number] = curd->new.buttons; - port->corr[number] = curd->corr; - - spin_lock_irqsave(&js_lock, flags); - - while (*ptrd) { ptrd=&(*ptrd)->next; i++; } - *ptrd = curd; - - spin_unlock_irqrestore(&js_lock, flags); - - sprintf(devfs_name, "js%d", i); - curd->devfs_handle = devfs_register(devfs_handle, devfs_name, 0, - DEVFS_FL_DEFAULT, - JOYSTICK_MAJOR, i, - S_IFCHR | S_IRUGO | S_IWUSR, 0, 0, - &js_fops, NULL); - - return i; -} - -void js_unregister_device(struct js_dev *dev) -{ - struct js_dev **curd = &js_dev; - unsigned long flags; - - spin_lock_irqsave(&js_lock, flags); - - while (*curd && (*curd != dev)) curd = &((*curd)->next); - *curd = (*curd)->next; - - spin_unlock_irqrestore(&js_lock, flags); - - devfs_unregister(dev->devfs_handle); - kfree(dev); -} - -/* - * The operations structure. - */ - -static struct file_operations js_fops = -{ - read: js_read, - poll: js_poll, - ioctl: js_ioctl, - open: js_open, - release: js_release, -}; - -/* - * js_init() registers the driver and calls the probe function. - * also initializes some crucial variables. - */ - -#ifdef MODULE -int init_module(void) -#else -int __init js_init(void) -#endif -{ - - if (devfs_register_chrdev(JOYSTICK_MAJOR, "js", &js_fops)) { - printk(KERN_ERR "js: unable to get major %d for joystick\n", JOYSTICK_MAJOR); - return -EBUSY; - } - devfs_handle = devfs_mk_dir(NULL, "joysticks", 9, NULL); - - printk(KERN_INFO "js: Joystick driver v%d.%d.%d (c) 1999 Vojtech Pavlik \n", - JS_VERSION >> 16 & 0xff, JS_VERSION >> 8 & 0xff, JS_VERSION & 0xff); - - spin_lock_init(&js_lock); - - init_timer(&js_timer); - js_timer.function = js_do_timer; - js_timer.data = 1; - - memset(&js_comp_glue, 0, sizeof(struct JS_DATA_SAVE_TYPE)); - js_comp_glue.JS_TIMEOUT = JS_DEF_TIMEOUT; - js_comp_glue.JS_TIMELIMIT = JS_DEF_TIMELIMIT; - -#ifndef MODULE -#ifdef CONFIG_JOY_PCI - js_pci_init(); -#endif -#ifdef CONFIG_JOY_LIGHTNING - js_l4_init(); -#endif -#ifdef CONFIG_JOY_SIDEWINDER - js_sw_init(); -#endif -#ifdef CONFIG_JOY_ASSASSIN - js_as_init(); -#endif -#ifdef CONFIG_JOY_LOGITECH - js_lt_init(); -#endif -#ifdef CONFIG_JOY_THRUSTMASTER - js_tm_init(); -#endif -#ifdef CONFIG_JOY_GRAVIS - js_gr_init(); -#endif -#ifdef CONFIG_JOY_CREATIVE - js_cr_init(); -#endif -#ifdef CONFIG_JOY_ANALOG - js_an_init(); -#endif -#ifdef CONFIG_JOY_CONSOLE - js_console_init(); -#endif -#ifdef CONFIG_JOY_DB9 - js_db9_init(); -#endif -#ifdef CONFIG_JOY_TURBOGRAFX - js_tg_init(); -#endif -#ifdef CONFIG_JOY_AMIGA - js_am_init(); -#endif -#ifdef CONFIG_JOY_MAGELLAN - js_mag_init(); -#endif -#ifdef CONFIG_JOY_WARRIOR - js_war_init(); -#endif -#ifdef CONFIG_JOY_SPACEORB - js_orb_init(); -#endif -#ifdef CONFIG_JOY_SPACEBALL - js_sball_init(); -#endif -#endif - - return 0; -} - -/* - * cleanup_module() handles module removal. - */ - -#ifdef MODULE -void cleanup_module(void) -{ - del_timer(&js_timer); - devfs_unregister(devfs_handle); - if (devfs_unregister_chrdev(JOYSTICK_MAJOR, "js")) - printk(KERN_ERR "js: can't unregister device\n"); -} -#endif - diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/lightning.c linux/drivers/char/joystick/lightning.c --- v2.4.0-test1/linux/drivers/char/joystick/lightning.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick/lightning.c Wed Jun 21 08:22:21 2000 @@ -0,0 +1,300 @@ +/* + * $Id: lightning.c,v 1.7 2000/05/24 19:36:03 vojtech Exp $ + * + * Copyright (c) 1998-2000 Vojtech Pavlik + * + * Sponsored by SuSE + */ + +/* + * PDPI Lightning 4 gamecard driver for Linux. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define L4_PORT 0x201 +#define L4_SELECT_ANALOG 0xa4 +#define L4_SELECT_DIGITAL 0xa5 +#define L4_SELECT_SECONDARY 0xa6 +#define L4_CMD_ID 0x80 +#define L4_CMD_GETCAL 0x92 +#define L4_CMD_SETCAL 0x93 +#define L4_ID 0x04 +#define L4_BUSY 0x01 +#define L4_TIMEOUT 80 /* 80 us */ + +MODULE_AUTHOR("Vojtech Pavlik "); + +struct l4 { + struct gameport gameport; + unsigned char port; +} *l4_port[8]; + +/* + * l4_wait_ready() waits for the L4 to become ready. + */ + +static int l4_wait_ready(void) +{ + unsigned int t; + t = L4_TIMEOUT; + while ((inb(L4_PORT) & L4_BUSY) && t > 0) t--; + return -(t<=0); +} + +/* + * l4_cooked_read() reads data from the Lightning 4. + */ + +static int l4_cooked_read(struct gameport *gameport, int *axes, int *buttons) +{ + struct l4 *l4 = gameport->driver; + unsigned char status; + int i, result = -1; + + outb(L4_SELECT_ANALOG, L4_PORT); + outb(L4_SELECT_DIGITAL + (l4->port >> 2), L4_PORT); + + if (inb(L4_PORT) & L4_BUSY) goto fail; + outb(l4->port & 3, L4_PORT); + + if (l4_wait_ready()) goto fail; + status = inb(L4_PORT); + + for (i = 0; i < 4; i++) + if (status & (1 << i)) { + if (l4_wait_ready()) goto fail; + axes[i] = inb(L4_PORT); + if (axes[i] > 252) axes[i] = -1; + } + + if (status & 0x10) { + if (l4_wait_ready()) goto fail; + *buttons = inb(L4_PORT) & 0x0f; + } + + result = 0; + +fail: outb(L4_SELECT_ANALOG, L4_PORT); + return result; +} + +static int l4_open(struct gameport *gameport, int mode) +{ + struct l4 *l4 = gameport->driver; + if (l4->port != 0 && mode != GAMEPORT_MODE_COOKED) + return -1; + outb(L4_SELECT_ANALOG, L4_PORT); + return 0; +} + +/* + * l4_getcal() reads the L4 with calibration values. + */ + +static int l4_getcal(int port, int *cal) +{ + int i, result = -1; + + outb(L4_SELECT_ANALOG, L4_PORT); + outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT); + + if (inb(L4_PORT) & L4_BUSY) goto fail; + outb(L4_CMD_GETCAL, L4_PORT); + + if (l4_wait_ready()) goto fail; + if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2)) goto fail; + + if (l4_wait_ready()) goto fail; + outb(port & 3, L4_PORT); + + for (i = 0; i < 4; i++) { + if (l4_wait_ready()) goto fail; + cal[i] = inb(L4_PORT); + } + + result = 0; + +fail: outb(L4_SELECT_ANALOG, L4_PORT); + return result; +} + +/* + * l4_setcal() programs the L4 with calibration values. + */ + +static int l4_setcal(int port, int *cal) +{ + int i, result = -1; + + outb(L4_SELECT_ANALOG, L4_PORT); + outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT); + + if (inb(L4_PORT) & L4_BUSY) goto fail; + outb(L4_CMD_SETCAL, L4_PORT); + + if (l4_wait_ready()) goto fail; + if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2)) goto fail; + + if (l4_wait_ready()) goto fail; + outb(port & 3, L4_PORT); + + for (i = 0; i < 4; i++) { + if (l4_wait_ready()) goto fail; + outb(cal[i], L4_PORT); + } + + result = 0; + +fail: outb(L4_SELECT_ANALOG, L4_PORT); + return result; +} + +/* + * l4_calibrate() calibrates the L4 for the attached device, so + * that the device's resistance fits into the L4's 8-bit range. + */ + +static int l4_calibrate(struct gameport *gameport, int *axes, int *max) +{ + int i, t; + int cal[4]; + struct l4 *l4 = gameport->driver; + + if (l4_getcal(l4->port, cal)) + return -1; + + for (i = 0; i < 4; i++) { + t = (max[i] * cal[i]) / 200; + t = (t < 1) ? 1 : ((t > 255) ? 255 : t); + axes[i] = (axes[i] < 0) ? -1 : (axes[i] * cal[i]) / t; + axes[i] = (axes[i] > 252) ? 252 : axes[i]; + cal[i] = t; + } + + if (l4_setcal(l4->port, cal)) + return -1; + + return 0; +} + +int __init l4_init(void) +{ + int cal[4] = {255,255,255,255}; + int i, j, rev, cards = 0; + struct gameport *gameport; + struct l4 *l4; + + if (!request_region(L4_PORT, 1, "lightning")) + return -1; + + for (i = 0; i < 2; i++) { + + outb(L4_SELECT_ANALOG, L4_PORT); + outb(L4_SELECT_DIGITAL + i, L4_PORT); + + if (inb(L4_PORT) & L4_BUSY) continue; + outb(L4_CMD_ID, L4_PORT); + + if (l4_wait_ready()) continue; + if (inb(L4_PORT) != L4_SELECT_DIGITAL + i) continue; + + if (l4_wait_ready()) continue; + if (inb(L4_PORT) != L4_ID) continue; + + if (l4_wait_ready()) continue; + rev = inb(L4_PORT); + + if (!rev) continue; + + if (!(l4_port[i * 4] = kmalloc(sizeof(struct l4) * 4, GFP_KERNEL))) { + printk(KERN_ERR "lightning: Out of memory allocating ports.\n"); + continue; + } + memset(l4_port[i * 4], 0, sizeof(struct l4) * 4); + + for (j = 0; j < 4; j++) { + + l4 = l4_port[i * 4 + j] = l4_port[i * 4] + j; + l4->port = i * 4 + j; + + gameport = &l4->gameport; + gameport->driver = l4; + gameport->open = l4_open; + gameport->cooked_read = l4_cooked_read; + gameport->calibrate = l4_calibrate; + gameport->type = GAMEPORT_EXT; + + if (!i && !j) { + gameport->io = L4_PORT; + gameport->size = 1; + } + + if (rev > 0x28) /* on 2.9+ the setcal command works correctly */ + l4_setcal(l4->port, cal); + + gameport_register_port(gameport); + } + + printk(KERN_INFO "gameport%d,%d,%d,%d: PDPI Lightning 4 %s card v%d.%d at %#x\n", + l4_port[i * 4 + 0]->gameport.number, l4_port[i * 4 + 1]->gameport.number, + l4_port[i * 4 + 2]->gameport.number, l4_port[i * 4 + 3]->gameport.number, + i ? "secondary" : "primary", rev >> 4, rev, L4_PORT); + + cards++; + } + + outb(L4_SELECT_ANALOG, L4_PORT); + + if (!cards) { + release_region(L4_PORT, 1); + return -1; + } + + return 0; +} + +void __init l4_exit(void) +{ + int i; + int cal[4] = {59, 59, 59, 59}; + + for (i = 0; i < 8; i++) + if (l4_port[i]) { + l4_setcal(l4_port[i]->port, cal); + gameport_unregister_port(&l4_port[i]->gameport); + } + outb(L4_SELECT_ANALOG, L4_PORT); + release_region(L4_PORT, 1); +} + +module_init(l4_init); +module_exit(l4_exit); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/magellan.c linux/drivers/char/joystick/magellan.c --- v2.4.0-test1/linux/drivers/char/joystick/magellan.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick/magellan.c Wed Jun 21 08:22:21 2000 @@ -0,0 +1,210 @@ +/* + * $Id: magellan.c,v 1.8 2000/05/31 13:17:12 vojtech Exp $ + * + * Copyright (c) 1999-2000 Vojtech Pavlik + * + * Sponsored by SuSE + */ + +/* + * Magellan and Space Mouse 6dof controller driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include + +/* + * Definitions & global arrays. + */ + +#define MAGELLAN_MAX_LENGTH 32 + +static int magellan_buttons[] = { BTN_0, BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8}; +static int magellan_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ}; +static char *magellan_name = "LogiCad3D Magellan"; + +/* + * Per-Magellan data. + */ + +struct magellan { + struct input_dev dev; + int idx; + unsigned char data[MAGELLAN_MAX_LENGTH]; +}; + +/* + * magellan_crunch_nibbles() verifies that the bytes sent from the Magellan + * have correct upper nibbles for the lower ones, if not, the packet will + * be thrown away. It also strips these upper halves to simplify further + * processing. + */ + +static int magellan_crunch_nibbles(unsigned char *data, int count) +{ + static unsigned char nibbles[16] = "0AB3D56GH9:Kdev; + unsigned char *data = magellan->data; + int i, t; + + if (!magellan->idx) return; + + switch (magellan->data[0]) { + + case 'd': /* Axis data */ + if (magellan->idx != 25) return; + if (magellan_crunch_nibbles(data, 24)) return; + for (i = 0; i < 6; i++) + input_report_abs(dev, magellan_axes[i], + (data[(i << 2) + 1] << 12 | data[(i << 2) + 2] << 8 | + data[(i << 2) + 3] << 4 | data[(i << 2) + 4]) - 32768); + break; + + case 'k': /* Button data */ + if (magellan->idx != 4) return; + if (magellan_crunch_nibbles(data, 3)) return; + t = (data[1] << 1) | (data[2] << 5) | data[3]; + for (i = 0; i < 9; i++) input_report_key(dev, magellan_buttons[i], (t >> i) & 1); + break; + } +} + +static void magellan_interrupt(struct serio *serio, unsigned char data, unsigned int flags) +{ + struct magellan* magellan = serio->private; + + if (data == '\r') { + magellan_process_packet(magellan); + magellan->idx = 0; + } else { + if (magellan->idx < MAGELLAN_MAX_LENGTH) + magellan->data[magellan->idx++] = data; + } +} + +/* + * magellan_disconnect() is the opposite of magellan_connect() + */ + +static void magellan_disconnect(struct serio *serio) +{ + struct magellan* magellan = serio->private; + input_unregister_device(&magellan->dev); + serio_close(serio); + kfree(magellan); +} + +/* + * magellan_connect() is the routine that is called when someone adds a + * new serio device. It looks for the Magellan, and if found, registers + * it as an input device. + */ + +static void magellan_connect(struct serio *serio, struct serio_dev *dev) +{ + struct magellan *magellan; + int i, t; + + if (serio->type != (SERIO_RS232 | SERIO_MAGELLAN)) + return; + + if (!(magellan = kmalloc(sizeof(struct magellan), GFP_KERNEL))) + return; + + memset(magellan, 0, sizeof(struct magellan)); + + magellan->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + + for (i = 0; i < 9; i++) + set_bit(magellan_buttons[i], &magellan->dev.keybit); + + for (i = 0; i < 6; i++) { + t = magellan_axes[i]; + set_bit(t, magellan->dev.absbit); + magellan->dev.absmin[t] = -360; + magellan->dev.absmax[t] = 360; + } + + magellan->dev.private = magellan; + magellan->dev.name = magellan_name; + magellan->dev.idbus = BUS_RS232; + magellan->dev.idvendor = SERIO_MAGELLAN; + magellan->dev.idproduct = 0x0001; + magellan->dev.idversion = 0x0100; + + serio->private = magellan; + + if (serio_open(serio, dev)) { + kfree(magellan); + return; + } + + input_register_device(&magellan->dev); + + printk(KERN_INFO "input%d: %s on serio%d\n", magellan->dev.number, magellan_name, serio->number); +} + +/* + * The serio device structure. + */ + +static struct serio_dev magellan_dev = { + interrupt: magellan_interrupt, + connect: magellan_connect, + disconnect: magellan_disconnect, +}; + +/* + * The functions for inserting/removing us as a module. + */ + +int __init magellan_init(void) +{ + serio_register_device(&magellan_dev); + return 0; +} + +void __exit magellan_exit(void) +{ + serio_unregister_device(&magellan_dev); +} + +module_init(magellan_init); +module_exit(magellan_exit); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/ns558.c linux/drivers/char/joystick/ns558.c --- v2.4.0-test1/linux/drivers/char/joystick/ns558.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick/ns558.c Wed Jun 21 08:22:21 2000 @@ -0,0 +1,366 @@ +/* + * $Id: ns558.c,v 1.11 2000/06/20 23:35:03 vojtech Exp $ + * + * Copyright (c) 1999-2000 Vojtech Pavlik + * Copyright (c) 1999 Brian Gerst + * + * Sponsored by SuSE + */ + +/* + * NS558 based standard IBM game port driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); + +#define NS558_ISA 1 +#define NS558_PNP 2 +#define NS558_PCI 3 + +static int ns558_isa_portlist[] = { 0x201, 0x202, 0x203, 0x204, 0x205, 0x207, 0x209, + 0x20b, 0x20c, 0x20e, 0x20f, 0x211, 0x219, 0x101, 0 }; + +struct ns558 { + int type; + struct pci_dev *dev; + struct ns558 *next; + struct gameport gameport; +}; + +static struct ns558 *ns558 = NULL; + +/* + * ns558_isa_probe() tries to find an isa gameport at the + * specified address, and also checks for mirrors. + * A joystick must be attached for this to work. + */ + +static struct ns558* ns558_isa_probe(int io, struct ns558 *next) +{ + int i, j, b; + unsigned char c, u, v; + struct ns558 *port; + +/* + * No one should be using this address. + */ + + if (check_region(io, 1)) + return next; + +/* + * We must not be able to write arbitrary values to the port. + * The lower two axis bits must be 1 after a write. + */ + + c = inb(io); + outb(~c & ~3, io); + if (~(u = v = inb(io)) & 3) { + outb(c, io); + return next; + } +/* + * After a trigger, there must be at least some bits changing. + */ + + for (i = 0; i < 1000; i++) v &= inb(io); + + if (u == v) { + outb(c, io); + return next; + } + wait_ms(3); +/* + * After some time (4ms) the axes shouldn't change anymore. + */ + + u = inb(io); + for (i = 0; i < 1000; i++) + if ((u ^ inb(io)) & 0xf) { + outb(c, io); + return next; + } +/* + * And now find the number of mirrors of the port. + */ + + for (i = 1; i < 5; i++) { + + if (check_region(io & (-1 << i), (1 << i))) /* Don't disturb anyone */ + break; + + outb(0xff, io & (-1 << i)); + for (j = b = 0; j < 1000; j++) + if (inb(io & (-1 << i)) != inb((io & (-1 << i)) + (1 << i) - 1)) b++; + wait_ms(3); + + if (b > 300) /* We allow 30% difference */ + break; + } + + i--; + + if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) { + printk(KERN_ERR "Memory allocation failed.\n"); + return next; + } + memset(port, 0, sizeof(struct ns558)); + + port->next = next; + port->type = NS558_ISA; + port->gameport.io = io; + port->gameport.size = (1 << i); + + request_region(port->gameport.io, port->gameport.size, "ns558-isa"); + + gameport_register_port(&port->gameport); + + printk(KERN_INFO "gameport%d: NS558 ISA at %#x", port->gameport.number, port->gameport.io); + if (port->gameport.size > 1) printk(" size %d", port->gameport.size); + printk(" speed %d kHz\n", port->gameport.speed); + + return port; +} + +#ifdef CONFIG_PCI +static struct pci_device_id ns558_pci_tbl[] __devinitdata = { + { 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB Live! gameport */ + { 0x125d, 0x1969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, /* ESS Solo 1 */ + { 0x5333, 0xca00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, /* S3 SonicVibes */ + { 0, } +}; +MODULE_DEVICE_TABLE(pci, ns558_pci_tbl); + +static int __devinit ns558_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int ioport, iolen; + int rc; + struct ns558 *port; + + rc = pci_enable_device(pdev); + if (rc) { + printk(KERN_ERR "ns558: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n", + pdev->bus->number, pdev->devfn, rc); + return rc; + } + + ioport = pci_resource_start(pdev, ent->driver_data); + iolen = pci_resource_len(pdev, ent->driver_data); + + if (!request_region(ioport, iolen, "ns558-pci")) + return -EBUSY; + + if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) { + printk(KERN_ERR "Memory allocation failed.\n"); + return -ENOMEM; + } + memset(port, 0, sizeof(struct ns558)); + + port->next = ns558; + port->type = NS558_PCI; + port->gameport.io = ioport; + port->gameport.size = iolen; + port->dev = pdev; + ns558 = port; + + pdev->driver_data = port; + + gameport_register_port(&port->gameport); + + printk(KERN_INFO "gameport%d: NS558 PCI at %#x", port->gameport.number, port->gameport.io); + if (port->gameport.size > 1) printk(" size %d", port->gameport.size); + printk(" speed %d kHz\n", port->gameport.speed); + + return 0; +} + +static void __devexit ns558_pci_remove(struct pci_dev *pdev) +{ + struct ns558 *port = (struct ns558 *)pdev->driver_data; + release_region(port->gameport.io, port->gameport.size); +} + +static struct pci_driver ns558_pci_driver = { + name: "PCI Gameport", + id_table: ns558_pci_tbl, + probe: ns558_pci_probe, + remove: ns558_pci_remove, +}; +#endif /* CONFIG_PCI */ + + +#ifdef CONFIG_ISAPNP +/* + * PnP IDs: + * + * CTL00c1 - SB AWE32 PnP + * CTL00c3 - SB AWE64 PnP + * CTL00f0 - SB16 PnP / Vibra 16x + * CTL7001 - SB Vibra16C PnP + * CSC0b35 - Crystal ** doesn't have compatibility ID ** + * TER1141 - Terratec AD1818 + * YMM0800 - Yamaha OPL3-SA3 + * + * PNPb02f - Generic gameport + */ + +static struct pnp_devid { + unsigned int vendor, device; +} pnp_devids[] = { + { ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7002) }, + { ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0b35) }, + { ISAPNP_VENDOR('P','N','P'), ISAPNP_DEVICE(0xb02f) }, + { 0, }, +}; + +static struct ns558* ns558_pnp_probe(struct pci_dev *dev, struct ns558 *next) +{ + int ioport, iolen; + struct ns558 *port; + + if (dev->prepare && dev->prepare(dev) < 0) + return next; + + if (!(dev->resource[0].flags & IORESOURCE_IO)) { + printk(KERN_WARNING "No i/o ports on a gameport? Weird\n"); + return next; + } + + if (dev->activate && dev->activate(dev) < 0) { + printk(KERN_ERR "PnP resource allocation failed\n"); + return next; + } + + ioport = pci_resource_start(dev, 0); + iolen = pci_resource_len(dev, 0); + + if (!request_region(ioport, iolen, "ns558-pnp")) + goto deactivate; + + if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) { + printk(KERN_ERR "Memory allocation failed.\n"); + goto deactivate; + } + memset(port, 0, sizeof(struct ns558)); + + port->next = next; + port->type = NS558_PNP; + port->gameport.io = ioport; + port->gameport.size = iolen; + port->dev = dev; + + gameport_register_port(&port->gameport); + + printk(KERN_INFO "gameport%d: NS558 PnP at %#x", port->gameport.number, port->gameport.io); + if (port->gameport.size > 1) printk(" size %d", port->gameport.size); + printk(" speed %d kHz\n", port->gameport.speed); + + return port; + +deactivate: + if (dev->deactivate) + dev->deactivate(dev); + return next; +} +#endif + +int __init ns558_init(void) +{ + int i = 0; +#ifdef CONFIG_ISAPNP + struct pci_dev *dev = NULL; + struct pnp_devid *devid; +#endif + +/* + * Probe for ISA ports. + */ + + while (ns558_isa_portlist[i]) + ns558 = ns558_isa_probe(ns558_isa_portlist[i++], ns558); + +/* + * Probe for PCI ports. + */ +#ifdef CONFIG_PCI + pci_register_driver(&ns558_pci_driver); +#endif + +/* + * Probe for PnP ports. + */ + +#ifdef CONFIG_ISAPNP + for (devid = pnp_devids; devid->vendor; devid++) { + while ((dev = isapnp_find_dev(NULL, devid->vendor, devid->device, dev))) { + ns558 = ns558_pnp_probe(dev, ns558); + } + } +#endif + + return -!ns558; +} + +void __exit ns558_exit(void) +{ + struct ns558 *port = ns558; + + while (port) { + gameport_unregister_port(&port->gameport); + switch (port->type) { + +#ifdef CONFIG_ISAPNP + case NS558_PNP: + if (port->dev->deactivate) + port->dev->deactivate(port->dev); + /* fall through */ +#endif + + case NS558_ISA: + release_region(port->gameport.io, port->gameport.size); + break; + + default: + break; + } + + port = port->next; + } + +#ifdef CONFIG_PCI + pci_unregister_driver(&ns558_pci_driver); +#endif +} + +module_init(ns558_init); +module_exit(ns558_exit); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/pcigame.c linux/drivers/char/joystick/pcigame.c --- v2.4.0-test1/linux/drivers/char/joystick/pcigame.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick/pcigame.c Wed Jun 21 08:22:21 2000 @@ -0,0 +1,198 @@ +/* + * $Id: pcigame.c,v 1.6 2000/05/25 12:05:24 vojtech Exp $ + * + * Copyright (c) 2000 Vojtech Pavlik + * + * Based on the work of: + * Raymond Ingles + * + * Sponsored by SuSE + */ + +/* + * Trident 4DWave and Aureal Vortex gameport driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PCI_VENDOR_ID_AUREAL 0x12eb + +#define PCIGAME_DATA_WAIT 20 /* 20 ms */ + +#define PCIGAME_4DWAVE 0 +#define PCIGAME_VORTEX 1 +#define PCIGAME_VORTEX2 2 + +struct pcigame_data { + int gcr; /* Gameport control register */ + int legacy; /* Legacy port location */ + int axes; /* Axes start */ + int axsize; /* Axis field size */ + int axmax; /* Axis field max value */ + int adcmode; /* Value to enable ADC mode in GCR */ +}; + +static struct pcigame_data pcigame_data[] __devinitdata = +{{ 0x00030, 0x00031, 0x00034, 2, 0xffff, 0x80 }, + { 0x1100c, 0x11008, 0x11010, 4, 0x1fff, 0x40 }, + { 0x2880c, 0x28808, 0x28810, 4, 0x1fff, 0x40 }, + { 0 }}; + +struct pcigame { + struct gameport gameport; + struct pci_dev *dev; + unsigned char *base; + struct pcigame_data *data; +}; + +static unsigned char pcigame_read(struct gameport *gameport) +{ + struct pcigame *pcigame = gameport->driver; + return readb(pcigame->base + pcigame->data->legacy); +} + +static void pcigame_trigger(struct gameport *gameport) +{ + struct pcigame *pcigame = gameport->driver; + writeb(0xff, pcigame->base + pcigame->data->legacy); +} + +static int pcigame_cooked_read(struct gameport *gameport, int *axes, int *buttons) +{ + struct pcigame *pcigame = gameport->driver; + int i; + + *buttons = (~readb(pcigame->base + pcigame->data->legacy) >> 4) & 0xf; + + for (i = 0; i < 4; i++) { + axes[i] = readw(pcigame->base + pcigame->data->axes + i * pcigame->data->axsize); + if (axes[i] == pcigame->data->axmax) axes[i] = -1; + } + + return 0; +} + +static int pcigame_open(struct gameport *gameport, int mode) +{ + struct pcigame *pcigame = gameport->driver; + + switch (mode) { + case GAMEPORT_MODE_COOKED: + writeb(pcigame->data->adcmode, pcigame->base + pcigame->data->gcr); + wait_ms(PCIGAME_DATA_WAIT); + return 0; + case GAMEPORT_MODE_RAW: + writeb(0, pcigame->base + pcigame->data->gcr); + return 0; + default: + return -1; + } + + return 0; +} + +static int __devinit pcigame_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct pcigame *pcigame; + int i; + + if (!(pcigame = kmalloc(sizeof(struct pcigame), GFP_KERNEL))) + return -1; + memset(pcigame, 0, sizeof(struct pcigame)); + + + pcigame->data = pcigame_data + id->driver_data; + + pcigame->dev = dev; + dev->driver_data = pcigame; + + pcigame->gameport.driver = pcigame; + pcigame->gameport.type = GAMEPORT_EXT; + pcigame->gameport.fuzz = 64; + + pcigame->gameport.read = pcigame_read; + pcigame->gameport.trigger = pcigame_trigger; + pcigame->gameport.cooked_read = pcigame_cooked_read; + pcigame->gameport.open = pcigame_open; + + for (i = 0; i < 6; i++) + if (~pci_resource_flags(dev, i) & IORESOURCE_IO) + break; + + pci_enable_device(dev); + + pcigame->base = ioremap(pci_resource_start(pcigame->dev, i), + pci_resource_len(pcigame->dev, i)); + + gameport_register_port(&pcigame->gameport); + + printk(KERN_INFO "gameport%d: %s at pci%02x:%02x.%x speed %d kHz\n", + pcigame->gameport.number, dev->name, dev->bus->number, + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), pcigame->gameport.speed); + + return 0; +} + +static void __devexit pcigame_remove(struct pci_dev *dev) +{ + struct pcigame *pcigame = dev->driver_data; + gameport_unregister_port(&pcigame->gameport); + iounmap(pcigame->base); + kfree(pcigame); +} + +static struct pci_device_id pcigame_id_table[] __devinitdata = +{{ PCI_VENDOR_ID_TRIDENT, 0x2000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_4DWAVE }, + { PCI_VENDOR_ID_TRIDENT, 0x2001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_4DWAVE }, + { PCI_VENDOR_ID_AUREAL, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_VORTEX }, + { PCI_VENDOR_ID_AUREAL, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_VORTEX2 }, + { 0 }}; + +static struct pci_driver pcigame_driver = { + name: "pcigame", + id_table: pcigame_id_table, + probe: pcigame_probe, + remove: pcigame_remove, +}; + +int __init pcigame_init(void) +{ + return pci_module_init(&pcigame_driver); +} + +void __exit pcigame_exit(void) +{ + pci_unregister_driver(&pcigame_driver); +} + +module_init(pcigame_init); +module_exit(pcigame_exit); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/serio.c linux/drivers/char/joystick/serio.c --- v2.4.0-test1/linux/drivers/char/joystick/serio.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick/serio.c Thu Jun 22 06:59:58 2000 @@ -0,0 +1,132 @@ +/* + * $Id: serio.c,v 1.5 2000/06/04 17:44:59 vojtech Exp $ + * + * Copyright (c) 1999-2000 Vojtech Pavlik + * + * Sponsored by SuSE + */ + +/* + * The Serio abstraction module + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); + +EXPORT_SYMBOL(serio_register_port); +EXPORT_SYMBOL(serio_unregister_port); +EXPORT_SYMBOL(serio_register_device); +EXPORT_SYMBOL(serio_unregister_device); +EXPORT_SYMBOL(serio_open); +EXPORT_SYMBOL(serio_close); +EXPORT_SYMBOL(serio_rescan); + +static struct serio *serio_list = NULL; +static struct serio_dev *serio_dev = NULL; +static int serio_number = 0; + +static void serio_find_dev(struct serio *serio) +{ + struct serio_dev *dev = serio_dev; + + while (dev && !serio->dev) { + if (dev->connect) + dev->connect(serio, dev); + dev = dev->next; + } +} + +void serio_rescan(struct serio *serio) +{ + if (serio->dev && serio->dev->disconnect) + serio->dev->disconnect(serio); + serio_find_dev(serio); +} + +void serio_register_port(struct serio *serio) +{ + serio->number = serio_number++; + serio->next = serio_list; + serio_list = serio; + serio_find_dev(serio); +} + +void serio_unregister_port(struct serio *serio) +{ + struct serio **serioptr = &serio_list; + + while (*serioptr && (*serioptr != serio)) serioptr = &((*serioptr)->next); + *serioptr = (*serioptr)->next; + + if (serio->dev && serio->dev->disconnect) + serio->dev->disconnect(serio); + + serio_number--; +} + +void serio_register_device(struct serio_dev *dev) +{ + struct serio *serio = serio_list; + + dev->next = serio_dev; + serio_dev = dev; + + while (serio) { + if (!serio->dev && dev->connect) + dev->connect(serio, dev); + serio = serio->next; + } +} + +void serio_unregister_device(struct serio_dev *dev) +{ + struct serio_dev **devptr = &serio_dev; + struct serio *serio = serio_list; + + while (*devptr && (*devptr != dev)) devptr = &((*devptr)->next); + *devptr = (*devptr)->next; + + while (serio) { + if (serio->dev == dev && dev->disconnect) + dev->disconnect(serio); + serio_find_dev(serio); + serio = serio->next; + } +} + +int serio_open(struct serio *serio, struct serio_dev *dev) +{ + if (serio->open(serio)) + return -1; + serio->dev = dev; + return 0; +} + +void serio_close(struct serio *serio) +{ + serio->close(serio); + serio->dev = NULL; +} diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/serport.c linux/drivers/char/joystick/serport.c --- v2.4.0-test1/linux/drivers/char/joystick/serport.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick/serport.c Wed Jun 21 08:22:21 2000 @@ -0,0 +1,220 @@ +/* + * $Id: serport.c,v 1.4 2000/05/29 10:54:53 vojtech Exp $ + * + * Copyright (c) 1999-2000 Vojtech Pavlik + * + * Sponsored by SuSE + */ + +/* + * This is a module that converts a tty line into a much simpler + * 'serial io port' abstraction that the input device drivers use. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include + +struct serport { + struct tty_struct *tty; + wait_queue_head_t wait; + struct serio serio; +}; + +/* + * Callback functions from the serio code. + */ + +static int serport_serio_write(struct serio *serio, unsigned char data) +{ + struct serport *serport = serio->driver; + return -(serport->tty->driver.write(serport->tty, 0, &data, 1) != 1); +} + +static int serport_serio_open(struct serio *serio) +{ + return 0; +} + +static void serport_serio_close(struct serio *serio) +{ + struct serport *serport = serio->driver; + wake_up_interruptible(&serport->wait); +} + +/* + * serport_ldisc_open() is the routine that is called upon setting our line + * discipline on a tty. It looks for the Mag, and if found, registers + * it as a joystick device. + */ + +static int serport_ldisc_open(struct tty_struct *tty) +{ + struct serport *serport; + + MOD_INC_USE_COUNT; + + if (!(serport = kmalloc(sizeof(struct serport), GFP_KERNEL))) { + MOD_DEC_USE_COUNT; + return -ENOMEM; + } + + memset(serport, 0, sizeof(struct serport)); + + serport->tty = tty; + tty->disc_data = serport; + + serport->serio.type = SERIO_RS232; + serport->serio.write = serport_serio_write; + serport->serio.open = serport_serio_open; + serport->serio.close = serport_serio_close; + serport->serio.driver = serport; + + init_waitqueue_head(&serport->wait); + + return 0; +} + +/* + * serport_ldisc_close() is the opposite of serport_ldisc_open() + */ + +static void serport_ldisc_close(struct tty_struct *tty) +{ + struct serport *serport = (struct serport*) tty->disc_data; + kfree(serport); + MOD_DEC_USE_COUNT; +} + +/* + * serport_ldisc_receive() is called by the low level tty driver when characters + * are ready for us. We forward the characters, one by one to the 'interrupt' + * routine. + */ + +static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) +{ + struct serport *serport = (struct serport*) tty->disc_data; + int i; + for (i = 0; i < count; i++) + if (serport->serio.dev) + serport->serio.dev->interrupt(&serport->serio, cp[i], 0); +} + +/* + * serport_ldisc_room() reports how much room we do have for receiving data. + * Although we in fact have infinite room, we need to specify some value + * here, and 256 seems to be reasonable. + */ + +static int serport_ldisc_room(struct tty_struct *tty) +{ + return 256; +} + +/* + * serport_ldisc_read() just waits indefinitely if everything goes well. + * However, when the serio driver closes the serio port, it finishes, + * returning 0 characters. + */ + +static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, unsigned char * buf, size_t nr) +{ + struct serport *serport = (struct serport*) tty->disc_data; + DECLARE_WAITQUEUE(wait, current); + char name[32]; + + sprintf(name, tty->driver.name, MINOR(tty->device) - tty->driver.minor_start); + + serio_register_port(&serport->serio); + + printk(KERN_INFO "serio%d: Serial port %s\n", serport->serio.number, name); + + add_wait_queue(&serport->wait, &wait); + current->state = TASK_INTERRUPTIBLE; + + while(serport->serio.type && !signal_pending(current)) schedule(); + + current->state = TASK_RUNNING; + remove_wait_queue(&serport->wait, &wait); + + serio_unregister_port(&serport->serio); + + return 0; +} + +/* + * serport_ldisc_ioctl() allows to set the port protocol, and device ID + */ + +static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg) +{ + struct serport *serport = (struct serport*) tty->disc_data; + + switch (cmd) { + case SPIOCSTYPE: + return get_user(serport->serio.type, (unsigned long *) arg); + } + + return -EINVAL; +} + +/* + * The line discipline structure. + */ + +static struct tty_ldisc serport_ldisc = { + name: "input", + open: serport_ldisc_open, + close: serport_ldisc_close, + read: serport_ldisc_read, + ioctl: serport_ldisc_ioctl, + receive_buf: serport_ldisc_receive, + receive_room: serport_ldisc_room, +}; + +/* + * The functions for insering/removing us as a module. + */ + +int __init serport_init(void) +{ + if (tty_register_ldisc(N_MOUSE, &serport_ldisc)) { + printk(KERN_ERR "serport.c: Error registering line discipline.\n"); + return -ENODEV; + } + + return 0; +} + +void __exit serport_exit(void) +{ + tty_register_ldisc(N_MOUSE, NULL); +} + +module_init(serport_init); +module_exit(serport_exit); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/sidewinder.c linux/drivers/char/joystick/sidewinder.c --- v2.4.0-test1/linux/drivers/char/joystick/sidewinder.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick/sidewinder.c Thu Jun 22 06:59:58 2000 @@ -0,0 +1,756 @@ +/* + * $Id: sidewinder.c,v 1.14 2000/05/29 11:27:55 vojtech Exp $ + * + * Copyright (c) 1998-2000 Vojtech Pavlik + * + * Sponsored by SuSE + */ + +/* + * Microsoft SideWinder joystick family driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * These are really magic values. Changing them can make a problem go away, + * as well as break everything. + */ + +#undef SW_DEBUG + +#define SW_START 400 /* The time we wait for the first bit [400 us] */ +#define SW_STROBE 45 /* Max time per bit [45 us] */ +#define SW_TIMEOUT 4000 /* Wait for everything to settle [4 ms] */ +#define SW_KICK 45 /* Wait after A0 fall till kick [45 us] */ +#define SW_END 8 /* Number of bits before end of packet to kick */ +#define SW_FAIL 16 /* Number of packet read errors to fail and reinitialize */ +#define SW_BAD 2 /* Number of packet read errors to switch off 3d Pro optimization */ +#define SW_OK 64 /* Number of packet read successes to switch optimization back on */ +#define SW_LENGTH 512 /* Max number of bits in a packet */ +#define SW_REFRESH HZ/50 /* Time to wait between updates of joystick data [20 ms] */ + +#ifdef SW_DEBUG +#define dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg) +#else +#define dbg(format, arg...) do {} while (0) +#endif + +/* + * SideWinder joystick types ... + */ + +#define SW_ID_3DP 0 +#define SW_ID_GP 1 +#define SW_ID_PP 2 +#define SW_ID_FFP 3 +#define SW_ID_FSP 4 +#define SW_ID_FFW 5 + +/* + * Names, buttons, axes ... + */ + +static char *sw_name[] = { "3D Pro", "GamePad", "Precision Pro", "Force Feedback Pro", "FreeStyle Pro", + "Force Feedback Wheel" }; + +static char sw_abs[][7] = { + { ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y }, + { ABS_X, ABS_Y }, + { ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y }, + { ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y }, + { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y }, + { ABS_RX, ABS_RUDDER, ABS_THROTTLE }}; + +static char sw_bit[][7] = { + { 10, 10, 9, 10, 1, 1 }, + { 1, 1 }, + { 10, 10, 6, 7, 1, 1 }, + { 10, 10, 6, 7, 1, 1 }, + { 10, 10, 6, 1, 1 }, + { 10, 7, 7, 1, 1 }}; + +static short sw_btn[][12] = { + { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_MODE }, + { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE }, + { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_SELECT }, + { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_SELECT }, + { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT }, + { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3 }}; + +static struct { + int x; + int y; +} sw_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; + +struct sw { + struct gameport *gameport; + struct timer_list timer; + struct input_dev dev[4]; + char name[64]; + int length; + int type; + int bits; + int number; + int fail; + int ok; + int reads; + int bads; + int used; +}; + +/* + * sw_read_packet() is a function which reads either a data packet, or an + * identification packet from a SideWinder joystick. The protocol is very, + * very, very braindamaged. Microsoft patented it in US patent #5628686. + */ + +static int sw_read_packet(struct gameport *gameport, unsigned char *buf, int length, int id) +{ + unsigned long flags; + int timeout, bitout, sched, i, kick, start, strobe; + unsigned char pending, u, v; + + i = -id; /* Don't care about data, only want ID */ + timeout = id ? gameport_time(gameport, SW_TIMEOUT) : 0; /* Set up global timeout for ID packet */ + kick = id ? gameport_time(gameport, SW_KICK) : 0; /* Set up kick timeout for ID packet */ + start = gameport_time(gameport, SW_START); + strobe = gameport_time(gameport, SW_STROBE); + bitout = start; + pending = 0; + sched = 0; + + __save_flags(flags); /* Quiet, please */ + __cli(); + + gameport_trigger(gameport); /* Trigger */ + v = gameport_read(gameport); + + do { + bitout--; + u = v; + v = gameport_read(gameport); + } while (!(~v & u & 0x10) && (bitout > 0)); /* Wait for first falling edge on clock */ + + if (bitout > 0) bitout = strobe; /* Extend time if not timed out */ + + while ((timeout > 0 || bitout > 0) && (i < length)) { + + timeout--; + bitout--; /* Decrement timers */ + sched--; + + u = v; + v = gameport_read(gameport); + + if ((~u & v & 0x10) && (bitout > 0)) { /* Rising edge on clock - data bit */ + if (i >= 0) /* Want this data */ + buf[i] = v >> 5; /* Store it */ + i++; /* Advance index */ + bitout = strobe; /* Extend timeout for next bit */ + } + + if (kick && (~v & u & 0x01)) { /* Falling edge on axis 0 */ + sched = kick; /* Schedule second trigger */ + kick = 0; /* Don't schedule next time on falling edge */ + pending = 1; /* Mark schedule */ + } + + if (pending && sched < 0 && (i > -SW_END)) { /* Second trigger time */ + gameport_trigger(gameport); /* Trigger */ + bitout = start; /* Long bit timeout */ + pending = 0; /* Unmark schedule */ + timeout = 0; /* Switch from global to bit timeouts */ + } + } + + __restore_flags(flags); /* Done - relax */ + +#ifdef SW_DEBUG + { + int j; + printk(KERN_DEBUG "sidewinder.c: Read %d triplets. [", i); + for (j = 0; j < i; j++) printk("%d", buf[j]); + printk("]\n"); + } +#endif + + return i; +} + +/* + * sw_get_bits() and GB() compose bits from the triplet buffer into a __u64. + * Parameter 'pos' is bit number inside packet where to start at, 'num' is number + * of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits + * is number of bits per triplet. + */ + +#define GB(pos,num) sw_get_bits(buf, pos, num, sw->bits) + +static __u64 sw_get_bits(unsigned char *buf, int pos, int num, char bits) +{ + __u64 data = 0; + int tri = pos % bits; /* Start position */ + int i = pos / bits; + int bit = 0; + + while (num--) { + data |= (__u64)((buf[i] >> tri++) & 1) << bit++; /* Transfer bit */ + if (tri == bits) { + i++; /* Next triplet */ + tri = 0; + } + } + + return data; +} + +/* + * sw_init_digital() initializes a SideWinder 3D Pro joystick + * into digital mode. + */ + +static void sw_init_digital(struct gameport *gameport) +{ + int seq[] = { 140, 140+725, 140+300, 0 }; + unsigned long flags; + int i, t; + + __save_flags(flags); + __cli(); + + i = 0; + do { + gameport_trigger(gameport); /* Trigger */ + t = gameport_time(gameport, SW_TIMEOUT); + while ((gameport_read(gameport) & 1) && t) t--; /* Wait for axis to fall back to 0 */ + udelay(seq[i]); /* Delay magic time */ + } while (seq[++i]); + + gameport_trigger(gameport); /* Last trigger */ + + __restore_flags(flags); +} + +/* + * sw_parity() computes parity of __u64 + */ + +static int sw_parity(__u64 t) +{ + int x = t ^ (t >> 32); + x ^= x >> 16; + x ^= x >> 8; + x ^= x >> 4; + x ^= x >> 2; + x ^= x >> 1; + return x & 1; +} + +/* + * sw_ccheck() checks synchronization bits and computes checksum of nibbles. + */ + +static int sw_check(__u64 t) +{ + unsigned char sum = 0; + + if ((t & 0x8080808080808080ULL) ^ 0x80) /* Sync */ + return -1; + + while (t) { /* Sum */ + sum += t & 0xf; + t >>= 4; + } + + return sum & 0xf; +} + +/* + * sw_parse() analyzes SideWinder joystick data, and writes the results into + * the axes and buttons arrays. + */ + +static int sw_parse(unsigned char *buf, struct sw *sw) +{ + int hat, i, j; + struct input_dev *dev = sw->dev; + + switch (sw->type) { + + case SW_ID_3DP: + + if (sw_check(GB(0,64)) || (hat = (GB(6,1) << 3) | GB(60,3)) > 8) return -1; + + input_report_abs(dev, ABS_X, (GB( 3,3) << 7) | GB(16,7)); + input_report_abs(dev, ABS_Y, (GB( 0,3) << 7) | GB(24,7)); + input_report_abs(dev, ABS_RZ, (GB(35,2) << 7) | GB(40,7)); + input_report_abs(dev, ABS_THROTTLE, (GB(32,3) << 7) | GB(48,7)); + + input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x); + input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y); + + for (j = 0; j < 7; j++) + input_report_key(dev, sw_btn[SW_ID_3DP][j], !GB(j+8,1)); + + input_report_key(dev, BTN_BASE4, !GB(38,1)); + input_report_key(dev, BTN_BASE5, !GB(37,1)); + + return 0; + + case SW_ID_GP: + + for (i = 0; i < sw->number; i ++) { + + if (sw_parity(GB(i*15,15))) return -1; + + input_report_key(dev + i, ABS_X, GB(i*15+3,1) - GB(i*15+2,1)); + input_report_key(dev + i, ABS_Y, GB(i*15+0,1) - GB(i*15+1,1)); + + for (j = 0; j < 10; j++) + input_report_key(dev, sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1)); + } + + return 0; + + case SW_ID_PP: + case SW_ID_FFP: + + if (!sw_parity(GB(0,48)) || (hat = GB(42,4)) > 8) return -1; + + input_report_abs(dev, ABS_X, GB( 9,10)); + input_report_abs(dev, ABS_Y, GB(19,10)); + input_report_abs(dev, ABS_RZ, GB(36, 6)); + input_report_abs(dev, ABS_THROTTLE, GB(29, 7)); + + input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x); + input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y); + + for (j = 0; j < 9; j++) + input_report_key(dev, sw_btn[SW_ID_PP][j], !GB(j,1)); + + return 0; + + case SW_ID_FSP: + + if (!sw_parity(GB(0,43)) || (hat = GB(28,4)) > 8) return -1; + + input_report_abs(dev, ABS_X, GB( 0,10)); + input_report_abs(dev, ABS_Y, GB(16,10)); + input_report_abs(dev, ABS_THROTTLE, GB(32, 6)); + + input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x); + input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y); + + for (j = 0; j < 6; j++) + input_report_key(dev, sw_btn[SW_ID_FSP][j], !GB(j+10,1)); + + input_report_key(dev, BTN_TR, GB(26,1)); + input_report_key(dev, BTN_START, GB(27,1)); + input_report_key(dev, BTN_MODE, GB(38,1)); + input_report_key(dev, BTN_SELECT, GB(39,1)); + + return 0; + + case SW_ID_FFW: + + if (!sw_parity(GB(0,33))) return -1; + + input_report_abs(dev, ABS_RX, GB( 0,10)); + input_report_abs(dev, ABS_RUDDER, GB(10, 6)); + input_report_abs(dev, ABS_THROTTLE, GB(16, 6)); + + for (j = 0; j < 8; j++) + input_report_key(dev, sw_btn[SW_ID_FFW][j], !GB(j+22,1)); + + return 0; + } + + return -1; +} + +/* + * sw_read() reads SideWinder joystick data, and reinitializes + * the joystick in case of persistent problems. This is the function that is + * called from the generic code to poll the joystick. + */ + +static int sw_read(struct sw *sw) +{ + unsigned char buf[SW_LENGTH]; + int i; + + i = sw_read_packet(sw->gameport, buf, sw->length, 0); + + if (sw->type == SW_ID_3DP && sw->length == 66 && i != 66) { /* Broken packet, try to fix */ + + if (i == 64 && !sw_check(sw_get_bits(buf,0,64,1))) { /* Last init failed, 1 bit mode */ + printk(KERN_WARNING "sidewinder.c: Joystick in wrong mode on gameport%d" + " - going to reinitialize.\n", sw->gameport->number); + sw->fail = SW_FAIL; /* Reinitialize */ + i = 128; /* Bogus value */ + } + + if (i < 66 && GB(0,64) == GB(i*3-66,64)) /* 1 == 3 */ + i = 66; /* Everything is fine */ + + if (i < 66 && GB(0,64) == GB(66,64)) /* 1 == 2 */ + i = 66; /* Everything is fine */ + + if (i < 66 && GB(i*3-132,64) == GB(i*3-66,64)) { /* 2 == 3 */ + memmove(buf, buf + i - 22, 22); /* Move data */ + i = 66; /* Carry on */ + } + } + + if (i == sw->length && !sw_parse(buf, sw)) { /* Parse data */ + + sw->fail = 0; + sw->ok++; + + if (sw->type == SW_ID_3DP && sw->length == 66 /* Many packets OK */ + && sw->ok > SW_OK) { + + printk(KERN_INFO "sidewinder.c: No more trouble on gameport%d" + " - enabling optimization again.\n", sw->gameport->number); + sw->length = 22; + } + + return 0; + } + + sw->ok = 0; + sw->fail++; + + if (sw->type == SW_ID_3DP && sw->length == 22 && sw->fail > SW_BAD) { /* Consecutive bad packets */ + + printk(KERN_INFO "sidewinder.c: Many bit errors on gameport%d" + " - disabling optimization.\n", sw->gameport->number); + sw->length = 66; + } + + if (sw->fail < SW_FAIL) return -1; /* Not enough, don't reinitialize yet */ + + printk(KERN_WARNING "sidewinder.c: Too many bit errors on gameport%d" + " - reinitializing joystick.\n", sw->gameport->number); + + if (!i && sw->type == SW_ID_3DP) { /* 3D Pro can be in analog mode */ + udelay(3 * SW_TIMEOUT); + sw_init_digital(sw->gameport); + } + + udelay(SW_TIMEOUT); + i = sw_read_packet(sw->gameport, buf, SW_LENGTH, 0); /* Read normal data packet */ + udelay(SW_TIMEOUT); + sw_read_packet(sw->gameport, buf, SW_LENGTH, i); /* Read ID packet, this initializes the stick */ + + sw->fail = SW_FAIL; + + return -1; +} + +static void sw_timer(unsigned long private) +{ + struct sw *sw = (void *) private; + + sw->reads++; + if (sw_read(sw)) sw->bads++; + mod_timer(&sw->timer, jiffies + SW_REFRESH); +} + +static int sw_open(struct input_dev *dev) +{ + struct sw *sw = dev->private; + if (!sw->used++) + mod_timer(&sw->timer, jiffies + SW_REFRESH); + return 0; +} + +static void sw_close(struct input_dev *dev) +{ + struct sw *sw = dev->private; + if (!--sw->used) + del_timer(&sw->timer); +} + +/* + * sw_print_packet() prints the contents of a SideWinder packet. + */ + +static void sw_print_packet(char *name, int length, unsigned char *buf, char bits) +{ + int i; + + printk(KERN_INFO "sidewinder.c: %s packet, %d bits. [", name, length); + for (i = (((length + 3) >> 2) - 1); i >= 0; i--) + printk("%x", (int)sw_get_bits(buf, i << 2, 4, bits)); + printk("]\n"); +} + +/* + * sw_3dp_id() translates the 3DP id into a human legible string. + * Unfortunately I don't know how to do this for the other SW types. + */ + +static void sw_3dp_id(unsigned char *buf, char *comment) +{ + int i; + char pnp[8], rev[9]; + + for (i = 0; i < 7; i++) /* ASCII PnP ID */ + pnp[i] = sw_get_bits(buf, 24+8*i, 8, 1); + + for (i = 0; i < 8; i++) /* ASCII firmware revision */ + rev[i] = sw_get_bits(buf, 88+8*i, 8, 1); + + pnp[7] = rev[8] = 0; + + sprintf(comment, " [PnP %d.%02d id %s rev %s]", + (int) ((sw_get_bits(buf, 8, 6, 1) << 6) | /* Two 6-bit values */ + sw_get_bits(buf, 16, 6, 1)) / 100, + (int) ((sw_get_bits(buf, 8, 6, 1) << 6) | + sw_get_bits(buf, 16, 6, 1)) % 100, + pnp, rev); +} + +/* + * sw_guess_mode() checks the upper two button bits for toggling - + * indication of that the joystick is in 3-bit mode. This is documented + * behavior for 3DP ID packet, and for example the FSP does this in + * normal packets instead. Fun ... + */ + +static int sw_guess_mode(unsigned char *buf, int len) +{ + int i; + unsigned char xor = 0; + for (i = 1; i < len; i++) xor |= (buf[i - 1] ^ buf[i]) & 6; + return !!xor * 2 + 1; +} + +/* + * sw_connect() probes for SideWinder type joysticks. + */ + +static void sw_connect(struct gameport *gameport, struct gameport_dev *dev) +{ + struct sw *sw; + int i, j, k, l; + unsigned char buf[SW_LENGTH]; + unsigned char idbuf[SW_LENGTH]; + unsigned char m = 1; + char comment[40]; + + comment[0] = 0; + + if (!(sw = kmalloc(sizeof(struct sw), GFP_KERNEL))) return; + memset(sw, 0, sizeof(struct sw)); + + gameport->private = sw; + + sw->gameport = gameport; + init_timer(&sw->timer); + sw->timer.data = (long) sw; + sw->timer.function = sw_timer; + + if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) + goto fail1; + + i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Read normal packet */ + m |= sw_guess_mode(buf, i); /* Data packet (1-bit) can carry mode info [FSP] */ + udelay(SW_TIMEOUT); + dbg("Init 1: Mode %d. Length %d.", m , i); + + if (!i) { /* No data. 3d Pro analog mode? */ + sw_init_digital(gameport); /* Switch to digital */ + udelay(SW_TIMEOUT); + i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Retry reading packet */ + udelay(SW_TIMEOUT); + dbg("Init 1b: Length %d.", i); + if (!i) goto fail2; /* No data -> FAIL */ + } + + j = sw_read_packet(gameport, idbuf, SW_LENGTH, i); /* Read ID. This initializes the stick */ + m |= sw_guess_mode(idbuf, j); /* ID packet should carry mode info [3DP] */ + dbg("Init 2: Mode %d. ID Length %d.", m , j); + + if (!j) { /* Read ID failed. Happens in 1-bit mode on PP */ + udelay(SW_TIMEOUT); + i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Retry reading packet */ + dbg("Init 2b: Mode %d. Length %d.", m, i); + if (!i) goto fail2; + udelay(SW_TIMEOUT); + j = sw_read_packet(gameport, idbuf, SW_LENGTH, i); /* Retry reading ID */ + dbg("Init 2c: ID Length %d.", j); + } + + sw->type = -1; + k = SW_FAIL; /* Try SW_FAIL times */ + l = 0; + + do { + k--; + udelay(SW_TIMEOUT); + i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Read data packet */ + dbg("Init 3: Mode %d. Length %d. Last %d. Tries %d.", m, i, l, k); + + if (i > l) { /* Longer? As we can only lose bits, it makes */ + /* no sense to try detection for a packet shorter */ + l = i; /* than the previous one */ + + sw->number = 1; + sw->gameport = gameport; + sw->length = i; + sw->bits = m; + + dbg("Init 3a: Case %d.\n", i * m); + + switch (i * m) { + case 60: + sw->number++; + case 45: /* Ambiguous packet length */ + if (j <= 40) { /* ID length less or eq 40 -> FSP */ + case 43: + sw->type = SW_ID_FSP; + break; + } + sw->number++; + case 30: + sw->number++; + case 15: + sw->type = SW_ID_GP; + break; + case 33: + case 31: + sw->type = SW_ID_FFW; + break; + case 48: /* Ambiguous */ + if (j == 14) { /* ID length 14*3 -> FFP */ + sw->type = SW_ID_FFP; + sprintf(comment, " [AC %s]", sw_get_bits(idbuf,38,1,3) ? "off" : "on"); + } else + sw->type = SW_ID_PP; + break; + case 198: + sw->length = 22; + case 64: + sw->type = SW_ID_3DP; + if (j == 160) sw_3dp_id(idbuf, comment); + break; + } + } + + } while (k && (sw->type == -1)); + + if (sw->type == -1) { + printk(KERN_WARNING "sidewinder.c: unknown joystick device detected " + "on gameport%d, contact \n", gameport->number); + sw_print_packet("ID", j * 3, idbuf, 3); + sw_print_packet("Data", i * m, buf, m); + goto fail2; + } + +#ifdef SW_DEBUG + sw_print_packet("ID", j * 3, idbuf, 3); + sw_print_packet("Data", i * m, buf, m); +#endif + + k = i; + l = j; + + for (i = 0; i < sw->number; i++) { + int bits, code; + + sprintf(sw->name, "Microsoft SideWinder %s", sw_name[sw->type]); + + sw->dev[i].private = sw; + + sw->dev[i].open = sw_open; + sw->dev[i].close = sw_close; + + sw->dev[i].name = sw->name; + sw->dev[i].idbus = BUS_GAMEPORT; + sw->dev[i].idvendor = GAMEPORT_ID_VENDOR_MICROSOFT; + sw->dev[i].idproduct = sw->type; + sw->dev[i].idversion = 0x0100; + + sw->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + + for (j = 0; (bits = sw_bit[sw->type][j]); j++) { + code = sw_abs[sw->type][j]; + set_bit(code, sw->dev[i].absbit); + sw->dev[i].absmax[code] = (1 << bits) - 1; + sw->dev[i].absmin[code] = (bits == 1) ? -1 : 0; + sw->dev[i].absfuzz[code] = ((bits >> 1) >= 2) ? (1 << ((bits >> 1) - 2)) : 0; + if (code != ABS_THROTTLE) + sw->dev[i].absflat[code] = (bits >= 5) ? (1 << (bits - 5)) : 0; + } + + for (j = 0; (code = sw_btn[sw->type][j]); j++) + set_bit(code, sw->dev[i].keybit); + + input_register_device(sw->dev + i); + printk(KERN_INFO "input%d: %s%s on gameport%d.%d [%d-bit id %d data %d]\n", + sw->dev[i].number, sw->name, comment, gameport->number, i, m, l, k); + } + + return; +fail2: gameport_close(gameport); +fail1: kfree(sw); +} + +static void sw_disconnect(struct gameport *gameport) +{ + int i; + + struct sw *sw = gameport->private; + for (i = 0; i < sw->number; i++) + input_unregister_device(sw->dev + i); + gameport_close(gameport); + kfree(sw); +} + +static struct gameport_dev sw_dev = { + connect: sw_connect, + disconnect: sw_disconnect, +}; + +int __init sw_init(void) +{ + gameport_register_device(&sw_dev); + return 0; +} + +void __exit sw_exit(void) +{ + gameport_unregister_device(&sw_dev); +} + +module_init(sw_init); +module_exit(sw_exit); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/spaceball.c linux/drivers/char/joystick/spaceball.c --- v2.4.0-test1/linux/drivers/char/joystick/spaceball.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick/spaceball.c Wed Jun 21 08:22:21 2000 @@ -0,0 +1,231 @@ +/* + * $Id: spaceball.c,v 1.6 2000/05/29 11:19:51 vojtech Exp $ + * + * Copyright (c) 1999-2000 Vojtech Pavlik + * + * Based on the work of: + * David Thompson + * Joseph Krahn + * + * Sponsored by SuSE + */ + +/* + * SpaceTec SpaceBall 4000 FLX driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include + +/* + * Constants. + */ + +#define JS_SBALL_MAX_LENGTH 128 +static int spaceball_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ }; +static char *spaceball_name = "SpaceTec SpaceBall 4000 FLX"; + +/* + * Per-Ball data. + */ + +struct spaceball { + struct input_dev dev; + struct serio *serio; + int idx; + int escape; + unsigned char data[JS_SBALL_MAX_LENGTH]; +}; + +/* + * spaceball_process_packet() decodes packets the driver receives from the + * SpaceBall. + */ + +static void spaceball_process_packet(struct spaceball* spaceball) +{ + struct input_dev *dev = &spaceball->dev; + unsigned char *data = spaceball->data; + int i, d; + + if (spaceball->idx < 2) return; + + switch (spaceball->data[0]) { + + case '@': /* Reset packet */ + spaceball->data[spaceball->idx - 1] = 0; + for (i = 1; i < spaceball->idx && spaceball->data[i] == ' '; i++); + printk(KERN_INFO "input%d: %s [%s] on serio%d\n", + spaceball->dev.number, spaceball_name, spaceball->data + i, spaceball->serio->number); + break; + + case 'D': /* Ball data */ + if (spaceball->idx != 16) return; + for (i = 0; i < 6; i++) { + d = ((data[2 * i + 3] << 8) | data[2 * i + 2]); + input_report_abs(dev, spaceball_axes[i], d - ((d & 0x8000) ? 0x10000 : 0)); + } + break; + + case '.': /* Button data, part2 */ + if (spaceball->idx != 4) return; + input_report_key(dev, BTN_LEFT, data[2] & 1); + input_report_key(dev, BTN_RIGHT, data[2] & 2); + break; + + case '?': /* Error packet */ + spaceball->data[spaceball->idx - 1] = 0; + printk(KERN_ERR "spaceball: Device error. [%s]\n", spaceball->data + 1); + break; + } +} + +/* + * Spaceball 4000 FLX packets all start with a one letter packet-type decriptor, + * and end in 0x0d. It uses '^' as an escape for 0x0d characters which can + * occur in the axis values. ^M, ^Q and ^S all mean 0x0d, depending (I think) + * on whether the axis value is increasing, decreasing, or same as before. + * (I don't see why this is useful). + */ + +static void spaceball_interrupt(struct serio *serio, unsigned char data, unsigned int flags) +{ + struct spaceball *spaceball = serio->private; + + switch (data) { + case 0xd: + if (spaceball->idx) + spaceball_process_packet(spaceball); + spaceball->idx = 0; + spaceball->escape = 0; + return; + case 'M': + case 'Q': + case 'S': + if (spaceball->escape) + data = 0xd; + case '^': + spaceball->escape ^= 1; + default: + if (spaceball->escape) { + printk(KERN_WARNING "spaceball.c: Unknown escaped character: %#x\n", data); + spaceball->escape = 0; + } + if (spaceball->idx < JS_SBALL_MAX_LENGTH) + spaceball->data[spaceball->idx++] = data; + return; + } +} + +/* + * spaceball_disconnect() is the opposite of spaceball_connect() + */ + +static void spaceball_disconnect(struct serio *serio) +{ + struct spaceball* spaceball = serio->private; + input_unregister_device(&spaceball->dev); + serio_close(serio); + kfree(spaceball); +} + +/* + * spaceball_connect() is the routine that is called when someone adds a + * new serio device. It looks for the Magellan, and if found, registers + * it as an input device. + */ + +static void spaceball_connect(struct serio *serio, struct serio_dev *dev) +{ + struct spaceball *spaceball; + int i, t; + + if (serio->type != (SERIO_RS232 | SERIO_SPACEBALL)) + return; + + if (!(spaceball = kmalloc(sizeof(struct spaceball), GFP_KERNEL))) + return; + memset(spaceball, 0, sizeof(struct spaceball)); + + spaceball->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + spaceball->dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT); + + for (i = 0; i < 6; i++) { + t = spaceball_axes[i]; + set_bit(t, spaceball->dev.absbit); + spaceball->dev.absmin[t] = i < 3 ? -10000 : -2000; + spaceball->dev.absmax[t] = i < 3 ? 10000 : 2000; + spaceball->dev.absflat[t] = i < 3 ? 50 : 10; + spaceball->dev.absfuzz[t] = i < 3 ? 12 : 2; + } + + spaceball->serio = serio; + spaceball->dev.private = spaceball; + + spaceball->dev.name = spaceball_name; + spaceball->dev.idbus = BUS_RS232; + spaceball->dev.idvendor = SERIO_SPACEBALL; + spaceball->dev.idproduct = 0x0001; + spaceball->dev.idversion = 0x0100; + + serio->private = spaceball; + + if (serio_open(serio, dev)) { + kfree(spaceball); + return; + } + + input_register_device(&spaceball->dev); +} + +/* + * The serio device structure. + */ + +static struct serio_dev spaceball_dev = { + interrupt: spaceball_interrupt, + connect: spaceball_connect, + disconnect: spaceball_disconnect, +}; + +/* + * The functions for inserting/removing us as a module. + */ + +int __init spaceball_init(void) +{ + serio_register_device(&spaceball_dev); + return 0; +} + +void __exit spaceball_exit(void) +{ + serio_unregister_device(&spaceball_dev); +} + +module_init(spaceball_init); +module_exit(spaceball_exit); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/spaceorb.c linux/drivers/char/joystick/spaceorb.c --- v2.4.0-test1/linux/drivers/char/joystick/spaceorb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick/spaceorb.c Wed Jun 21 08:22:21 2000 @@ -0,0 +1,225 @@ +/* + * $Id: spaceorb.c,v 1.7 2000/05/29 11:19:51 vojtech Exp $ + * + * Copyright (c) 1999-2000 Vojtech Pavlik + * + * Based on the work of: + * David Thompson + * + * Sponsored by SuSE + */ + +/* + * SpaceTec SpaceOrb 360 and Avenger 6dof controller driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include + +/* + * Constants. + */ + +#define SPACEORB_MAX_LENGTH 64 + +static int spaceorb_buttons[] = { BTN_TL, BTN_TR, BTN_Y, BTN_X, BTN_B, BTN_A, BTN_MODE}; +static int spaceorb_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ}; +static char *spaceorb_name = "SpaceTec SpaceOrb 360"; + +/* + * Per-Orb data. + */ + +struct spaceorb { + struct input_dev dev; + struct serio *serio; + int idx; + unsigned char data[SPACEORB_MAX_LENGTH]; +}; + +static unsigned char spaceorb_xor[] = "SpaceWare"; + +static unsigned char *spaceorb_errors[] = { "EEPROM storing 0 failed", "Receive queue overflow", "Transmit queue timeout", + "Bad packet", "Power brown-out", "EEPROM checksum error", "Hardware fault" }; + +/* + * spaceorb_process_packet() decodes packets the driver receives from the + * SpaceOrb. + */ + +static void spaceorb_process_packet(struct spaceorb *spaceorb) +{ + struct input_dev *dev = &spaceorb->dev; + unsigned char *data = spaceorb->data; + unsigned char c = 0; + int axes[6]; + int i; + + if (spaceorb->idx < 2) return; + for (i = 0; i < spaceorb->idx; i++) c ^= data[i]; + if (c) return; + + switch (data[0]) { + + case 'R': /* Reset packet */ + spaceorb->data[spaceorb->idx - 1] = 0; + for (i = 1; i < spaceorb->idx && spaceorb->data[i] == ' '; i++); + printk(KERN_INFO "input%d: %s [%s] on serio%d\n", + spaceorb->dev.number, spaceorb_name, spaceorb->data + i, spaceorb->serio->number); + break; + + case 'D': /* Ball + button data */ + if (spaceorb->idx != 12) return; + for (i = 0; i < 9; i++) spaceorb->data[i+2] ^= spaceorb_xor[i]; + axes[0] = ( data[2] << 3) | (data[ 3] >> 4); + axes[1] = ((data[3] & 0x0f) << 6) | (data[ 4] >> 1); + axes[2] = ((data[4] & 0x01) << 9) | (data[ 5] << 2) | (data[4] >> 5); + axes[3] = ((data[6] & 0x1f) << 5) | (data[ 7] >> 2); + axes[4] = ((data[7] & 0x03) << 8) | (data[ 8] << 1) | (data[7] >> 6); + axes[5] = ((data[9] & 0x3f) << 4) | (data[10] >> 3); + for (i = 0; i < 6; i++) + input_report_abs(dev, spaceorb_axes[i], axes[i] - ((axes[i] & 0x200) ? 1024 : 0)); + for (i = 0; i < 8; i++) + input_report_key(dev, spaceorb_buttons[i], (data[1] >> i) & 1); + break; + + case 'K': /* Button data */ + if (spaceorb->idx != 5) return; + for (i = 0; i < 7; i++) + input_report_key(dev, spaceorb_buttons[i], (data[2] >> i) & 1); + + break; + + case 'E': /* Error packet */ + if (spaceorb->idx != 4) return; + printk(KERN_ERR "joy-spaceorb: Device error. [ "); + for (i = 0; i < 7; i++) if (data[1] & (1 << i)) printk("%s ", spaceorb_errors[i]); + printk("]\n"); + break; + } +} + +static void spaceorb_interrupt(struct serio *serio, unsigned char data, unsigned int flags) +{ + struct spaceorb* spaceorb = serio->private; + + if (~data & 0x80) { + if (spaceorb->idx) spaceorb_process_packet(spaceorb); + spaceorb->idx = 0; + } + if (spaceorb->idx < SPACEORB_MAX_LENGTH) + spaceorb->data[spaceorb->idx++] = data & 0x7f; +} + +/* + * spaceorb_disconnect() is the opposite of spaceorb_connect() + */ + +static void spaceorb_disconnect(struct serio *serio) +{ + struct spaceorb* spaceorb = serio->private; + input_unregister_device(&spaceorb->dev); + serio_close(serio); + kfree(spaceorb); +} + +/* + * spaceorb_connect() is the routine that is called when someone adds a + * new serio device. It looks for the SpaceOrb/Avenger, and if found, registers + * it as an input device. + */ + +static void spaceorb_connect(struct serio *serio, struct serio_dev *dev) +{ + struct spaceorb *spaceorb; + int i, t; + + if (serio->type != (SERIO_RS232 | SERIO_SPACEORB)) + return; + + if (!(spaceorb = kmalloc(sizeof(struct spaceorb), GFP_KERNEL))) + return; + memset(spaceorb, 0, sizeof(struct spaceorb)); + + spaceorb->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + + for (i = 0; i < 7; i++) + set_bit(spaceorb_buttons[i], &spaceorb->dev.keybit); + + for (i = 0; i < 6; i++) { + t = spaceorb_axes[i]; + set_bit(t, spaceorb->dev.absbit); + spaceorb->dev.absmin[t] = -508; + spaceorb->dev.absmax[t] = 508; + } + + spaceorb->serio = serio; + spaceorb->dev.private = spaceorb; + + spaceorb->dev.name = spaceorb_name; + spaceorb->dev.idbus = BUS_RS232; + spaceorb->dev.idvendor = SERIO_SPACEORB; + spaceorb->dev.idproduct = 0x0001; + spaceorb->dev.idversion = 0x0100; + + serio->private = spaceorb; + + if (serio_open(serio, dev)) { + kfree(spaceorb); + return; + } + + input_register_device(&spaceorb->dev); +} + +/* + * The serio device structure. + */ + +static struct serio_dev spaceorb_dev = { + interrupt: spaceorb_interrupt, + connect: spaceorb_connect, + disconnect: spaceorb_disconnect, +}; + +/* + * The functions for inserting/removing us as a module. + */ + +int __init spaceorb_init(void) +{ + serio_register_device(&spaceorb_dev); + return 0; +} + +void __exit spaceorb_exit(void) +{ + serio_unregister_device(&spaceorb_dev); +} + +module_init(spaceorb_init); +module_exit(spaceorb_exit); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/tmdc.c linux/drivers/char/joystick/tmdc.c --- v2.4.0-test1/linux/drivers/char/joystick/tmdc.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick/tmdc.c Wed Jun 21 08:22:21 2000 @@ -0,0 +1,348 @@ +/* + * $Id: tmdc.c,v 1.18 2000/06/08 19:59:59 vojtech Exp $ + * + * Copyright (c) 1998-2000 Vojtech Pavlik + * + * Sponsored by SuSE + * + * Based on the work of: + * Trystan Larey-Williams + * + */ + +/* + * ThrustMaster DirectConnect (BSP) joystick family driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include + +#define TMDC_MAX_START 400 /* 400 us */ +#define TMDC_MAX_STROBE 45 /* 45 us */ +#define TMDC_MAX_LENGTH 13 +#define TMDC_REFRESH_TIME HZ/50 /* 20 ms */ + +#define TMDC_MODE_M3DI 1 +#define TMDC_MODE_3DRP 3 +#define TMDC_MODE_FGP 163 + +#define TMDC_BYTE_ID 10 +#define TMDC_BYTE_REV 11 +#define TMDC_BYTE_DEF 12 + +#define TMDC_ABS 7 +#define TMDC_ABS_HAT 4 +#define TMDC_BTN_PAD 10 +#define TMDC_BTN_JOY 16 + +static unsigned char tmdc_byte_a[16] = { 0, 1, 3, 4, 6, 7 }; +static unsigned char tmdc_byte_d[16] = { 2, 5, 8, 9 }; + +static unsigned char tmdc_abs[TMDC_ABS] = + { ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE, ABS_RX, ABS_RY, ABS_RZ }; +static unsigned char tmdc_abs_hat[TMDC_ABS_HAT] = + { ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y }; +static unsigned short tmdc_btn_pad[TMDC_BTN_PAD] = + { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_START, BTN_SELECT, BTN_TL, BTN_TR }; +static unsigned short tmdc_btn_joy[TMDC_BTN_JOY] = + { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_THUMB2, BTN_PINKIE, + BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z }; + +struct tmdc { + struct gameport *gameport; + struct timer_list timer; + struct input_dev dev[2]; + char name[2][64]; + int mode[2]; + int used; + int reads; + int bads; + unsigned char exists; +}; + +/* + * tmdc_read_packet() reads a ThrustMaster packet. + */ + +static int tmdc_read_packet(struct gameport *gameport, unsigned char data[2][TMDC_MAX_LENGTH]) +{ + unsigned char u, v, w, x; + unsigned long flags; + int i[2], j[2], t[2], p, k; + + p = gameport_time(gameport, TMDC_MAX_STROBE); + + for (k = 0; k < 2; k++) { + t[k] = gameport_time(gameport, TMDC_MAX_START); + i[k] = j[k] = 0; + } + + __save_flags(flags); + __cli(); + gameport_trigger(gameport); + + w = gameport_read(gameport) >> 4; + + do { + x = w; + w = gameport_read(gameport) >> 4; + + for (k = 0, v = w, u = x; k < 2; k++, v >>= 2, u >>= 2) { + if (~v & u & 2) { + if (t[k] <= 0 || i[k] >= TMDC_MAX_LENGTH) continue; + t[k] = p; + if (j[k] == 0) { /* Start bit */ + if (~v & 1) t[k] = 0; + data[k][i[k]] = 0; j[k]++; continue; + } + if (j[k] == 9) { /* Stop bit */ + if (v & 1) t[k] = 0; + j[k] = 0; i[k]++; continue; + } + data[k][i[k]] |= (~v & 1) << (j[k]++ - 1); /* Data bit */ + } + t[k]--; + } + } while (t[0] > 0 || t[1] > 0); + + __restore_flags(flags); + + return (i[0] == TMDC_MAX_LENGTH) | ((i[1] == TMDC_MAX_LENGTH) << 1); +} + +/* + * tmdc_read() reads and analyzes ThrustMaster joystick data. + */ + +static void tmdc_timer(unsigned long private) +{ + unsigned char data[2][TMDC_MAX_LENGTH]; + struct tmdc *tmdc = (void *) private; + struct input_dev *dev; + unsigned char r, bad = 0; + int i, j; + + tmdc->reads++; + + if ((r = tmdc_read_packet(tmdc->gameport, data)) != tmdc->exists) + bad = 1; + + for (j = 0; j < 2; j++) + if (r & (1 << j) & tmdc->exists) { + + if (data[j][TMDC_BYTE_ID] != tmdc->mode[j]) { + bad = 1; + continue; + } + + dev = tmdc->dev + j; + + for (i = 0; i < data[j][TMDC_BYTE_DEF] >> 4; i++) + input_report_abs(dev, tmdc_abs[i], data[j][tmdc_byte_a[i]]); + + switch (tmdc->mode[j]) { + + case TMDC_MODE_M3DI: + + i = tmdc_byte_d[0]; + + input_report_abs(dev, ABS_HAT0X, ((data[j][i] >> 3) & 1) - ((data[j][i] >> 1) & 1)); + input_report_abs(dev, ABS_HAT0Y, ((data[j][i] >> 2) & 1) - ( data[j][i] & 1)); + + for (i = 0; i < 4; i++) + input_report_key(dev, tmdc_btn_joy[i], + (data[j][tmdc_byte_d[0]] >> (i + 4)) & 1); + for (i = 0; i < 2; i++) + input_report_key(dev, tmdc_btn_joy[i + 4], + (data[j][tmdc_byte_d[1]] >> (i + 6)) & 1); + + break; + + case TMDC_MODE_3DRP: + case TMDC_MODE_FGP: + + for (i = 0; i < 10; i++) + input_report_key(dev, tmdc_btn_pad[i], + (data[j][tmdc_byte_d[i >> 3]] >> (i & 7)) & 1); + + break; + + default: + + for (i = 0; i < ((data[j][TMDC_BYTE_DEF] & 0xf) << 3) && i < TMDC_BTN_JOY; i++) + input_report_key(dev, tmdc_btn_joy[i], + (data[j][tmdc_byte_d[i >> 3]] >> (i & 7)) & 1); + + break; + + } + } + + tmdc->bads += bad; + + mod_timer(&tmdc->timer, jiffies + TMDC_REFRESH_TIME); +} + +static int tmdc_open(struct input_dev *dev) +{ + struct tmdc *tmdc = dev->private; + if (!tmdc->used++) + mod_timer(&tmdc->timer, jiffies + TMDC_REFRESH_TIME); + return 0; +} + +static void tmdc_close(struct input_dev *dev) +{ + struct tmdc *tmdc = dev->private; + if (!--tmdc->used) + del_timer(&tmdc->timer); +} + +/* + * tmdc_probe() probes for ThrustMaster type joysticks. + */ + +static void tmdc_connect(struct gameport *gameport, struct gameport_dev *dev) +{ + struct tmdc *tmdc; + struct js_tm_models { + unsigned char id; + char *name; + char abs; + char hats; + char joybtn; + char padbtn; + } models[] = { { 1, "ThrustMaster Millenium 3D Inceptor", 6, 0, 6, 0 }, + { 3, "ThrustMaster Rage 3D Gamepad", 2, 0, 0, 10 }, + { 163, "Thrustmaster Fusion GamePad", 2, 0, 0, 10 }, + { 0, "Unknown %d-axis, %d-button TM device %d", 0, 0, 0, 0 }}; + unsigned char data[2][TMDC_MAX_LENGTH]; + int i, j, m; + + if (!(tmdc = kmalloc(sizeof(struct tmdc), GFP_KERNEL))) + return; + memset(tmdc, 0, sizeof(struct tmdc)); + + gameport->private = tmdc; + + tmdc->gameport = gameport; + init_timer(&tmdc->timer); + tmdc->timer.data = (long) tmdc; + tmdc->timer.function = tmdc_timer; + + if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) + goto fail1; + + if (!(tmdc->exists = tmdc_read_packet(gameport, data))) + goto fail2; + + for (j = 0; j < 2; j++) + if (tmdc->exists & (1 << j)) { + + tmdc->mode[j] = data[j][TMDC_BYTE_ID]; + + for (m = 0; models[m].id && models[m].id != tmdc->mode[j]; m++); + + if (!models[m].id) { + models[m].abs = data[j][TMDC_BYTE_DEF] >> 4; + models[m].joybtn = (data[j][TMDC_BYTE_DEF] & 0xf) << 3; + } + + sprintf(tmdc->name[j], models[m].name, models[m].abs, models[m].joybtn, tmdc->mode[j]); + + tmdc->dev[j].private = tmdc; + tmdc->dev[j].open = tmdc_open; + tmdc->dev[j].close = tmdc_close; + + tmdc->dev[j].name = tmdc->name[j]; + tmdc->dev[j].idbus = BUS_GAMEPORT; + tmdc->dev[j].idvendor = GAMEPORT_ID_VENDOR_THRUSTMASTER; + tmdc->dev[j].idproduct = models[m].id; + tmdc->dev[j].idversion = 0x0100; + + tmdc->dev[j].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + + for (i = 0; i < models[m].abs && i < TMDC_ABS; i++) { + set_bit(tmdc_abs[i], tmdc->dev[j].absbit); + tmdc->dev[j].absmin[tmdc_abs[i]] = 8; + tmdc->dev[j].absmax[tmdc_abs[i]] = 248; + tmdc->dev[j].absfuzz[tmdc_abs[i]] = 2; + tmdc->dev[j].absflat[tmdc_abs[i]] = 4; + } + + for (i = 0; i < models[m].hats && i < TMDC_ABS_HAT; i++) { + set_bit(tmdc_abs_hat[i], tmdc->dev[j].absbit); + tmdc->dev[j].absmin[tmdc_abs_hat[i]] = -1; + tmdc->dev[j].absmax[tmdc_abs_hat[i]] = 1; + } + + for (i = 0; i < models[m].joybtn && i < TMDC_BTN_JOY; i++) + set_bit(tmdc_btn_joy[i], tmdc->dev[j].keybit); + + for (i = 0; i < models[m].padbtn && i < TMDC_BTN_PAD; i++) + set_bit(tmdc_btn_pad[i], tmdc->dev[j].keybit); + + input_register_device(tmdc->dev + j); + printk(KERN_INFO "input%d: %s on gameport%d.%d\n", + tmdc->dev[j].number, tmdc->name[j], gameport->number, j); + } + + return; +fail2: gameport_close(gameport); +fail1: kfree(tmdc); +} + +static void tmdc_disconnect(struct gameport *gameport) +{ + struct tmdc *tmdc = gameport->private; + int i; + for (i = 0; i < 2; i++) + if (tmdc->exists & (1 << i)) + input_unregister_device(tmdc->dev + i); + gameport_close(gameport); + kfree(tmdc); +} + +static struct gameport_dev tmdc_dev = { + connect: tmdc_connect, + disconnect: tmdc_disconnect, +}; + +int __init tmdc_init(void) +{ + gameport_register_device(&tmdc_dev); + return 0; +} + +void __exit tmdc_exit(void) +{ + gameport_unregister_device(&tmdc_dev); +} + +module_init(tmdc_init); +module_exit(tmdc_exit); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/turbografx.c linux/drivers/char/joystick/turbografx.c --- v2.4.0-test1/linux/drivers/char/joystick/turbografx.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick/turbografx.c Wed Jun 21 08:22:21 2000 @@ -0,0 +1,258 @@ +/* + * $Id: turbografx.c,v 1.8 2000/05/29 20:39:38 vojtech Exp $ + * + * Copyright (c) 1998-2000 Vojtech Pavlik + * + * Based on the work of: + * Steffen Schwenke + * + * Sponsored by SuSE + */ + +/* + * TurboGraFX parallel port interface driver for Linux. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_PARM(tgfx, "2-8i"); +MODULE_PARM(tgfx_2, "2-8i"); +MODULE_PARM(tgfx_3, "2-8i"); + +#define TGFX_REFRESH_TIME HZ/100 /* 10 ms */ + +#define TGFX_TRIGGER 0x08 +#define TGFX_UP 0x10 +#define TGFX_DOWN 0x20 +#define TGFX_LEFT 0x40 +#define TGFX_RIGHT 0x80 + +#define TGFX_THUMB 0x02 +#define TGFX_THUMB2 0x04 +#define TGFX_TOP 0x01 +#define TGFX_TOP2 0x08 + +static int tgfx[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; +static int tgfx_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; +static int tgfx_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; + +static int tgfx_buttons[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2 }; +static char *tgfx_name = "TurboGraFX Multisystem joystick"; + +struct tgfx { + struct pardevice *pd; + struct timer_list timer; + struct input_dev dev[7]; + int sticks; + int used; +} *tgfx_base[3]; + +/* + * tgfx_timer() reads and analyzes TurboGraFX joystick data. + */ + +static void tgfx_timer(unsigned long private) +{ + struct tgfx *tgfx = (void *) private; + struct input_dev *dev; + int data1, data2, i; + + for (i = 0; i < 7; i++) + if (tgfx->sticks & (1 << i)) { + + dev = tgfx->dev + i; + + parport_write_data(tgfx->pd->port, ~(1 << i)); + data1 = parport_read_status(tgfx->pd->port) ^ 0x7f; + data2 = parport_read_control(tgfx->pd->port) ^ 0x04; /* CAVEAT parport */ + + input_report_abs(dev, ABS_X, !!(data1 & TGFX_RIGHT) - !!(data1 & TGFX_LEFT)); + input_report_abs(dev, ABS_Y, !!(data1 & TGFX_DOWN ) - !!(data1 & TGFX_UP )); + + input_report_key(dev, BTN_TRIGGER, (data1 & TGFX_TRIGGER)); + input_report_key(dev, BTN_THUMB, (data2 & TGFX_THUMB )); + input_report_key(dev, BTN_THUMB2, (data2 & TGFX_THUMB2 )); + input_report_key(dev, BTN_TOP, (data2 & TGFX_TOP )); + input_report_key(dev, BTN_TOP2, (data2 & TGFX_TOP2 )); + } + + mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME); +} + +static int tgfx_open(struct input_dev *dev) +{ + struct tgfx *tgfx = dev->private; + if (!tgfx->used++) { + parport_claim(tgfx->pd); + parport_write_control(tgfx->pd->port, 0x04); + mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME); + } + return 0; +} + +static void tgfx_close(struct input_dev *dev) +{ + struct tgfx *tgfx = dev->private; + if (!--tgfx->used) { + del_timer(&tgfx->timer); + parport_write_control(tgfx->pd->port, 0x00); + parport_release(tgfx->pd); + } +} + +/* + * tgfx_probe() probes for tg gamepads. + */ + +static struct tgfx __init *tgfx_probe(int *config) +{ + struct tgfx *tgfx; + struct parport *pp; + int i, j; + + if (config[0] < 0) + return NULL; + + for (pp = parport_enumerate(); pp && (config[0] > 0); pp = pp->next) + config[0]--; + + if (!pp) { + printk(KERN_ERR "turbografx.c: no such parport\n"); + return NULL; + } + + if (!(tgfx = kmalloc(sizeof(struct tgfx), GFP_KERNEL))) + return NULL; + memset(tgfx, 0, sizeof(struct tgfx)); + + tgfx->pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); + + if (!tgfx->pd) { + printk(KERN_ERR "turbografx.c: parport busy already - lp.o loaded?\n"); + kfree(tgfx); + return NULL; + } + + init_timer(&tgfx->timer); + tgfx->timer.data = (long) tgfx; + tgfx->timer.function = tgfx_timer; + + tgfx->sticks = 0; + + for (i = 0; i < 7; i++) + if (config[i+1] > 0 && config[i+1] < 6) { + + tgfx->sticks |= (1 << i); + + tgfx->dev[i].private = tgfx; + tgfx->dev[i].open = tgfx_open; + tgfx->dev[i].close = tgfx_close; + + tgfx->dev[i].name = tgfx_name; + tgfx->dev[i].idbus = BUS_PARPORT; + tgfx->dev[i].idvendor = 0x0003; + tgfx->dev[i].idproduct = config[i+1]; + tgfx->dev[i].idversion = 0x0100; + + tgfx->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + tgfx->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + + for (j = 0; j < config[i+1]; j++) + set_bit(tgfx_buttons[j], tgfx->dev[i].keybit); + + tgfx->dev[i].absmin[ABS_X] = -1; tgfx->dev[i].absmax[ABS_X] = 1; + tgfx->dev[i].absmin[ABS_Y] = -1; tgfx->dev[i].absmax[ABS_Y] = 1; + + input_register_device(tgfx->dev + i); + printk(KERN_INFO "input%d: %d-button Multisystem joystick on %s\n", + tgfx->dev[i].number, config[i+1], tgfx->pd->port->name); + } + + if (!tgfx->sticks) { + parport_unregister_device(tgfx->pd); + kfree(tgfx); + return NULL; + } + + return tgfx; +} + +#ifndef MODULE +int __init tgfx_setup(char *str) +{ + int i, ints[9]; + get_options(str, ARRAY_SIZE(ints), ints); + for (i = 0; i <= ints[0] && i < 8; i++) tgfx[i] = ints[i + 1]; + return 1; +} +int __init tgfx_setup_2(char *str) +{ + int i, ints[9]; + get_options(str, ARRAY_SIZE(ints), ints); + for (i = 0; i <= ints[0] && i < 8; i++) tgfx_2[i] = ints[i + 1]; + return 1; +} +int __init tgfx_setup_3(char *str) +{ + int i, ints[9]; + get_options(str, ARRAY_SIZE(ints), ints); + for (i = 0; i <= ints[0] && i < 8; i++) tgfx_3[i] = ints[i + 1]; + return 1; +} +__setup("tgfx=", tgfx_setup); +__setup("tgfx_2=", tgfx_setup_2); +__setup("tgfx_3=", tgfx_setup_3); +#endif + +int __init tgfx_init(void) +{ + tgfx_base[0] = tgfx_probe(tgfx); + tgfx_base[1] = tgfx_probe(tgfx_2); + tgfx_base[2] = tgfx_probe(tgfx_3); + + if (tgfx_base[0] || tgfx_base[1] || tgfx_base[2]) + return 0; + + return -ENODEV; +} + +void __exit tgfx_exit(void) +{ + int i, j; + + for (i = 0; i < 3; i++) + if (tgfx_base[i]) { + for (j = 0; j < 7; j++) + if (tgfx_base[i]->sticks & (1 << j)) + input_unregister_device(tgfx_base[i]->dev + j); + parport_unregister_device(tgfx_base[i]->pd); + } +} + +module_init(tgfx_init); +module_exit(tgfx_exit); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/joystick/warrior.c linux/drivers/char/joystick/warrior.c --- v2.4.0-test1/linux/drivers/char/joystick/warrior.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick/warrior.c Wed Jun 21 08:22:21 2000 @@ -0,0 +1,212 @@ +/* + * $Id: warrior.c,v 1.8 2000/05/31 13:17:12 vojtech Exp $ + * + * Copyright (c) 1999-2000 Vojtech Pavlik + * + * Sponsored by SuSE + */ + +/* + * Logitech WingMan Warrior joystick driver for Linux + */ + +/* + * This program is free warftware; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include + +/* + * Constants. + */ + +#define WARRIOR_MAX_LENGTH 16 +static char warrior_lengths[] = { 0, 4, 12, 3, 4, 4, 0, 0 }; +static char *warrior_name = "Logitech WingMan Warrior"; + +/* + * Per-Warrior data. + */ + +struct warrior { + struct input_dev dev; + int idx, len; + unsigned char data[WARRIOR_MAX_LENGTH]; +}; + +/* + * warrior_process_packet() decodes packets the driver receives from the + * Warrior. It updates the data accordingly. + */ + +static void warrior_process_packet(struct warrior *warrior) +{ + struct input_dev *dev = &warrior->dev; + unsigned char *data = warrior->data; + + if (!warrior->idx) return; + + switch ((data[0] >> 4) & 7) { + case 1: /* Button data */ + input_report_key(dev, BTN_TRIGGER, data[3] & 1); + input_report_key(dev, BTN_THUMB, (data[3] >> 1) & 1); + input_report_key(dev, BTN_TOP, (data[3] >> 2) & 1); + input_report_key(dev, BTN_TOP2, (data[3] >> 3) & 1); + return; + case 3: /* XY-axis info->data */ + input_report_abs(dev, ABS_X, ((data[0] & 8) << 5) - (data[2] | ((data[0] & 4) << 5))); + input_report_abs(dev, ABS_Y, (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7)); + return; + case 5: /* Throttle, spinner, hat info->data */ + input_report_abs(dev, ABS_THROTTLE, (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7)); + input_report_abs(dev, ABS_HAT0X, (data[3] & 2 ? 1 : 0) - (data[3] & 1 ? 1 : 0)); + input_report_abs(dev, ABS_HAT0Y, (data[3] & 8 ? 1 : 0) - (data[3] & 4 ? 1 : 0)); + input_report_rel(dev, REL_DIAL, (data[2] | ((data[0] & 4) << 5)) - ((data[0] & 8) << 5)); + return; + } +} + +/* + * warrior_interrupt() is called by the low level driver when characters + * are ready for us. We then buffer them for further processing, or call the + * packet processing routine. + */ + +static void warrior_interrupt(struct serio *serio, unsigned char data, unsigned int flags) +{ + struct warrior* warrior = serio->private; + + if (data & 0x80) { + if (warrior->idx) warrior_process_packet(warrior); + warrior->idx = 0; + warrior->len = warrior_lengths[(data >> 4) & 7]; + } + + if (warrior->idx < warrior->len) + warrior->data[warrior->idx++] = data; + + if (warrior->idx == warrior->len) { + if (warrior->idx) warrior_process_packet(warrior); + warrior->idx = 0; + warrior->len = 0; + } +} + +/* + * warrior_disconnect() is the opposite of warrior_connect() + */ + +static void warrior_disconnect(struct serio *serio) +{ + struct warrior* warrior = serio->private; + input_unregister_device(&warrior->dev); + serio_close(serio); + kfree(warrior); +} + +/* + * warrior_connect() is the routine that is called when someone adds a + * new serio device. It looks for the Warrior, and if found, registers + * it as an input device. + */ + +static void warrior_connect(struct serio *serio, struct serio_dev *dev) +{ + struct warrior *warrior; + int i; + + if (serio->type != (SERIO_RS232 | SERIO_WARRIOR)) + return; + + if (!(warrior = kmalloc(sizeof(struct warrior), GFP_KERNEL))) + return; + + memset(warrior, 0, sizeof(struct warrior)); + + warrior->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); + warrior->dev.keybit[LONG(BTN_TRIGGER)] = BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_TOP2); + warrior->dev.relbit[0] = BIT(REL_DIAL); + warrior->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y); + + warrior->dev.name = warrior_name; + warrior->dev.idbus = BUS_RS232; + warrior->dev.idvendor = SERIO_WARRIOR; + warrior->dev.idproduct = 0x0001; + warrior->dev.idversion = 0x0100; + + for (i = 0; i < 2; i++) { + warrior->dev.absmax[ABS_X+i] = -64; + warrior->dev.absmin[ABS_X+i] = 64; + warrior->dev.absflat[ABS_X+i] = 8; + } + + warrior->dev.absmax[ABS_THROTTLE] = -112; + warrior->dev.absmin[ABS_THROTTLE] = 112; + + for (i = 0; i < 2; i++) { + warrior->dev.absmax[ABS_HAT0X+i] = -1; + warrior->dev.absmin[ABS_HAT0X+i] = 1; + } + + warrior->dev.private = warrior; + + serio->private = warrior; + + if (serio_open(serio, dev)) { + kfree(warrior); + return; + } + + input_register_device(&warrior->dev); + + printk(KERN_INFO "input%d: Logitech WingMan Warrior on serio%d\n", warrior->dev.number, serio->number); +} + +/* + * The serio device structure. + */ + +static struct serio_dev warrior_dev = { + interrupt: warrior_interrupt, + connect: warrior_connect, + disconnect: warrior_disconnect, +}; + +/* + * The functions for inserting/removing us as a module. + */ + +int __init warrior_init(void) +{ + serio_register_device(&warrior_dev); + return 0; +} + +void __exit warrior_exit(void) +{ + serio_unregister_device(&warrior_dev); +} + +module_init(warrior_init); +module_exit(warrior_exit); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/logibusmouse.c linux/drivers/char/logibusmouse.c --- v2.4.0-test1/linux/drivers/char/logibusmouse.c Sun Nov 7 16:37:34 1999 +++ linux/drivers/char/logibusmouse.c Mon Jun 19 13:25:06 2000 @@ -107,7 +107,6 @@ { MSE_INT_OFF(); free_irq(mouse_irq, NULL); - MOD_DEC_USE_COUNT; return 0; } @@ -119,13 +118,12 @@ { if (request_irq(mouse_irq, mouse_interrupt, 0, "busmouse", NULL)) return -EBUSY; - MOD_INC_USE_COUNT; MSE_INT_ON(); return 0; } static struct busmouse busmouse = { - LOGITECH_BUSMOUSE, "busmouse", open_mouse, close_mouse, 7 + LOGITECH_BUSMOUSE, "busmouse", THIS_MODULE, open_mouse, close_mouse, 7 }; static int __init logi_busmouse_init(void) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/lp.c linux/drivers/char/lp.c --- v2.4.0-test1/linux/drivers/char/lp.c Tue May 23 15:31:34 2000 +++ linux/drivers/char/lp.c Wed Jun 21 22:31:01 2000 @@ -371,8 +371,6 @@ if (test_and_set_bit(LP_BUSY_BIT_POS, &LP_F(minor))) return -EBUSY; - MOD_INC_USE_COUNT; - /* If ABORTOPEN is set and the printer is offline or out of paper, we may still want to open it to perform ioctl()s. Therefore we have commandeered O_NONBLOCK, even though it is being used in @@ -385,24 +383,20 @@ parport_release (lp_table[minor].dev); if (status & LP_POUTPA) { printk(KERN_INFO "lp%d out of paper\n", minor); - MOD_DEC_USE_COUNT; LP_F(minor) &= ~LP_BUSY; return -ENOSPC; } else if (!(status & LP_PSELECD)) { printk(KERN_INFO "lp%d off-line\n", minor); - MOD_DEC_USE_COUNT; LP_F(minor) &= ~LP_BUSY; return -EIO; } else if (!(status & LP_PERRORP)) { printk(KERN_ERR "lp%d printer error\n", minor); - MOD_DEC_USE_COUNT; LP_F(minor) &= ~LP_BUSY; return -EIO; } } lp_table[minor].lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL); if (!lp_table[minor].lp_buffer) { - MOD_DEC_USE_COUNT; LP_F(minor) &= ~LP_BUSY; return -ENOMEM; } @@ -415,7 +409,6 @@ kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE); lp_table[minor].lp_buffer = NULL; - MOD_DEC_USE_COUNT; LP_F(minor) &= ~LP_BUSY; return 0; } @@ -526,6 +519,7 @@ } static struct file_operations lp_fops = { + owner: THIS_MODULE, write: lp_write, ioctl: lp_ioctl, open: lp_open, @@ -681,9 +675,9 @@ lp_reset(nr); sprintf (name, "%d", nr); - devfs_register (devfs_handle, name, 0, + devfs_register (devfs_handle, name, DEVFS_FL_DEFAULT, LP_MAJOR, nr, - S_IFCHR | S_IRUGO | S_IWUGO, 0, 0, + S_IFCHR | S_IRUGO | S_IWUGO, &lp_fops, NULL); printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/mem.c linux/drivers/char/mem.c --- v2.4.0-test1/linux/drivers/char/mem.c Tue May 23 15:31:34 2000 +++ linux/drivers/char/mem.c Wed Jun 21 22:31:01 2000 @@ -18,7 +18,6 @@ #include #include #include -#include #include #include @@ -606,9 +605,9 @@ int i; for (i=0; i<(sizeof(list)/sizeof(*list)); i++) - devfs_register (NULL, list[i].name, 0, DEVFS_FL_NONE, + devfs_register (NULL, list[i].name, DEVFS_FL_NONE, MEM_MAJOR, list[i].minor, - list[i].mode | S_IFCHR, 0, 0, + list[i].mode | S_IFCHR, list[i].fops, NULL); } @@ -652,13 +651,6 @@ #ifdef CONFIG_SPARCAUDIO sparcaudio_init(); #endif -#ifdef CONFIG_JOYSTICK - /* - * Some joysticks only appear when the sound card they are - * connected to is configured. Keep the sound/joystick ordering. - */ - js_init(); -#endif #if CONFIG_QIC02_TAPE qic02_tape_init(); #endif diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/misc.c linux/drivers/char/misc.c --- v2.4.0-test1/linux/drivers/char/misc.c Thu May 11 15:30:06 2000 +++ linux/drivers/char/misc.c Wed Jun 21 22:31:01 2000 @@ -111,8 +111,7 @@ int minor = MINOR(inode->i_rdev); struct miscdevice *c; int err = -ENODEV; - - file->f_op = NULL; + struct file_operations *old_fops; down(&misc_sem); @@ -133,14 +132,22 @@ goto fail; } - if ((file->f_op = c->fops) && file->f_op->open) + old_fops = file->f_op; + file->f_op = fops_get(c->fops); + if (file->f_op && file->f_op->open) err=file->f_op->open(inode,file); + if (err) { + fops_put(file->f_op); + file->f_op = fops_get(old_fops); + } + fops_put(old_fops); fail: up(&misc_sem); return err; } static struct file_operations misc_fops = { + owner: THIS_MODULE, open: misc_open, }; @@ -185,9 +192,9 @@ if (!devfs_handle) devfs_handle = devfs_mk_dir (NULL, "misc", 4, NULL); misc->devfs_handle = - devfs_register (devfs_handle, misc->name, 0, DEVFS_FL_NONE, + devfs_register (devfs_handle, misc->name, DEVFS_FL_NONE, MISC_MAJOR, misc->minor, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, misc->fops, NULL); /* diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/mixcomwd.c linux/drivers/char/mixcomwd.c --- v2.4.0-test1/linux/drivers/char/mixcomwd.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/char/mixcomwd.c Tue Jun 20 07:32:13 2000 @@ -94,8 +94,6 @@ mixcomwd_timer_alive=0; } #endif - MOD_INC_USE_COUNT; - return 0; } @@ -114,7 +112,6 @@ mixcomwd_timer_alive=1; add_timer(&mixcomwd_timer); #endif - MOD_DEC_USE_COUNT; clear_bit(0,&mixcomwd_opened); return 0; @@ -171,6 +168,7 @@ static struct file_operations mixcomwd_fops= { + owner: THIS_MODULE, write: mixcomwd_write, ioctl: mixcomwd_ioctl, open: mixcomwd_open, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/msbusmouse.c linux/drivers/char/msbusmouse.c --- v2.4.0-test1/linux/drivers/char/msbusmouse.c Sun Nov 7 16:37:34 1999 +++ linux/drivers/char/msbusmouse.c Mon Jun 19 13:25:06 2000 @@ -108,7 +108,6 @@ { MS_MSE_INT_OFF(); free_irq(mouse_irq, NULL); - MOD_DEC_USE_COUNT; return 0; } @@ -118,13 +117,12 @@ return -EBUSY; outb(MS_MSE_START, MS_MSE_CONTROL_PORT); - MOD_INC_USE_COUNT; MS_MSE_INT_ON(); return 0; } static struct busmouse msbusmouse = { - MICROSOFT_BUSMOUSE, "msbusmouse", open_mouse, release_mouse, 0 + MICROSOFT_BUSMOUSE, "msbusmouse", THIS_MODULE, open_mouse, release_mouse, 0 }; static int __init ms_bus_mouse_init(void) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/msp3400.c linux/drivers/char/msp3400.c --- v2.4.0-test1/linux/drivers/char/msp3400.c Tue May 23 15:31:34 2000 +++ linux/drivers/char/msp3400.c Tue Jun 20 07:32:13 2000 @@ -1,7 +1,7 @@ /* * programming the msp34* sound processor family * - * (c) 1997,1998 Gerd Knorr + * (c) 1997-2000 Gerd Knorr * * what works and what doesn't: * @@ -46,6 +46,7 @@ #include #include #include +#include #ifdef CONFIG_SMP #include @@ -57,16 +58,14 @@ #include "audiochip.h" -#define WAIT_QUEUE wait_queue_head_t - /* sound mixer stuff */ -#if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE) +#if 0 /* defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE) */ # define REGISTER_MIXER 1 #endif /* Addresses to scan */ static unsigned short normal_i2c[] = {I2C_CLIENT_END}; -static unsigned short normal_i2c_range[] = {0x40,0x44,I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = {0x40,0x40,I2C_CLIENT_END}; static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; @@ -102,7 +101,7 @@ /* thread */ struct task_struct *thread; - WAIT_QUEUE wq; + wait_queue_head_t wq; struct semaphore *notify; int active,restart,rmmod; @@ -680,10 +679,10 @@ #endif exit_mm(current); + exit_fs(current); current->session = 1; current->pgrp = 1; sigfillset(¤t->blocked); - current->fs->umask = 0; strcpy(current->comm,"msp3400"); msp->thread = current; @@ -932,10 +931,10 @@ #endif exit_mm(current); + exit_fs(current); current->session = 1; current->pgrp = 1; sigfillset(¤t->blocked); - current->fs->umask = 0; strcpy(current->comm,"msp3410 [auto]"); msp->thread = current; @@ -1256,7 +1255,6 @@ if (client->adapter->inc_use) client->adapter->inc_use(client->adapter); - MOD_INC_USE_COUNT; return 0; } @@ -1267,7 +1265,6 @@ if (client->adapter->dec_use) client->adapter->dec_use(client->adapter); - MOD_DEC_USE_COUNT; return 0; } @@ -1278,6 +1275,7 @@ } static struct file_operations msp3400c_mixer_fops = { + owner: THIS_MODULE, llseek: msp3400c_mixer_llseek, ioctl: msp3400c_mixer_ioctl, open: msp3400c_mixer_open, @@ -1370,7 +1368,7 @@ if (simple == -1) { /* default mode */ - msp->simple = 0; + msp->simple = (((rev2>>8)&0xff) == 0) ? 0 : 1; } else { /* use insmod option */ msp->simple = simple; @@ -1632,22 +1630,19 @@ /* ----------------------------------------------------------------------- */ -#ifdef MODULE -int init_module(void) -#else -int msp3400c_init(void) -#endif +int msp3400_init_module(void) { i2c_add_driver(&driver); return 0; } -#ifdef MODULE -void cleanup_module(void) +void msp3400_cleanup_module(void) { i2c_del_driver(&driver); } -#endif + +module_init(msp3400_init_module); +module_exit(msp3400_cleanup_module); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/mxser.c linux/drivers/char/mxser.c --- v2.4.0-test1/linux/drivers/char/mxser.c Thu May 11 15:30:06 2000 +++ linux/drivers/char/mxser.c Mon Jun 19 13:25:06 2000 @@ -618,6 +618,8 @@ mxser_pcibrds[b].device_id, pdev); if (!pdev) break; + if (pci_enable_device(pdev)) + continue; b++; hwconf.pdev = pdev; printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n", diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/n_hdlc.c linux/drivers/char/n_hdlc.c --- v2.4.0-test1/linux/drivers/char/n_hdlc.c Wed Apr 26 16:34:07 2000 +++ linux/drivers/char/n_hdlc.c Wed Jun 21 10:10:02 2000 @@ -663,7 +663,7 @@ #if LINUX_VERSION_CODE < VERSION(2,3,0) kill_fasync (n_hdlc->tty->fasync, SIGIO); #else - kill_fasync (n_hdlc->tty->fasync, SIGIO, POLL_IN); + kill_fasync(&n_hdlc->tty->fasync, SIGIO, POLL_IN); #endif } /* end of n_hdlc_tty_receive() */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c --- v2.4.0-test1/linux/drivers/char/n_tty.c Wed Apr 26 16:34:07 2000 +++ linux/drivers/char/n_tty.c Wed Jun 21 10:10:02 2000 @@ -630,8 +630,7 @@ put_tty_queue(c, tty); tty->canon_head = tty->read_head; tty->canon_data++; - if (tty->fasync) - kill_fasync(tty->fasync, SIGIO, POLL_IN); + kill_fasync(&tty->fasync, SIGIO, POLL_IN); if (waitqueue_active(&tty->read_wait)) wake_up_interruptible(&tty->read_wait); return; @@ -735,8 +734,7 @@ } if (!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) { - if (tty->fasync) - kill_fasync(tty->fasync, SIGIO, POLL_IN); + kill_fasync(&tty->fasync, SIGIO, POLL_IN); if (waitqueue_active(&tty->read_wait)) wake_up_interruptible(&tty->read_wait); } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/nvram.c linux/drivers/char/nvram.c --- v2.4.0-test1/linux/drivers/char/nvram.c Wed Apr 26 16:34:07 2000 +++ linux/drivers/char/nvram.c Tue Jun 20 07:37:58 2000 @@ -332,7 +332,6 @@ if (file->f_mode & 2) nvram_open_mode |= NVRAM_WRITE; nvram_open_cnt++; - MOD_INC_USE_COUNT; return( 0 ); } @@ -344,7 +343,6 @@ if (file->f_mode & 2) nvram_open_mode &= ~NVRAM_WRITE; - MOD_DEC_USE_COUNT; return( 0 ); } @@ -393,6 +391,7 @@ #endif /* CONFIG_PROC_FS */ static struct file_operations nvram_fops = { + owner: THIS_MODULE, llseek: nvram_llseek, read: nvram_read, write: nvram_write, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/nwbutton.c linux/drivers/char/nwbutton.c --- v2.4.0-test1/linux/drivers/char/nwbutton.c Fri May 12 14:18:55 2000 +++ linux/drivers/char/nwbutton.c Tue Jun 20 07:37:58 2000 @@ -172,34 +172,6 @@ ? -EFAULT : bcount; } -/* - * This function is called when a user space process attempts to open the - * device. If the driver is compiled into the kernel it does nothing but - * succeed, but if it is compiled in as a module it also increments the - * module usage count to prevent the module from being removed whilst a - * process has the device open. - */ - -static int button_open (struct inode *inode, struct file *filp) -{ - MOD_INC_USE_COUNT; - return 0; -} - -/* - * This function is called when a user space process attempts to close the - * device. If the driver is compiled into the kernel it does nothing at all, - * but if it is compiled in as a module it also decrements the module usage - * count so that it will be possible to unload the module again once all the - * user processes have closed the device. - */ - -static int button_release (struct inode *inode, struct file *filp) -{ - MOD_DEC_USE_COUNT; - return 0; -} - /* * This structure is the file operations structure, which specifies what * callbacks functions the kernel should call when a user mode process @@ -207,9 +179,8 @@ */ static struct file_operations button_fops = { + owner: THIS_MODULE, read: button_read, - open: button_open, - release: button_release, }; /* diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/nwflash.c linux/drivers/char/nwflash.c --- v2.4.0-test1/linux/drivers/char/nwflash.c Fri May 12 14:18:55 2000 +++ linux/drivers/char/nwflash.c Tue Jun 20 07:37:58 2000 @@ -39,7 +39,6 @@ MSTATIC int erase_block(int nBlock); MSTATIC int write_block(unsigned long p, const char *buf, int count); static int open_flash(struct inode *inodep, struct file *filep); -static int release_flash(struct inode *inodep, struct file *filep); static int flash_ioctl(struct inode *inodep, struct file *filep, unsigned int cmd, unsigned long arg); static ssize_t flash_read(struct file *file, char *buf, size_t count, loff_t * ppos); static ssize_t flash_write(struct file *file, const char *buf, size_t count, loff_t * ppos); @@ -60,12 +59,12 @@ static struct file_operations flash_fops = { + owner: THIS_MODULE, llseek: flash_llseek, read: flash_read, write: flash_write, ioctl: flash_ioctl, open: open_flash, - release: release_flash, }; static struct miscdevice flash_miscdev = @@ -128,18 +127,9 @@ printk("Flash: incorrect ID 0x%04X.\n", id); return -ENXIO; } - MOD_INC_USE_COUNT; return 0; } - - -static int release_flash(struct inode *inodep, struct file *filep) -{ - MOD_DEC_USE_COUNT; - return 0; -} - static int flash_ioctl(struct inode *inodep, struct file *filep, unsigned int cmd, unsigned long arg) { diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/pc110pad.c linux/drivers/char/pc110pad.c --- v2.4.0-test1/linux/drivers/char/pc110pad.c Thu May 11 15:30:06 2000 +++ linux/drivers/char/pc110pad.c Wed Jun 21 10:10:02 2000 @@ -83,8 +83,7 @@ static void wake_readers(void) { wake_up_interruptible(&queue); - if(asyncptr) - kill_fasync(asyncptr, SIGIO, POLL_IN); + kill_fasync(&asyncptr, SIGIO, POLL_IN); } @@ -588,7 +587,6 @@ if (--active) return 0; outb(0x30, current_params.io+2); /* switch off digitiser */ - MOD_DEC_USE_COUNT; return 0; } @@ -610,7 +608,6 @@ if (active++) return 0; - MOD_INC_USE_COUNT; save_flags(flags); cli(); @@ -772,6 +769,7 @@ static struct file_operations pad_fops = { + owner: THIS_MODULE, read: read_pad, write: write_pad, poll: pad_poll, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c --- v2.4.0-test1/linux/drivers/char/pc_keyb.c Wed Apr 26 16:34:07 2000 +++ linux/drivers/char/pc_keyb.c Wed Jun 21 10:10:02 2000 @@ -415,8 +415,7 @@ head = (head + 1) & (AUX_BUF_SIZE-1); if (head != queue->tail) { queue->head = head; - if (queue->fasync) - kill_fasync(queue->fasync, SIGIO, POLL_IN); + kill_fasync(&queue->fasync, SIGIO, POLL_IN); wake_up_interruptible(&queue->proc_list); } } @@ -452,7 +451,9 @@ scancode = kbd_read_input(); -#if 0 + /* Error bytes must be ignored to make the + Synaptics touchpads compaq use work */ +#if 1 /* Ignore error bytes */ if (!(status & (KBD_STAT_GTO | KBD_STAT_PERR))) #endif diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/pcmcia/serial_cb.c linux/drivers/char/pcmcia/serial_cb.c --- v2.4.0-test1/linux/drivers/char/pcmcia/serial_cb.c Thu May 11 15:30:06 2000 +++ linux/drivers/char/pcmcia/serial_cb.c Mon Jun 19 17:59:40 2000 @@ -92,6 +92,7 @@ if (loc->bus != LOC_PCI) goto err_out; pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn); if (!pdev) goto err_out; + if (pci_enable_device(pdev)) goto err_out; printk(KERN_INFO "serial_attach(bus %d, fn %d)\n", pdev->bus->number, pdev->devfn); io = pci_resource_start (pdev, 0); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/pcwd.c linux/drivers/char/pcwd.c --- v2.4.0-test1/linux/drivers/char/pcwd.c Tue Apr 11 15:09:17 2000 +++ linux/drivers/char/pcwd.c Tue Jun 20 07:37:58 2000 @@ -414,7 +414,6 @@ is_open = 1; return(0); case TEMP_MINOR: - MOD_INC_USE_COUNT; return(0); default: return (-ENODEV); @@ -450,7 +449,6 @@ static int pcwd_close(struct inode *ino, struct file *filep) { - MOD_DEC_USE_COUNT; if (MINOR(ino->i_rdev)==WATCHDOG_MINOR) { is_open = 0; @@ -543,6 +541,7 @@ } static struct file_operations pcwd_fops = { + owner: THIS_MODULE, read: pcwd_read, write: pcwd_write, ioctl: pcwd_ioctl, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/ppdev.c linux/drivers/char/ppdev.c --- v2.4.0-test1/linux/drivers/char/ppdev.c Wed Apr 26 16:34:07 2000 +++ linux/drivers/char/ppdev.c Wed Jun 21 22:31:01 2000 @@ -83,6 +83,63 @@ /* ROUND_UP macro from fs/select.c */ #define ROUND_UP(x,y) (((x)+(y)-1)/(y)) +struct pp_port_list_struct { + struct parport *port; + struct pp_port_list_struct *next; +}; +static struct pp_port_list_struct *pp_port_list; +static DECLARE_MUTEX(pp_port_list_lock); + +/* pp_attach and pp_detach are for keeping a list of currently + * available ports, held under a mutex. We do this rather than + * using parport_enumerate because it stops a load of races. + */ + +static void pp_attach (struct parport *port) +{ + struct pp_port_list_struct *add; + + add = kmalloc (sizeof (struct pp_port_list_struct), GFP_KERNEL); + if (!add) { + printk (KERN_WARNING CHRDEV ": memory squeeze\n"); + return; + } + + add->next = pp_port_list; + down (&pp_port_list_lock); + pp_port_list = add; + up (&pp_port_list_lock); +} + +static void pp_detach (struct parport *port) +{ + struct pp_port_list_struct *del; + + down (&pp_port_list_lock); + del = pp_port_list; + if (del->port == port) + pp_port_list = del->next; + else { + struct pp_port_list_struct *prev; + do { + prev = del; + del = del->next; + } while (del && del->port != port); + if (del) + prev->next = del->next; + } + up (&pp_port_list_lock); + + if (del) + kfree (del); +} + +static struct parport_driver ppdev_driver = { + name: CHRDEV, + attach: pp_attach, + detach: pp_detach +}; + static inline void pp_enable_irq (struct pp_struct *pp) { struct parport *port = pp->pdev->port; @@ -216,7 +273,7 @@ static int register_device (int minor, struct pp_struct *pp) { - struct parport * port; + struct pp_port_list_struct *ports; struct pardevice * pdev = NULL; char *name; int fl; @@ -226,20 +283,24 @@ return -ENOMEM; sprintf (name, CHRDEV "%x", minor); - port = parport_enumerate (); /* FIXME: use attach/detach */ - while (port && port->number != minor) - port = port->next; + down (&pp_port_list_lock); + ports = pp_port_list; + while (ports && ports->port->number != minor) + ports = ports->next; + if (ports->port) { + fl = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0; + pdev = parport_register_device (ports->port, name, NULL, + NULL, pp_irq, fl, pp); + } + up (&pp_port_list_lock); - if (!port) { + if (!ports->port) { printk (KERN_WARNING "%s: no associated port!\n", name); kfree (name); return -ENXIO; } - fl = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0; - pdev = parport_register_device (port, name, NULL, NULL, pp_irq, fl, - pp); if (!pdev) { printk (KERN_WARNING "%s: failed to register device!\n", name); @@ -507,13 +568,9 @@ if (minor >= PARPORT_MAX) return -ENXIO; - MOD_INC_USE_COUNT; - pp = kmalloc (sizeof (struct pp_struct), GFP_KERNEL); - if (!pp) { - MOD_DEC_USE_COUNT; + if (!pp) return -ENOMEM; - } pp->state.mode = IEEE1284_MODE_COMPAT; pp->state.phase = init_phase (pp->state.mode); @@ -565,7 +622,6 @@ kfree (pp); - MOD_DEC_USE_COUNT; return 0; } @@ -583,6 +639,7 @@ } static struct file_operations pp_fops = { + owner: THIS_MODULE, llseek: pp_lseek, read: pp_read, write: pp_write, @@ -596,6 +653,10 @@ static int __init ppdev_init (void) { + if (parport_register_driver (&ppdev_driver)) { + printk (KERN_WARNING CHRDEV ": unable to register driver\n"); + return -EIO; + } if (devfs_register_chrdev (PP_MAJOR, CHRDEV, &pp_fops)) { printk (KERN_WARNING CHRDEV ": unable to get major %d\n", PP_MAJOR); @@ -604,7 +665,7 @@ devfs_handle = devfs_mk_dir (NULL, "parports", 0, NULL); devfs_register_series (devfs_handle, "%u", PARPORT_MAX, DEVFS_FL_DEFAULT, PP_MAJOR, 0, - S_IFCHR | S_IRUGO | S_IWUGO, 0, 0, + S_IFCHR | S_IRUGO | S_IWUGO, &pp_fops, NULL); printk (KERN_INFO PP_VERSION "\n"); @@ -616,6 +677,7 @@ /* Clean up all parport stuff */ devfs_unregister (devfs_handle); devfs_unregister_chrdev (PP_MAJOR, CHRDEV); + parport_unregister_driver (&ppdev_driver); } module_init(ppdev_init); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/qpmouse.c linux/drivers/char/qpmouse.c --- v2.4.0-test1/linux/drivers/char/qpmouse.c Thu Feb 10 17:11:08 2000 +++ linux/drivers/char/qpmouse.c Wed Jun 21 10:10:02 2000 @@ -133,8 +133,7 @@ head &= QP_BUF_SIZE-1; } queue->head = head; - if (queue->fasync) - kill_fasync(queue->fasync, SIGIO, POLL_IN); + kill_fasync(&queue->fasync, SIGIO, POLL_IN); wake_up_interruptible(&queue->proc_list); } @@ -151,7 +150,6 @@ if (!poll_qp_status()) printk("Warning: Mouse device busy in release_qp()\n"); free_irq(QP_IRQ, NULL); - MOD_DEC_USE_COUNT; } return 0; } @@ -196,7 +194,6 @@ } outb_p(AUX_ENABLE_DEV, qp_data); /* Wake up mouse */ - MOD_INC_USE_COUNT; return 0; } @@ -290,6 +287,7 @@ } struct file_operations qp_fops = { + owner: THIS_MODULE, read: read_qp, write: write_qp, poll: poll_qp, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/radio-aimslab.c linux/drivers/char/radio-aimslab.c --- v2.4.0-test1/linux/drivers/char/radio-aimslab.c Mon Oct 4 15:49:29 1999 +++ linux/drivers/char/radio-aimslab.c Mon Jun 19 13:25:06 2000 @@ -355,7 +355,7 @@ return -EINVAL; request_region(io, 2, "rtrack"); - printk(KERN_INFO "AIMSlab Radiotrack/radioreveal card driver.\n"); + printk(KERN_INFO "AIMSlab RadioTrack/RadioReveal card driver.\n"); /* Set up the I/O locking */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/random.c linux/drivers/char/random.c --- v2.4.0-test1/linux/drivers/char/random.c Wed Apr 26 16:34:07 2000 +++ linux/drivers/char/random.c Mon Jun 19 13:25:06 2000 @@ -139,7 +139,7 @@ * add_interrupt_randomness() uses the inter-interrupt timing as random * inputs to the entropy pool. Note that not all interrupts are good * sources of randomness! For example, the timer interrupts is not a - * good choice, because the periodicity of the interrupts is to + * good choice, because the periodicity of the interrupts is too * regular, and hence predictable to an attacker. Disk interrupts are * a better measure, since the timing of the disk interrupts are more * unpredictable. diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/rio/rio_linux.c linux/drivers/char/rio/rio_linux.c --- v2.4.0-test1/linux/drivers/char/rio/rio_linux.c Tue May 23 15:31:34 2000 +++ linux/drivers/char/rio/rio_linux.c Tue Jun 20 07:37:58 2000 @@ -201,8 +201,6 @@ static int rio_chars_in_buffer (void * ptr); static int rio_fw_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -static int rio_fw_open(struct inode *inode, struct file *filp); -static INT rio_fw_release(struct inode *inode, struct file *filp); static int rio_init_drivers(void); @@ -277,9 +275,8 @@ */ static struct file_operations rio_fw_fops = { + owner: THIS_MODULE, ioctl: rio_fw_ioctl, - open: rio_fw_open, - release: rio_fw_release, }; struct miscdevice rio_fw_device = { @@ -634,32 +631,6 @@ func_exit(); } - - -/* ********************************************************************** * - * Here are the routines that actually * - * interface with the rest of the system * - * ********************************************************************** */ - - -static int rio_fw_open(struct inode *inode, struct file *filp) -{ - func_enter (); - rio_inc_mod_count (); - func_exit (); - return 0; -} - - -static INT rio_fw_release(struct inode *inode, struct file *filp) -{ - func_enter (); - rio_dec_mod_count (); - func_exit (); - return NO_ERROR; -} - - /* I haven't the foggiest why the decrement use count has to happen here. The whole linux serial drivers stuff needs to be redesigned. My guess is that this is a hack to minimize the impact of a bug @@ -1149,6 +1120,7 @@ while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, pdev))) { + if (pci_enable_device(pdev)) continue; #else for (i=0;i< RIO_NBOARDS;i++) { if (pcibios_find_device (PCI_VENDOR_ID_SPECIALIX, @@ -1234,6 +1206,7 @@ while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_RIO, pdev))) { + if (pci_enable_device(pdev)) continue; #else for (i=0;i< RIO_NBOARDS;i++) { if (pcibios_find_device (PCI_VENDOR_ID_SPECIALIX, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/rocket.c linux/drivers/char/rocket.c --- v2.4.0-test1/linux/drivers/char/rocket.c Tue Nov 23 22:42:20 1999 +++ linux/drivers/char/rocket.c Mon Jun 19 13:25:06 2000 @@ -1957,7 +1957,10 @@ if (!dev) return 0; - rcktpt_io_addr[i] = dev->resource[0].start; + if (pci_enable_device(dev)) + return 0; + + rcktpt_io_addr[i] = pci_resource_start (dev, 0); switch(dev->device) { case PCI_DEVICE_ID_RP4QUAD: str = "Quadcable"; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/rtc.c linux/drivers/char/rtc.c --- v2.4.0-test1/linux/drivers/char/rtc.c Tue May 23 15:31:34 2000 +++ linux/drivers/char/rtc.c Wed Jun 21 10:10:02 2000 @@ -179,8 +179,7 @@ /* Now do the rest of the actions */ wake_up_interruptible(&rtc_wait); - if (rtc_async_queue) - kill_fasync (rtc_async_queue, SIGIO, POLL_IN); + kill_fasync (&rtc_async_queue, SIGIO, POLL_IN); } #endif @@ -514,8 +513,6 @@ if(rtc_status & RTC_IS_OPEN) return -EBUSY; - MOD_INC_USE_COUNT; - rtc_status |= RTC_IS_OPEN; spin_lock_irq (&rtc_lock); @@ -559,7 +556,6 @@ } #endif - MOD_DEC_USE_COUNT; spin_lock_irq (&rtc_lock); rtc_irq_data = 0; @@ -591,6 +587,7 @@ */ static struct file_operations rtc_fops = { + owner: THIS_MODULE, llseek: rtc_llseek, read: rtc_read, #ifndef __alpha__ @@ -781,8 +778,7 @@ /* Now we have new data */ wake_up_interruptible(&rtc_wait); - if (rtc_async_queue) - kill_fasync (rtc_async_queue, SIGIO, POLL_IN); + kill_fasync (&rtc_async_queue, SIGIO, POLL_IN); } #endif diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/sbc60xxwdt.c linux/drivers/char/sbc60xxwdt.c --- v2.4.0-test1/linux/drivers/char/sbc60xxwdt.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/sbc60xxwdt.c Mon Jun 19 13:25:06 2000 @@ -0,0 +1,338 @@ +/* + * 60xx Single Board Computer Watchdog Timer driver for Linux 2.2.x + * + * Based on acquirewdt.c by Alan Cox. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * The author does NOT admit liability nor provide warranty for + * any of this software. This material is provided "AS-IS" in + * the hope that it may be useful for others. + * + * (c) Copyright 2000 Jakob Oestergaard + * + * 12/4 - 2000 [Initial revision] + * 25/4 - 2000 Added /dev/watchdog support + * + * + * Theory of operation: + * A Watchdog Timer (WDT) is a hardware circuit that can + * reset the computer system in case of a software fault. + * You probably knew that already. + * + * Usually a userspace daemon will notify the kernel WDT driver + * via the /proc/watchdog special device file that userspace is + * still alive, at regular intervals. When such a notification + * occurs, the driver will usually tell the hardware watchdog + * that everything is in order, and that the watchdog should wait + * for yet another little while to reset the system. + * If userspace fails (RAM error, kernel bug, whatever), the + * notifications cease to occur, and the hardware watchdog will + * reset the system (causing a reboot) after the timeout occurs. + * + * This WDT driver is different from the other Linux WDT + * drivers in several ways: + * *) The driver will ping the watchdog by itself, because this + * particular WDT has a very short timeout (one second) and it + * would be insane to count on any userspace daemon always + * getting scheduled within that time frame. + * *) This driver expects the userspace daemon to send a specific + * character code ('V') to /dev/watchdog before closing the + * /dev/watchdog file. If the userspace daemon closes the file + * without sending this special character, the driver will assume + * that the daemon (and userspace in general) died, and will + * stop pinging the WDT without disabling it first. This will + * cause a reboot. + * + * Why `V' ? Well, `V' is the character in ASCII for the value 86, + * and we all know that 86 is _the_ most random number in the universe. + * Therefore it is the letter that has the slightest chance of occuring + * by chance, when the system becomes corrupted. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OUR_NAME "sbc60xxwdt" + +/* + * You must set these - The driver cannot probe for the settings + */ + +#define WDT_STOP 0x45 +#define WDT_START 0x443 + +/* + * The 60xx board can use watchdog timeout values from one second + * to several minutes. The default is one second, so if we reset + * the watchdog every ~250ms we should be safe. + */ + +#define WDT_INTERVAL (HZ/4+1) + +/* + * We must not require too good response from the userspace daemon. + * Here we require the userspace daemon to send us a heartbeat + * char to /dev/watchdog every 10 seconds. + * If the daemon pulses us every 5 seconds, we can still afford + * a 5 second scheduling delay on the (high priority) daemon. That + * should be sufficient for a box under any load. + */ + +#define WDT_HEARTBEAT (HZ * 10) + +static void wdt_timer_ping(unsigned long); +static struct timer_list timer; +static unsigned long next_heartbeat = 0; +static int wdt_is_open = 0; +static int wdt_expect_close = 0; + +/* + * Whack the dog + */ + +static void wdt_timer_ping(unsigned long data) +{ + /* If we got a heartbeat pulse within the WDT_US_INTERVAL + * we agree to ping the WDT + */ + if(time_before(jiffies, next_heartbeat)) + { + /* Ping the WDT by reading from WDT_START */ + inb_p(WDT_START); + /* Re-set the timer interval */ + timer.expires = jiffies + WDT_INTERVAL; + add_timer(&timer); + } else { + printk(OUR_NAME ": Heartbeat lost! Will not ping the watchdog\n"); + } +} + +/* + * Utility routines + */ + +static void wdt_startup(void) +{ + next_heartbeat = jiffies + WDT_HEARTBEAT; + + /* Start the timer */ + timer.expires = jiffies + WDT_INTERVAL; + add_timer(&timer); + printk(OUR_NAME ": Watchdog timer is now enabled.\n"); +} + +static void wdt_turnoff(void) +{ + /* Stop the timer */ + del_timer(&timer); + inb_p(WDT_STOP); + printk(OUR_NAME ": Watchdog timer is now disabled...\n"); +} + + +/* + * /dev/watchdog handling + */ + +static ssize_t fop_write(struct file * file, const char * buf, size_t count, loff_t * ppos) +{ + /* We can't seek */ + if(ppos != &file->f_pos) + return -ESPIPE; + + /* See if we got the magic character */ + if(count) + { + size_t ofs; + + /* note: just in case someone wrote the magic character + * five months ago... */ + wdt_expect_close = 0; + + /* now scan */ + for(ofs = 0; ofs != count; ofs++) + if(buf[ofs] == 'V') + wdt_expect_close = 1; + + /* Well, anyhow someone wrote to us, we should return that favour */ + next_heartbeat = jiffies + WDT_HEARTBEAT; + } + return 0; +} + +static ssize_t fop_read(struct file * file, char * buf, size_t count, loff_t * ppos) +{ + /* No can do */ + return -EINVAL; +} + +static int fop_open(struct inode * inode, struct file * file) +{ + switch(MINOR(inode->i_rdev)) + { + case WATCHDOG_MINOR: + /* Just in case we're already talking to someone... */ + if(wdt_is_open) + return -EBUSY; + /* Good, fire up the show */ + wdt_is_open = 1; + wdt_startup(); + return 0; + + default: + return -ENODEV; + } +} + +static int fop_close(struct inode * inode, struct file * file) +{ + if(MINOR(inode->i_rdev) == WATCHDOG_MINOR) + { + if(wdt_expect_close) + wdt_turnoff(); + else { + del_timer(&timer); + printk(OUR_NAME ": device file closed unexpectedly. Will not stop the WDT!\n"); + } + } + wdt_is_open = 0; + return 0; +} + +static long long fop_llseek(struct file *file, long long offset, int origin) +{ + return -ESPIPE; +} + +static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + static struct watchdog_info ident= + { + 0, + 1, + "SB60xx" + }; + + switch(cmd) + { + default: + return -ENOIOCTLCMD; + case WDIOC_GETSUPPORT: + return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0; + case WDIOC_KEEPALIVE: + next_heartbeat = jiffies + WDT_HEARTBEAT; + return 0; + } +} + +static struct file_operations wdt_fops = { + owner: THIS_MODULE, + llseek: fop_llseek, + read: fop_read, + write: fop_write, + open: fop_open, + release: fop_close, + ioctl: fop_ioctl +}; + +static struct miscdevice wdt_miscdev = { + WATCHDOG_MINOR, + "watchdog", + &wdt_fops +}; + +/* + * Notifier for system down + */ + +static int wdt_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if(code==SYS_DOWN || code==SYS_HALT) + wdt_turnoff(); + return NOTIFY_DONE; +} + +/* + * The WDT needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ + +static struct notifier_block wdt_notifier= +{ + wdt_notify_sys, + 0, + 0 +}; + +static void __exit sbc60xxwdt_unload(void) +{ + wdt_turnoff(); + + /* Deregister */ + misc_deregister(&wdt_miscdev); + + unregister_reboot_notifier(&wdt_notifier); + release_region(WDT_START,1); + release_region(WDT_STOP,1); +} + +static int __init sbc60xxwdt_init(void) +{ + int rc = -EBUSY; + + if (!request_region(WDT_STOP, 1, "SBC 60XX WDT")) + goto err_out; + if (!request_region(WDT_START, 1, "SBC 60XX WDT")) + goto err_out_region1; + + init_timer(&timer); + timer.function = wdt_timer_ping; + timer.data = 0; + + rc = misc_register(&wdt_miscdev); + if (rc) + goto err_out_region2; + + rc = register_reboot_notifier(&wdt_notifier); + if (rc) + goto err_out_miscdev; + + printk(KERN_INFO OUR_NAME ": WDT driver for 60XX single board computer initialised.\n"); + + return 0; + +err_out_miscdev: + misc_deregister(&wdt_miscdev); +err_out_region2: + release_region(WDT_START,1); +err_out_region1: + release_region(WDT_STOP,1); +err_out: + return rc; +} + +module_init(sbc60xxwdt_init); +module_exit(sbc60xxwdt_unload) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/scan_keyb.c linux/drivers/char/scan_keyb.c --- v2.4.0-test1/linux/drivers/char/scan_keyb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/scan_keyb.c Mon Jun 19 17:59:40 2000 @@ -0,0 +1,127 @@ +/* + * $Id: scan_keyb.c,v 1.1 2000/06/10 21:45:30 yaegashi Exp $ + * Copyright (C) 2000 YAEGASHI Takeshi + * Generic scan keyboard driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct scan_keyboard { + struct scan_keyboard *next; + void (*scan)(unsigned char *buffer); + const unsigned char *table; + unsigned char *s0, *s1; + int length; +}; + +static struct scan_keyboard *keyboards=NULL; +static struct tq_struct task_scan_kbd; + +static void check_kbd(const unsigned char *table, + unsigned char *new, unsigned char *old, int length) +{ + int need_tasklet_schedule=0; + unsigned char xor, bit; + + while(length-->0) { + if((xor=*new^*old)==0) { + table+=8; + } + else { + for(bit=0x80; bit!=0; bit>>=1) { + if(xor&bit) { + handle_scancode(*table, !(*new&bit)); + need_tasklet_schedule=1; + } + table++; + } + } + new++; old++; + } + + if(need_tasklet_schedule) + tasklet_schedule(&keyboard_tasklet); +} + + +static void scan_kbd(void *dummy) +{ + struct scan_keyboard *kbd; + + for(kbd=keyboards; kbd!=NULL; kbd=kbd->next) { + if(jiffies&1) { + kbd->scan(kbd->s0); + check_kbd(kbd->table, kbd->s0, kbd->s1, kbd->length); + } + else { + kbd->scan(kbd->s1); + check_kbd(kbd->table, kbd->s1, kbd->s0, kbd->length); + } + + } + queue_task(&task_scan_kbd, &tq_timer); +} + + +int register_scan_keyboard(void (*scan)(unsigned char *buffer), + const unsigned char *table, + int length) +{ + struct scan_keyboard *kbd; + + if((kbd=kmalloc(sizeof(struct scan_keyboard), GFP_KERNEL))==NULL) + goto error_out; + + kbd->scan=scan; + kbd->table=table; + kbd->length=length; + + kbd->s0=kbd->s1=NULL; + if((kbd->s0=kmalloc(length, GFP_KERNEL))==NULL) + goto error_out; + if((kbd->s1=kmalloc(length, GFP_KERNEL))==NULL) + goto error_out; + + kbd->scan(kbd->s0); + kbd->scan(kbd->s1); + + kbd->next=keyboards; + keyboards=kbd; + + return 0; + + error_mem_free: + if(kbd->s0) + kfree(kbd->s0); + if(kbd->s1) + kfree(kbd->s1); + kfree(kbd); + + error_out: + return -ENOMEM; +} + + +void __init scan_kbd_init(void) +{ + + task_scan_kbd.next=NULL; + task_scan_kbd.sync=0; + task_scan_kbd.routine=scan_kbd; + task_scan_kbd.data=NULL; + queue_task(&task_scan_kbd, &tq_timer); + printk(KERN_INFO "Generic scan keyboard driver initialized\n"); +} diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/scan_keyb.h linux/drivers/char/scan_keyb.h --- v2.4.0-test1/linux/drivers/char/scan_keyb.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/scan_keyb.h Mon Jun 19 17:59:40 2000 @@ -0,0 +1,15 @@ +#ifndef __DRIVER_CHAR_SCAN_KEYB_H +#define __DRIVER_CHAR_SCAN_KEYB_H +/* + * $Id: scan_keyb.h,v 1.1 2000/06/10 21:45:30 yaegashi Exp $ + * Copyright (C) 2000 YAEGASHI Takeshi + * Generic scan keyboard driver + */ + +int register_scan_keyboard(void (*scan)(unsigned char *buffer), + const unsigned char *table, + int length); + +void __init scan_kbd_init(void); + +#endif diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/serial.c linux/drivers/char/serial.c --- v2.4.0-test1/linux/drivers/char/serial.c Thu May 11 15:30:07 2000 +++ linux/drivers/char/serial.c Wed Jun 21 12:43:38 2000 @@ -43,13 +43,16 @@ * few races on freeing buffers too. * Alan Modra * + * 5/00: Support for the RSA-DV II/S card added. + * Kiyokazu SUTO + * * This module exports the following rs232 io functions: * * int rs_init(void); */ -static char *serial_version = "4.93"; -static char *serial_revdate = "2000-03-20"; +static char *serial_version = "5.01"; +static char *serial_revdate = "2000-05-29"; /* * Serial driver configuration section. Here are the various options: @@ -134,6 +137,8 @@ #endif #endif +#define CONFIG_SERIAL_RSA + #define RS_STROBE_TIME (10*HZ) #define RS_ISR_PASS_LIMIT 256 @@ -277,9 +282,20 @@ UART_STARTECH }, { "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, + { "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO }, { 0, 0} }; +#if defined(CONFIG_SERIAL_RSA) && defined(MODULE) + +#define PORT_RSA_MAX 4 +static int probe_rsa[PORT_RSA_MAX]; +static int force_rsa[PORT_RSA_MAX]; + +MODULE_PARM(probe_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i"); +MODULE_PARM(force_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i"); +#endif /* CONFIG_SERIAL_RSA */ + static struct serial_state rs_table[RS_TABLE_SIZE] = { SERIAL_PORT_DFNS /* Defined in serial.h */ }; @@ -293,11 +309,8 @@ static struct pci_board_inst serial_pci_board[NR_PCI_BOARDS]; static int serial_pci_board_idx = 0; #endif -#ifndef PCI_BASE_ADDRESS -#define PCI_BASE_ADDRESS(dev, r) ((dev)->resource[r].start) -#define PCI_BASE_REGION_SIZE(dev, r) ((dev)->resource[r].end - \ - (dev)->resource[r].start) -#define IS_PCI_REGION_IOPORT(dev, r) ((dev)->resource[r].flags & \ +#ifndef IS_PCI_REGION_IOPORT +#define IS_PCI_REGION_IOPORT(dev, r) (pci_resource_flags((dev), (r)) & \ IORESOURCE_IO) #endif #ifndef PCI_IRQ_RESOURCE @@ -314,7 +327,8 @@ #define ACTIVATE_FUNC(dev) (dev->activate) #define DEACTIVATE_FUNC(dev) (dev->deactivate) #endif - + +#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) static struct tty_struct *serial_table[NR_PORTS]; static struct termios *serial_termios[NR_PORTS]; @@ -996,6 +1010,9 @@ tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); wake_up_interruptible(&tty->write_wait); +#ifdef SERIAL_HAVE_POLL_WAIT + wake_up_interruptible(&tty->poll_wait); +#endif } } @@ -1090,6 +1107,50 @@ IRQ_timeout[irq] = timeout ? timeout : 1; } +#ifdef CONFIG_SERIAL_RSA +/* Attempts to turn on the RSA FIFO. Returns zero on failure */ +static int enable_rsa(struct async_struct *info) +{ + unsigned char mode; + int result; + unsigned long flags; + + save_flags(flags); cli(); + mode = serial_inp(info, UART_RSA_MSR); + result = mode & UART_RSA_MSR_FIFO; + + if (!result) { + serial_outp(info, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); + mode = serial_inp(info, UART_RSA_MSR); + result = mode & UART_RSA_MSR_FIFO; + } + + restore_flags(flags); + return result; +} + +/* Attempts to turn off the RSA FIFO. Returns zero on failure */ +static int disable_rsa(struct async_struct *info) +{ + unsigned char mode; + int result; + unsigned long flags; + + save_flags(flags); cli(); + mode = serial_inp(info, UART_RSA_MSR); + result = !(mode & UART_RSA_MSR_FIFO); + + if (!result) { + serial_outp(info, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); + mode = serial_inp(info, UART_RSA_MSR); + result = !(mode & UART_RSA_MSR_FIFO); + } + + restore_flags(flags); + return result; +} +#endif /* CONFIG_SERIAL_RSA */ + static int startup(struct async_struct * info) { unsigned long flags; @@ -1127,7 +1188,7 @@ printk("starting up ttys%d (irq %d)...", info->line, state->irq); #endif - if (uart_config[info->state->type].flags & UART_STARTECH) { + if (uart_config[state->type].flags & UART_STARTECH) { /* Wake up UART */ serial_outp(info, UART_LCR, 0xBF); serial_outp(info, UART_EFR, UART_EFR_ECB); @@ -1145,7 +1206,7 @@ /* * For a XR16C850, we need to set the trigger levels */ - if (info->state->type == PORT_16850) { + if (state->type == PORT_16850) { serial_outp(info, UART_FCTR, UART_FCTR_TRGD | UART_FCTR_RX); serial_outp(info, UART_TRG, UART_TRG_96); @@ -1156,12 +1217,12 @@ serial_outp(info, UART_LCR, 0); } - if (info->state->type == PORT_16750) { + if (state->type == PORT_16750) { /* Wake up UART */ serial_outp(info, UART_IER, 0); } - if (info->state->type == PORT_16C950) { + if (state->type == PORT_16C950) { /* Wake up and initialize UART */ info->ACR = 0; serial_outp(info, UART_LCR, 0xBF); @@ -1174,6 +1235,20 @@ serial_outp(info, UART_LCR, 0); } +#ifdef CONFIG_SERIAL_RSA + /* + * If this is an RSA port, see if we can kick it up to the + * higher speed clock. + */ + if (state->type == PORT_RSA) { + if (state->baud_base != SERIAL_RSA_BAUD_BASE && + enable_rsa(info)) + state->baud_base = SERIAL_RSA_BAUD_BASE; + if (state->baud_base == SERIAL_RSA_BAUD_BASE) + serial_outp(info, UART_RSA_FRR, 0); + } +#endif + /* * Clear the FIFO buffers and disable them * (they will be reenabled in change_speed()) @@ -1199,7 +1274,8 @@ * if it is, then bail out, because there's likely no UART * here. */ - if (serial_inp(info, UART_LSR) == 0xff) { + if (!(info->flags & ASYNC_BUGGY_UART) && + (serial_inp(info, UART_LSR) == 0xff)) { printk("LSR safety check engaged!\n"); if (capable(CAP_SYS_ADMIN)) { if (info->tty) @@ -1425,6 +1501,17 @@ UART_FCR_CLEAR_XMIT)); serial_outp(info, UART_FCR, 0); +#ifdef CONFIG_SERIAL_RSA + /* + * Reset the RSA board back to 115kbps compat mode. + */ + if ((state->type == PORT_RSA) && + (state->baud_base == SERIAL_RSA_BAUD_BASE && + disable_rsa(info))) + state->baud_base = SERIAL_RSA_BAUD_BASE_LO; +#endif + + (void)serial_in(info, UART_RX); /* read data port to reset things */ if (info->tty) @@ -1522,6 +1609,12 @@ baud = tty_get_baud_rate(info->tty); if (!baud) baud = 9600; /* B0 transition handled in rs_set_termios */ +#ifdef CONFIG_SERIAL_RSA + if ((info->state->type == PORT_RSA) && + (info->state->baud_base != SERIAL_RSA_BAUD_BASE) && + enable_rsa(info)) + info->state->baud_base = SERIAL_RSA_BAUD_BASE; +#endif baud_base = info->state->baud_base; if (info->state->type == PORT_16C950) { if (baud <= baud_base) @@ -1583,6 +1676,10 @@ if (uart_config[info->state->type].flags & UART_USE_FIFO) { if ((info->state->baud_base / quot) < 2400) fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; +#ifdef CONFIG_SERIAL_RSA + else if (info->state->type == PORT_RSA) + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14; +#endif else fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8; } @@ -1810,6 +1907,9 @@ info->xmit.head = info->xmit.tail = 0; restore_flags(flags); wake_up_interruptible(&tty->write_wait); +#ifdef SERIAL_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); @@ -1912,6 +2012,10 @@ tmp.type = state->type; tmp.line = state->line; tmp.port = state->port; + if (HIGH_BITS_OFFSET) + tmp.port_high = state->port >> HIGH_BITS_OFFSET; + else + tmp.port_high = 0; tmp.irq = state->irq; tmp.flags = state->flags; tmp.xmit_fifo_size = state->xmit_fifo_size; @@ -1933,14 +2037,19 @@ struct serial_state old_state, *state; unsigned int i,change_irq,change_port; int retval = 0; + unsigned long new_port; if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) return -EFAULT; state = info->state; old_state = *state; - + + new_port = new_serial.port; + if (HIGH_BITS_OFFSET) + new_port += new_serial.port_high << HIGH_BITS_OFFSET; + change_irq = new_serial.irq != state->irq; - change_port = (new_serial.port != state->port) || + change_port = (new_port != ((int) state->port)) || (new_serial.hub6 != state->hub6); if (!capable(CAP_SYS_ADMIN)) { @@ -1978,7 +2087,7 @@ if (new_serial.type) { for (i = 0 ; i < NR_PORTS; i++) if ((state != &rs_table[i]) && - (rs_table[i].port == new_serial.port) && + (rs_table[i].port == new_port) && rs_table[i].type) return -EADDRINUSE; } @@ -2005,8 +2114,14 @@ info->xmit_fifo_size = state->xmit_fifo_size = new_serial.xmit_fifo_size; - if ((state->type != PORT_UNKNOWN) && state->port) + if ((state->type != PORT_UNKNOWN) && state->port) { +#ifdef CONFIG_SERIAL_RSA + if (old_state.type == PORT_RSA) + release_region(state->port + UART_RSA_BASE, 16); + else +#endif release_region(state->port,8); + } state->type = new_serial.type; if (change_port || change_irq) { /* @@ -2015,15 +2130,22 @@ */ shutdown(info); state->irq = new_serial.irq; - info->port = state->port = new_serial.port; + info->port = state->port = new_port; info->hub6 = state->hub6 = new_serial.hub6; if (info->hub6) info->io_type = state->io_type = SERIAL_IO_HUB6; else if (info->io_type == SERIAL_IO_HUB6) info->io_type = state->io_type = SERIAL_IO_PORT; } - if ((state->type != PORT_UNKNOWN) && state->port) - request_region(state->port,8,"serial(set)"); + if ((state->type != PORT_UNKNOWN) && state->port) { +#ifdef CONFIG_SERIAL_RSA + if (state->type == PORT_RSA) + request_region(state->port + UART_RSA_BASE, + 16, "serial_rsa(set)"); + else +#endif + request_region(state->port,8,"serial(set)"); + } check_and_exit: @@ -2462,6 +2584,9 @@ /* note the counters on entry */ cprev = info->state->icount; restore_flags(flags); + /* Force modem status interrupts on */ + info->IER |= UART_IER_MSI; + serial_out(info, UART_IER, info->IER); while (1) { interruptible_sleep_on(&info->delta_msr_wait); /* see if a signal did it */ @@ -3348,6 +3473,16 @@ * LSR register (which serial_icr_read does) */ if (state->type == PORT_16550A) { + /* + * EFR [4] must be set else this test fails + * + * This shouldn't be necessary, but Mike Hudson + * (Exoray@isys.ca) claims that it's needed for 952 + * dual UART's (which are not recommended for new designs). + */ + serial_out(info, UART_LCR, 0xBF); + serial_out(info, UART_EFR, 0x10); + serial_out(info, UART_LCR, 0x00); /* Check for Oxford Semiconductor 16C950 */ scratch = serial_icr_read(info, UART_ID1); scratch2 = serial_icr_read(info, UART_ID2); @@ -3434,7 +3569,8 @@ save_flags(flags); cli(); - if (!state->iomem_base) { + if (!(state->flags & ASYNC_BUGGY_UART) && + !state->iomem_base) { /* * Do a simple existence test first; if we fail this, * there's no point trying anything else. @@ -3459,8 +3595,9 @@ serial_outp(info, UART_IER, scratch); if (scratch2 || scratch3 != 0x0F) { #ifdef SERIAL_DEBUG_AUTOCONF - printk("serial: ttyS%d: simple autoconfig failed\n", - state->line); + printk("serial: ttyS%d: simple autoconfig failed " + "(%02x, %02x)\n", state->line, + scratch2, scratch3); #endif restore_flags(flags); return; /* We failed; there's nothing here */ @@ -3545,6 +3682,25 @@ } serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); } +#if defined(CONFIG_SERIAL_RSA) && defined(MODULE) + if (state->type == PORT_16550A) { + int i; + + for (i = 0 ; i < PORT_RSA_MAX ; ++i) { + if (!probe_rsa[i] && !force_rsa[i]) + break; + if (((probe_rsa[i] != state->port) || + check_region(state->port + UART_RSA_BASE, 16)) && + (force_rsa[i] != state->port)) + continue; + if (!enable_rsa(info)) + continue; + state->type = PORT_RSA; + state->baud_base = SERIAL_RSA_BAUD_BASE; + break; + } + } +#endif serial_outp(info, UART_LCR, save_lcr); if (state->type == PORT_16450) { scratch = serial_in(info, UART_SCR); @@ -3564,12 +3720,23 @@ return; } - if (info->port) - request_region(info->port,8,"serial(auto)"); + if (info->port) { +#ifdef CONFIG_SERIAL_RSA + if (state->type == PORT_RSA) + request_region(info->port + UART_RSA_BASE, 16, + "serial_rsa(auto)"); + else +#endif + request_region(info->port,8,"serial(auto)"); + } /* * Reset the UART. */ +#ifdef CONFIG_SERIAL_RSA + if (state->type == PORT_RSA) + serial_outp(info, UART_RSA_FRR, 0); +#endif serial_outp(info, UART_MCR, save_mcr); serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | @@ -3614,7 +3781,7 @@ static _INLINE_ int get_pci_port(struct pci_dev *dev, struct pci_board *board, - struct serial_struct *state, + struct serial_struct *req, int idx) { unsigned long port; @@ -3626,24 +3793,28 @@ base_idx += idx; if (board->flags & SPCI_FL_REGION_SZ_CAP) { - max_port = PCI_BASE_REGION_SIZE(dev, base_idx) / 8; + max_port = pci_resource_len(dev, base_idx) / 8; if (idx >= max_port) return 1; } - port = PCI_BASE_ADDRESS(dev, base_idx) + board->first_uart_offset; + port = pci_resource_start(dev, base_idx) + board->first_uart_offset; if ((board->flags & SPCI_FL_BASE_TABLE) == 0) port += idx * (board->uart_offset ? board->uart_offset : 8); if (IS_PCI_REGION_IOPORT(dev, base_idx)) { - state->port = port; + req->port = port; + if (HIGH_BITS_OFFSET) + req->port_high = port >> HIGH_BITS_OFFSET; + else + req->port_high = 0; return 0; } - state->io_type = SERIAL_IO_MEM; - state->iomem_base = ioremap(port, board->uart_offset); - state->iomem_reg_shift = board->reg_shift; - state->port = 0; + req->io_type = SERIAL_IO_MEM; + req->iomem_base = ioremap(port, board->uart_offset); + req->iomem_reg_shift = board->reg_shift; + req->port = 0; return 0; } @@ -3670,23 +3841,28 @@ struct pci_board *board) { int k, line; - struct serial_struct fake_state; + struct serial_struct serial_req; int base_baud; if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) { - printk("SERIAL: PNP device '"); + printk("serial: PNP device '"); printk_pnp_dev_id(board->vendor, board->device); printk("' prepare failed\n"); return; } if (ACTIVATE_FUNC(dev) && (ACTIVATE_FUNC(dev))(dev) < 0) { - printk("SERIAL: PNP device '"); + printk("serial: PNP device '"); printk_pnp_dev_id(board->vendor, board->device); printk("' activate failed\n"); return; } + if (!(board->flags & SPCI_FL_ISPNP) && pci_enable_device(dev)) { + printk("serial: PCI device enable failed\n"); + return; + } + /* * Run the initialization function, if any */ @@ -3710,18 +3886,18 @@ base_baud = board->base_baud; if (!base_baud) base_baud = BASE_BAUD; - memset(&fake_state, 0, sizeof(fake_state)); + memset(&serial_req, 0, sizeof(serial_req)); for (k=0; k < board->num_ports; k++) { - fake_state.irq = get_pci_irq(dev, board, k); - if (get_pci_port(dev, board, &fake_state, k)) + serial_req.irq = get_pci_irq(dev, board, k); + if (get_pci_port(dev, board, &serial_req, k)) break; - fake_state.flags = ASYNC_SKIP_TEST; + serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE; #ifdef SERIAL_DEBUG_PCI printk("Setup PCI/PNP port: port %x, irq %d, type %d\n", - fake_state.port, fake_state.irq, fake_state.io_type); + serial_req.port, serial_req.irq, serial_req.io_type); #endif - line = register_serial(&fake_state); + line = register_serial(&serial_req); if (line < 0) break; rs_table[line].baud_base = base_baud; @@ -3742,28 +3918,45 @@ #endif pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable) { - u8 data, *p, scratch; + u8 data, *p, irq_config; + int pci_config; + irq_config = 0x41; + pci_config = PCI_COMMAND_MEMORY; + if (dev->vendor == PCI_VENDOR_ID_PANACOM) + irq_config = 0x43; + if ((dev->vendor == PCI_VENDOR_ID_PLX) && + (dev->device == PCI_VENDOR_ID_PLX_ROMULUS)) { + /* + * As the megawolf cards have the int pins active + * high, and have 2 UART chips, both ints must be + * enabled on the 9050. Also, the UARTS are set in + * 16450 mode by default, so we have to enable the + * 16C950 'enhanced' mode so that we can use the deep + * FIFOs + */ + irq_config = 0x5b; + pci_config = PCI_COMMAND_MEMORY | PCI_COMMAND_IO; + } + pci_read_config_byte(dev, PCI_COMMAND, &data); if (enable) pci_write_config_byte(dev, PCI_COMMAND, - data | PCI_COMMAND_MEMORY); + data | pci_config); /* enable/disable interrupts */ - p = ioremap(PCI_BASE_ADDRESS(dev, 0), 0x80); - scratch = 0x41; - if (dev->vendor == PCI_VENDOR_ID_PANACOM) - scratch = 0x43; - writel(enable ? scratch : 0x00, (unsigned long)p + 0x4c); + p = ioremap(pci_resource_start(dev, 0), 0x80); + writel(enable ? irq_config : 0x00, (unsigned long)p + 0x4c); iounmap(p); if (!enable) pci_write_config_byte(dev, PCI_COMMAND, - data & ~PCI_COMMAND_MEMORY); + data & ~pci_config); return 0; } + /* * SIIG serial cards have an PCI interface chip which also controls * the UART clocking frequency. Each UART can be clocked independently @@ -3796,7 +3989,7 @@ if (!enable) return 0; - p = ioremap(PCI_BASE_ADDRESS(dev, 0), 0x80); + p = ioremap(pci_resource_start(dev, 0), 0x80); switch (dev->device & 0xfff8) { case PCI_DEVICE_ID_SIIG_1S_10x: /* 1S */ @@ -3841,6 +4034,36 @@ return 0; } +/* Added for EKF Intel i960 serial boards */ +static int +#ifndef MODULE +__init +#endif +pci_inteli960ni_fn(struct pci_dev *dev, + struct pci_board *board, + int enable) +{ + unsigned long oldval; + + if (!(board->subdevice & 0x1000)) + return(-1); + + if (!enable) /* is there something to deinit? */ + return(0); + +#ifdef SERIAL_DEBUG_PCI + printk(KERN_DEBUG " Subsystem ID %lx (intel 960)\n", + (unsigned long) board->subdevice); +#endif + /* is firmware started? */ + pci_read_config_dword(dev, 0x44, (void*) &oldval); + if (oldval == 0x00001000L) { /* RESET value */ + printk(KERN_DEBUG "Local i960 firmware missing"); + return(-1); + } + return(0); +} + /* * This is the configuration table for all of the PCI serial boards @@ -3851,8 +4074,9 @@ * Vendor ID, Device ID, * Subvendor ID, Subdevice ID, * PCI Flags, Number of Ports, Base (Maximum) Baud Rate, - * Offset to get to next UART's registers - * Register shift to use for memory-mapped I/O + * Offset to get to next UART's registers, + * Register shift to use for memory-mapped I/O, + * Initialization function, first UART offset */ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, PCI_SUBVENDOR_ID_CONNECT_TECH, @@ -3942,6 +4166,10 @@ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200, PCI_ANY_ID, PCI_ANY_ID, SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 }, + /* VScom SPCOM800, from sl@s.pl */ + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2, 8, 921600 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_KEYSPAN, PCI_SUBDEVICE_ID_KEYSPAN_SX2, @@ -3979,6 +4207,12 @@ PCI_SUBVENDOR_ID_CHASE_PCIRAS, PCI_SUBDEVICE_ID_CHASE_PCIRAS8, SPCI_FL_BASE2, 8, 460800 }, + /* Megawolf Romulus PCI Serial Card, from Mike Hudson */ + /* (Exoray@isys.ca) */ + { PCI_VENDOR_ID_PLX, PCI_VENDOR_ID_PLX_ROMULUS, + 0x10b5, 0x106a, + SPCI_FL_BASE2, 4, 921600, + 0x20, 2, pci_plx9050_fn, 0x03 }, { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100, PCI_ANY_ID, PCI_ANY_ID, SPCI_FL_BASE1, 4, 115200 }, @@ -4164,7 +4398,7 @@ PCI_ANY_ID, PCI_ANY_ID, SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600, 0, 0, pci_siig20x_fn }, - /* Computone devices submitted by Doug McNash dougm@computone.com */ + /* Computone devices submitted by Doug McNash dmcnash@computone.com */ { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4, SPCI_FL_BASE0, 4, 921600, /* IOMEM */ @@ -4198,6 +4432,15 @@ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B, PCI_ANY_ID, PCI_ANY_ID, SPCI_FL_BASE0, 4, 921600 }, + /* EKF addition for i960 Boards form EKF with serial port */ + { PCI_VENDOR_ID_INTEL, 0x1960, + 0xE4BF, PCI_ANY_ID, + SPCI_FL_BASE0, 32, 921600, /* max 256 ports */ + 8<<2, 2, pci_inteli960ni_fn, 0x10000}, + /* RAStel 2 port modem, gerg@moreton.com.au */ + { PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* * Untested PCI modems, sent in from various folks... */ @@ -4221,12 +4464,12 @@ }; /* - * Given a complete unknown PCI device, try to use some hueristics to + * Given a complete unknown PCI device, try to use some heuristics to * guess what the configuration might be, based on the pitiful PCI * serial specs. Returns 0 on success, 1 on failure. */ -static int _INLINE_ serial_guess_board(struct pci_dev *dev, - struct pci_board *board) +static int _INLINE_ serial_pci_guess_board(struct pci_dev *dev, + struct pci_board *board) { int num_iomem = 0, num_port = 0, first_port = -1; int i; @@ -4281,13 +4524,6 @@ printk(KERN_DEBUG "Entered probe_serial_pci()\n"); #endif - if (!pcibios_present()) { -#ifdef SERIAL_DEBUG_PCI - printk(KERN_DEBUG "Leaving probe_serial_pci() (no pcibios)\n"); -#endif - return; - } - pci_for_each_dev(dev) { for (board = pci_boards; board->vendor; board++) { if (board->vendor != (unsigned short) PCI_ANY_ID && @@ -4305,7 +4541,7 @@ break; } - if (board->vendor == 0 && serial_guess_board(dev, board)) + if (board->vendor == 0 && serial_pci_guess_board(dev, board)) continue; start_pci_pnp_board(dev, board); @@ -4321,58 +4557,280 @@ #ifdef ENABLE_SERIAL_PNP -static struct pci_board pnp_devices[] __initdata = { - /* Motorola VoiceSURFR 56K Modem */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15F0), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, +struct pnp_board { + unsigned short vendor; + unsigned short device; +}; + +static struct pnp_board pnp_devices[] __initdata = { + /* Archtek America Corp. */ + /* Archtek SmartLink Modem 3334BT Plug & Play */ + { ISAPNP_VENDOR('A', 'A', 'C'), ISAPNP_DEVICE(0x000F) }, + /* Anchor Datacomm BV */ + /* SXPro 144 External Data Fax Modem Plug & Play */ + { ISAPNP_VENDOR('A', 'D', 'C'), ISAPNP_DEVICE(0x0001) }, + /* SXPro 288 External Data Fax Modem Plug & Play */ + { ISAPNP_VENDOR('A', 'D', 'C'), ISAPNP_DEVICE(0x0002) }, /* Rockwell 56K ACF II Fax+Data+Voice Modem */ - { ISAPNP_VENDOR('A', 'K', 'Y'), ISAPNP_DEVICE(0x1021), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_NO_SHIRQ | SPCI_FL_PNPDEFAULT, - 1, 115200 }, + { ISAPNP_VENDOR('A', 'K', 'Y'), ISAPNP_DEVICE(0x1021) }, /* AZT3005 PnP SOUND DEVICE */ - { ISAPNP_VENDOR('A', 'Z', 'T'), ISAPNP_DEVICE(0x4001), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, + { ISAPNP_VENDOR('A', 'Z', 'T'), ISAPNP_DEVICE(0x4001) }, /* Best Data Products Inc. Smart One 336F PnP Modem */ - { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, + { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336) }, + /* Boca Research */ + /* Boca Complete Ofc Communicator 14.4 Data-FAX */ + { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x0A49) }, /* Boca Research 33,600 ACF Modem */ - { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x1400), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, + { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x1400) }, + /* Boca 33.6 Kbps Internal FD34FSVD */ + { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x3400) }, + /* Boca 33.6 Kbps Internal FD34FSVD */ + { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x0A49) }, + /* Best Data Products Inc. Smart One 336F PnP Modem */ + { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336) }, + /* Computer Peripherals Inc */ + /* EuroViVa CommCenter-33.6 SP PnP */ + { ISAPNP_VENDOR('C', 'P', 'I'), ISAPNP_DEVICE(0x4050) }, + /* Creative Labs */ + /* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */ + { ISAPNP_VENDOR('C', 'T', 'L'), ISAPNP_DEVICE(0x3001) }, + /* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */ + { ISAPNP_VENDOR('C', 'T', 'L'), ISAPNP_DEVICE(0x3011) }, + /* Creative */ /* Creative Modem Blaster Flash56 DI5601-1 */ - { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x1032), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, + { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x1032) }, /* Creative Modem Blaster V.90 DI5660 */ - { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x2001), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, + { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x2001) }, + /* FUJITSU */ + /* Fujitsu 33600 PnP-I2 R Plug & Play */ + { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0202) }, + /* Fujitsu FMV-FX431 Plug & Play */ + { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0205) }, + /* Fujitsu 33600 PnP-I4 R Plug & Play */ + { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0206) }, + /* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */ + { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0209) }, + /* Archtek America Corp. */ + /* Archtek SmartLink Modem 3334BT Plug & Play */ + { ISAPNP_VENDOR('G', 'V', 'C'), ISAPNP_DEVICE(0x000F) }, + /* Hayes */ + /* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */ + { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x0001) }, + /* Hayes Optima 336 V.34 + FAX + Voice PnP */ + { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x000C) }, + /* Hayes Optima 336B V.34 + FAX + Voice PnP */ + { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x000D) }, + /* Hayes Accura 56K Ext Fax Modem PnP */ + { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5670) }, + /* Hayes Accura 56K Ext Fax Modem PnP */ + { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5674) }, + /* Hayes Accura 56K Fax Modem PnP */ + { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5675) }, + /* Hayes 288, V.34 + FAX */ + { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0xF000) }, + /* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */ + { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0xF001) }, + /* IBM */ + /* IBM Thinkpad 701 Internal Modem Voice */ + { ISAPNP_VENDOR('I', 'B', 'M'), ISAPNP_DEVICE(0x0033) }, + /* Intertex */ + /* Intertex 28k8 33k6 Voice EXT PnP */ + { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xC801) }, + /* Intertex 33k6 56k Voice EXT PnP */ + { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xC901) }, + /* Intertex 28k8 33k6 Voice SP EXT PnP */ + { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xD801) }, + /* Intertex 33k6 56k Voice SP EXT PnP */ + { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xD901) }, + /* Intertex 28k8 33k6 Voice SP INT PnP */ + { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF401) }, + /* Intertex 28k8 33k6 Voice SP EXT PnP */ + { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF801) }, + /* Intertex 33k6 56k Voice SP EXT PnP */ + { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF901) }, + /* Kortex International */ + /* KORTEX 28800 Externe PnP */ + { ISAPNP_VENDOR('K', 'O', 'R'), ISAPNP_DEVICE(0x4522) }, + /* KXPro 33.6 Vocal ASVD PnP */ + { ISAPNP_VENDOR('K', 'O', 'R'), ISAPNP_DEVICE(0xF661) }, + /* Lasat */ + /* LASAT Internet 33600 PnP */ + { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x4040) }, + /* Lasat Safire 560 PnP */ + { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x4540) }, + /* Lasat Safire 336 PnP */ + { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x5440) }, + /* Microcom, Inc. */ + /* Microcom TravelPorte FAST V.34 Plug & Play */ + { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x281) }, + /* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */ + { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0336) }, + /* Microcom DeskPorte FAST EP 28.8 Plug & Play */ + { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0339) }, + /* Microcom DeskPorte 28.8P Plug & Play */ + { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0342) }, + /* Microcom DeskPorte FAST ES 28.8 Plug & Play */ + { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0500) }, + /* Microcom DeskPorte FAST ES 28.8 Plug & Play */ + { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0501) }, + /* Microcom DeskPorte 28.8S Internal Plug & Play */ + { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0502) }, + /* Motorola */ + /* Motorola BitSURFR Plug & Play */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1105) }, + /* Motorola TA210 Plug & Play */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1111) }, + /* Motorola HMTA 200 (ISDN) Plug & Play */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1114) }, + /* Motorola BitSURFR Plug & Play */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1115) }, + /* Motorola Lifestyle 28.8 Internal */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1190) }, + /* Motorola V.3400 Plug & Play */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1501) }, + /* Motorola Lifestyle 28.8 V.34 Plug & Play */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1502) }, + /* Motorola Power 28.8 V.34 Plug & Play */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1505) }, + /* Motorola ModemSURFR External 28.8 Plug & Play */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1509) }, + /* Motorola Premier 33.6 Desktop Plug & Play */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x150A) }, + /* Motorola VoiceSURFR 56K External PnP */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x150F) }, + /* Motorola ModemSURFR 56K External PnP */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1510) }, + /* Motorola ModemSURFR 56K Internal PnP */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1550) }, + /* Motorola ModemSURFR Internal 28.8 Plug & Play */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1560) }, + /* Motorola Premier 33.6 Internal Plug & Play */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1580) }, + /* Motorola OnlineSURFR 28.8 Internal Plug & Play */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15B0) }, + /* Motorola VoiceSURFR 56K Internal PnP */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15F0) }, + /* Com 1 */ + /* Deskline K56 Phone System PnP */ + { ISAPNP_VENDOR('M', 'V', 'X'), ISAPNP_DEVICE(0x00A1) }, + /* PC Rider K56 Phone System PnP */ + { ISAPNP_VENDOR('M', 'V', 'X'), ISAPNP_DEVICE(0x00F2) }, /* Pace 56 Voice Internal Plug & Play Modem */ - { ISAPNP_VENDOR('P', 'M', 'C'), ISAPNP_DEVICE(0x2430), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, - /* SupraExpress 28.8 Data/Fax PnP modem */ - { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1310), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, - /* US Robotics Sporster 33600 Modem */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0006), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, - /* U.S. Robotics 56K FAX INT */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3031), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, - /* Viking 56K FAX INT */ - { ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x0262), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, - - /* These ID's are taken from M$ documentation */ - /* Compaq 14400 Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC000), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, - /* Compaq 2400/9600 Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC001), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, + { ISAPNP_VENDOR('P', 'M', 'C'), ISAPNP_DEVICE(0x2430) }, + /* Generic */ /* Generic standard PC COM port */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0500), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0500) }, /* Generic 16550A-compatible COM port */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0501), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0501) }, + /* Compaq 14400 Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC000) }, + /* Compaq 2400/9600 Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC001) }, + /* Dial-Up Networking Serial Cable between 2 PCs */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC031) }, + /* Dial-Up Networking Parallel Cable between 2 PCs */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC032) }, + /* Standard 9600 bps Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC100) }, + /* Standard 14400 bps Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC101) }, + /* Standard 28800 bps Modem*/ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC102) }, + /* Standard Modem*/ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC103) }, + /* Standard 9600 bps Modem*/ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC104) }, + /* Standard 14400 bps Modem*/ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC105) }, + /* Standard 28800 bps Modem*/ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC106) }, + /* Standard Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC107) }, + /* Standard 9600 bps Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC108) }, + /* Standard 14400 bps Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC109) }, + /* Standard 28800 bps Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10A) }, + /* Standard Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10B) }, + /* Standard 9600 bps Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10C) }, + /* Standard 14400 bps Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10D) }, + /* Standard 28800 bps Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10E) }, + /* Standard Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10F) }, + /* Standard PCMCIA Card Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x2000) }, + /* Rockwell */ + /* Modular Technology */ + /* Rockwell 33.6 DPF Internal PnP */ + /* Modular Technology 33.6 Internal PnP */ + { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x0030) }, + /* Kortex International */ + /* KORTEX 14400 Externe PnP */ + { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x0100) }, + /* Viking Components, Inc */ + /* Viking 28.8 INTERNAL Fax+Data+Voice PnP */ + { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x4920) }, + /* Rockwell */ + /* British Telecom */ + /* Modular Technology */ + /* Rockwell 33.6 DPF External PnP */ + /* BT Prologue 33.6 External PnP */ + /* Modular Technology 33.6 External PnP */ + { ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x00A0) }, + /* Viking 56K FAX INT */ + { ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x0262) }, + /* SupraExpress 28.8 Data/Fax PnP modem */ + { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1310) }, + /* SupraExpress 33.6 Data/Fax PnP modem */ + { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1421) }, + /* SupraExpress 33.6 Data/Fax PnP modem */ + { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1590) }, + /* SupraExpress 33.6 Data/Fax PnP modem */ + { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1760) }, + /* Phoebe Micro */ + /* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */ + { ISAPNP_VENDOR('T', 'E', 'X'), ISAPNP_DEVICE(0x0011) }, + /* Archtek America Corp. */ + /* Archtek SmartLink Modem 3334BT Plug & Play */ + { ISAPNP_VENDOR('U', 'A', 'C'), ISAPNP_DEVICE(0x000F) }, + /* 3Com Corp. */ + /* Gateway Telepath IIvi 33.6 */ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0000) }, + /* Sportster Vi 14.4 PnP FAX Voicemail */ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0004) }, + /* U.S. Robotics 33.6K Voice INT PnP */ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0006) }, + /* U.S. Robotics 33.6K Voice EXT PnP */ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0007) }, + /* U.S. Robotics 33.6K Voice INT PnP */ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2002) }, + /* U.S. Robotics 56K Voice INT PnP */ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2070) }, + /* U.S. Robotics 56K Voice EXT PnP */ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2080) }, + /* U.S. Robotics 56K FAX INT */ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3031) }, + /* U.S. Robotics 56K Voice INT PnP */ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3070) }, + /* U.S. Robotics 56K Voice EXT PnP */ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3080) }, + /* U.S. Robotics 56K Voice INT PnP */ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3090) }, + /* U.S. Robotics 56K Message */ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9100) }, + /* U.S. Robotics 56K FAX EXT PnP*/ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9160) }, + /* U.S. Robotics 56K FAX INT PnP*/ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9170) }, + /* U.S. Robotics 56K Voice EXT PnP*/ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9180) }, + /* U.S. Robotics 56K Voice INT PnP*/ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9190) }, { 0, } }; @@ -4394,10 +4852,80 @@ irq->map = map; } +static char *modem_names[] __initdata = { + "MODEM", "Modem", "modem", "FAX", "Fax", "fax", + "56K", "56k", "K56", "33.6", "28.8", "14.4", + "33,600", "28,800", "14,400", "33.600", "28.800", "14.400", + "33600", "28800", "14400", "V.90", "V.34", "V.32", 0 +}; + +static int __init check_name(char *name) +{ + char **tmp = modem_names; + + while (*tmp) { + if (strstr(name, *tmp)) + return 1; + tmp++; + } + return 0; +} + +static int inline check_compatible_id(struct pci_dev *dev) +{ + int i; + for (i = 0; i < DEVICE_COUNT_COMPATIBLE; i++) + if ((dev->vendor_compatible[i] == + ISAPNP_VENDOR('P', 'N', 'P')) && + (swab16(dev->device_compatible[i]) >= 0xc000) && + (swab16(dev->device_compatible[i]) <= 0xdfff)) + return 0; + return 1; +} + +/* + * Given a complete unknown ISA PnP device, try to use some heuristics to + * detect modems. Currently use such heuristic set: + * - dev->name or dev->bus->name must contain "modem" substring; + * - device must have only one IO region (8 byte long) with base adress + * 0x2e8, 0x3e8, 0x2f8 or 0x3f8. + * + * Such detection looks very ugly, but can detect at least some of numerous + * ISA PnP modems, alternatively we must hardcode all modems in pnp_devices[] + * table. + */ +static int _INLINE_ serial_pnp_guess_board(struct pci_dev *dev, + struct pci_board *board) +{ + struct isapnp_resources *res = (struct isapnp_resources *)dev->sysdata; + struct isapnp_resources *resa; + + if (!(check_name(dev->name) || check_name(dev->bus->name)) && + !(check_compatible_id(dev))) + return 1; + + if (!res || res->next) + return 1; + + for (resa = res->alt; resa; resa = resa->alt) { + struct isapnp_port *port; + for (port = res->port; port; port = port->next) + if ((port->size == 8) && + ((port->min == 0x2f8) || + (port->min == 0x3f8) || + (port->min == 0x2e8) || + (port->min == 0x3e8))) + return 0; + } + + return 1; +} + static void __init probe_serial_pnp(void) { struct pci_dev *dev = NULL; - struct pci_board *board; + struct pnp_board *pnp_board; + struct pci_board board; #ifdef SERIAL_DEBUG_PNP printk("Entered probe_serial_pnp()\n"); @@ -4409,13 +4937,35 @@ return; } - for (board = pnp_devices; board->vendor; board++) { - while ((dev = isapnp_find_dev(NULL, board->vendor, - board->device, dev))) { - if (board->flags & SPCI_FL_NO_SHIRQ) - avoid_irq_share(dev); - start_pci_pnp_board(dev, board); - } + isapnp_for_each_dev(dev) { + if (dev->active) + continue; + + memset(&board, 0, sizeof(board)); + board.flags = SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT; + board.num_ports = 1; + board.base_baud = 115200; + + for (pnp_board = pnp_devices; pnp_board->vendor; pnp_board++) + if ((dev->vendor == pnp_board->vendor) && + (dev->device == pnp_board->device)) + break; + + if (pnp_board->vendor) { + board.vendor = pnp_board->vendor; + board.device = pnp_board->device; + /* Special case that's more efficient to hardcode */ + if ((board.vendor == ISAPNP_VENDOR('A', 'K', 'Y') && + board.device == ISAPNP_DEVICE(0x1021))) + board.flags |= SPCI_FL_NO_SHIRQ; + } else { + if (serial_pnp_guess_board(dev, &board)) + continue; + } + + if (board.flags & SPCI_FL_NO_SHIRQ) + avoid_irq_share(dev); + start_pci_pnp_board(dev, &board); } #ifdef SERIAL_DEBUG_PNP @@ -4477,7 +5027,7 @@ #if (LINUX_VERSION_CODE > 0x20100) serial_driver.driver_name = "serial"; #endif -#ifdef CONFIG_DEVFS_FS +#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) serial_driver.name = "tts/%d"; #else serial_driver.name = "ttyS"; @@ -4525,7 +5075,7 @@ * major number and the subtype code. */ callout_driver = serial_driver; -#ifdef CONFIG_DEVFS_FS +#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) callout_driver.name = "cua/%d"; #else callout_driver.name = "cua"; @@ -4615,14 +5165,25 @@ unsigned long flags; struct serial_state *state; struct async_struct *info; + unsigned long port; + + port = req->port; + if (HIGH_BITS_OFFSET) + port += req->port_high << HIGH_BITS_OFFSET; save_flags(flags); cli(); for (i = 0; i < NR_PORTS; i++) { - if ((rs_table[i].port == req->port) && + if ((rs_table[i].port == port) && (rs_table[i].iomem_base == req->iomem_base)) break; } if (i == NR_PORTS) { + for (i = 4; i < NR_PORTS; i++) + if ((rs_table[i].type == PORT_UNKNOWN) && + (rs_table[i].count == 0)) + break; + } + if (i == NR_PORTS) { for (i = 0; i < NR_PORTS; i++) if ((rs_table[i].type == PORT_UNKNOWN) && (rs_table[i].count == 0)) @@ -4636,11 +5197,11 @@ if (rs_table[i].count) { restore_flags(flags); printk("Couldn't configure serial #%d (port=%ld,irq=%d): " - "device already open\n", i, req->port, req->irq); + "device already open\n", i, port, req->irq); return -1; } state->irq = req->irq; - state->port = req->port; + state->port = port; state->flags = req->flags; state->io_type = req->io_type; state->iomem_base = req->iomem_base; @@ -4648,7 +5209,7 @@ if (req->baud_base) state->baud_base = req->baud_base; if ((info = state->info) != NULL) { - info->port = req->port; + info->port = port; info->flags = req->flags; info->io_type = req->io_type; info->iomem_base = req->iomem_base; @@ -4721,10 +5282,10 @@ timer_table[RS_TIMER].expires = 0; remove_bh(SERIAL_BH); if ((e1 = tty_unregister_driver(&serial_driver))) - printk("SERIAL: failed to unregister serial driver (%d)\n", + 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", + printk("serial: failed to unregister callout driver (%d)\n", e2); restore_flags(flags); @@ -4733,8 +5294,15 @@ rs_table[i].info = NULL; kfree_s(info, sizeof(struct async_struct)); } - if ((rs_table[i].type != PORT_UNKNOWN) && rs_table[i].port) - release_region(rs_table[i].port, 8); + if ((rs_table[i].type != PORT_UNKNOWN) && rs_table[i].port) { +#ifdef CONFIG_SERIAL_RSA + if (rs_table[i].type == PORT_RSA) + release_region(rs_table[i].port + + UART_RSA_BASE, 16); + else +#endif + release_region(rs_table[i].port, 8); + } #if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP) if (rs_table[i].iomem_base) iounmap(rs_table[i].iomem_base); @@ -4881,9 +5449,6 @@ int cflag = CREAD | HUPCL | CLOCAL; int quot = 0; char *s; -#if defined(CONFIG_KDB) - extern int kdb_port; -#endif if (options) { baud = simple_strtoul(options, NULL, 10); @@ -4987,14 +5552,6 @@ if (serial_in(info, UART_LSR) == 0xff) return -1; -#if defined(CONFIG_KDB) - /* - * Remember I/O port for kdb - */ - if (kdb_port == 0 ) - kdb_port = ser->port; -#endif /* CONFIG_KDB */ - return 0; } @@ -5023,6 +5580,6 @@ /* Local variables: - compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -fno-strength-reduce -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c" + compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -fno-strength-reduce -march=i586 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c" End: */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/sh-sci.c linux/drivers/char/sh-sci.c --- v2.4.0-test1/linux/drivers/char/sh-sci.c Tue May 23 15:31:34 2000 +++ linux/drivers/char/sh-sci.c Mon Jun 19 17:59:40 2000 @@ -5,6 +5,7 @@ * SuperH on-chip serial module support. (SCI with no FIFO / with FIFO) * Copyright (C) 1999, 2000 Niibe Yutaka * Copyright (C) 2000 Sugioka Toshinobu + * Modified to support multiple serial ports. Stuart Menefy (May 2000). * * TTY code is based on sx.c (Specialix SX driver) by: * @@ -31,7 +32,9 @@ #include #include #include +#ifdef CONFIG_SERIAL_CONSOLE #include +#endif #include #include @@ -40,15 +43,23 @@ #include #include -#include "sh-sci.h" #ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB static void gdb_detach(void); +static int in_gdb = 1; +#define IN_GDB in_gdb #endif +#include "sh-sci.h" -struct sci_port sci_ports[1]; +#ifdef CONFIG_SERIAL_CONSOLE +static struct console sercons; +static struct sci_port* sercons_port; +static int sercons_baud; +#endif /* Function prototypes */ +static void sci_init_pins_sci(struct sci_port* port, unsigned int cflag); +static void sci_init_pins_scif(struct sci_port* port, unsigned int cflag); static void sci_disable_tx_interrupts(void *ptr); static void sci_enable_tx_interrupts(void *ptr); static void sci_disable_rx_interrupts(void *ptr); @@ -63,9 +74,10 @@ static struct tty_driver sci_driver, sci_callout_driver; -#define SCI_NPORTS 1 +static struct sci_port sci_ports[SCI_NPORTS] = SCI_INIT; static struct tty_struct *sci_table[SCI_NPORTS] = { NULL, }; -static struct termios *sci_termios[2]; /* nomal, locked */ +static struct termios *sci_termios[SCI_NPORTS]; +static struct termios *sci_termios_locked[SCI_NPORTS]; int sci_refcount; int sci_debug = 0; @@ -88,6 +100,63 @@ NULL }; +#if defined(SCI_ONLY) || defined(SCI_AND_SCIF) +static void sci_init_pins_sci(struct sci_port* port, unsigned int cflag) +{ +} +#endif + +#if defined(SCIF_ONLY) || defined(SCI_AND_SCIF) +#if defined(__sh3__) +/* For SH7709, SH7709A, SH7729 */ +static void sci_init_pins_scif(struct sci_port* port, unsigned int cflag) +{ + unsigned int fcr_val = 0; + + { + unsigned short data; + + /* We need to set SCPCR to enable RTS/CTS */ + data = ctrl_inw(SCPCR); + /* Clear out SCP7MD1,0, SCP6MD1,0, SCP4MD1,0*/ + ctrl_outw(data&0x0fcf, SCPCR); + } + if (cflag & CRTSCTS) + fcr_val |= SCFCR_MCE; + else { + unsigned short data; + + /* We need to set SCPCR to enable RTS/CTS */ + data = ctrl_inw(SCPCR); + /* Clear out SCP7MD1,0, SCP4MD1,0, + Set SCP6MD1,0 = {01} (output) */ + ctrl_outw((data&0x0fcf)|0x1000, SCPCR); + + data = ctrl_inb(SCPDR); + /* Set /RTS2 (bit6) = 0 */ + ctrl_outb(data&0xbf, SCPDR); + } + sci_out(port, SCFCR, fcr_val); +} + +#else + +/* For SH7750 */ +static void sci_init_pins_scif(struct sci_port* port, unsigned int cflag) +{ + unsigned int fcr_val = 0; + + if (cflag & CRTSCTS) { + fcr_val |= SCFCR_MCE; + } else { + ctrl_outw(0x0080, SCSPTR2); /* Set RTS = 1 */ + } + sci_out(port, SCFCR, fcr_val); +} + +#endif +#endif /* SCIF_ONLY || SCI_AND_SCIF */ + static void sci_setsignals(struct sci_port *port, int dtr, int rts) { /* This routine is used for seting signals of: DTR, DCD, CTS/RTS */ @@ -112,11 +181,11 @@ */ } -static void sci_set_baud(struct sci_port *port) +static void sci_set_baud(struct sci_port *port, int baud) { int t; - switch (port->gs.baud) { + switch (baud) { case 0: t = -1; break; @@ -136,7 +205,7 @@ t = BPS_38400; break; default: - printk(KERN_INFO "sci: unsupported baud rate: %d, use 115200 instead.\n", port->gs.baud); + printk(KERN_INFO "sci: unsupported baud rate: %d, use 115200 instead.\n", baud); case 115200: t = BPS_115200; break; @@ -145,93 +214,57 @@ if (t > 0) { sci_setsignals (port, 1, -1); if(t >= 256) { - ctrl_out((ctrl_in(SCSMR) & ~3) | 1, SCSMR); + sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1); t >>= 2; } - ctrl_outb(t, SCBRR); - ctrl_outw(0xa400, RFCR); /* Refresh counter clear */ - while (ctrl_inw(RFCR) < WAIT_RFCR_COUNTER) - ; + sci_out(port, SCBRR, t); + udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */ } else { sci_setsignals (port, 0, -1); } } -static void sci_set_termios_cflag(struct sci_port *port) +static void sci_set_termios_cflag(struct sci_port *port, int cflag, int baud) { - unsigned short status; - unsigned short smr_val; -#if defined(CONFIG_SH_SCIF_SERIAL) - unsigned short fcr_val=6; /* TFRST=1, RFRST=1 */ -#endif + unsigned int status; + unsigned int smr_val; do - status = ctrl_in(SC_SR); - while (!(status & SCI_TEND)); + status = sci_in(port, SCxSR); + while (!(status & SCxSR_TEND(port))); - port->old_cflag = port->gs.tty->termios->c_cflag; + sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */ - ctrl_out(0x00, SCSCR); /* TE=0, RE=0, CKE1=0 */ -#if defined(CONFIG_SH_SCIF_SERIAL) - ctrl_out(fcr_val, SCFCR); - fcr_val = 0; -#endif + if (port->type == PORT_SCIF) { + sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST); + } - smr_val = ctrl_in(SCSMR) & 3; - if ((port->gs.tty->termios->c_cflag & CSIZE) == CS7) + smr_val = sci_in(port, SCSMR) & 3; + if ((cflag & CSIZE) == CS7) smr_val |= 0x40; - if (C_PARENB(port->gs.tty)) + if (cflag & PARENB) smr_val |= 0x20; - if (C_PARODD(port->gs.tty)) + if (cflag & PARODD) smr_val |= 0x10; - if (C_CSTOPB(port->gs.tty)) + if (cflag & CSTOPB) smr_val |= 0x08; - ctrl_out(smr_val, SCSMR); + sci_out(port, SCSMR, smr_val); -#if defined(CONFIG_SH_SCIF_SERIAL) -#if defined(__sh3__) - { /* For SH7709, SH7709A, SH7729 */ - unsigned short data; + port->init_pins(port, cflag); - /* We need to set SCPCR to enable RTS/CTS */ - data = ctrl_inw(SCPCR); - /* Clear out SCP7MD1,0, SCP6MD1,0, SCP4MD1,0*/ - ctrl_outw(data&0x0fcf, SCPCR); - } -#endif - if (C_CRTSCTS(port->gs.tty)) - fcr_val |= 0x08; - else { -#if defined(__sh3__) - unsigned short data; - - /* We need to set SCPCR to enable RTS/CTS */ - data = ctrl_inw(SCPCR); - /* Clear out SCP7MD1,0, SCP4MD1,0, - Set SCP6MD1,0 = {01} (output) */ - ctrl_outw((data&0x0fcf)|0x1000, SCPCR); - - data = ctrl_inb(SCPDR); - /* Set /RTS2 (bit6) = 0 */ - ctrl_outb(data&0xbf, SCPDR); -#elif defined(__SH4__) - ctrl_outw(0x0080, SCSPTR); /* Set RTS = 1 */ -#endif - } - ctrl_out(fcr_val, SCFCR); -#endif - - sci_set_baud(port); - ctrl_out(SCSCR_INIT, SCSCR); /* TIE=0,RIE=0,TE=1,RE=1 */ - sci_enable_rx_interrupts(port); + sci_set_baud(port, baud); + sci_out(port, SCSCR, SCSCR_INIT(port)); } static int sci_set_real_termios(void *ptr) { struct sci_port *port = ptr; - if (port->old_cflag != port->gs.tty->termios->c_cflag) - sci_set_termios_cflag(port); + if (port->old_cflag != port->gs.tty->termios->c_cflag) { + port->old_cflag = port->gs.tty->termios->c_cflag; + sci_set_termios_cflag(port, port->old_cflag, port->gs.baud); + sci_enable_rx_interrupts(port); + } /* Tell line discipline whether we will do input cooking */ if (I_OTHER(port->gs.tty)) @@ -265,27 +298,27 @@ unsigned short ctrl; unsigned char c; - status = ctrl_in(SC_SR); - if (!(status & SCI_TD_E)) { + status = sci_in(port, SCxSR); + if (!(status & SCxSR_TDxE(port))) { save_and_cli(flags); - ctrl = ctrl_in(SCSCR); + ctrl = sci_in(port, SCSCR); if (port->gs.xmit_cnt == 0) { ctrl &= ~SCI_CTRL_FLAGS_TIE; port->gs.flags &= ~GS_TX_INTEN; } else ctrl |= SCI_CTRL_FLAGS_TIE; - ctrl_out(ctrl, SCSCR); + sci_out(port, SCSCR, ctrl); restore_flags(flags); return; } while (1) { count = port->gs.xmit_cnt; -#if defined(CONFIG_SH_SCIF_SERIAL) - txroom = 16 - (ctrl_inw(SCFDR)>>8); -#else - txroom = (ctrl_in(SC_SR)&SCI_TD_E)?1:0; -#endif + if (port->type == PORT_SCIF) { + txroom = 16 - (sci_in(port, SCFDR)>>8); + } else { + txroom = (sci_in(port, SCxSR) & SCI_TDRE)?1:0; + } if (count > txroom) count = txroom; @@ -299,9 +332,9 @@ for (i=0; igs.xmit_buf[port->gs.xmit_tail + i]; - ctrl_outb(c, SC_TDR); + sci_out(port, SCxTDR, c); } - ctrl_out(SCI_TD_E_CLEAR, SC_SR); + sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); /* Update the kernel buffer end */ port->gs.xmit_tail = (port->gs.xmit_tail + count) & (SERIAL_XMIT_SIZE-1); @@ -319,18 +352,18 @@ } save_and_cli(flags); - ctrl = ctrl_in(SCSCR); + ctrl = sci_in(port, SCSCR); if (port->gs.xmit_cnt == 0) { ctrl &= ~SCI_CTRL_FLAGS_TIE; port->gs.flags &= ~GS_TX_INTEN; } else { -#if defined(CONFIG_SH_SCIF_SERIAL) - ctrl_in(SC_SR); /* Dummy read */ - ctrl_out(SCI_TD_E_CLEAR, SC_SR); -#endif + if (port->type == PORT_SCIF) { + sci_in(port, SCxSR); /* Dummy read */ + sci_out(port, SCxSR, SCIF_TDFE); + } ctrl |= SCI_CTRL_FLAGS_TIE; } - ctrl_out(ctrl, SCSCR); + sci_out(port, SCSCR, ctrl); restore_flags(flags); } @@ -341,17 +374,17 @@ int copied=0; unsigned short status; - status = ctrl_in(SC_SR); - if (!(status & SCI_RD_F)) + status = sci_in(port, SCxSR); + if (!(status & SCxSR_RDxF(port))) return; tty = port->gs.tty; while (1) { -#if defined(CONFIG_SH_SCIF_SERIAL) - count = ctrl_inw(SCFDR)&0x001f; -#else - count = (ctrl_in(SC_SR)&SCI_RD_F)?1:0; -#endif + if (port->type == PORT_SCIF) { + count = sci_in(port, SCFDR)&0x001f; + } else { + count = (sci_in(port, SCxSR)&SCxSR_RDxF(port))?1:0; + } /* Don't copy more bytes than there is room for in the buffer */ if (tty->flip.count + count > TTY_FLIPBUF_SIZE) @@ -362,9 +395,9 @@ break; for (i=0; iflip.char_buf_ptr[i] = ctrl_inb(SC_RDR); - ctrl_in(SC_SR); /* dummy read */ - ctrl_out(SCI_RDRF_CLEAR, SC_SR); + tty->flip.char_buf_ptr[i] = sci_in(port, SCxRDR); + sci_in(port, SCxSR); /* dummy read */ + sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); memset(tty->flip.flag_buf_ptr, TTY_NORMAL, count); @@ -384,16 +417,13 @@ static void sci_rx_interrupt(int irq, void *ptr, struct pt_regs *regs) { struct sci_port *port = ptr; - unsigned long flags; if (port->gs.flags & GS_ACTIVE) if (!(port->gs.flags & SCI_RX_THROTTLE)) { sci_receive_chars(port); return; } - save_and_cli(flags); - ctrl_out(ctrl_in(SCSCR) & ~SCI_CTRL_FLAGS_RIE, SCSCR); - restore_flags(flags); + sci_disable_rx_interrupts(port); } static void sci_tx_interrupt(int irq, void *ptr, struct pt_regs *regs) @@ -403,19 +433,17 @@ if (port->gs.flags & GS_ACTIVE) sci_transmit_chars(port); else { - unsigned long flags; - - save_and_cli(flags); - ctrl_out(ctrl_in(SCSCR) & ~SCI_CTRL_FLAGS_TIE, SCSCR); - restore_flags(flags); + sci_disable_tx_interrupts(port); } } static void sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs) { + struct sci_port *port = ptr; + /* Handle errors */ - if (ctrl_in(SC_SR) & SCI_ERRORS) - ctrl_out(SCI_ERROR_CLEAR, SC_SR); + if (sci_in(port, SCxSR) & SCxSR_ERRORS(port)) + sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); /* Kick the transmission */ sci_tx_interrupt(irq, ptr, regs); @@ -428,14 +456,15 @@ static void sci_disable_tx_interrupts(void *ptr) { + struct sci_port *port = ptr; unsigned long flags; unsigned short ctrl; /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */ save_and_cli(flags); - ctrl = ctrl_in(SCSCR); + ctrl = sci_in(port, SCSCR); ctrl &= ~SCI_CTRL_FLAGS_TIE; - ctrl_out(ctrl, SCSCR); + sci_out(port, SCSCR, ctrl); restore_flags(flags); } @@ -443,34 +472,36 @@ { struct sci_port *port = ptr; - disable_irq(SCI_TXI_IRQ); + disable_irq(port->irqs[SCIx_TXI_IRQ]); sci_transmit_chars(port); - enable_irq(SCI_TXI_IRQ); + enable_irq(port->irqs[SCIx_TXI_IRQ]); } static void sci_disable_rx_interrupts(void * ptr) { + struct sci_port *port = ptr; unsigned long flags; unsigned short ctrl; /* Clear RIE (Receive Interrupt Enable) bit in SCSCR */ save_and_cli(flags); - ctrl = ctrl_in(SCSCR); + ctrl = sci_in(port, SCSCR); ctrl &= ~SCI_CTRL_FLAGS_RIE; - ctrl_out(ctrl, SCSCR); + sci_out(port, SCSCR, ctrl); restore_flags(flags); } static void sci_enable_rx_interrupts(void * ptr) { + struct sci_port *port = ptr; unsigned long flags; unsigned short ctrl; /* Set RIE (Receive Interrupt Enable) bit in SCSCR */ save_and_cli(flags); - ctrl = ctrl_in(SCSCR); + ctrl = sci_in(port, SCSCR); ctrl |= SCI_CTRL_FLAGS_RIE; - ctrl_out(ctrl, SCSCR); + sci_out(port, SCSCR, ctrl); restore_flags(flags); } @@ -482,11 +513,13 @@ static int sci_chars_in_buffer(void * ptr) { -#if defined(CONFIG_SH_SCIF_SERIAL) - return (ctrl_inw(SCFDR) >> 8) + ((ctrl_in(SC_SR) & SCI_TEND)? 0: 1); -#else - return (ctrl_in(SC_SR) & SCI_TEND)? 0: 1; -#endif + struct sci_port *port = ptr; + + if (port->type == PORT_SCIF) { + return (sci_in(port, SCFDR) >> 8) + ((sci_in(port, SCxSR) & SCxSR_TEND(port))? 0: 1); + } else { + return (sci_in(port, SCxSR) & SCxSR_TEND(port))? 0: 1; + } } static void sci_shutdown_port(void * ptr) @@ -551,6 +584,15 @@ sci_set_real_termios(port); } +#ifdef CONFIG_SERIAL_CONSOLE + if (sercons.cflag && sercons.index == line) { + tty->termios->c_cflag = sercons.cflag; + port->gs.baud = sercons_baud; + sercons.cflag = 0; + sci_set_real_termios(port); + } +#endif + sci_enable_rx_interrupts(port); port->gs.session = current->session; @@ -665,6 +707,25 @@ return; } +#ifdef CONFIG_PROC_FS +static int sci_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int i; + struct sci_port *port; + int len = 0; + + len += sprintf(page, "serinfo:1.0\n"); + for (i = 0; i < SCI_NPORTS && len < 4000; i++) { + port = &sci_ports[i]; + len += sprintf(page+len, "%d: uart:%s address: %08x\n", i, + (port->type == PORT_SCI) ? "SCI" : "SCIF", + port->base); + } + return len; +} +#endif + /* ********************************************************************** * * Here are the initialization routines. * * ********************************************************************** */ @@ -678,20 +739,19 @@ sci_driver.magic = TTY_DRIVER_MAGIC; sci_driver.driver_name = "serial"; sci_driver.name = "ttyS"; - sci_driver.major = TTY_MAJOR; + sci_driver.major = SCI_MAJOR; sci_driver.minor_start = SCI_MINOR_START; - sci_driver.num = 1; + sci_driver.num = SCI_NPORTS; sci_driver.type = TTY_DRIVER_TYPE_SERIAL; sci_driver.subtype = SERIAL_TYPE_NORMAL; sci_driver.init_termios = tty_std_termios; sci_driver.init_termios.c_cflag = - B115200 | CS8 | CREAD | HUPCL | CLOCAL | CRTSCTS; + B9600 | CS8 | CREAD | HUPCL | CLOCAL | CRTSCTS; sci_driver.flags = TTY_DRIVER_REAL_RAW; sci_driver.refcount = &sci_refcount; sci_driver.table = sci_table; - sci_driver.termios = &sci_termios[0]; - sci_driver.termios_locked = &sci_termios[1]; - sci_termios[0] = sci_termios[1] = NULL; + sci_driver.termios = sci_termios; + sci_driver.termios_locked = sci_termios_locked; sci_driver.open = sci_open; sci_driver.close = gs_close; @@ -708,11 +768,15 @@ sci_driver.stop = gs_stop; sci_driver.start = gs_start; sci_driver.hangup = gs_hangup; +#ifdef CONFIG_PROC_FS + sci_driver.read_proc = sci_read_proc; +#endif sci_callout_driver = sci_driver; - sci_callout_driver.name = "cua"; - sci_callout_driver.major = TTYAUX_MAJOR; + sci_callout_driver.name = "cusc"; + 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", @@ -726,16 +790,17 @@ return 1; } - port = &sci_ports[0]; - port->gs.callout_termios = tty_std_termios; - port->gs.normal_termios = tty_std_termios; - port->gs.magic = SCI_MAGIC; - port->gs.close_delay = HZ/2; - port->gs.closing_wait = 30 * HZ; - port->gs.rd = &sci_real_driver; - init_waitqueue_head(&port->gs.open_wait); - init_waitqueue_head(&port->gs.close_wait); - port->old_cflag = 0; + 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; + port->gs.closing_wait = 30 * HZ; + port->gs.rd = &sci_real_driver; + init_waitqueue_head(&port->gs.open_wait); + init_waitqueue_head(&port->gs.close_wait); + port->old_cflag = 0; + } return 0; } @@ -744,26 +809,20 @@ { struct sci_port *port; int i; - - for (i=SCI_ERI_IRQ; iirqs[i], port->intc_addr, port->intc_pos, SCI_PRIORITY); + + if (request_irq(port->irqs[i], handlers[i], SA_INTERRUPT, + "serial", port)) { + printk(KERN_ERR "sci: Cannot allocate irq.\n"); + return -ENODEV; + } + } } /* XXX: How about BRI interrupt?? */ @@ -802,121 +861,21 @@ * ------------------------------------------------------------ */ -static inline void put_char(char c) -{ - unsigned long flags; - unsigned short status; - - save_and_cli(flags); - - do - status = ctrl_in(SC_SR); - while (!(status & SCI_TD_E)); - - ctrl_outb(c, SC_TDR); - ctrl_in(SC_SR); /* Dummy read */ - ctrl_out(SCI_TD_E_CLEAR, SC_SR); - - restore_flags(flags); -} - #ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB -static int in_gdb = 1; -static inline void handle_error(void) -{ /* Clear error flags */ - ctrl_out(SCI_ERROR_CLEAR, SC_SR); -} - -static inline int get_char(void) -{ - unsigned long flags; - unsigned short status; - int c; - - save_and_cli(flags); - do { - status = ctrl_in(SC_SR); - if (status & SCI_ERRORS) { - handle_error(); - continue; - } - } while (!(status & SCI_RD_F)); - c = ctrl_inb(SC_RDR); - ctrl_in(SC_SR); /* Dummy read */ - ctrl_out(SCI_RDRF_CLEAR, SC_SR); - restore_flags(flags); - - return c; -} - -/* Taken from sh-stub.c of GDB 4.18 */ -static const char hexchars[] = "0123456789abcdef"; -static char highhex(int x) -{ - return hexchars[(x >> 4) & 0xf]; -} - -static char lowhex(int x) -{ - return hexchars[x & 0xf]; -} - -static void gdb_detach(void) +static void __init gdb_detach(void) { asm volatile("trapa #0xff"); if (in_gdb == 1) { in_gdb = 0; - get_char(); - put_char('\r'); - put_char('\n'); + get_char(sercons_port); + put_char(sercons_port, '\r'); + put_char(sercons_port, '\n'); } } #endif -/* send the packet in buffer. The host get's one chance to read it. - This routine does not wait for a positive acknowledge. */ - -static void -put_string(const char *buffer, int count) -{ - int i; - const unsigned char *p = buffer; -#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB - int checksum; - -if (in_gdb) { - /* $#. */ - do { - unsigned char c; - put_char('$'); - put_char('O'); /* 'O'utput to console */ - checksum = 'O'; - - for (i=0; iindex); + return MKDEV(SCI_MAJOR, SCI_MINOR_START + c->index); } /* @@ -949,12 +908,14 @@ */ static int __init serial_console_setup(struct console *co, char *options) { - int baud = 115200; + int baud = 9600; int bits = 8; int parity = 'n'; int cflag = CREAD | HUPCL | CLOCAL; char *s; + sercons_port = &sci_ports[co->index]; + if (options) { baud = simple_strtoul(options, NULL, 10); s = options; @@ -983,6 +944,7 @@ case 9600: default: cflag |= B9600; + baud = 9600; break; } switch (bits) { @@ -1002,14 +964,18 @@ cflag |= PARENB; break; } + co->cflag = cflag; + sercons_baud = baud; + + sci_set_termios_cflag(sercons_port, cflag, baud); + sercons_port->old_cflag = cflag; - /* XXX: set baud, char, and parity here. */ return 0; } static struct console sercons = { - "ttyS", + "ttySC", serial_console_write, NULL, serial_console_device, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/sh-sci.h linux/drivers/char/sh-sci.h --- v2.4.0-test1/linux/drivers/char/sh-sci.h Tue May 23 15:31:34 2000 +++ linux/drivers/char/sh-sci.h Mon Jun 19 17:59:40 2000 @@ -5,148 +5,135 @@ * SuperH on-chip serial module support. (SCI with no FIFO / with FIFO) * Copyright (C) 1999, 2000 Niibe Yutaka * Copyright (C) 2000 Greg Banks + * Modified to support multiple serial ports. Stuart Menefy (May 2000). * */ #include -#if defined(CONFIG_SH_SCI_SERIAL) -#if defined(__sh3__) -#define SCSMR (volatile unsigned char *)0xfffffe80 -#define SCBRR 0xfffffe82 -#define SCSCR (volatile unsigned char *)0xfffffe84 -#define SC_TDR 0xfffffe86 -#define SC_SR (volatile unsigned char *)0xfffffe88 -#define SC_RDR 0xfffffe8a -#define SCSPTR 0xffffff7c -#elif defined(__SH4__) -#define SCSMR (volatile unsigned char *)0xffe00000 -#define SCBRR 0xffe00004 -#define SCSCR (volatile unsigned char *)0xffe00008 -#define SC_TDR 0xffe0000c -#define SC_SR (volatile unsigned char *)0xffe00010 -#define SC_RDR 0xffe00014 -#define SCSPTR 0xffe0001c +/* Values for sci_port->type */ +#define PORT_SCI 0 +#define PORT_SCIF 1 + +/* Offsets into the sci_port->irqs array */ +#define SCIx_ERI_IRQ 0 +#define SCIx_RXI_IRQ 1 +#define SCIx_TXI_IRQ 2 + +/* ERI, RXI, TXI, INTC reg, INTC pos */ +#define SCI_IRQS { 23, 24, 25 }, INTC_IPRB, 1 +#define SH3_SCIF_IRQS { 56, 57, 59 }, INTC_IPRE, 1 +#define SH4_SCIF_IRQS { 40, 41, 43 }, INTC_IPRC, 1 + +#if defined(CONFIG_CPU_SUBTYPE_SH7708) +# define SCI_NPORTS 1 +# define SCI_INIT { \ + { {}, PORT_SCI, 0xfffffe80, SCI_IRQS, sci_init_pins_sci } \ +} +# define SCSPTR 0xffffff7c /* 8 bit */ +# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ +# define SCI_ONLY +#elif defined(CONFIG_CPU_SUBTYPE_SH7709) +# define SCI_NPORTS 2 +# define SCI_INIT { \ + { {}, PORT_SCI, 0xfffffe80, SCI_IRQS, sci_init_pins_sci }, \ + { {}, PORT_SCIF, 0xA4000150, SH3_SCIF_IRQS, sci_init_pins_scif } \ +} +# define SCPCR 0xA4000116 /* 16 bit SCI and SCIF */ +# define SCPDR 0xA4000136 /* 8 bit SCI and SCIF */ +# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ +# define SCI_AND_SCIF +#elif defined(CONFIG_CPU_SUBTYPE_SH7750) +# define SCI_NPORTS 2 +# define SCI_INIT { \ + { {}, PORT_SCI, 0xffe00000, SCI_IRQS, sci_init_pins_sci }, \ + { {}, PORT_SCIF, 0xFFE80000, SH4_SCIF_IRQS, sci_init_pins_scif } \ +} +# define SCSPTR1 0xffe0001c /* 8 bit SCI */ +# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */ +# define SCLSR2 0xFFE80024 /* 16 bit SCIF */ +# define SCSCR_INIT(port) (((port)->type == PORT_SCI) ? \ + 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \ + 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ ) +# define SCI_AND_SCIF +#else +# error CPU subtype not defined #endif -#define SCSCR_INIT 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ - -#define SCI_TD_E 0x80 -#define SCI_RD_F 0x40 -#define SCI_ORER 0x20 -#define SCI_FER 0x10 -#define SCI_PER 0x08 -#define SCI_TEND 0x04 +/* SCSCR */ +#define SCI_CTRL_FLAGS_TIE 0x80 /* all */ +#define SCI_CTRL_FLAGS_RIE 0x40 /* all */ +#define SCI_CTRL_FLAGS_TE 0x20 /* all */ +#define SCI_CTRL_FLAGS_RE 0x10 /* all */ +/* SCI_CTRL_FLAGS_REIE 0x08 * 7750 SCIF */ +/* SCI_CTRL_FLAGS_MPIE 0x08 * 7708 SCI, 7709 SCI, 7750 SCI */ +/* SCI_CTRL_FLAGS_TEIE 0x04 * 7708 SCI, 7709 SCI, 7750 SCI */ +/* SCI_CTRL_FLAGS_CKE1 0x02 * all */ +/* SCI_CTRL_FLAGS_CKE0 0x01 * 7708 SCI, 7709 SCI/SCIF, 7750 SCI */ + +/* SCxSR SCI */ +#define SCI_TDRE 0x80 /* 7708 SCI, 7709 SCI, 7750 SCI */ +#define SCI_RDRF 0x40 /* 7708 SCI, 7709 SCI, 7750 SCI */ +#define SCI_ORER 0x20 /* 7708 SCI, 7709 SCI, 7750 SCI */ +#define SCI_FER 0x10 /* 7708 SCI, 7709 SCI, 7750 SCI */ +#define SCI_PER 0x08 /* 7708 SCI, 7709 SCI, 7750 SCI */ +#define SCI_TEND 0x04 /* 7708 SCI, 7709 SCI, 7750 SCI */ +/* SCI_MPB 0x02 * 7708 SCI, 7709 SCI, 7750 SCI */ +/* SCI_MPBT 0x01 * 7708 SCI, 7709 SCI, 7750 SCI */ #define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ORER) -#define SCI_TD_E_CLEAR 0x78 -#define SCI_RDRF_CLEAR 0xbc -#define SCI_ERROR_CLEAR 0xc4 - -#define SCI_CTRL_FLAGS_TIE 0x80 -#define SCI_CTRL_FLAGS_RIE 0x40 -#define SCI_CTRL_FLAGS_TE 0x20 -#define SCI_CTRL_FLAGS_RE 0x10 -/* TEIE=0x04 */ -#define SCI_CTRL_FLAGS_CKE1 0x02 -#define SCI_CTRL_FLAGS_CKE0 0x01 - -#define SCI_ERI_IRQ 23 -#define SCI_RXI_IRQ 24 -#define SCI_TXI_IRQ 25 -#define SCI_TEI_IRQ 26 -#define SCI_IRQ_END 27 - -#define SCI_IPR_ADDR INTC_IPRB -#define SCI_IPR_POS 1 -#endif - -#if defined(CONFIG_SH_SCIF_SERIAL) -#if defined(__sh3__) -#define SCSMR (volatile unsigned char *)0xA4000150 -#define SCBRR 0xA4000152 -#define SCSCR (volatile unsigned char *)0xA4000154 -#define SC_TDR 0xA4000156 -#define SC_SR (volatile unsigned short *)0xA4000158 -#define SC_RDR 0xA400015A -#define SCFCR (volatile unsigned char *)0xA400015C -#define SCFDR 0xA400015E - -#undef SCSPTR /* SH7709 doesn't have SCSPTR */ -#define SCPCR 0xA4000116 /* Instead, it has SCPCR and SCPDR */ -#define SCPDR 0xA4000136 -#undef SCLSR - -#define SCSCR_INIT 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ - /* 0x33 when external clock is used */ -#define SCI_IPR_ADDR INTC_IPRE -#define SCI_IPR_POS 1 - -#elif defined(__SH4__) -#define SCSMR (volatile unsigned short *)0xFFE80000 -#define SCBRR 0xFFE80004 -#define SCSCR (volatile unsigned short *)0xFFE80008 -#define SC_TDR 0xFFE8000C -#define SC_SR (volatile unsigned short *)0xFFE80010 -#define SC_RDR 0xFFE80014 -#define SCFCR (volatile unsigned short *)0xFFE80018 -#define SCFDR 0xFFE8001C -#define SCSPTR 0xFFE80020 -#define SCLSR 0xFFE80024 - -#define SCSCR_INIT 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ -#define SCI_IPR_ADDR INTC_IPRC -#define SCI_IPR_POS 1 +/* SCxSR SCIF */ +#define SCIF_ER 0x0080 /* 7709 SCIF, 7750 SCIF */ +#define SCIF_TEND 0x0040 /* 7709 SCIF, 7750 SCIF */ +#define SCIF_TDFE 0x0020 /* 7709 SCIF, 7750 SCIF */ +#define SCIF_BRK 0x0010 /* 7709 SCIF, 7750 SCIF */ +#define SCIF_FER 0x0008 /* 7709 SCIF, 7750 SCIF */ +#define SCIF_PER 0x0004 /* 7709 SCIF, 7750 SCIF */ +#define SCIF_RDF 0x0002 /* 7709 SCIF, 7750 SCIF */ +#define SCIF_DR 0x0001 /* 7709 SCIF, 7750 SCIF */ + +#define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK) + +#if defined(SCI_ONLY) +# define SCxSR_TEND(port) SCI_TEND +# define SCxSR_ERRORS(port) SCI_ERRORS +# define SCxSR_RDxF(port) SCI_RDRF +# define SCxSR_TDxE(port) SCI_TDRE +# define SCxSR_RDxF_CLEAR(port) 0xbc +# define SCxSR_ERROR_CLEAR(port) 0xc4 +# define SCxSR_TDxE_CLEAR(port) 0x78 +#elif defined(SCIF_ONLY) +# define SCxSR_TEND(port) SCIF_TEND +# define SCxSR_ERRORS(port) SCIF_ERRORS +# define SCxSR_RDxF(port) SCIF_RDF +# define SCxSR_TDxE(port) SCIF_TDFE +# define SCxSR_RDxF_CLEAR(port) 0x00fc +# define SCxSR_ERROR_CLEAR(port) 0x0063 +# define SCxSR_TDxE_CLEAR(port) 0x00df +#else +# define SCxSR_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND) +# define SCxSR_ERRORS(port) (((port)->type == PORT_SCI) ? SCI_ERRORS : SCIF_ERRORS) +# define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_RDF) +# define SCxSR_TDxE(port) (((port)->type == PORT_SCI) ? SCI_TDRE : SCIF_TDFE) +# define SCxSR_RDxF_CLEAR(port) (((port)->type == PORT_SCI) ? 0xbc : 0x00fc) +# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0063) +# define SCxSR_TDxE_CLEAR(port) (((port)->type == PORT_SCI) ? 0x78 : 0x00df) #endif -#define SCI_ER 0x0080 -#define SCI_TEND 0x0040 -#define SCI_TD_E 0x0020 -#define SCI_BRK 0x0010 -#define SCI_FER 0x0008 -#define SCI_PER 0x0004 -#define SCI_RD_F 0x0002 -#define SCI_DR 0x0001 - -#define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ER | SCI_BRK) -#define SCI_TD_E_CLEAR 0x00df -#define SCI_TEND_CLEAR 0x00bf -#define SCI_RDRF_CLEAR 0x00fc -#define SCI_ERROR_CLEAR 0x0063 - -#define SCI_CTRL_FLAGS_TIE 0x80 -#define SCI_CTRL_FLAGS_RIE 0x40 -#define SCI_CTRL_FLAGS_TE 0x20 -#define SCI_CTRL_FLAGS_RE 0x10 -#define SCI_CTRL_FLAGS_REIE 0x08 -#define SCI_CTRL_FLAGS_CKE1 0x02 - -#if defined(__sh3__) -#define SCI_ERI_IRQ 56 -#define SCI_RXI_IRQ 57 -#define SCI_BRI_IRQ 58 -#define SCI_TXI_IRQ 59 -#define SCI_IRQ_END 60 -#elif defined(__SH4__) -#define SCI_ERI_IRQ 40 -#define SCI_RXI_IRQ 41 -#define SCI_BRI_IRQ 42 -#define SCI_TXI_IRQ 43 -#define SCI_IRQ_END 44 -#endif -#endif - -#if defined(__sh3__) -#define RFCR 0xffffff74 -#elif defined(__SH4__) -#define RFCR 0xFF800028 -#endif +/* SCFCR */ +#define SCFCR_RFRST 0x0002 +#define SCFCR_TFRST 0x0004 +#define SCFCR_MCE 0x0008 #define SCI_PRIORITY 3 -#define SCI_MINOR_START 64 +#define SCI_MAJOR 204 +#define SCI_MINOR_START 8 + +/* Generic serial flags */ #define SCI_RX_THROTTLE 0x0000001 +/* generic serial tty */ #define O_OTHER(tty) \ ((O_OLCUC(tty)) ||\ (O_ONLCR(tty)) ||\ @@ -173,10 +160,85 @@ struct sci_port { struct gs_port gs; + int type; + unsigned int base; + unsigned char irqs[3]; /* ERI, RXI, TXI */ + unsigned int intc_addr, intc_pos; + void (*init_pins)(struct sci_port* port, unsigned int cflag); unsigned int old_cflag; }; -#define WAIT_RFCR_COUNTER 200 +#define SCI_IN(size, offset) \ + unsigned int addr = port->base + (offset); \ + if ((size) == 8) { \ + return ctrl_inb(addr); \ + } else { \ + return ctrl_inw(addr); \ + } +#define SCI_OUT(size, offset, value) \ + unsigned int addr = port->base + (offset); \ + if ((size) == 8) { \ + ctrl_outb(value, addr); \ + } else { \ + ctrl_outw(value, addr); \ + } + +#define CPU_SCIx_FNS(name, sci_offset, sci_size, scif_offset, scif_size)\ + static inline unsigned int sci_##name##_in(struct sci_port* port) \ + { \ + if (port->type == PORT_SCI) { \ + SCI_IN(sci_size, sci_offset) \ + } else { \ + SCI_IN(scif_size, scif_offset); \ + } \ + } \ + static inline void sci_##name##_out(struct sci_port* port, unsigned int value) \ + { \ + if (port->type == PORT_SCI) { \ + SCI_OUT(sci_size, sci_offset, value) \ + } else { \ + SCI_OUT(scif_size, scif_offset, value); \ + } \ + } + +#define CPU_SCIF_FNS(name, scif_offset, scif_size) \ + static inline unsigned int sci_##name##_in(struct sci_port* port) \ + { \ + SCI_IN(scif_size, scif_offset); \ + } \ + static inline void sci_##name##_out(struct sci_port* port, unsigned int value) \ + { \ + SCI_OUT(scif_size, scif_offset, value); \ + } + +#ifdef __sh3__ +#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \ + sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh3_scif_offset, sh3_scif_size) +#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIF_FNS(name, sh3_scif_offset, sh3_scif_size) +#else +#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \ + sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size) +#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) +#endif + +/* reg SCI/SH3 SCI/SH4 SCIF/SH3 SCIF/SH4 */ +/* name off sz off sz off sz off sz */ +SCIx_FNS(SCSMR, 0x00, 8, 0x00, 8, 0x00, 8, 0x00, 16) +SCIx_FNS(SCBRR, 0x02, 8, 0x04, 8, 0x02, 8, 0x04, 8) +SCIx_FNS(SCSCR, 0x04, 8, 0x08, 8, 0x04, 8, 0x08, 16) +SCIx_FNS(SCxTDR, 0x06, 8, 0x0c, 8, 0x06, 8, 0x0C, 8) +SCIx_FNS(SCxSR, 0x08, 8, 0x10, 8, 0x08, 16, 0x10, 16) +SCIx_FNS(SCxRDR, 0x0a, 8, 0x14, 8, 0x0A, 8, 0x14, 8) +SCIF_FNS(SCFCR, 0x0c, 8, 0x18, 16) +SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16) + +#define sci_in(port, reg) sci_##reg##_in(port) +#define sci_out(port, reg, value) sci_##reg##_out(port, value) + /* * Values for the BitRate Register (SCBRR) @@ -191,22 +253,17 @@ * the SCSMR register would also need to be set to non-zero values. * * -- Greg Banks 27Feb2000 + * + * Answer: The SCBRR register is only eight bits, and the value in + * it gets larger with lower baud rates. At around 2400 (depending on + * the peripherial module clock) you run out of bits. However the + * lower two bits of SCSMR allow the module clock to be divided down, + * scaling the value which is needed in SCBRR. + * + * -- Stuart Menefy - 23 May 2000 */ -/* - * XXX: Well, this is not relevant... - * Should we have config option for peripheral clock? - * Or we get the value from time.c. - */ -#if defined(__sh3__) -#if defined(CONFIG_CPU_SUBTYPE_SH7709) -#define PCLK 33333333 -#else -#define PCLK 14745600 /* Isn't it 15MHz? */ -#endif -#elif defined(__SH4__) -#define PCLK 33333333 -#endif +#define PCLK (current_cpu_data.module_clock) #define SCBRR_VALUE(bps) (PCLK/(32*bps)-1) #define BPS_2400 SCBRR_VALUE(2400) @@ -215,3 +272,107 @@ #define BPS_19200 SCBRR_VALUE(19200) #define BPS_38400 SCBRR_VALUE(38400) #define BPS_115200 SCBRR_VALUE(115200) + +#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB +/* Taken from sh-stub.c of GDB 4.18 */ +static const char hexchars[] = "0123456789abcdef"; + +static __inline__ char highhex(int x) +{ + return hexchars[(x >> 4) & 0xf]; +} + +static __inline__ char lowhex(int x) +{ + return hexchars[x & 0xf]; +} +#endif + +static __inline__ void put_char(struct sci_port *port, char c) +{ + unsigned long flags; + unsigned short status; + + save_and_cli(flags); + + do + status = sci_in(port, SCxSR); + while (!(status & SCxSR_TDxE(port))); + + sci_out(port, SCxTDR, c); + sci_in(port, SCxSR); /* Dummy read */ + sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); + + restore_flags(flags); +} + +static __inline__ void handle_error(struct sci_port *port) +{ /* Clear error flags */ + sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); +} + +static __inline__ int get_char(struct sci_port *port) +{ + unsigned long flags; + unsigned short status; + int c; + + save_and_cli(flags); + do { + status = sci_in(port, SCxSR); + if (status & SCxSR_ERRORS(port)) { + handle_error(port); + continue; + } + } while (!(status & SCxSR_RDxF(port))); + c = sci_in(port, SCxRDR); + sci_in(port, SCxSR); /* Dummy read */ + sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + restore_flags(flags); + + return c; +} + +/* + * Send the packet in buffer. The host get's one chance to read it. + * This routine does not wait for a positive acknowledge. + */ + +static __inline__ void put_string(struct sci_port *port, + const char *buffer, int count) +{ + int i; + const unsigned char *p = buffer; +#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB + int checksum; + +if (IN_GDB) { + /* $#. */ + do { + unsigned char c; + put_char(port, '$'); + put_char(port, 'O'); /* 'O'utput to console */ + checksum = 'O'; + + for (i=0; iresource[0].start, devp->resource[1].start, - devp->resource[2].start, devp->resource[3].start, devp->irq); + pci_resource_start(devp, 0), pci_resource_start(devp, 1), + pci_resource_start(devp, 2), pci_resource_start(devp, 3), devp->irq); #endif /* @@ -2805,22 +2802,16 @@ */ switch (brdtype) { case BRD_ECHPCI: - brdp->ioaddr2 = (devp->resource[0].start & - PCI_BASE_ADDRESS_IO_MASK); - brdp->ioaddr1 = (devp->resource[1].start & - PCI_BASE_ADDRESS_IO_MASK); + brdp->ioaddr2 = pci_resource_start(devp, 0); + brdp->ioaddr1 = pci_resource_start(devp, 1); break; case BRD_ECH64PCI: - brdp->ioaddr2 = (devp->resource[2].start & - PCI_BASE_ADDRESS_IO_MASK); - brdp->ioaddr1 = (devp->resource[1].start & - PCI_BASE_ADDRESS_IO_MASK); + brdp->ioaddr2 = pci_resource_start(devp, 2); + brdp->ioaddr1 = pci_resource_start(devp, 1); break; case BRD_EASYIOPCI: - brdp->ioaddr1 = (devp->resource[2].start & - PCI_BASE_ADDRESS_IO_MASK); - brdp->ioaddr2 = (devp->resource[1].start & - PCI_BASE_ADDRESS_IO_MASK); + brdp->ioaddr1 = pci_resource_start(devp, 2); + brdp->ioaddr2 = pci_resource_start(devp, 1); break; default: printk("STALLION: unknown PCI board type=%d\n", brdtype); @@ -3123,27 +3114,6 @@ /*****************************************************************************/ /* - * Memory device open code. Need to keep track of opens and close - * for module handling. - */ - -static int stl_memopen(struct inode *ip, struct file *fp) -{ - MOD_INC_USE_COUNT; - return(0); -} - -/*****************************************************************************/ - -static int stl_memclose(struct inode *ip, struct file *fp) -{ - MOD_DEC_USE_COUNT; - return(0); -} - -/*****************************************************************************/ - -/* * The "staliomem" device is also required to do some special operations * on the board and/or ports. In this driver it is mostly used for stats * collection. @@ -3224,7 +3194,7 @@ devfs_handle = devfs_mk_dir (NULL, "staliomem", 9, NULL); devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT, STL_SIOMEMMAJOR, 0, - S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR, &stl_fsiomem, NULL); /* diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/stradis.c linux/drivers/char/stradis.c --- v2.4.0-test1/linux/drivers/char/stradis.c Thu May 11 15:30:07 2000 +++ linux/drivers/char/stradis.c Mon Jun 19 13:25:06 2000 @@ -2055,10 +2055,13 @@ saa->id = dev->device; saa->irq = dev->irq; saa->video_dev.minor = -1; - saa->saa7146_adr = dev->resource[0].start; + saa->saa7146_adr = pci_resource_start(dev, 0); pci_read_config_byte(dev, PCI_CLASS_REVISION, &saa->revision); - saa->saa7146_mem = ioremap(((saa->saa7146_adr) & - PCI_BASE_ADDRESS_MEM_MASK), 0x200); + + saa->saa7146_mem = ioremap(saa->saa7146_adr, 0x200); + if (!saa->saa7146_mem) + return -EIO; + memcpy(&(saa->i2c), &saa7146_i2c_bus_template, sizeof(struct i2c_bus)); memcpy(&saa->video_dev, &saa_template, sizeof(saa_template)); sprintf(saa->i2c.name, "stradis%d", num); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/sx.c linux/drivers/char/sx.c --- v2.4.0-test1/linux/drivers/char/sx.c Mon Jun 19 16:31:59 2000 +++ linux/drivers/char/sx.c Tue Jun 20 07:37:58 2000 @@ -304,8 +304,6 @@ static int sx_init_portstructs (int nboards, int nports); static int sx_fw_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -static int sx_fw_open(struct inode *inode, struct file *filp); -static INT sx_fw_release(struct inode *inode, struct file *filp); static int sx_init_drivers(void); @@ -419,9 +417,8 @@ */ static struct file_operations sx_fw_fops = { + owner: THIS_MODULE, ioctl: sx_fw_ioctl, - open: sx_fw_open, - release: sx_fw_release, }; struct miscdevice sx_fw_device = { @@ -1417,25 +1414,6 @@ * Here are the routines that actually * * interface with the rest of the system * * ********************************************************************** */ - - -static int sx_fw_open(struct inode *inode, struct file *filp) -{ - func_enter (); - MOD_INC_USE_COUNT; - func_exit (); - return 0; -} - - -static INT sx_fw_release(struct inode *inode, struct file *filp) -{ - func_enter (); - MOD_DEC_USE_COUNT; - func_exit (); - return NO_ERROR; -} - static int sx_open (struct tty_struct * tty, struct file * filp) { diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/tpqic02.c linux/drivers/char/tpqic02.c --- v2.4.0-test1/linux/drivers/char/tpqic02.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/char/tpqic02.c Wed Jun 21 22:31:01 2000 @@ -2177,10 +2177,6 @@ int open_error; open_error = qic02_tape_open_no_use_count(inode, filp); - if (!open_error) - { - MOD_INC_USE_COUNT; - } return open_error; } @@ -2440,9 +2436,6 @@ (void) do_qic_cmd(QCMD_REWIND, TIM_R); } } -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif return 0; } /* qic02_tape_release */ @@ -2766,6 +2759,7 @@ /* These are (most) of the interface functions: */ static struct file_operations qic02_tape_fops = { + owner: THIS_MODULE, llseek: qic02_tape_lseek, /* not allowed */ read: qic02_tape_read, write: qic02_tape_write, @@ -2911,37 +2905,37 @@ #endif return -ENODEV; } - devfs_register (NULL, "ntpqic11", 0, DEVFS_FL_NONE, + devfs_register (NULL, "ntpqic11", DEVFS_FL_DEFAULT, QIC02_TAPE_MAJOR, 2, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, &qic02_tape_fops, NULL); - devfs_register (NULL, "tpqic11", 0, DEVFS_FL_NONE, + devfs_register (NULL, "tpqic11", DEVFS_FL_DEFAULT, QIC02_TAPE_MAJOR, 3, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, &qic02_tape_fops, NULL); - devfs_register (NULL, "ntpqic24", 0, DEVFS_FL_NONE, + devfs_register (NULL, "ntpqic24", DEVFS_FL_DEFAULT, QIC02_TAPE_MAJOR, 4, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, &qic02_tape_fops, NULL); - devfs_register (NULL, "tpqic24", 0, DEVFS_FL_NONE, + devfs_register (NULL, "tpqic24", DEVFS_FL_DEFAULT, QIC02_TAPE_MAJOR, 5, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, &qic02_tape_fops, NULL); - devfs_register (NULL, "ntpqic120", 0, DEVFS_FL_NONE, + devfs_register (NULL, "ntpqic120", DEVFS_FL_DEFAULT, QIC02_TAPE_MAJOR, 6, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, &qic02_tape_fops, NULL); - devfs_register (NULL, "tpqic120", 0, DEVFS_FL_NONE, + devfs_register (NULL, "tpqic120", DEVFS_FL_DEFAULT, QIC02_TAPE_MAJOR, 7, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, &qic02_tape_fops, NULL); - devfs_register (NULL, "ntpqic150", 0, DEVFS_FL_NONE, + devfs_register (NULL, "ntpqic150", DEVFS_FL_DEFAULT, QIC02_TAPE_MAJOR, 8, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, &qic02_tape_fops, NULL); - devfs_register (NULL, "tpqic150", 0, DEVFS_FL_NONE, + devfs_register (NULL, "tpqic150", DEVFS_FL_DEFAULT, QIC02_TAPE_MAJOR, 9, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, &qic02_tape_fops, NULL); init_waitqueue_head(&qic02_tape_transfer); /* prepare timer */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.4.0-test1/linux/drivers/char/tty_io.c Tue May 23 15:31:34 2000 +++ linux/drivers/char/tty_io.c Wed Jun 21 22:31:01 2000 @@ -1427,49 +1427,6 @@ return 0; } -/* - * fasync_helper() is used by some character device drivers (mainly mice) - * to set up the fasync queue. It returns negative on error, 0 if it did - * no changes and positive if it added/deleted the entry. - */ -int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp) -{ - struct fasync_struct *fa, **fp; - unsigned long flags; - - for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) { - if (fa->fa_file == filp) - break; - } - - if (on) { - if (fa) { - fa->fa_fd = fd; - return 0; - } - fa = (struct fasync_struct *)kmalloc(sizeof(struct fasync_struct), GFP_KERNEL); - if (!fa) - return -ENOMEM; - fa->magic = FASYNC_MAGIC; - fa->fa_file = filp; - fa->fa_fd = fd; - save_flags(flags); - cli(); - fa->fa_next = *fapp; - *fapp = fa; - restore_flags(flags); - return 1; - } - if (!fa) - return 0; - save_flags(flags); - cli(); - *fp = fa->fa_next; - restore_flags(flags); - kfree(fa); - return 1; -} - static int tty_fasync(int fd, struct file * filp, int on) { struct tty_struct * tty; @@ -2011,8 +1968,6 @@ { #ifdef CONFIG_DEVFS_FS umode_t mode = S_IFCHR | S_IRUSR | S_IWUSR; - uid_t uid = 0; - gid_t gid = 0; struct tty_struct tty; char buf[32]; @@ -2036,14 +1991,11 @@ } # ifdef CONFIG_UNIX98_PTYS if ( (driver->major >= UNIX98_PTY_SLAVE_MAJOR) && - (driver->major < UNIX98_PTY_SLAVE_MAJOR + UNIX98_NR_MAJORS) ) { - uid = current->uid; - gid = current->gid; - } + (driver->major < UNIX98_PTY_SLAVE_MAJOR + UNIX98_NR_MAJORS) ) + flags |= DEVFS_FL_CURRENT_OWNER; # endif - devfs_register (NULL, tty_name (&tty, buf), 0,flags | DEVFS_FL_DEFAULT, - driver->major, minor, mode, uid, gid, - &tty_fops, NULL); + devfs_register (NULL, tty_name (&tty, buf), flags | DEVFS_FL_DEFAULT, + driver->major, minor, mode, &tty_fops, NULL); #endif /* CONFIG_DEVFS_FS */ } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/tuner.c linux/drivers/char/tuner.c --- v2.4.0-test1/linux/drivers/char/tuner.c Tue Apr 11 15:09:17 2000 +++ linux/drivers/char/tuner.c Tue Jun 20 07:37:58 2000 @@ -10,6 +10,7 @@ #include #include #include +#include #include "tuner.h" #include "audiochip.h" @@ -428,22 +429,19 @@ EXPORT_NO_SYMBOLS; -#ifdef MODULE -int init_module(void) -#else -int i2c_tuner_init(void) -#endif +int tuner_init_module(void) { i2c_add_driver(&driver); return 0; } -#ifdef MODULE -void cleanup_module(void) +void tuner_cleanup_module(void) { i2c_del_driver(&driver); } -#endif + +module_init(tuner_init_module); +module_exit(tuner_cleanup_module); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/tvmixer.c linux/drivers/char/tvmixer.c --- v2.4.0-test1/linux/drivers/char/tvmixer.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/tvmixer.c Tue Jun 20 07:37:58 2000 @@ -0,0 +1,351 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "audiochip.h" + +#define DEV_MAX 4 + +static int debug = 0; +static int devnr = -1; + +MODULE_PARM(debug,"i"); +MODULE_PARM(devnr,"i"); + +/* ----------------------------------------------------------------------- */ + +struct TVMIXER { + struct i2c_client *dev; + int minor; + int count; +}; + +static struct TVMIXER devices[DEV_MAX]; + +static int tvmixer_adapters(struct i2c_adapter *adap); +static int tvmixer_clients(struct i2c_client *client); + +static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); +static int tvmixer_open(struct inode *inode, struct file *file); +static int tvmixer_release(struct inode *inode, struct file *file); +static loff_t tvmixer_llseek(struct file *file, loff_t offset, int origin); + + +static struct i2c_driver driver = { + "tv card mixer driver", + 42 /* I2C_DRIVERID_FIXME */, + I2C_DF_DUMMY, + tvmixer_adapters, + tvmixer_clients, +}; + +static struct file_operations tvmixer_fops = { + owner: THIS_MODULE, + llseek: tvmixer_llseek, + ioctl: tvmixer_ioctl, + open: tvmixer_open, + release: tvmixer_release, +}; + +/* ----------------------------------------------------------------------- */ + +static int mix_to_v4l(int i) +{ + int r; + + r = ((i & 0xff) * 65536 + 50) / 100; + if (r > 65535) r = 65535; + if (r < 0) r = 0; + return r; +} + +static int v4l_to_mix(int i) +{ + int r; + + r = (i * 100 + 32768) / 65536; + if (r > 100) r = 100; + if (r < 0) r = 0; + return r | (r << 8); +} + +static int v4l_to_mix2(int l, int r) +{ + r = (r * 100 + 32768) / 65536; + if (r > 100) r = 100; + if (r < 0) r = 0; + l = (l * 100 + 32768) / 65536; + if (l > 100) l = 100; + if (l < 0) l = 0; + return (r << 8) | l; +} + +static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct video_audio va; + int left,right,ret,val = 0; + struct TVMIXER *mix = file->private_data; + struct i2c_client *client = mix->dev; + + if (NULL == client) + return -ENODEV; + + if (cmd == SOUND_MIXER_INFO) { + mixer_info info; + strncpy(info.id, "tv card", sizeof(info.id)); + strncpy(info.name, client->name, sizeof(info.name)); + info.modify_counter = 42 /* FIXME */; + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } + if (cmd == SOUND_OLD_MIXER_INFO) { + _old_mixer_info info; + strncpy(info.id, "tv card", sizeof(info.id)); + strncpy(info.name, client->name, sizeof(info.name)); + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } + if (cmd == OSS_GETVERSION) + return put_user(SOUND_VERSION, (int *)arg); + + if (_SIOC_DIR(cmd) & _SIOC_WRITE) + if (get_user(val, (int *)arg)) + return -EFAULT; + + /* read state */ + memset(&va,0,sizeof(va)); + client->driver->command(client,VIDIOCGAUDIO,&va); + + switch (cmd) { + case MIXER_READ(SOUND_MIXER_RECMASK): + case MIXER_READ(SOUND_MIXER_CAPS): + case MIXER_READ(SOUND_MIXER_RECSRC): + case MIXER_WRITE(SOUND_MIXER_RECSRC): + ret = 0; + break; + + case MIXER_READ(SOUND_MIXER_STEREODEVS): + ret = SOUND_MASK_VOLUME; + break; + case MIXER_READ(SOUND_MIXER_DEVMASK): + ret = SOUND_MASK_VOLUME; + if (va.flags & VIDEO_AUDIO_BASS) + ret |= SOUND_MASK_BASS; + if (va.flags & VIDEO_AUDIO_TREBLE) + ret |= SOUND_MASK_TREBLE; + break; + + case MIXER_WRITE(SOUND_MIXER_VOLUME): + left = mix_to_v4l(val); + right = mix_to_v4l(val >> 8); + va.volume = MAX(left,right); + va.balance = (32768*MIN(left,right)) / (va.volume ? va.volume : 1); + va.balance = (leftdriver->command(client,VIDIOCSAUDIO,&va); + client->driver->command(client,VIDIOCGAUDIO,&va); + /* fall throuth */ + case MIXER_READ(SOUND_MIXER_VOLUME): + left = (MIN(65536 - va.balance,32768) * + va.volume) / 32768; + right = (MIN(va.balance,32768) * + va.volume) / 32768; + ret = v4l_to_mix2(left,right); + break; + + case MIXER_WRITE(SOUND_MIXER_BASS): + va.bass = mix_to_v4l(val); + client->driver->command(client,VIDIOCSAUDIO,&va); + client->driver->command(client,VIDIOCGAUDIO,&va); + /* fall throuth */ + case MIXER_READ(SOUND_MIXER_BASS): + ret = v4l_to_mix(va.bass); + break; + + case MIXER_WRITE(SOUND_MIXER_TREBLE): + va.treble = mix_to_v4l(val); + client->driver->command(client,VIDIOCSAUDIO,&va); + client->driver->command(client,VIDIOCGAUDIO,&va); + /* fall throuth */ + case MIXER_READ(SOUND_MIXER_TREBLE): + ret = v4l_to_mix(va.treble); + break; + + default: + return -EINVAL; + } + if (put_user(ret, (int *)arg)) + return -EFAULT; + return 0; +} + +static int tvmixer_open(struct inode *inode, struct file *file) +{ + int i, minor = MINOR(inode->i_rdev); + struct TVMIXER *mix = NULL; + struct i2c_client *client = NULL; + + for (i = 0; i < DEV_MAX; i++) { + if (devices[i].minor == minor) { + mix = devices+i; + client = mix->dev; + break; + } + } + + if (NULL == client) + return -ENODEV; + + /* lock bttv in memory while the mixer is in use */ + file->private_data = mix; + if (client->adapter->inc_use) + client->adapter->inc_use(client->adapter); + return 0; +} + +static int tvmixer_release(struct inode *inode, struct file *file) +{ + struct TVMIXER *mix = file->private_data; + struct i2c_client *client = mix->dev; + + if (NULL == client) + return -ENODEV; + + if (client->adapter->dec_use) + client->adapter->dec_use(client->adapter); + return 0; +} + +static loff_t tvmixer_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +/* ----------------------------------------------------------------------- */ + +static int tvmixer_adapters(struct i2c_adapter *adap) +{ + return 0; +} + +static int tvmixer_clients(struct i2c_client *client) +{ + struct video_audio va; + int i,minor; + + /* TV card ??? */ + if (client->adapter->id != (I2C_ALGO_BIT | I2C_HW_B_BT848)) { + if (debug) + printk("tvmixer: %s is not a tv card\n", + client->adapter->name); + return -1; + } + printk("tvmixer: debug: %s\n",client->name); + + /* unregister ?? */ + for (i = 0; i < DEV_MAX; i++) { + if (devices[i].dev == client) { + /* unregister */ + unregister_sound_mixer(devices[i].minor); + devices[i].dev = NULL; + devices[i].minor = -1; + printk("tvmixer: %s unregistered (#1)\n",client->name); + return 0; + } + } + + /* look for a free slot */ + for (i = 0; i < DEV_MAX; i++) + if (NULL == devices[i].dev) + break; + if (i == DEV_MAX) { + printk(KERN_WARNING "tvmixer: DEV_MAX too small\n"); + return -1; + } + + /* audio chip with mixer ??? */ + if (NULL == client->driver->command) { + if (debug) + printk("tvmixer: %s: driver->command is NULL\n", + client->driver->name); + return -1; + } + memset(&va,0,sizeof(va)); + if (0 != client->driver->command(client,VIDIOCGAUDIO,&va)) { + if (debug) + printk("tvmixer: %s: VIDIOCGAUDIO failed\n", + client->name); + return -1; + } + if (0 == (va.flags & VIDEO_AUDIO_VOLUME)) { + if (debug) + printk("tvmixer: %s: has no volume control\n", + client->name); + return -1; + } + + /* everything is fine, register */ + if ((minor = register_sound_mixer(&tvmixer_fops,devnr)) < 0) { + printk(KERN_ERR "tvmixer: cannot allocate mixer device\n"); + return -1; + } + + devices[i].minor = minor; + devices[i].count = 0; + devices[i].dev = client; + printk("tvmixer: %s (%s) registered with minor %d\n", + client->name,client->adapter->name,minor); + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +int tvmixer_init_module(void) +{ + int i; + + for (i = 0; i < DEV_MAX; i++) + devices[i].minor = -1; + i2c_add_driver(&driver); + return 0; +} + +void tvmixer_cleanup_module(void) +{ + int i; + + i2c_del_driver(&driver); + for (i = 0; i < DEV_MAX; i++) { + if (devices[i].minor != -1) { + unregister_sound_mixer(devices[i].minor); + printk("tvmixer: %s unregistered (#2)\n", + devices[i].dev->name); + } + } +} + +module_init(tvmixer_init_module); +module_exit(tvmixer_cleanup_module); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/vc_screen.c linux/drivers/char/vc_screen.c --- v2.4.0-test1/linux/drivers/char/vc_screen.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/char/vc_screen.c Wed Jun 21 22:31:01 2000 @@ -476,12 +476,12 @@ } else { - devfs_register (devfs_handle, name + 1, 0, DEVFS_FL_DEFAULT, + devfs_register (devfs_handle, name + 1, DEVFS_FL_DEFAULT, VCS_MAJOR, index + 1, - S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, &vcs_fops, NULL); - devfs_register (devfs_handle, name, 0, DEVFS_FL_DEFAULT, + S_IFCHR | S_IRUSR | S_IWUSR, &vcs_fops, NULL); + devfs_register (devfs_handle, name, DEVFS_FL_DEFAULT, VCS_MAJOR, index + 129, - S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, &vcs_fops, NULL); + S_IFCHR | S_IRUSR | S_IWUSR, &vcs_fops, NULL); } #endif /* CONFIG_DEVFS_FS */ } @@ -496,12 +496,12 @@ printk("unable to get major %d for vcs device", VCS_MAJOR); devfs_handle = devfs_mk_dir (NULL, "vcc", 3, NULL); - devfs_register (devfs_handle, "0", 1, DEVFS_FL_DEFAULT, + devfs_register (devfs_handle, "0", DEVFS_FL_DEFAULT, VCS_MAJOR, 0, - S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, &vcs_fops, NULL); - devfs_register (devfs_handle, "a", 1, DEVFS_FL_DEFAULT, + S_IFCHR | S_IRUSR | S_IWUSR, &vcs_fops, NULL); + devfs_register (devfs_handle, "a", DEVFS_FL_DEFAULT, VCS_MAJOR, 128, - S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, &vcs_fops, NULL); + S_IFCHR | S_IRUSR | S_IWUSR, &vcs_fops, NULL); return error; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/videodev.c linux/drivers/char/videodev.c --- v2.4.0-test1/linux/drivers/char/videodev.c Mon Jun 19 16:31:59 2000 +++ linux/drivers/char/videodev.c Wed Jun 21 22:31:01 2000 @@ -51,7 +51,6 @@ char name[16]; struct video_device *vdev; struct proc_dir_entry *proc_entry; - struct video_capability vcap; }; static struct proc_dir_entry *video_dev_proc_entry = NULL; @@ -470,9 +469,9 @@ * has serious privacy issues. */ vfd->devfs_handle = - devfs_register (NULL, name, 0, DEVFS_FL_DEFAULT, + devfs_register (NULL, name, DEVFS_FL_DEFAULT, VIDEO_MAJOR, vfd->minor, - S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR, &video_fops, NULL); #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/vt.c linux/drivers/char/vt.c --- v2.4.0-test1/linux/drivers/char/vt.c Thu May 11 15:30:07 2000 +++ linux/drivers/char/vt.c Mon Jun 19 13:25:06 2000 @@ -62,7 +62,7 @@ */ unsigned char keyboard_type = KB_101; -#if !defined(__alpha__) && !defined(__mips__) && !defined(__arm__) +#if !defined(__alpha__) && !defined(__mips__) && !defined(__arm__) && !defined(__sh__) asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on); #endif @@ -472,7 +472,7 @@ ucval = keyboard_type; goto setchar; -#if !defined(__alpha__) && !defined(__mips__) && !defined(__arm__) +#if !defined(__alpha__) && !defined(__mips__) && !defined(__arm__) && !defined(__sh__) /* * These cannot be implemented on any machine that implements * ioperm() in user level (such as Alpha PCs). @@ -592,6 +592,8 @@ case KDGETKEYCODE: case KDSETKEYCODE: + if(!capable(CAP_SYS_ADMIN)) + perm=0; return do_kbkeycode_ioctl(cmd, (struct kbkeycode *)arg, perm); case KDGKBENT: diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/wdt.c linux/drivers/char/wdt.c --- v2.4.0-test1/linux/drivers/char/wdt.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/char/wdt.c Tue Jun 20 07:37:58 2000 @@ -337,7 +337,6 @@ case WATCHDOG_MINOR: if(wdt_is_open) return -EBUSY; - MOD_INC_USE_COUNT; /* * Activate */ @@ -353,7 +352,6 @@ outb_p(0, WDT_DC); /* Enable */ return 0; case TEMP_MINOR: - MOD_INC_USE_COUNT; return 0; default: return -ENODEV; @@ -382,7 +380,6 @@ #endif wdt_is_open=0; } - MOD_DEC_USE_COUNT; return 0; } @@ -416,6 +413,7 @@ static struct file_operations wdt_fops = { + owner: THIS_MODULE, llseek: wdt_llseek, read: wdt_read, write: wdt_write, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/wdt_pci.c linux/drivers/char/wdt_pci.c --- v2.4.0-test1/linux/drivers/char/wdt_pci.c Tue Apr 11 15:09:17 2000 +++ linux/drivers/char/wdt_pci.c Tue Jun 20 07:37:58 2000 @@ -28,6 +28,7 @@ * Parameterized timeout * JP Nollmann : Added support for PCI wdt501p * Alan Cox : Split ISA and PCI cards into two drivers + * Jeff Garzik : PCI cleanups */ #include @@ -53,6 +54,8 @@ #include +#define PFX "wdt_pci: " + /* * Until Access I/O gets their application for a PCI vendor ID approved, * I don't think that it's appropriate to move these constants into the @@ -487,12 +490,86 @@ 0 }; -#ifdef MODULE -#define wdtpci_init init_module +static int __init wdtpci_init_one (struct pci_dev *dev, + const struct pci_device_id *ent) +{ + static int dev_count = 0; + + dev_count++; + if (dev_count > 1) { + printk (KERN_ERR PFX + "this driver only supports 1 device\n"); + return -ENODEV; + } + + irq = dev->irq; + io = pci_resource_start (dev, 2); + printk ("WDT501-P(PCI-WDG-CSM) driver 0.07 at %X " + "(Interrupt %d)\n", io, irq); + + if (pci_enable_device (dev)) + goto err_out; + + if (request_region (io, 16, "wdt-pci") == NULL) { + printk (KERN_ERR PFX "I/O %d is not free.\n", io); + goto err_out; + } + + if (request_irq (irq, wdtpci_interrupt, SA_INTERRUPT | SA_SHIRQ, + "wdt-pci", &wdtpci_miscdev)) { + printk (KERN_ERR PFX "IRQ %d is not free.\n", irq); + goto err_out_free_res; + } + + misc_register (&wdtpci_miscdev); + +#ifdef CONFIG_WDT_501 + misc_register (&temp_miscdev); +#endif + + register_reboot_notifier (&wdtpci_notifier); + + return 0; + +err_out_free_res: + release_region (io, 16); +err_out: + return -EIO; +} + + +static void __exit wdtpci_remove_one (struct pci_dev *pdev) +{ + /* here we assume only one device will ever have + * been picked up and registered by probe function */ + unregister_reboot_notifier(&wdtpci_notifier); +#ifdef CONFIG_WDT_501_PCI + misc_deregister(&temp_miscdev); +#endif + misc_deregister(&wdtpci_miscdev); + free_irq(irq, &wdtpci_miscdev); + release_region(io, 16); +} + + +static struct pci_device_id wdtpci_pci_tbl[] __initdata = { + { PCI_VENDOR_ID_ACCESSIO, PCI_DEVICE_ID_WDG_CSM, PCI_ANY_ID, PCI_ANY_ID, }, + { 0, }, /* terminate list */ +}; +MODULE_DEVICE_TABLE(pci, wdtpci_pci_tbl); + + +static struct pci_driver wdtpci_driver = { + name: "wdt-pci", + id_table: wdtpci_pci_tbl, + probe: wdtpci_init_one, + remove: wdtpci_remove_one, +}; + /** - * cleanup_module: + * wdtpci_cleanup: * * Unload the watchdog. You cannot do this with any file handles open. * If your watchdog is set to continue ticking on close and you unload @@ -501,18 +578,11 @@ * module in 60 seconds or reboot. */ -void cleanup_module(void) +static void __exit wdtpci_cleanup(void) { - misc_deregister(&wdtpci_miscdev); -#ifdef CONFIG_WDT_501_PCI - misc_deregister(&temp_miscdev); -#endif - unregister_reboot_notifier(&wdtpci_notifier); - release_region(io,16); - free_irq(irq, &wdtpci_miscdev); + pci_unregister_driver (&wdtpci_driver); } -#endif /** * wdtpci_init: @@ -522,37 +592,16 @@ * The open() function will actually kick the board off. */ -int __init wdtpci_init(void) +static int __init wdtpci_init(void) { - struct pci_dev *dev = NULL; - - if (pci_present()) - { - while ((dev = pci_find_device(PCI_VENDOR_ID_ACCESSIO, - PCI_DEVICE_ID_WDG_CSM, dev))) { - /* See if we can do this device */ - irq = dev->irq; - io = dev->resource[2].start; - printk("WDT501-P(PCI-WDG-CSM) driver 0.07 at %X " - "(Interrupt %d)\n", io, irq); - } - } - if(request_region(io, 16, "wdt-pci")==NULL) - { - printk(KERN_ERR "I/O %d is not free.\n", io); - return -EIO; - } - if(request_irq(irq, wdtpci_interrupt, SA_INTERRUPT|SA_SHIRQ, "wdt-pci", &wdtpci_miscdev)) - { - printk(KERN_ERR "IRQ %d is not free.\n", irq); - release_region(io, 16); - return -EIO; - } - misc_register(&wdtpci_miscdev); -#ifdef CONFIG_WDT_501 - misc_register(&temp_miscdev); -#endif - register_reboot_notifier(&wdtpci_notifier); + int rc = pci_register_driver (&wdtpci_driver); + + if (rc < 1) + return -ENODEV; + return 0; } + +module_init(wdtpci_init); +module_exit(wdtpci_cleanup); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/i2c/Makefile linux/drivers/i2c/Makefile --- v2.4.0-test1/linux/drivers/i2c/Makefile Mon Dec 20 18:48:21 1999 +++ linux/drivers/i2c/Makefile Tue Jun 20 13:58:42 2000 @@ -2,97 +2,27 @@ # Makefile for the kernel i2c bus driver. # -SUB_DIRS := -MOD_SUB_DIRS := $(SUB_DIRS) -ALL_SUB_DIRS := $(SUB_DIRS) MOD_LIST_NAME := I2C_MODULES +O_TARGET := i2c.o -L_TARGET := i2c.a -MX_OBJS := -M_OBJS := -LX_OBJS := -L_OBJS := +export-objs := i2c-core.o i2c-algo-bit.o i2c-algo-pcf.o -# ----- -# i2c core components -# ----- - -ifeq ($(CONFIG_I2C),y) - LX_OBJS += i2c-core.o -else - ifeq ($(CONFIG_I2C),m) - MX_OBJS += i2c-core.o - endif -endif - -ifeq ($(CONFIG_I2C_CHARDEV),y) - L_OBJS += i2c-dev.o -else - ifeq ($(CONFIG_I2C_CHARDEV),m) - M_OBJS += i2c-dev.o - endif -endif - -# ----- -# Bit banging adapters... -# ----- - -ifeq ($(CONFIG_I2C_ALGOBIT),y) - LX_OBJS += i2c-algo-bit.o -else - ifeq ($(CONFIG_I2C_ALGOBIT),m) - MX_OBJS += i2c-algo-bit.o - endif -endif - -ifeq ($(CONFIG_I2C_PHILIPSPAR),y) - L_OBJS += i2c-philips-par.o -else - ifeq ($(CONFIG_I2C_PHILIPSPAR),m) - M_OBJS += i2c-philips-par.o - endif -endif - -ifeq ($(CONFIG_I2C_ELV),y) - L_OBJS += i2c-elv.o -else - ifeq ($(CONFIG_I2C_ELV),m) - M_OBJS += i2c-elv.o - endif -endif - -ifeq ($(CONFIG_I2C_VELLEMAN),y) - L_OBJS += i2c-velleman.o -else - ifeq ($(CONFIG_I2C_VELLEMAN),m) - M_OBJS += i2c-velleman.o - endif -endif - - - -# ----- -# PCF components -# ----- - -ifeq ($(CONFIG_I2C_ALGOPCF),y) - LX_OBJS += i2c-algo-pcf.o -else - ifeq ($(CONFIG_I2C_ALGOPCF),m) - MX_OBJS += i2c-algo-pcf.o - endif -endif - -ifeq ($(CONFIG_I2C_ELEKTOR),y) - L_OBJS += i2c-elektor.o -else - ifeq ($(CONFIG_I2C_ELEKTOR),m) - M_OBJS += i2c-elektor.o - endif -endif +obj-$(CONFIG_I2C) += i2c-core.o +obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o +obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bit.o +obj-$(CONFIG_I2C_PHILIPSPAR) += i2c-philips-par.o +obj-$(CONFIG_I2C_ELV) += i2c-elv.o +obj-$(CONFIG_I2C_VELLEMAN) += i2c-velleman.o +obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o +obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o # This is needed for automatic patch generation: sensors code starts here # This is needed for automatic patch generation: sensors code ends here + +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test1/linux/drivers/i2o/Makefile linux/drivers/i2o/Makefile --- v2.4.0-test1/linux/drivers/i2o/Makefile Thu Aug 5 15:04:52 1999 +++ linux/drivers/i2o/Makefile Mon Jun 19 13:30:55 2000 @@ -1,75 +1,25 @@ # # Makefile for the kernel I2O OSM. # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definition is now inherited from the -# parent makefile. -# - -# # Note : at this point, these files are compiled on all systems. # In the future, some of these should be built conditionally. # -SUB_DIRS := -MOD_SUB_DIRS := $(SUB_DIRS) -ALL_SUB_DIRS := $(SUB_DIRS) - - -L_TARGET := i2o.a -L_OBJS := -M_OBJS := - -ifeq ($(CONFIG_I2O_PCI),y) -L_OBJS += i2o_pci.o -else - ifeq ($(CONFIG_I2O_PCI),m) - MX_OBJS += i2o_pci.o - endif -endif - -ifeq ($(CONFIG_I2O),y) -LX_OBJS += i2o_core.o i2o_config.o -else - ifeq ($(CONFIG_I2O),m) - MX_OBJS += i2o_core.o i2o_config.o - endif -endif - -ifeq ($(CONFIG_I2O_BLOCK),y) -LX_OBJS += i2o_block.o -else - ifeq ($(CONFIG_I2O_BLOCK),m) - MX_OBJS += i2o_block.o - endif -endif - -ifeq ($(CONFIG_I2O_LAN),y) -LX_OBJS += i2o_lan.o -else - ifeq ($(CONFIG_I2O_LAN),m) - MX_OBJS += i2o_lan.o - endif -endif +O_TARGET := i2o.o -ifeq ($(CONFIG_I2O_SCSI),y) -LX_OBJS += i2o_scsi.o -else - ifeq ($(CONFIG_I2O_SCSI),m) - MX_OBJS += i2o_scsi.o - endif -endif +export-objs := i2o_pci.o i2o_core.o i2o_config.o i2o_block.o i2o_lan.o i2o_scsi.o i2o_proc.o -ifeq ($(CONFIG_I2O_PROC),y) -LX_OBJS += i2o_proc.o -else - ifeq ($(CONFIG_I2O_PROC),m) - MX_OBJS += i2o_proc.o - endif -endif +obj-$(CONFIG_I2O_PCI) += i2o_pci.o +obj-$(CONFIG_I2O) += i2o_core.o i2o_config.o +obj-$(CONFIG_I2O_BLOCK) += i2o_block.o +obj-$(CONFIG_I2O_LAN) += i2o_lan.o +obj-$(CONFIG_I2O_SCSI) += i2o_scsi.o +obj-$(CONFIG_I2O_PROC) += i2o_proc.o + +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test1/linux/drivers/i2o/README linux/drivers/i2o/README --- v2.4.0-test1/linux/drivers/i2o/README Wed Apr 26 16:34:07 2000 +++ linux/drivers/i2o/README Mon Jun 19 13:30:55 2000 @@ -92,7 +92,6 @@ Lan: o Performance tuning o Test Fibre Channel code -o Fix lan_set_mc_list() Tape: o Anyone seen anything implementing this ? diff -u --recursive --new-file v2.4.0-test1/linux/drivers/i2o/README.ioctl linux/drivers/i2o/README.ioctl --- v2.4.0-test1/linux/drivers/i2o/README.ioctl Wed Apr 26 16:34:07 2000 +++ linux/drivers/i2o/README.ioctl Mon Jun 19 13:30:55 2000 @@ -25,10 +25,10 @@ II. IOP Access Access to the I2O subsystem is provided through the device file named -/dev/i2octl. This file is a character file with major number 10 and minor +/dev/i2o/ctl. This file is a character file with major number 10 and minor number 166. It can be created through the following command: - mknod /dev/i2octl c 10 166 + mknod /dev/i2o/ctl c 10 166 III. Determining the IOP Count @@ -373,7 +373,7 @@ In the process of determining this. Current idea is to have use the select() interface to allow user apps to periodically poll - the /dev/i2octl device for events. When select() notifies the user + the /dev/i2o/ctl device for events. When select() notifies the user that an event is available, the user would call read() to retrieve a list of all the events that are pending for the specific device. diff -u --recursive --new-file v2.4.0-test1/linux/drivers/i2o/i2o_block.c linux/drivers/i2o/i2o_block.c --- v2.4.0-test1/linux/drivers/i2o/i2o_block.c Thu May 11 15:30:07 2000 +++ linux/drivers/i2o/i2o_block.c Mon Jun 19 13:30:55 2000 @@ -1575,7 +1575,7 @@ static struct gendisk i2ob_gendisk = { MAJOR_NR, - "i2ohd", + "i2o/hd", 4, 1<<4, i2ob, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/i2o/i2o_config.c linux/drivers/i2o/i2o_config.c --- v2.4.0-test1/linux/drivers/i2o/i2o_config.c Thu May 11 15:30:07 2000 +++ linux/drivers/i2o/i2o_config.c Mon Jun 19 13:30:56 2000 @@ -161,8 +161,7 @@ // printk(KERN_INFO "File %p w/id %d has %d events\n", // inf->fp, inf->q_id, inf->q_len); - if(inf->fasync) - kill_fasync(inf->fasync, SIGIO, POLL_IN); + kill_fasync(&inf->fasync, SIGIO, POLL_IN); } return; @@ -840,7 +839,6 @@ open_files = tmp; spin_unlock_irqrestore(&i2o_config_lock, flags); - MOD_INC_USE_COUNT; return 0; } @@ -873,7 +871,6 @@ } spin_unlock_irqrestore(&i2o_config_lock, flags); - MOD_DEC_USE_COUNT; return 0; } @@ -894,6 +891,7 @@ static struct file_operations config_fops = { + owner: THIS_MODULE, llseek: cfg_llseek, read: cfg_read, write: cfg_write, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/i2o/i2o_core.c linux/drivers/i2o/i2o_core.c --- v2.4.0-test1/linux/drivers/i2o/i2o_core.c Mon Jun 19 16:31:59 2000 +++ linux/drivers/i2o/i2o_core.c Mon Jun 19 13:30:56 2000 @@ -189,7 +189,8 @@ * I2O configuration spinlock. This isnt a big deal for contention * so we have one only */ -static struct semaphore i2o_configuration_lock; + +static DECLARE_MUTEX(i2o_configuration_lock); /* * Event spinlock. Used to keep event queue sane and from @@ -883,11 +884,11 @@ switch(msg[4]) { case I2O_EVT_IND_EXEC_RESOURCE_LIMITS: - printk(KERN_ERR "iop%d: Out of resources\n", c->unit); + printk(KERN_ERR "%s: Out of resources\n", c->name); break; case I2O_EVT_IND_EXEC_POWER_FAIL: - printk(KERN_ERR "iop%d: Power failure\n", c->unit); + printk(KERN_ERR "%s: Power failure\n", c->name); break; case I2O_EVT_IND_EXEC_HW_FAIL: @@ -1027,12 +1028,12 @@ entries -= 3; entries /= 9; - dprintk(KERN_INFO "I2O: Dynamic LCT Update\n"); - dprintk(KERN_INFO "I2O: Dynamic LCT contains %d entries\n", entries); + dprintk(KERN_INFO "%s: Dynamic LCT Update\n",c->name); + dprintk(KERN_INFO "%s: Dynamic LCT contains %d entries\n", c->name, entries); if(!entries) { - printk(KERN_INFO "iop%d: Empty LCT???\n", c->unit); + printk(KERN_INFO "%s: Empty LCT???\n", c->name); continue; } @@ -1059,7 +1060,7 @@ } if(!found) { - dprintk(KERN_INFO "Deleted device!\n"); + dprintk(KERN_INFO "i2o_core: Deleted device!\n"); spin_lock(&i2o_dev_lock); i2o_delete_device(d); spin_unlock(&i2o_dev_lock); @@ -1111,7 +1112,6 @@ struct i2o_message *m; u32 mv; u32 *msg; - int count = 0; /* * Old 960 steppings had a bug in the I2O unit that caused @@ -1126,8 +1126,6 @@ m=(struct i2o_message *)bus_to_virt(mv); msg=(u32*)m; - count++; - /* * Temporary Debugging */ @@ -1148,7 +1146,6 @@ /* That 960 bug again... */ if((mv=I2O_REPLY_READ32(c))==0xFFFFFFFF) mv=I2O_REPLY_READ32(c); - } } @@ -1281,7 +1278,6 @@ } if((ret=i2o_query_scalar(c, unit, 0xF100, 4, buf, 16))>=0) { - buf[16]=0; printk(KERN_INFO " Device: %s\n", buf); } @@ -1657,7 +1653,8 @@ * time, we assume the IOP could not reboot properly. */ - dprintk(KERN_INFO "Reset in progress, waiting for reboot\n"); + dprintk(KERN_INFO "%s: Reset in progress, waiting for reboot...\n", + c->name); time = jiffies; m = I2O_POST_READ32(c); @@ -1733,8 +1730,7 @@ m=i2o_wait_message(c, "StatusGet"); if(m==0xFFFFFFFF) - return -ETIMEDOUT; - + return -ETIMEDOUT; msg=(u32 *)(c->mem_offset+m); msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_0; @@ -1897,12 +1893,12 @@ { struct i2o_controller *iop, *niop = NULL; - printk(KERN_INFO "Activating I2O controllers\n"); + printk(KERN_INFO "Activating I2O controllers...\n"); printk(KERN_INFO "This may take a few minutes if there are many devices\n"); /* In INIT state, Activate IOPs */ for (iop = i2o_controller_chain; iop; iop = niop) { - dprintk(KERN_INFO "Calling i2o_activate_controller for %s\n", + dprintk(KERN_INFO "Calling i2o_activate_controller for %s...\n", iop->name); niop = iop->next; if (i2o_activate_controller(iop) < 0) @@ -1919,7 +1915,7 @@ * If build_sys_table fails, we kill everything and bail * as we can't init the IOPs w/o a system table */ - dprintk(KERN_INFO "calling i2o_build_sys_table\n"); + dprintk(KERN_INFO "i2o_core: Calling i2o_build_sys_table...\n"); if (i2o_build_sys_table() < 0) { i2o_sys_shutdown(); return; @@ -1928,7 +1924,7 @@ /* If IOP don't get online, we need to rebuild the System table */ for (iop = i2o_controller_chain; iop; iop = niop) { niop = iop->next; - dprintk(KERN_INFO "Calling i2o_online_controller for %s\n", iop->name); + dprintk(KERN_INFO "Calling i2o_online_controller for %s...\n", iop->name); if (i2o_online_controller(iop) < 0) { i2o_delete_controller(iop); goto rebuild_sys_tab; @@ -1992,7 +1988,8 @@ /* In READY state, Get status */ if (i2o_status_get(iop) < 0) { - printk(KERN_INFO "Unable to obtain status of IOP, attempting a reset.\n"); + printk(KERN_INFO "Unable to obtain status of %s, " + "attempting a reset.\n", iop->name); if (i2o_reset_controller(iop) < 0) return -1; } @@ -2002,18 +1999,19 @@ return -1; } + if (iop->status_block->i2o_version > I2OVER15) { + printk(KERN_ERR "%s: Not running vrs. 1.5. of the I2O Specification.\n", + iop->name); + return -1; + } + if (iop->status_block->iop_state == ADAPTER_STATE_READY || iop->status_block->iop_state == ADAPTER_STATE_OPERATIONAL || iop->status_block->iop_state == ADAPTER_STATE_HOLD || iop->status_block->iop_state == ADAPTER_STATE_FAILED) { - u32 m[MSG_FRAME_SIZE]; - dprintk(KERN_INFO "%s: Already running, trying to reset\n", + dprintk(KERN_INFO "%s: Already running, trying to reset...\n", iop->name); - - i2o_init_outbound_q(iop); - I2O_REPLY_WRITE32(iop,virt_to_bus(m)); - if (i2o_reset_controller(iop) < 0) return -1; } @@ -2048,7 +2046,7 @@ u32 *msg; u32 time; - dprintk(KERN_INFO "%s: Initializing Outbound Queue\n", c->name); + dprintk(KERN_INFO "%s: Initializing Outbound Queue...\n", c->name); m=i2o_wait_message(c, "OutboundInit"); if(m==0xFFFFFFFF) return -ETIMEDOUT; @@ -2217,13 +2215,13 @@ /* In READY state */ - dprintk(KERN_INFO "Attempting to enable iop%d\n", iop->unit); + dprintk(KERN_INFO "%s: Attempting to enable...\n", iop->name); if (i2o_enable_controller(iop) < 0) return -1; /* In OPERATIONAL state */ - dprintk(KERN_INFO "Attempting to get/parse lct iop%d\n", iop->unit); + dprintk(KERN_INFO "%s: Attempting to get/parse lct...\n", iop->name); if (i2o_lct_get(iop) < 0) return -1; @@ -2275,7 +2273,7 @@ */ if(i2o_status_get(iop)) { printk(KERN_ERR "%s: Deleting b/c could not get status while" - "attempting to build system table", iop->name); + "attempting to build system table\n", iop->name); i2o_delete_controller(iop); sys_tbl->num_entries--; continue; // try the next one @@ -2338,7 +2336,6 @@ } while(m==0xFFFFFFFF && (jiffies-t)= 0xA0 && cmd <= 0xEF)) - i2o_report_common_dsc(detailed_status); - - if (h->class == I2O_CLASS_LAN && cmd >= 0x30 && cmd <= 0x3F) + i2o_report_common_dsc(detailed_status); + else if (h->class == I2O_CLASS_LAN && cmd >= 0x30 && cmd <= 0x3F) i2o_report_lan_dsc(detailed_status); else printk(" / DetailedStatus = %0#4x.\n", detailed_status); @@ -3189,7 +3185,7 @@ return 0; } else - printk(KERN_INFO "event thread created as pid %d\n", evt_pid); + printk(KERN_INFO "I2O: Event thread created as pid %d\n", evt_pid); if(i2o_num_controllers) i2o_sys_init(); @@ -3215,7 +3211,7 @@ stat = kill_proc(evt_pid, SIGTERM, 1); if(!stat) { int count = 10 * 100; - while(evt_running && count) { + while(evt_running && count--) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(1); } @@ -3247,8 +3243,6 @@ { printk(KERN_INFO "Loading I2O Core - (c) Copyright 1999 Red Hat Software\n"); - init_MUTEX(&i2o_configuration_lock); - if (i2o_install_handler(&i2o_core_handler) < 0) { printk(KERN_ERR @@ -3285,9 +3279,6 @@ i2o_config_init(); #ifdef CONFIG_I2O_BLOCK i2o_block_init(); -#endif -#ifdef CONFIG_I2O_SCSI - i2o_scsi_init(); #endif #ifdef CONFIG_I2O_LAN i2o_lan_init(); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/i2o/i2o_lan.c linux/drivers/i2o/i2o_lan.c --- v2.4.0-test1/linux/drivers/i2o/i2o_lan.c Thu May 11 15:30:07 2000 +++ linux/drivers/i2o/i2o_lan.c Mon Jun 19 13:30:56 2000 @@ -1,7 +1,7 @@ /* * drivers/i2o/i2o_lan.c * - * I2O LAN CLASS OSM May 4th 2000 + * I2O LAN CLASS OSM May 26th 2000 * * (C) Copyright 1999, 2000 University of Helsinki, * Department of Computer Science @@ -68,9 +68,7 @@ static struct net_device *i2o_landevs[MAX_LAN_CARDS+1]; static int unit = -1; /* device unit number */ -extern rwlock_t dev_mc_lock; - -static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m); +static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m); static void i2o_lan_send_post_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m); static int i2o_lan_receive_post(struct net_device *dev); static void i2o_lan_receive_post_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m); @@ -86,7 +84,7 @@ NULL, NULL, NULL, - "I2O Lan OSM send", + "I2O LAN OSM send", -1, I2O_CLASS_LAN }; @@ -97,7 +95,7 @@ NULL, NULL, NULL, - "I2O Lan OSM receive", + "I2O LAN OSM receive", -1, I2O_CLASS_LAN }; @@ -108,7 +106,7 @@ NULL, NULL, NULL, - "I2O Lan OSM", + "I2O LAN OSM", -1, I2O_CLASS_LAN }; @@ -133,7 +131,6 @@ struct i2o_controller *iop = i2o_dev->controller; u32 *preserved_msg = (u32*)(iop->mem_offset + msg[7]); - // FIXME on 64-bit host u32 *sgl_elem = &preserved_msg[4]; struct sk_buff *skb = NULL; u8 le_flag; @@ -259,11 +256,13 @@ i2o_report_status(KERN_INFO, dev->name, msg); #endif - /* DDM has handled transmit request(s), free sk_buffs */ - + /* DDM has handled transmit request(s), free sk_buffs. + * We get similar single transaction reply also in error cases + * (except if msg failure or transaction error). + */ while (trl_count) { dev_kfree_skb_irq((struct sk_buff *)msg[4 + trl_count]); - dprintk(KERN_INFO "%s: Request skb freed (trl_count=%d).\n", + dprintk(KERN_INFO "%s: tx skb freed (trl_count=%d).\n", dev->name, trl_count); atomic_dec(&priv->tx_out); trl_count--; @@ -296,15 +295,8 @@ if (i2o_lan_handle_status(dev, msg)) return; - /* Getting unused buckets back? */ - - if (msg[4] & I2O_LAN_DSC_CANCELED || - msg[4] & I2O_LAN_DSC_RECEIVE_ABORTED) { - i2o_lan_release_buckets(dev, msg); - return; - } - - /* If other DetailedStatusCodes need special code, add it here */ + i2o_lan_release_buckets(dev, msg); + return; } #ifdef DRIVERDEBUG @@ -410,26 +402,43 @@ if (i2o_lan_handle_status(dev, msg)) return; - /* This should NOT be reached */ + /* In other error cases just report and continue */ + + i2o_report_status(KERN_INFO, dev->name, msg); } #ifdef DRIVERDEBUG i2o_report_status(KERN_INFO, dev->name, msg); #endif - switch (msg[1] >> 24) { - case LAN_RESET: - case LAN_SUSPEND: - /* default reply without payload */ + case LAN_RESET: + case LAN_SUSPEND: + /* default reply without payload */ break; - case I2O_CMD_UTIL_EVT_REGISTER: - case I2O_CMD_UTIL_EVT_ACK: - i2o_lan_handle_event(dev, msg); + + case I2O_CMD_UTIL_EVT_REGISTER: + case I2O_CMD_UTIL_EVT_ACK: + i2o_lan_handle_event(dev, msg); break; - default: - printk(KERN_ERR "%s: No handler for the reply.\n", - dev->name); - i2o_report_status(KERN_INFO, dev->name, msg); + + case I2O_CMD_UTIL_PARAMS_SET: + /* default reply, results in ReplyPayload (not examined) */ + switch (msg[3] >> 16) { + case 1: dprintk(KERN_INFO "%s: Reply to set MAC filter mask.\n", + dev->name); + break; + case 2: dprintk(KERN_INFO "%s: Reply to set MAC table.\n", + dev->name); + break; + default: printk(KERN_WARNING "%s: Bad group 0x%04X\n", + dev->name,msg[3] >> 16); + } + break; + + default: + printk(KERN_ERR "%s: No handler for the reply.\n", + dev->name); + i2o_report_status(KERN_INFO, dev->name, msg); } } @@ -446,7 +455,7 @@ u32 *pskb = &msg[6]; while (trl_count--) { - dprintk(KERN_DEBUG "%s: Releasing unused sk_buff %p (trl_count=%d).\n", + dprintk(KERN_DEBUG "%s: Releasing unused rx skb %p (trl_count=%d).\n", dev->name, (struct sk_buff*)(*pskb),trl_count+1); dev_kfree_skb_irq((struct sk_buff *)(*pskb)); pskb += 1 + trl_elem_size; @@ -464,22 +473,15 @@ struct i2o_controller *iop = i2o_dev->controller; u32 max_evt_data_size =iop->status_block->inbound_frame_size-5; struct i2o_reply { - u8 version_offset; - u8 msg_flags; - u16 msg_size; - u32 tid:12; - u32 initiator:12; - u32 function:8; - u32 initiator_context; - u32 transaction_context; + u32 header[4]; u32 evt_indicator; - u32 data[max_evt_data_size]; /* max */ + u32 data[max_evt_data_size]; } *evt = (struct i2o_reply *)msg; - int evt_data_len = (evt->msg_size - 5) * 4; /* real */ + int evt_data_len = ((msg[0]>>16) - 5) * 4; /* real size*/ printk(KERN_INFO "%s: I2O event - ", dev->name); - if (evt->function == I2O_CMD_UTIL_EVT_ACK) { + if (msg[1]>>24 == I2O_CMD_UTIL_EVT_ACK) { printk("Event acknowledgement reply.\n"); return; } @@ -505,17 +507,19 @@ break; } - case I2O_EVT_IND_GENERAL_WARNING: - printk("General warning 0x%04x.\n", evt->data[0]); - break; - - case I2O_EVT_IND_CONFIGURATION_FLAG: - printk("Configuration requested.\n"); + case I2O_EVT_IND_FIELD_MODIFIED: { + u16 *work16 = (u16 *)evt->data; + printk("Group 0x%04x, field %d changed.\n", work16[0], work16[1]); break; + } - case I2O_EVT_IND_CAPABILITY_CHANGE: - printk("Capability change 0x%04x.\n", evt->data[0]); + case I2O_EVT_IND_VENDOR_EVT: { + int i; + printk("Vendor event:\n"); + for (i = 0; i < evt_data_len / 4; i++) + printk(" 0x%08x\n", evt->data[i]); break; + } case I2O_EVT_IND_DEVICE_RESET: /* Spec 2.0 p. 6-121: @@ -526,48 +530,43 @@ printk("%s: Event Acknowledge timeout.\n", dev->name); break; +#if 0 case I2O_EVT_IND_EVT_MASK_MODIFIED: printk("Event mask modified, 0x%08x.\n", evt->data[0]); break; - case I2O_EVT_IND_FIELD_MODIFIED: { - u16 *work16 = (u16 *)evt->data; - printk("Group 0x%04x, field %d changed.\n", work16[0], work16[1]); + case I2O_EVT_IND_GENERAL_WARNING: + printk("General warning 0x%04x.\n", evt->data[0]); + break; + case I2O_EVT_IND_CONFIGURATION_FLAG: + printk("Configuration requested.\n"); break; - } - case I2O_EVT_IND_VENDOR_EVT: { - int i; - printk("Vendor event:\n"); - for (i = 0; i < evt_data_len / 4; i++) - printk(" 0x%08x\n", evt->data[i]); + case I2O_EVT_IND_CAPABILITY_CHANGE: + printk("Capability change 0x%04x.\n", evt->data[0]); break; - } case I2O_EVT_IND_DEVICE_STATE: printk("Device state changed 0x%08x.\n", evt->data[0]); break; - +#endif case I2O_LAN_EVT_LINK_DOWN: + netif_carrier_off(dev); printk("Link to the physical device is lost.\n"); break; case I2O_LAN_EVT_LINK_UP: + netif_carrier_on(dev); printk("Link to the physical device is (re)established.\n"); break; case I2O_LAN_EVT_MEDIA_CHANGE: printk("Media change.\n"); break; - default: printk("0x%08x. No handler.\n", evt->evt_indicator); } - - /* Note: EventAck necessary only for events that cause the device to - * syncronize with the user. - */ } /* @@ -722,7 +721,7 @@ printk(KERN_WARNING "%s: Unable to set RxMaxPacketsBucket.\n", dev->name); else - dprintk(KERN_INFO "%s: RxMaxPacketsBucket set to &d.\n", + dprintk(KERN_INFO "%s: RxMaxPacketsBucket set to %d.\n", dev->name, val); return; } @@ -739,6 +738,7 @@ struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; struct i2o_device *i2o_dev = priv->i2o_dev; struct i2o_controller *iop = i2o_dev->controller; + u32 mc_addr_group[64]; MOD_INC_USE_COUNT; @@ -756,6 +756,18 @@ i2o_lan_reset(dev); + /* Get the max number of multicast addresses */ + + if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0001, -1, + &mc_addr_group, sizeof(mc_addr_group)) < 0 ) { + printk(KERN_WARNING "%s: Unable to query LAN_MAC_ADDRESS group.\n", dev->name); + MOD_DEC_USE_COUNT; + return -EAGAIN; + } + priv->max_size_mc_table = mc_addr_group[8]; + + /* Malloc space for free bucket list to resuse reveive post buckets */ + priv->i2o_fbl = kmalloc(priv->max_buckets_out * sizeof(struct sk_buff *), GFP_KERNEL); if (priv->i2o_fbl == NULL) { @@ -819,9 +831,6 @@ /* * i2o_lan_batch_send(): Send packets in batch. * Both i2o_lan_sdu_send and i2o_lan_packet_send use this. - * - * This is a coarse first approximation for the tx_batching. - * If you come up with something better, please tell me. -taneli */ static void i2o_lan_batch_send(struct net_device *dev) { @@ -864,7 +873,7 @@ * If tx_batch_mode = 0x01 forced to batch mode * If tx_batch_mode = 0x10 switch automatically, current mode immediate * If tx_batch_mode = 0x11 switch automatically, current mode batch - * If gap between two packets is > 2 ticks, switch to immediate + * If gap between two packets is > 0 ticks, switch to immediate */ if (priv->tx_batch_mode >> 1) // switch automatically priv->tx_batch_mode = tickssofar ? 0x02 : 0x03; @@ -996,7 +1005,7 @@ if (!(priv->tx_batch_mode & 0x01) || priv->tx_count == priv->sgl_max) { dev->trans_start = jiffies; i2o_post_message(iop, priv->m); - dprintk(KERN_DEBUG"%s: %d packets sent.\n", dev->name, priv->tx_count); + dprintk(KERN_DEBUG "%s: %d packets sent.\n", dev->name, priv->tx_count); priv->tx_count = 0; } @@ -1134,100 +1143,90 @@ return (struct net_device_stats *)&priv->stats; } -/* - * i2o_lan_set_mc_list(): Enable a network device to receive packets - * not send to the protocol address. +/* + * i2o_lan_set_mc_filter(): Post a request to set multicast filter. */ - -static void i2o_lan_set_mc_list(struct net_device *dev) +int i2o_lan_set_mc_filter(struct net_device *dev, u32 filter_mask) { - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; struct i2o_device *i2o_dev = priv->i2o_dev; struct i2o_controller *iop = i2o_dev->controller; - u32 filter_mask; - u32 max_size_mc_table; - u32 mc_addr_group[64]; + u32 msg[10]; -// This isn't safe yet in SMP. Needs to be async. -// Seems to work in uniprocessor environment. + msg[0] = TEN_WORD_MSG_SIZE | SGL_OFFSET_5; + msg[1] = I2O_CMD_UTIL_PARAMS_SET << 24 | HOST_TID << 12 | i2o_dev->lct_data.tid; + msg[2] = priv->unit << 16 | lan_context; + msg[3] = 0x0001 << 16 | 3 ; // TransactionContext: group&field + msg[4] = 0; + msg[5] = 0xCC000000 | 16; // Immediate data SGL + msg[6] = 1; // OperationCount + msg[7] = 0x0001<<16 | I2O_PARAMS_FIELD_SET; // Group, Operation + msg[8] = 3 << 16 | 1; // FieldIndex, FieldCount + msg[9] = filter_mask; // Value -return; - -// read_lock_bh(&dev_mc_lock); - spin_lock(&dev->xmit_lock); - dev->xmit_lock_owner = smp_processor_id(); + return i2o_post_this(iop, msg, sizeof(msg)); +} - if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0001, -1, - &mc_addr_group, sizeof(mc_addr_group)) < 0 ) { - printk(KERN_WARNING "%s: Unable to query LAN_MAC_ADDRESS group.\n", dev->name); - return; +/* + * i2o_lan_set_mc_table(): Post a request to set LAN_MULTICAST_MAC_ADDRESS table. + */ +int i2o_lan_set_mc_table(struct net_device *dev) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + struct dev_mc_list *mc; + u32 msg[10 + 2 * dev->mc_count]; + u8 *work8 = (u8 *)(msg + 10); + + msg[0] = I2O_MESSAGE_SIZE(10 + 2 * dev->mc_count) | SGL_OFFSET_5; + msg[1] = I2O_CMD_UTIL_PARAMS_SET << 24 | HOST_TID << 12 | i2o_dev->lct_data.tid; + msg[2] = priv->unit << 16 | lan_context; // InitiatorContext + msg[3] = 0x0002 << 16 | (u16)-1; // TransactionContext + msg[4] = 0; // OperationFlags + msg[5] = 0xCC000000 | (16 + 8 * dev->mc_count); // Immediate data SGL + msg[6] = 2; // OperationCount + msg[7] = 0x0002 << 16 | I2O_PARAMS_TABLE_CLEAR; // Group, Operation + msg[8] = 0x0002 << 16 | I2O_PARAMS_ROW_ADD; // Group, Operation + msg[9] = dev->mc_count << 16 | (u16)-1; // RowCount, FieldCount + + for (mc = dev->mc_list; mc ; mc = mc->next, work8 += 8) { + memset(work8, 0, 8); + memcpy(work8, mc->dmi_addr, mc->dmi_addrlen); // Values } - max_size_mc_table = mc_addr_group[8]; + return i2o_post_this(iop, msg, sizeof(msg)); +} + +/* + * i2o_lan_set_multicast_list(): Enable a network device to receive packets + * not send to the protocol address. + */ +static void i2o_lan_set_multicast_list(struct net_device *dev) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + u32 filter_mask; if (dev->flags & IFF_PROMISC) { filter_mask = 0x00000002; - printk(KERN_INFO "%s: Enabling promiscuous mode...\n", dev->name); - } else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > max_size_mc_table) { + dprintk(KERN_INFO "%s: Enabling promiscuous mode...\n", dev->name); + } else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > priv->max_size_mc_table) { filter_mask = 0x00000004; - printk(KERN_INFO "%s: Enabling all multicast mode...\n", dev->name); + dprintk(KERN_INFO "%s: Enabling all multicast mode...\n", dev->name); } else if (dev->mc_count) { - struct dev_mc_list *mc; - u8 mc_table[2 + 8 * dev->mc_count]; // RowCount, Addresses - u64 *work64 = (u64 *)(mc_table + 2); - filter_mask = 0x00000000; - printk(KERN_INFO "%s: Enabling multicast mode...\n", dev->name); - - /* Fill multicast addr table */ - - memset(mc_table, 0, sizeof(mc_table)); - memcpy(mc_table, &dev->mc_count, 2); - for (mc = dev->mc_list; mc ; mc = mc->next, work64++ ) - memcpy(work64, mc->dmi_addr, mc->dmi_addrlen); - - /* Clear old mc table, copy new table to */ - - if (i2o_clear_table(iop, i2o_dev->lct_data.tid, 0x0002) < 0) - printk(KERN_INFO "%s: Unable to clear LAN_MULTICAST_MAC_ADDRESS table.\n", dev->name); - - if ((i2o_row_add_table(iop, i2o_dev->lct_data.tid, 0x0002, -1, - mc_table, sizeof(mc_table))) < 0) - printk(KERN_INFO "%s: Unable to set LAN_MULTICAST_MAC_ADDRESS table.\n", dev->name); + dprintk(KERN_INFO "%s: Enabling multicast mode...\n", dev->name); + if (i2o_lan_set_mc_table(dev) < 0) + printk(KERN_WARNING "%s: Unable to send MAC table.\n", dev->name); } else { filter_mask = 0x00000300; // Broadcast, Multicast disabled - printk(KERN_INFO "%s: Enabling unicast mode...\n", dev->name); + dprintk(KERN_INFO "%s: Enabling unicast mode...\n", dev->name); } - /* Finally copy new FilterMask to */ - - if (i2o_set_scalar(iop, i2o_dev->lct_data.tid, 0x0001, 3, - &filter_mask, sizeof(filter_mask)) <0) - printk(KERN_WARNING "%s: Unable to set MAC FilterMask.\n", dev->name); - - dev->xmit_lock_owner = -1; - spin_unlock(&dev->xmit_lock); -// read_unlock_bh(&dev_mc_lock); - - return; -} - -static struct tq_struct i2o_lan_set_mc_list_task = { - 0, 0, (void (*)(void *))i2o_lan_set_mc_list, (void *) 0 -}; + /* Finally copy new FilterMask to DDM */ -/* - * i2o_lan_set_multicast_list(): - * Queue routine i2o_lan_set_mc_list() to be called later. - * Needs to be async. - */ -static void i2o_lan_set_multicast_list(struct net_device *dev) -{ - if (in_interrupt()) { - i2o_lan_set_mc_list_task.data = (void *)dev; - queue_task(&i2o_lan_set_mc_list_task, &tq_scheduler); - } else - i2o_lan_set_mc_list(dev); + if (i2o_lan_set_mc_filter(dev, filter_mask) < 0) + printk(KERN_WARNING "%s: Unable to send MAC FilterMask.\n", dev->name); } /* diff -u --recursive --new-file v2.4.0-test1/linux/drivers/i2o/i2o_lan.h linux/drivers/i2o/i2o_lan.h --- v2.4.0-test1/linux/drivers/i2o/i2o_lan.h Thu May 11 15:30:07 2000 +++ linux/drivers/i2o/i2o_lan.h Mon Jun 19 13:30:56 2000 @@ -1,7 +1,7 @@ /* * i2o_lan.h I2O LAN Class definitions * - * I2O LAN CLASS OSM April 3rd 2000 + * I2O LAN CLASS OSM May 26th 2000 * * (C) Copyright 1999, 2000 University of Helsinki, * Department of Computer Science @@ -23,7 +23,7 @@ #define I2O_LAN_RX_COPYBREAK 200 #define I2O_LAN_TX_TIMEOUT (1*HZ) #define I2O_LAN_TX_BATCH_MODE 2 /* 2=automatic, 1=on, 0=off */ -#define I2O_LAN_EVENT_MASK 0; /* 0=None, 0xFFC00002=All */ +#define I2O_LAN_EVENT_MASK 0 /* 0=None, 0xFFC00002=All */ /* LAN types */ #define I2O_LAN_ETHERNET 0x0030 @@ -100,7 +100,7 @@ #define I2O_LAN_DSC_DEST_ADDRESS_DETECTED 0x0E #define I2O_LAN_DSC_DEST_ADDRESS_OMITTED 0x0F #define I2O_LAN_DSC_PARTIAL_PACKET_RETURNED 0x10 -#define I2O_LAN_DSC_TEMP_SUSPENDED_STATE 0x11 +#define I2O_LAN_DSC_SUSPENDED 0x11 struct i2o_packet_info { u32 offset : 24; @@ -143,6 +143,8 @@ spinlock_t fbl_lock; spinlock_t tx_lock; + + u32 max_size_mc_table; /* max number of multicast addresses */ /* LAN OSM configurable parameters are here: */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/i2o/i2o_pci.c linux/drivers/i2o/i2o_pci.c --- v2.4.0-test1/linux/drivers/i2o/i2o_pci.c Thu May 11 15:30:07 2000 +++ linux/drivers/i2o/i2o_pci.c Mon Jun 19 13:30:56 2000 @@ -132,9 +132,9 @@ for(i=0; i<6; i++) { /* Skip I/O spaces */ - if(!(dev->resource[i].flags&PCI_BASE_ADDRESS_SPACE)) + if(!(pci_resource_flags(dev, i) & IORESOURCE_IO)) { - memptr=dev->resource[i].start; + memptr = pci_resource_start(dev, i); break; } } @@ -256,6 +256,8 @@ printk(KERN_INFO "i2o: I2O Controller found but does not support I2O 1.5 (skipping).\n"); continue; } + if (pci_enable_device(dev)) + continue; printk(KERN_INFO "i2o: I2O controller on bus %d at %d.\n", dev->bus->number, dev->devfn); pci_set_master(dev); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/i2o/i2o_scsi.h linux/drivers/i2o/i2o_scsi.h --- v2.4.0-test1/linux/drivers/i2o/i2o_scsi.h Thu Nov 11 20:11:35 1999 +++ linux/drivers/i2o/i2o_scsi.h Mon Jun 19 13:30:56 2000 @@ -22,6 +22,7 @@ extern int i2o_scsi_reset(Scsi_Cmnd *, unsigned int); extern int i2o_scsi_bios_param(Disk *, kdev_t, int *); extern void i2o_scsi_setup(char *str, int *ints); +extern int i2o_scsi_release(struct Scsi_Host *host); #define I2OSCSI { \ next: NULL, \ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/Config.in linux/drivers/ide/Config.in --- v2.4.0-test1/linux/drivers/ide/Config.in Mon Jun 19 16:31:59 2000 +++ linux/drivers/ide/Config.in Tue Jun 20 13:58:42 2000 @@ -1,6 +1,8 @@ # # IDE ATA ATAPI Block device driver configuration # +# Andre Hedrick +# mainmenu_option next_comment comment 'IDE, ATA and ATAPI Block devices' @@ -21,6 +23,9 @@ dep_mbool ' Seagate Vendor Specific' CONFIG_BLK_DEV_IDEDISK_SEAGATE $CONFIG_BLK_DEV_IDEDISK_VENDOR dep_mbool ' Western Digital Vendor Specific' CONFIG_BLK_DEV_IDEDISK_WD $CONFIG_BLK_DEV_IDEDISK_VENDOR + define_bool CONFIG_BLK_DEV_COMMERIAL n + dep_mbool ' TiVo Commerial Application Specific' CONFIG_BLK_DEV_TIVO $CONFIG_BLK_DEV_COMMERIAL + dep_tristate ' PCMCIA IDE support' CONFIG_BLK_DEV_IDECS $CONFIG_BLK_DEV_IDE $CONFIG_PCMCIA dep_tristate ' Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE dep_tristate ' Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE @@ -44,32 +49,28 @@ dep_bool ' ATA Work(s) In Progress (EXPERIMENTAL)' CONFIG_IDEDMA_PCI_WIP $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL dep_bool ' Good-Bad DMA Model-Firmware (WIP)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_IDEDMA_PCI_WIP dep_bool ' AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI - dep_mbool ' AEC62XX Tuning support (WIP)' CONFIG_AEC62XX_TUNING $CONFIG_BLK_DEV_AEC62XX $CONFIG_IDEDMA_PCI_WIP + dep_mbool ' AEC62XX Tuning support' CONFIG_AEC62XX_TUNING $CONFIG_BLK_DEV_AEC62XX dep_bool ' ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3 dep_bool ' AMD Viper support' CONFIG_BLK_DEV_AMD7409 $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' AMD Viper ATA-66 Override (WIP)' CONFIG_AMD7409_OVERRIDE $CONFIG_BLK_DEV_AMD7409 $CONFIG_IDEDMA_PCI_WIP dep_bool ' CMD64X chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI - dep_mbool ' CMD64X chipset RAID (WIP)' CONFIG_CMD64X_RAID $CONFIG_BLK_DEV_CMD64X $CONFIG_IDEDMA_PCI_WIP - dep_bool ' CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI + dep_bool ' CY82C693 chipset support' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' HPT34X chipset support' CONFIG_BLK_DEV_HPT34X $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' HPT34X AUTODMA support (WIP)' CONFIG_HPT34X_AUTODMA $CONFIG_BLK_DEV_HPT34X $CONFIG_IDEDMA_PCI_WIP dep_bool ' HPT366 chipset support' CONFIG_BLK_DEV_HPT366 $CONFIG_BLK_DEV_IDEDMA_PCI - dep_bool ' HPT366 Fast Interrupts (WIP)' CONFIG_HPT366_FIP $CONFIG_BLK_DEV_HPT366 $CONFIG_IDEDMA_PCI_WIP - dep_mbool ' HPT366 mode Three (WIP)' CONFIG_HPT366_MODE3 $CONFIG_BLK_DEV_HPT366 $CONFIG_IDEDMA_PCI_WIP if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" ]; then dep_mbool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' PIIXn Tuning support' CONFIG_PIIX_TUNING $CONFIG_BLK_DEV_PIIX $CONFIG_IDEDMA_PCI_AUTO fi dep_bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL - dep_bool ' PROMISE PDC20246/PDC20262 support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI + dep_bool ' PROMISE PDC20246/PDC20262/PDC20267 support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX - dep_mbool ' Special Mode Feature (WIP)' CONFIG_PDC202XX_MASTER $CONFIG_BLK_DEV_PDC202XX $CONFIG_IDEDMA_PCI_WIP dep_bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86 dep_bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI - dep_bool ' VIA82CXXX chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI + dep_bool ' VIA82CXXX chipset support' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' VIA82CXXX Tuning support (WIP)' CONFIG_VIA82CXXX_TUNING $CONFIG_BLK_DEV_VIA82CXXX $CONFIG_IDEDMA_PCI_WIP fi if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then @@ -81,14 +82,13 @@ dep_bool ' PowerMac IDE DMA support' CONFIG_BLK_DEV_IDEDMA_PMAC $CONFIG_BLK_DEV_IDE_PMAC dep_bool ' Use DMA by default' CONFIG_IDEDMA_PMAC_AUTO $CONFIG_BLK_DEV_IDEDMA_PMAC define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PMAC - define_bool CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_BLK_DEV_IDEDMA_PMAC + define_bool CONFIG_BLK_DEV_IDEPCI $CONFIG_BLK_DEV_IDEDMA_PMAC fi if [ "$CONFIG_ARCH_ACORN" = "y" ]; then dep_bool ' ICS IDE interface support' CONFIG_BLK_DEV_IDE_ICSIDE $CONFIG_ARCH_ACORN dep_bool ' ICS DMA support' CONFIG_BLK_DEV_IDEDMA_ICS $CONFIG_BLK_DEV_IDE_ICSIDE dep_bool ' Use ICS DMA by default' CONFIG_IDEDMA_ICS_AUTO $CONFIG_BLK_DEV_IDEDMA_ICS define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_ICS - define_bool CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_BLK_DEV_IDEDMA_ICS dep_bool ' RapIDE interface support' CONFIG_BLK_DEV_IDE_RAPIDE $CONFIG_ARCH_ACORN fi if [ "$CONFIG_AMIGA" = "y" ]; then @@ -132,6 +132,17 @@ define_bool CONFIG_IDEDMA_AUTO n fi +if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" -o \ + "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" -o \ + "$CONFIG_BLK_DEV_IDEDMA_ICS" = "y" ]; then + bool ' IGNORE word93 Validation BITS' CONFIG_IDEDMA_IVB +fi + +if [ "$CONFIG_BLK_DEV_TIVO" = "y" ]; then + define_bool CONFIG_DMA_NONPCI y +else + define_bool CONFIG_DMA_NONPCI n +fi if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \ "$CONFIG_BLK_DEV_AEC62XX" = "y" -o \ "$CONFIG_BLK_DEV_ALI15X3" = "y" -o \ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/Makefile linux/drivers/ide/Makefile --- v2.4.0-test1/linux/drivers/ide/Makefile Mon Jun 19 16:31:59 2000 +++ linux/drivers/ide/Makefile Tue Jun 20 13:58:42 2000 @@ -18,11 +18,11 @@ MOD_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) -L_TARGET := ide.a -L_OBJS := ide-geometry.o +O_TARGET := idedriver.o +O_OBJS := ide-geometry.o M_OBJS := MOD_LIST_NAME := IDE_MODULES -LX_OBJS := +OX_OBJS := MX_OBJS := ifeq ($(CONFIG_BLK_DEV_AEC62XX),y) @@ -78,7 +78,7 @@ endif ifeq ($(CONFIG_BLK_DEV_HD),y) -L_OBJS += hd.o +O_OBJS += hd.o endif ifeq ($(CONFIG_BLK_DEV_HPT34X),y) @@ -97,7 +97,7 @@ IDE_OBJS += icside.o endif -ifeq ($(CONFIG_BLK_DEV_IDEDMA_PCI),y) +ifeq ($(CONFIG_BLK_DEV_IDEDMA),y) IDE_OBJS += ide-dma.o endif @@ -178,8 +178,8 @@ ###Collect ifeq ($(CONFIG_BLK_DEV_IDE),y) - LX_OBJS += ide.o ide-features.o - L_OBJS += ide-probe.o $(IDE_OBJS) + OX_OBJS += ide.o ide-features.o + O_OBJS += ide-probe.o $(IDE_OBJS) else ifeq ($(CONFIG_BLK_DEV_IDE),m) MIX_OBJS += ide.o ide-features.o $(IDE_OBJS) @@ -190,7 +190,7 @@ ############ ifeq ($(CONFIG_BLK_DEV_IDECS),y) -L_OBJS += ide-cs.o +O_OBJS += ide-cs.o else ifeq ($(CONFIG_BLK_DEV_IDECS),m) M_OBJS += ide-cs.o @@ -198,7 +198,7 @@ endif ifeq ($(CONFIG_BLK_DEV_IDEDISK),y) -L_OBJS += ide-disk.o +O_OBJS += ide-disk.o else ifeq ($(CONFIG_BLK_DEV_IDEDISK),m) M_OBJS += ide-disk.o @@ -206,7 +206,7 @@ endif ifeq ($(CONFIG_BLK_DEV_IDECD),y) -L_OBJS += ide-cd.o +O_OBJS += ide-cd.o else ifeq ($(CONFIG_BLK_DEV_IDECD),m) M_OBJS += ide-cd.o @@ -214,7 +214,7 @@ endif ifeq ($(CONFIG_BLK_DEV_IDETAPE),y) -L_OBJS += ide-tape.o +O_OBJS += ide-tape.o else ifeq ($(CONFIG_BLK_DEV_IDETAPE),m) M_OBJS += ide-tape.o @@ -222,7 +222,7 @@ endif ifeq ($(CONFIG_BLK_DEV_IDEFLOPPY),y) -L_OBJS += ide-floppy.o +O_OBJS += ide-floppy.o else ifeq ($(CONFIG_BLK_DEV_IDEFLOPPY),m) M_OBJS += ide-floppy.o diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/aec62xx.c linux/drivers/ide/aec62xx.c --- v2.4.0-test1/linux/drivers/ide/aec62xx.c Tue May 23 15:31:34 2000 +++ linux/drivers/ide/aec62xx.c Tue Jun 20 07:52:36 2000 @@ -1,7 +1,7 @@ /* - * linux/drivers/ide/aec62xx.c Version 0.08 Mar. 28, 2000 + * linux/drivers/ide/aec62xx.c Version 0.09 June. 9, 2000 * - * Copyright (C) 2000 Andre Hedrick (andre@suse.com) + * Copyright (C) 1999-2000 Andre Hedrick (andre@linux-ide.org) * May be copied or modified under the terms of the GNU General Public License * */ @@ -55,7 +55,7 @@ { char *p = buffer; - u32 bibma = bmide_dev->resource[4].start; + u32 bibma = pci_resource_start(bmide_dev, 4); u8 c0 = 0, c1 = 0; u8 art = 0, uart = 0; @@ -358,7 +358,7 @@ byte unit = (drive->select.b.unit & 0x01); unsigned long dma_base = hwif->dma_base; byte speed = -1; - byte ultra66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0; + byte ultra66 = eighty_ninty_three(drive); if (drive->media != ide_disk) return ((int) ide_dma_off_quietly); @@ -497,6 +497,23 @@ switch (func) { case ide_dma_check: return config_drive_xfer_rate(drive); + case ide_dma_lostirq: + case ide_dma_timeout: + switch(HWIF(drive)->pci_dev->device) { + case PCI_DEVICE_ID_ARTOP_ATP860: + case PCI_DEVICE_ID_ARTOP_ATP860R: +// { +// int i = 0; +// byte reg49h = 0; +// pci_read_config_byte(HWIF(drive)->pci_dev, 0x49, ®49h); +// for (i=0;i<256;i++) +// pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h|0x10); +// pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h & ~0x10); +// } +// return 0; + default: + break; + } default: break; } @@ -529,9 +546,6 @@ byte ata66 = 0; pci_read_config_byte(hwif->pci_dev, 0x49, &ata66); -#if 1 - printk("AEC6260: reg49h=0x%02x ATA-%s Cable Port%d\n", ata66, (ata66 & mask) ? "33" : "66", hwif->channel); -#endif return ((ata66 & mask) ? 0 : 1); } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/alim15x3.c linux/drivers/ide/alim15x3.c --- v2.4.0-test1/linux/drivers/ide/alim15x3.c Tue May 23 15:31:34 2000 +++ linux/drivers/ide/alim15x3.c Tue Jun 20 07:52:36 2000 @@ -1,17 +1,15 @@ /* - * linux/drivers/ide/alim15x3.c Version 0.09 Mar. 18, 2000 + * linux/drivers/ide/alim15x3.c Version 0.10 Jun. 9, 2000 * * Copyright (C) 1998-2000 Michel Aubry, Maintainer * Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer + * Copyright (C) 1999-2000 CJ, cjtsai@ali.com.tw, Maintainer * - * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com) + * Copyright (C) 1998-2000 Andre Hedrick (andre@linux-ide.org) * May be copied or modified under the terms of the GNU General Public License * * (U)DMA capable version of ali 1533/1543(C), 1535(D) * - * version: 1.0 beta2 (Sep. 2, 1999) - * e-mail your problems to cjtsai@ali.com.tw - * ********************************************************************** * 9/7/99 --Parts from the above author are included and need to be * converted into standard interface, once I finish the thought. @@ -237,7 +235,6 @@ static byte m5229_revision = 0; static byte chip_is_1543c_e = 0; -static byte cable_80_pin[2] = { 0, 0 }; byte ali_proc = 0; static struct pci_dev *isa_dev; @@ -346,7 +343,7 @@ /* * enable ultra dma and set timing */ - tmpbyte |= ((0x08 | (4-speed)) << (unit << 2)); + tmpbyte |= ((0x08 | ((4-speed)&0x07)) << (unit << 2)); pci_write_config_byte(dev, m5229_udma, tmpbyte); if (speed >= XFER_UDMA_3) { pci_read_config_byte(dev, 0x4b, &tmpbyte); @@ -370,12 +367,14 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra33) { struct hd_driveid *id = drive->id; - ide_hwif_t *hwif = HWIF(drive); byte speed = 0x00; - byte ultra66 = ((hwif->udma_four) && (id->hw_config & 0x2000)) ? 1 : 0; + byte ultra66 = eighty_ninty_three(drive); + byte ultra100 = (m5229_revision>=0xc4) ? 1 : 0; int rval; - if ((id->dma_ultra & 0x0010) && (ultra66) && (ultra33)) { + if ((id->dma_ultra & 0x0020) && (ultra100) && (ultra66) && (ultra33)) { + speed = XFER_UDMA_5; + } else if ((id->dma_ultra & 0x0010) && (ultra66) && (ultra33)) { speed = XFER_UDMA_4; } else if ((id->dma_ultra & 0x0008) && (ultra66) && (ultra33)) { speed = XFER_UDMA_3; @@ -454,7 +453,7 @@ } dma_func = ide_dma_off_quietly; if ((id->field_valid & 4) && (m5229_revision >= 0xC2)) { - if (id->dma_ultra & 0x001F) { + if (id->dma_ultra & 0x002F) { /* Force if Capable UltraDMA */ dma_func = config_chipset_for_dma(drive, can_ultra_dma); if ((id->field_valid & 2) && @@ -508,13 +507,13 @@ unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name) { - unsigned long fixdma_base = dev->resource[4].start; + unsigned long fixdma_base = pci_resource_start(dev, 4); pci_read_config_byte(dev, PCI_REVISION_ID, &m5229_revision); isa_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); - if (!fixdma_base || fixdma_base == PCI_BASE_ADDRESS_IO_MASK) { + if (!fixdma_base) { /* * */ @@ -539,11 +538,16 @@ return 0; } +/* + * This checks if the controller and the cable are capable + * of UDMA66 transfers. It doesn't check the drives. + * But see note 2 below! + */ unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif) { struct pci_dev *dev = hwif->pci_dev; - byte ata66mask = hwif->channel ? 0x02 : 0x01; unsigned int ata66 = 0; + byte cable_80_pin[2] = { 0, 0 }; unsigned long flags; byte tmpbyte; @@ -575,7 +579,7 @@ * 1543C-B0 (m1533, 0x79, bit 2) */ pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x04); - } else if (m5229_revision == 0xC3) { + } else if (m5229_revision >= 0xC3) { /* * 1553/1535 (m1533, 0x79, bit 1) */ @@ -596,6 +600,10 @@ * has 80-pin (from host view) */ if (!(tmpbyte & 0x02)) cable_80_pin[1] = 1; + /* + * Allow ata66 if cable of current channel has 80 pins + */ + ata66 = (hwif->channel)?cable_80_pin[1]:cable_80_pin[0]; } else { /* * revision 0x20 (1543-E, 1543-F) @@ -625,18 +633,6 @@ pci_write_config_byte(dev, 0x53, tmpbyte); - /* - * Ultra66 cable detection (from Host View) - * m5229, 0x4a, bit0: primary, bit1: secondary 80 pin - * - * 0x4a, bit0 is 0 => primary channel - * has 80-pin (from host view) - * - * 0x4a, bit1 is 0 => secondary channel - * has 80-pin (from host view) - */ - pci_read_config_byte(dev, 0x4a, &tmpbyte); - ata66 = (!(tmpbyte & ata66mask)) ? 1 : 0; __restore_flags(flags); return(ata66); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/amd7409.c linux/drivers/ide/amd7409.c --- v2.4.0-test1/linux/drivers/ide/amd7409.c Tue May 23 15:31:34 2000 +++ linux/drivers/ide/amd7409.c Tue Jun 20 07:52:36 2000 @@ -1,7 +1,7 @@ /* - * linux/drivers/ide/amd7409.c Version 0.04 Mar. 18, 2000 + * linux/drivers/ide/amd7409.c Version 0.05 June 9, 2000 * - * Copyright (C) 2000 Andre Hedrick + * Copyright (C) 1999-2000 Andre Hedrick * May be copied or modified under the terms of the GNU General Public License * */ @@ -40,7 +40,7 @@ static int amd7409_get_info (char *buffer, char **addr, off_t offset, int count) { char *p = buffer; - u32 bibma = bmide_dev->resource[4].start; + u32 bibma = pci_resource_start(bmide_dev, 4); u8 c0 = 0, c1 = 0; /* @@ -71,6 +71,20 @@ extern char *ide_xfer_verbose (byte xfer_rate); +static unsigned int amd7409_swdma_check (struct pci_dev *dev) +{ + unsigned int class_rev; + pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); + class_rev &= 0xff; + return ((int) (class_rev >= 7) ? 1 : 0); +} + +static int amd7409_swdma_error(ide_drive_t *drive) +{ + printk("%s: single-word DMA not support (revision < C4)\n", drive->name); + return 0; +} + /* * Here is where all the hard work goes to program the chipset. * @@ -122,64 +136,68 @@ case XFER_UDMA_4: ultra_timing |= 0x45; dma_pio_timing |= 0x20; - pio_timing |= (0x03 << drive->dn); break; case XFER_UDMA_3: ultra_timing |= 0x44; dma_pio_timing |= 0x20; - pio_timing |= (0x03 << drive->dn); break; case XFER_UDMA_2: ultra_timing |= 0x40; dma_pio_timing |= 0x20; - pio_timing |= (0x03 << drive->dn); break; case XFER_UDMA_1: ultra_timing |= 0x41; dma_pio_timing |= 0x20; - pio_timing |= (0x03 << drive->dn); break; case XFER_UDMA_0: ultra_timing |= 0x42; dma_pio_timing |= 0x20; - pio_timing |= (0x03 << drive->dn); break; case XFER_MW_DMA_2: dma_pio_timing |= 0x20; - pio_timing |= (0x03 << drive->dn); break; case XFER_MW_DMA_1: dma_pio_timing |= 0x21; - pio_timing |= (0x03 << drive->dn); break; case XFER_MW_DMA_0: dma_pio_timing |= 0x77; - pio_timing |= (0x03 << drive->dn); + break; + case XFER_SW_DMA_2: + if (!amd7409_swdma_check(dev)) + return amd7409_swdma_error(drive); + dma_pio_timing |= 0x42; + break; + case XFER_SW_DMA_1: + if (!amd7409_swdma_check(dev)) + return amd7409_swdma_error(drive); + dma_pio_timing |= 0x65; + break; + case XFER_SW_DMA_0: + if (!amd7409_swdma_check(dev)) + return amd7409_swdma_error(drive); + dma_pio_timing |= 0xA8; break; #endif /* CONFIG_BLK_DEV_IDEDMA */ case XFER_PIO_4: dma_pio_timing |= 0x20; - pio_timing |= (0x03 << drive->dn); break; case XFER_PIO_3: dma_pio_timing |= 0x22; - pio_timing |= (0x03 << drive->dn); break; case XFER_PIO_2: dma_pio_timing |= 0x42; - pio_timing |= (0x03 << drive->dn); break; case XFER_PIO_1: dma_pio_timing |= 0x65; - pio_timing |= (0x03 << drive->dn); break; case XFER_PIO_0: default: dma_pio_timing |= 0xA8; - pio_timing |= (0x03 << drive->dn); break; } + pio_timing |= (0x03 << drive->dn); + if (!drive->init_speed) drive->init_speed = speed; @@ -268,12 +286,14 @@ static int config_chipset_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; - byte udma_66 = ((id->hw_config & 0x2000) && - (HWIF(drive)->udma_four)) ? 1 : 0; + byte udma_66 = eighty_ninty_three(drive); + byte udma_100 = 0; byte speed = 0x00; int rval; - if ((id->dma_ultra & 0x0010) && (udma_66)) { + if ((id->dma_ultra & 0x0020) && (udma_66)&& (udma_100)) { + speed = XFER_UDMA_5; + } else if ((id->dma_ultra & 0x0010) && (udma_66)) { speed = XFER_UDMA_4; } else if ((id->dma_ultra & 0x0008) && (udma_66)) { speed = XFER_UDMA_3; @@ -318,7 +338,7 @@ } dma_func = ide_dma_off_quietly; if (id->field_valid & 4) { - if (id->dma_ultra & 0x001F) { + if (id->dma_ultra & 0x002F) { /* Force if Capable UltraDMA */ dma_func = config_chipset_for_dma(drive); if ((id->field_valid & 2) && @@ -327,12 +347,15 @@ } } else if (id->field_valid & 2) { try_dma_modes: - if (id->dma_mword & 0x0007) { + if ((id->dma_mword & 0x0007) || + ((id->dma_1word & 0x007) && + (amd7409_swdma_check(HWIF(drive)->pci_dev)))) { /* Force if Capable regular DMA modes */ dma_func = config_chipset_for_dma(drive); if (dma_func != ide_dma_on) goto no_dma_set; } + } else if (ide_dmaproc(ide_dma_good_drive, drive)) { if (id->eide_dma_time > 150) { goto no_dma_set; @@ -372,9 +395,14 @@ unsigned int __init pci_init_amd7409 (struct pci_dev *dev, const char *name) { - unsigned long fixdma_base = dev->resource[4].start; + unsigned long fixdma_base = pci_resource_start(dev, 4); + +#ifdef CONFIG_BLK_DEV_IDEDMA + if (!amd7409_swdma_check(dev)) + printk("%s: disabling single-word DMA support (revision < C4)\n", name); +#endif /* CONFIG_BLK_DEV_IDEDMA */ - if (!fixdma_base || fixdma_base == PCI_BASE_ADDRESS_IO_MASK) { + if (!fixdma_base) { /* * */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/cmd64x.c linux/drivers/ide/cmd64x.c --- v2.4.0-test1/linux/drivers/ide/cmd64x.c Tue May 23 15:31:34 2000 +++ linux/drivers/ide/cmd64x.c Tue Jun 20 07:52:36 2000 @@ -1,6 +1,6 @@ /* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16 * - * linux/drivers/ide/cmd64x.c Version 1.21 Mar. 18, 2000 + * linux/drivers/ide/cmd64x.c Version 1.22 June 9, 2000 * * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines. * Note, this driver is not used at all on other systems because @@ -10,7 +10,7 @@ * * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1998 David S. Miller (davem@redhat.com) - * Copyright (C) 1999-2000 Andre Hedrick (andre@suse.com) + * Copyright (C) 1999-2000 Andre Hedrick */ #include @@ -41,6 +41,8 @@ * CMD64x specific registers definition. */ +#define CFR 0x50 +#define CFR_INTR_CH0 0x02 #define CNTRL 0x51 #define CNTRL_DIS_RA0 0x40 #define CNTRL_DIS_RA1 0x80 @@ -52,6 +54,7 @@ #define ARTTIM1 0x55 #define DRWTIM1 0x56 #define ARTTIM23 0x57 +#define ARTTIM23_INTR_CH1 0x04 #define ARTTIM23_DIS_RA2 0x04 #define ARTTIM23_DIS_RA3 0x08 #define ARTTIM2 0x57 @@ -63,6 +66,10 @@ #define BMIDECR0 0x70 #define MRDMODE 0x71 +#define MRDMODE_INTR_CH0 0x04 +#define MRDMODE_INTR_CH1 0x08 +#define MRDMODE_BLK_CH0 0x10 +#define MRDMODE_BLK_CH1 0x20 #define BMIDESR0 0x72 #define UDIDETCR0 0x73 #define DTPR0 0x74 @@ -90,9 +97,13 @@ u8 reg57 = 0, reg58 = 0, reg5b; /* secondary */ u8 reg72 = 0, reg73 = 0; /* primary */ u8 reg7a = 0, reg7b = 0; /* secondary */ + u8 reg50 = 0, reg71 = 0; /* extra */ u8 hi_byte = 0, lo_byte = 0; switch(bmide_dev->device) { + case PCI_DEVICE_ID_CMD_649: + p += sprintf(p, "\n CMD649 Chipset.\n"); + break; case PCI_DEVICE_ID_CMD_648: p += sprintf(p, "\n CMD648 Chipset.\n"); break; @@ -106,6 +117,7 @@ p += sprintf(p, "\n CMD64? Chipse.\n"); break; } + (void) pci_read_config_byte(bmide_dev, CFR, ®50); (void) pci_read_config_byte(bmide_dev, ARTTIM0, ®53); (void) pci_read_config_byte(bmide_dev, DRWTIM0, ®54); (void) pci_read_config_byte(bmide_dev, ARTTIM1, ®55); @@ -113,6 +125,7 @@ (void) pci_read_config_byte(bmide_dev, ARTTIM2, ®57); (void) pci_read_config_byte(bmide_dev, DRWTIM2, ®58); (void) pci_read_config_byte(bmide_dev, DRWTIM3, ®5b); + (void) pci_read_config_byte(bmide_dev, MRDMODE, ®71); (void) pci_read_config_byte(bmide_dev, BMIDESR0, ®72); (void) pci_read_config_byte(bmide_dev, UDIDETCR0, ®73); (void) pci_read_config_byte(bmide_dev, BMIDESR1, ®7a); @@ -128,42 +141,42 @@ (reg72&0x20)?((reg73&0x01)?"UDMA":" DMA"):" PIO", (reg72&0x20)?( ((reg73&0x30)==0x30)?(((reg73&0x35)==0x35)?"3":"0"): ((reg73&0x20)==0x20)?(((reg73&0x25)==0x25)?"3":"1"): - ((reg73&0x10)==0x10)?(((reg73&0x15)==0x15)?"4":"2"):"X"):"?", + ((reg73&0x10)==0x10)?(((reg73&0x15)==0x15)?"4":"2"): + ((reg73&0x00)==0x00)?(((reg73&0x05)==0x05)?"5":"2"):"X"):"?", (reg72&0x40)?((reg73&0x02)?"UDMA":" DMA"):" PIO", (reg72&0x40)?( ((reg73&0xC0)==0xC0)?(((reg73&0xC5)==0xC5)?"3":"0"): ((reg73&0x80)==0x80)?(((reg73&0x85)==0x85)?"3":"1"): - ((reg73&0x40)==0x40)?(((reg73&0x4A)==0x4A)?"4":"2"):"X"):"?", + ((reg73&0x40)==0x40)?(((reg73&0x4A)==0x4A)?"4":"2"): + ((reg73&0x00)==0x00)?(((reg73&0x0A)==0x0A)?"5":"2"):"X"):"?", (reg7a&0x20)?((reg7b&0x01)?"UDMA":" DMA"):" PIO", (reg7a&0x20)?( ((reg7b&0x30)==0x30)?(((reg7b&0x35)==0x35)?"3":"0"): ((reg7b&0x20)==0x20)?(((reg7b&0x25)==0x25)?"3":"1"): - ((reg7b&0x10)==0x10)?(((reg7b&0x15)==0x15)?"4":"2"):"X"):"?", + ((reg7b&0x10)==0x10)?(((reg7b&0x15)==0x15)?"4":"2"): + ((reg7b&0x00)==0x00)?(((reg7b&0x05)==0x05)?"5":"2"):"X"):"?", (reg7a&0x40)?((reg7b&0x02)?"UDMA":" DMA"):" PIO", (reg7a&0x40)?( ((reg7b&0xC0)==0xC0)?(((reg7b&0xC5)==0xC5)?"3":"0"): ((reg7b&0x80)==0x80)?(((reg7b&0x85)==0x85)?"3":"1"): - ((reg7b&0x40)==0x40)?(((reg7b&0x4A)==0x4A)?"4":"2"):"X"):"?" ); + ((reg7b&0x40)==0x40)?(((reg7b&0x4A)==0x4A)?"4":"2"): + ((reg7b&0x00)==0x00)?(((reg7b&0x0A)==0x0A)?"5":"2"):"X"):"?" ); p += sprintf(p, "PIO Mode: %s %s %s %s\n", "?", "?", "?", "?"); - p += sprintf(p, "PIO\n"); + p += sprintf(p, " %s %s\n", + (reg50 & CFR_INTR_CH0) ? "interrupting" : "polling ", + (reg57 & ARTTIM23_INTR_CH1) ? "interrupting" : "polling"); + p += sprintf(p, " %s %s\n", + (reg71 & MRDMODE_INTR_CH0) ? "pending" : "clear ", + (reg71 & MRDMODE_INTR_CH1) ? "pending" : "clear"); + p += sprintf(p, " %s %s\n", + (reg71 & MRDMODE_BLK_CH0) ? "blocked" : "enabled", + (reg71 & MRDMODE_BLK_CH1) ? "blocked" : "enabled"); - SPLIT_BYTE(reg53, hi_byte, lo_byte); - p += sprintf(p, "ARTTIM0 = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg53, hi_byte, lo_byte); - SPLIT_BYTE(reg54, hi_byte, lo_byte); - p += sprintf(p, "DRWTIM0 = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg54, hi_byte, lo_byte); - SPLIT_BYTE(reg55, hi_byte, lo_byte); - p += sprintf(p, "ARTTIM1 = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg55, hi_byte, lo_byte); - SPLIT_BYTE(reg56, hi_byte, lo_byte); - p += sprintf(p, "DRWTIM1 = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg56, hi_byte, lo_byte); + SPLIT_BYTE(reg50, hi_byte, lo_byte); + p += sprintf(p, "CFR = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg50, hi_byte, lo_byte); SPLIT_BYTE(reg57, hi_byte, lo_byte); p += sprintf(p, "ARTTIM23 = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg57, hi_byte, lo_byte); - SPLIT_BYTE(reg58, hi_byte, lo_byte); - p += sprintf(p, "DRWTIM2 = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg58, hi_byte, lo_byte); - SPLIT_BYTE(reg5b, hi_byte, lo_byte); - p += sprintf(p, "DRWTIM3 = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg5b, hi_byte, lo_byte); - SPLIT_BYTE(reg73, hi_byte, lo_byte); - p += sprintf(p, "UDIDETCR0 = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg73, hi_byte, lo_byte); - SPLIT_BYTE(reg7b, hi_byte, lo_byte); - p += sprintf(p, "UDIDETCR1 = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg7b, hi_byte, lo_byte); + SPLIT_BYTE(reg71, hi_byte, lo_byte); + p += sprintf(p, "MRDMODE = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg71, hi_byte, lo_byte); return p-buffer; /* => must be less than 4k! */ } @@ -349,9 +362,9 @@ #ifdef CONFIG_BLK_DEV_IDEDMA ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - byte unit = (drive->select.b.unit & 0x01); int err = 0; + byte unit = (drive->select.b.unit & 0x01); u8 pciU = (hwif->channel) ? UDIDETCR1 : UDIDETCR0; u8 pciD = (hwif->channel) ? BMIDESR1 : BMIDESR0; u8 regU = 0; @@ -369,6 +382,7 @@ (void) pci_read_config_byte(dev, pciD, ®D); (void) pci_read_config_byte(dev, pciU, ®U); switch(speed) { + case XFER_UDMA_5: regU |= (unit ? 0x0A : 0x05); break; case XFER_UDMA_4: regU |= (unit ? 0x4A : 0x15); break; case XFER_UDMA_3: regU |= (unit ? 0x8A : 0x25); break; case XFER_UDMA_2: regU |= (unit ? 0x42 : 0x11); break; @@ -383,7 +397,7 @@ #else int err = 0; - switch(speed) { + switch(speed) { #endif /* CONFIG_BLK_DEV_IDEDMA */ case XFER_PIO_4: cmd64x_tuneproc(drive, 4); break; case XFER_PIO_3: cmd64x_tuneproc(drive, 3); break; @@ -394,6 +408,7 @@ default: return 1; } + #ifdef CONFIG_BLK_DEV_IDEDMA (void) pci_write_config_byte(dev, pciU, regU); #endif /* CONFIG_BLK_DEV_IDEDMA */ @@ -420,10 +435,12 @@ byte speed = 0x00; byte set_pio = 0x00; byte udma_33 = ((rev >= 0x05) || (ultra_66)) ? 1 : 0; - byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0; + byte udma_66 = eighty_ninty_three(drive); + byte udma_100 = 0; int rval; switch(dev->device) { + case PCI_DEVICE_ID_CMD_649: udma_100 = 1; break; case PCI_DEVICE_ID_CMD_648: case PCI_DEVICE_ID_CMD_646: case PCI_DEVICE_ID_CMD_643: @@ -446,7 +463,9 @@ * in the 646U2. * So we only do UltraDMA on revision 0x05 and 0x07 chipsets. */ - if ((id->dma_ultra & 0x0010) && (udma_66) && (udma_33)) { + if ((id->dma_ultra & 0x0020) && (udma_100) && (udma_66) && (udma_33)) { + speed = XFER_UDMA_5; + } else if ((id->dma_ultra & 0x0010) && (udma_66) && (udma_33)) { speed = XFER_UDMA_4; } else if ((id->dma_ultra & 0x0008) && (udma_66) && (udma_33)) { speed = XFER_UDMA_3; @@ -483,7 +502,7 @@ if (cmd64x_tune_chipset(drive, speed)) return ((int) ide_dma_off); - rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on : + rval = (int)( ((id->dma_ultra >> 11) & 7) ? ide_dma_on : ((id->dma_ultra >> 8) & 7) ? ide_dma_on : ((id->dma_mword >> 8) & 7) ? ide_dma_on : ((id->dma_1word >> 8) & 7) ? ide_dma_on : @@ -500,12 +519,15 @@ unsigned int class_rev = 0; byte can_ultra_33 = 0; byte can_ultra_66 = 0; + byte can_ultra_100 = 0; ide_dma_action_t dma_func = ide_dma_on; pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; switch(dev->device) { + case PCI_DEVICE_ID_CMD_649: + can_ultra_100 = 1; case PCI_DEVICE_ID_CMD_648: can_ultra_66 = 1; case PCI_DEVICE_ID_CMD_643: @@ -514,6 +536,7 @@ case PCI_DEVICE_ID_CMD_646: can_ultra_33 = (class_rev >= 0x05) ? 1 : 0; can_ultra_66 = 0; + can_ultra_100 = 0; break; default: return hwif->dmaproc(ide_dma_off, drive); @@ -528,7 +551,7 @@ } dma_func = ide_dma_off_quietly; if ((id->field_valid & 4) && (can_ultra_33)) { - if (id->dma_ultra & 0x001F) { + if (id->dma_ultra & 0x002F) { /* Force if Capable UltraDMA */ dma_func = config_chipset_for_dma(drive, class_rev, can_ultra_66); if ((id->field_valid & 2) && @@ -636,6 +659,7 @@ printk("\n"); break; case PCI_DEVICE_ID_CMD_648: + case PCI_DEVICE_ID_CMD_649: break; default: break; @@ -714,6 +738,7 @@ #ifdef CONFIG_BLK_DEV_IDEDMA switch(dev->device) { + case PCI_DEVICE_ID_CMD_649: case PCI_DEVICE_ID_CMD_648: case PCI_DEVICE_ID_CMD_643: hwif->dmaproc = &cmd64x_dmaproc; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/cs5530.c linux/drivers/ide/cs5530.c --- v2.4.0-test1/linux/drivers/ide/cs5530.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/cs5530.c Tue Jun 20 07:52:36 2000 @@ -1,7 +1,7 @@ /* * linux/drivers/ide/cs5530.c Version 0.6 Mar. 18, 2000 * - * Copyright (C) 2000 Andre Hedrick + * Copyright (C) 2000 Andre Hedrick * Ditto of GNU General Public License. * * Copyright (C) 2000 Mark Lord @@ -43,7 +43,7 @@ static int cs5530_get_info (char *buffer, char **addr, off_t offset, int count) { char *p = buffer; - u32 bibma = bmide_dev->resource[4].start; + u32 bibma = pci_resource_start(bmide_dev, 4); u8 c0 = 0, c1 = 0; /* diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/cy82c693.c linux/drivers/ide/cy82c693.c --- v2.4.0-test1/linux/drivers/ide/cy82c693.c Wed Apr 26 16:34:07 2000 +++ linux/drivers/ide/cy82c693.c Tue Jun 20 07:52:36 2000 @@ -1,8 +1,8 @@ /* * linux/drivers/ide/cy82c693.c Version 0.34 Dec. 13, 1999 * - * Copyright (C) 1998-99 Andreas S. Krebs (akrebs@altavista.net), Maintainer - * Copyright (C) 1998-99 Andre Hedrick, Integrater + * Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer + * Copyright (C) 1998-2000 Andre Hedrick , Integrater * * CYPRESS CY82C693 chipset IDE controller * diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/gayle.c linux/drivers/ide/gayle.c --- v2.4.0-test1/linux/drivers/ide/gayle.c Wed Apr 26 16:34:07 2000 +++ linux/drivers/ide/gayle.c Tue Jun 20 07:52:36 2000 @@ -67,11 +67,13 @@ #define GAYLE_NUM_HWIFS 1 #define GAYLE_NUM_PROBE_HWIFS GAYLE_NUM_HWIFS #define GAYLE_HAS_CONTROL_REG 1 +#define GAYLE_IDEREG_SIZE 0x2000 #else /* CONFIG_BLK_DEV_IDEDOUBLER */ #define GAYLE_NUM_HWIFS 2 #define GAYLE_NUM_PROBE_HWIFS (ide_doubler ? GAYLE_NUM_HWIFS : \ GAYLE_NUM_HWIFS-1) #define GAYLE_HAS_CONTROL_REG (!ide_doubler) +#define GAYLE_IDEREG_SIZE (ide_doubler ? 0x1000 : 0x2000) int ide_doubler = 0; /* support IDE doublers? */ #endif /* CONFIG_BLK_DEV_IDEDOUBLER */ @@ -121,23 +123,27 @@ ide_ack_intr_t *ack_intr; hw_regs_t hw; int index; + unsigned long phys_base, res_start, res_n; if (a4000) { - base = (ide_ioreg_t)ZTWO_VADDR(GAYLE_BASE_4000); + phys_base = GAYLE_BASE_4000; irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_4000); ack_intr = gayle_ack_intr_a4000; } else { - base = (ide_ioreg_t)ZTWO_VADDR(GAYLE_BASE_1200); + phys_base = GAYLE_BASE_1200; irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_1200); ack_intr = gayle_ack_intr_a1200; } + phys_base += i*GAYLE_NEXT_PORT; - if (GAYLE_HAS_CONTROL_REG) - ctrlport = base + GAYLE_CONTROL; - else - ctrlport = 0; + res_start = ((unsigned long)phys_base) & ~(GAYLE_NEXT_PORT-1); + res_n = GAYLE_IDEREG_SIZE; - base += i*GAYLE_NEXT_PORT; + if (!request_mem_region(res_start, res_n, "IDE")) + continue; + + base = (ide_ioreg_t)ZTWO_VADDR(phys_base); + ctrlport = GAYLE_HAS_CONTROL_REG ? (base + GAYLE_CONTROL) : 0; ide_setup_ports(&hw, base, gayle_offsets, ctrlport, irqport, ack_intr, IRQ_AMIGA_PORTS); @@ -155,7 +161,9 @@ break; #endif /* CONFIG_BLK_DEV_IDEDOUBLER */ } - } + } else + release_mem_region(res_start, res_n); + #if 1 /* TESTING */ if (i == 1) { volatile u_short *addr = (u_short *)base; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/hd.c linux/drivers/ide/hd.c --- v2.4.0-test1/linux/drivers/ide/hd.c Mon Jun 19 16:31:59 2000 +++ linux/drivers/ide/hd.c Tue Jun 20 07:52:36 2000 @@ -889,7 +889,7 @@ (void) get_options(line, ARRAY_SIZE(ints), ints); hd_setup(NULL, ints); - return 0; + return 1; } __setup("hd=", parse_hd_setup); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/hpt34x.c linux/drivers/ide/hpt34x.c --- v2.4.0-test1/linux/drivers/ide/hpt34x.c Tue May 23 15:31:34 2000 +++ linux/drivers/ide/hpt34x.c Tue Jun 20 07:52:36 2000 @@ -1,7 +1,7 @@ /* - * linux/drivers/ide/hpt34x.c Version 0.30 Mar. 18, 2000 + * linux/drivers/ide/hpt34x.c Version 0.31 June. 9, 2000 * - * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com) + * Copyright (C) 1998-2000 Andre Hedrick * May be copied or modified under the terms of the GNU General Public License * * @@ -62,7 +62,7 @@ static int hpt34x_get_info (char *buffer, char **addr, off_t offset, int count) { char *p = buffer; - u32 bibma = bmide_dev->resource[4].start; + u32 bibma = pci_resource_start(bmide_dev, 4); u8 c0 = 0, c1 = 0; /* @@ -360,7 +360,7 @@ unsigned int __init pci_init_hpt34x (struct pci_dev *dev, const char *name) { int i = 0; - unsigned long hpt34xIoBase = dev->resource[4].start; + unsigned long hpt34xIoBase = pci_resource_start(dev, 4); unsigned short cmd; unsigned long flags; @@ -371,7 +371,7 @@ pci_read_config_word(dev, PCI_COMMAND, &cmd); if (cmd & PCI_COMMAND_MEMORY) { - if (dev->resource[PCI_ROM_RESOURCE].start) { + if (pci_resource_start(dev, PCI_ROM_RESOURCE)) { pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n", dev->resource[PCI_ROM_RESOURCE].start); } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/hpt366.c linux/drivers/ide/hpt366.c --- v2.4.0-test1/linux/drivers/ide/hpt366.c Tue May 23 15:31:34 2000 +++ linux/drivers/ide/hpt366.c Tue Jun 20 07:52:36 2000 @@ -1,13 +1,16 @@ /* - * linux/drivers/ide/hpt366.c Version 0.17 Mar. 18, 2000 + * linux/drivers/ide/hpt366.c Version 0.18 June. 9, 2000 * - * Copyright (C) 1999-2000 Andre Hedrick + * Copyright (C) 1999-2000 Andre Hedrick * May be copied or modified under the terms of the GNU General Public License * * Thanks to HighPoint Technologies for their assistance, and hardware. * Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his * donation of an ABit BP6 mainboard, processor, and memory acellerated * development and support. + * + * Note that final HPT370 support was done by force extraction of GPL. + * */ #include @@ -30,13 +33,26 @@ #include "ide_modes.h" -#undef DISPLAY_HPT366_TIMINGS +#define DISPLAY_HPT366_TIMINGS #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) #include #include #endif /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */ +extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc); + +const char *quirk_drives[] = { + "QUANTUM FIREBALLlct08 08", + "QUANTUM FIREBALLP KA6.4", + "QUANTUM FIREBALLP LM20.5", + NULL +}; + +const char *bad_ata100_5[] = { + NULL +}; + const char *bad_ata66_4[] = { "WDC AC310200R", NULL @@ -60,70 +76,92 @@ struct chipset_bus_clock_list_entry { byte xfer_speed; - unsigned int chipset_settings; + unsigned int chipset_settings_write; + unsigned int chipset_settings_read; }; struct chipset_bus_clock_list_entry forty_base [] = { - { XFER_UDMA_4 , 0x900fd943 }, - { XFER_UDMA_3 , 0x900ad943 }, - { XFER_UDMA_2 , 0x900bd943 }, - { XFER_UDMA_1 , 0x9008d943 }, - { XFER_UDMA_0 , 0x9008d943 }, - - { XFER_MW_DMA_2 , 0xa008d943 }, - { XFER_MW_DMA_1 , 0xa010d955 }, - { XFER_MW_DMA_0 , 0xa010d9fc }, - - { XFER_PIO_4 , 0xc008d963 }, - { XFER_PIO_3 , 0xc010d974 }, - { XFER_PIO_2 , 0xc010d997 }, - { XFER_PIO_1 , 0xc010d9c7 }, - { XFER_PIO_0 , 0xc018d9d9 }, - { 0 , 0x0120d9d9 } + { XFER_UDMA_4, 0x900fd943, 0x900fd943 }, + { XFER_UDMA_3, 0x900ad943, 0x900ad943 }, + { XFER_UDMA_2, 0x900bd943, 0x900bd943 }, + { XFER_UDMA_1, 0x9008d943, 0x9008d943 }, + { XFER_UDMA_0, 0x9008d943, 0x9008d943 }, + + { XFER_MW_DMA_2, 0xa008d943, 0xa008d943 }, + { XFER_MW_DMA_1, 0xa010d955, 0xa010d955 }, + { XFER_MW_DMA_0, 0xa010d9fc, 0xa010d9fc }, + + { XFER_PIO_4, 0xc008d963, 0xc008d963 }, + { XFER_PIO_3, 0xc010d974, 0xc010d974 }, + { XFER_PIO_2, 0xc010d997, 0xc010d997 }, + { XFER_PIO_1, 0xc010d9c7, 0xc010d9c7 }, + { XFER_PIO_0, 0xc018d9d9, 0xc018d9d9 }, + { 0, 0x0120d9d9, 0x0120d9d9 } }; struct chipset_bus_clock_list_entry thirty_three_base [] = { - { XFER_UDMA_4 , 0x90c9a731 }, - { XFER_UDMA_3 , 0x90cfa731 }, - { XFER_UDMA_2 , 0x90caa731 }, - { XFER_UDMA_1 , 0x90cba731 }, - { XFER_UDMA_0 , 0x90c8a731 }, - - { XFER_MW_DMA_2 , 0xa0c8a731 }, - { XFER_MW_DMA_1 , 0xa0c8a732 }, /* 0xa0c8a733 */ - { XFER_MW_DMA_0 , 0xa0c8a797 }, - - { XFER_PIO_4 , 0xc0c8a731 }, - { XFER_PIO_3 , 0xc0c8a742 }, - { XFER_PIO_2 , 0xc0d0a753 }, - { XFER_PIO_1 , 0xc0d0a7a3 }, /* 0xc0d0a793 */ - { XFER_PIO_0 , 0xc0d0a7aa }, /* 0xc0d0a7a7 */ - { 0 , 0x0120a7a7 } + { XFER_UDMA_4, 0x90c9a731, 0x90c9a731 }, + { XFER_UDMA_3, 0x90cfa731, 0x90cfa731 }, + { XFER_UDMA_2, 0x90caa731, 0x90caa731 }, + { XFER_UDMA_1, 0x90cba731, 0x90cba731 }, + { XFER_UDMA_0, 0x90c8a731, 0x90c8a731 }, + + { XFER_MW_DMA_2, 0xa0c8a731, 0xa0c8a731 }, + { XFER_MW_DMA_1, 0xa0c8a732, 0xa0c8a732 }, /* 0xa0c8a733 */ + { XFER_MW_DMA_0, 0xa0c8a797, 0xa0c8a797 }, + + { XFER_PIO_4, 0xc0c8a731, 0xc0c8a731 }, + { XFER_PIO_3, 0xc0c8a742, 0xc0c8a742 }, + { XFER_PIO_2, 0xc0d0a753, 0xc0d0a753 }, + { XFER_PIO_1, 0xc0d0a7a3, 0xc0d0a7a3 }, /* 0xc0d0a793 */ + { XFER_PIO_0, 0xc0d0a7aa, 0xc0d0a7aa }, /* 0xc0d0a7a7 */ + { 0, 0x0120a7a7, 0x0120a7a7 } }; struct chipset_bus_clock_list_entry twenty_five_base [] = { - { XFER_UDMA_4 , 0x90c98521 }, - { XFER_UDMA_3 , 0x90cf8521 }, - { XFER_UDMA_2 , 0x90cf8521 }, - { XFER_UDMA_1 , 0x90cb8521 }, - { XFER_UDMA_0 , 0x90cb8521 }, - - { XFER_MW_DMA_2 , 0xa0ca8521 }, - { XFER_MW_DMA_1 , 0xa0ca8532 }, - { XFER_MW_DMA_0 , 0xa0ca8575 }, - - { XFER_PIO_4 , 0xc0ca8521 }, - { XFER_PIO_3 , 0xc0ca8532 }, - { XFER_PIO_2 , 0xc0ca8542 }, - { XFER_PIO_1 , 0xc0d08572 }, - { XFER_PIO_0 , 0xc0d08585 }, - { 0 , 0x01208585 } + { XFER_UDMA_4, 0x90c98521, 0x90c98521 }, + { XFER_UDMA_3, 0x90cf8521, 0x90cf8521 }, + { XFER_UDMA_2, 0x90cf8521, 0x90cf8521 }, + { XFER_UDMA_1, 0x90cb8521, 0x90cb8521 }, + { XFER_UDMA_0, 0x90cb8521, 0x90cb8521 }, + + { XFER_MW_DMA_2, 0xa0ca8521, 0xa0ca8521 }, + { XFER_MW_DMA_1, 0xa0ca8532, 0xa0ca8532 }, + { XFER_MW_DMA_0, 0xa0ca8575, 0xa0ca8575 }, + + { XFER_PIO_4, 0xc0ca8521, 0xc0ca8521 }, + { XFER_PIO_3, 0xc0ca8532, 0xc0ca8532 }, + { XFER_PIO_2, 0xc0ca8542, 0xc0ca8542 }, + { XFER_PIO_1, 0xc0d08572, 0xc0d08572 }, + { XFER_PIO_0, 0xc0d08585, 0xc0d08585 }, + { 0, 0x01208585, 0x01208585 } +}; + +struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = { + { XFER_UDMA_5, 0x1A85F442, 0x16454e31 }, + { XFER_UDMA_4, 0x16454e31, 0x16454e31 }, + { XFER_UDMA_3, 0x166d4e31, 0x166d4e31 }, + { XFER_UDMA_2, 0x16494e31, 0x16494e31 }, + { XFER_UDMA_1, 0x164d4e31, 0x164d4e31 }, + { XFER_UDMA_0, 0x16514e31, 0x16514e31 }, + + { XFER_MW_DMA_2, 0x26514e21, 0x26514e21 }, + { XFER_MW_DMA_1, 0x26514e33, 0x26514e33 }, + { XFER_MW_DMA_0, 0x26514e97, 0x26514e97 }, + + { XFER_PIO_4, 0x06514e21, 0x06514e21 }, + { XFER_PIO_3, 0x06514e22, 0x06514e22 }, + { XFER_PIO_2, 0x06514e33, 0x06514e33 }, + { XFER_PIO_1, 0x06914e43, 0x06914e43 }, + { XFER_PIO_0, 0x06914e57, 0x06914e57 }, + { 0, 0x06514e57, 0x06514e57 } }; #define HPT366_DEBUG_DRIVE_INFO 0 +#define HPT370_ALLOW_ATA100_5 1 #define HPT366_ALLOW_ATA66_4 1 #define HPT366_ALLOW_ATA66_3 1 @@ -139,7 +177,12 @@ char *p = buffer; u32 bibma = bmide_dev->resource[4].start; u32 bibma2 = bmide2_dev->resource[4].start; + char *chipset_names[] = {"HPT366", "HPT366", "HPT368", "HPT370", "HPT370A"}; u8 c0 = 0, c1 = 0; + u32 class_rev; + + pci_read_config_dword(bmide_dev, PCI_CLASS_REVISION, &class_rev); + class_rev &= 0xff; /* * at that point bibma+0x2 et bibma+0xa are byte registers @@ -149,7 +192,7 @@ if (bmide2_dev) c1 = inb_p((unsigned short)bibma2 + 0x02); - p += sprintf(p, "\n HPT366 Chipset.\n"); + p += sprintf(p, "\n %s Chipset.\n", chipset_names[class_rev]); p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); p += sprintf(p, " %sabled %sabled\n", (c0&0x80) ? "dis" : " en", @@ -173,74 +216,74 @@ byte hpt363_shared_irq = 0; byte hpt363_shared_pin = 0; -static unsigned int pci_rev_check_hpt366 (struct pci_dev *dev) +static unsigned int pci_rev_check_hpt3xx (struct pci_dev *dev) { unsigned int class_rev; pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; - return ((int) (class_rev == 0x03) ? 1 : 0); + return ((int) (class_rev > 0x02) ? 1 : 0); } static int check_in_drive_lists (ide_drive_t *drive, const char **list) { struct hd_driveid *id = drive->id; -#if HPT366_DEBUG_DRIVE_INFO - printk("check_in_drive_lists(%s, %p)\n", drive->name, list); -#endif /* HPT366_DEBUG_DRIVE_INFO */ - while (*list) { - if (!strcmp(*list++,id->model)) { -#ifdef DEBUG - printk("%s: Broken ASIC, BackSpeeding (U)DMA for %s\n", drive->name, id->model); -#endif /* DEBUG */ - return 1; + if (quirk_drives == list) { + while (*list) { + if (strstr(id->model, *list++)) { + return 1; + } + } + } else { + while (*list) { + if (!strcmp(*list++,id->model)) { + return 1; + } } } return 0; } -static unsigned int pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table) +static unsigned int pci_bus_clock_list (byte speed, int direction, struct chipset_bus_clock_list_entry * chipset_table) { -#if HPT366_DEBUG_DRIVE_INFO - printk("pci_bus_clock_list(speed=0x%02x, table=%p)\n", speed, chipset_table); -#endif /* HPT366_DEBUG_DRIVE_INFO */ for ( ; chipset_table->xfer_speed ; chipset_table++) if (chipset_table->xfer_speed == speed) { -#if HPT366_DEBUG_DRIVE_INFO - printk("pci_bus_clock_list: found match: 0x%08x\n", chipset_table->chipset_settings); -#endif /* HPT366_DEBUG_DRIVE_INFO */ - return chipset_table->chipset_settings; + return (direction) ? chipset_table->chipset_settings_write : chipset_table->chipset_settings_read; } -#if HPT366_DEBUG_DRIVE_INFO - printk("pci_bus_clock_list: using default: 0x%08x\n", 0x01208585); -#endif /* HPT366_DEBUG_DRIVE_INFO */ - return 0x01208585; + return (direction) ? chipset_table->chipset_settings_write : chipset_table->chipset_settings_read; } -static int hpt366_tune_chipset (ide_drive_t *drive, byte speed) +static void hpt366_tune_chipset (ide_drive_t *drive, byte speed, int direction) { - int err; byte regtime = (drive->select.b.unit & 0x01) ? 0x44 : 0x40; + byte regfast = (HWIF(drive)->channel) ? 0x55 : 0x51; + /* + * since the channel is always 0 it does not matter. + */ + unsigned int reg1 = 0; unsigned int reg2 = 0; + byte drive_fast = 0; -#if HPT366_DEBUG_DRIVE_INFO - printk("hpt366_tune_chipset(%s, speed=0x%02x)\n", drive->name, speed); -#endif /* HPT366_DEBUG_DRIVE_INFO */ + /* + * Disable the "fast interrupt" prediction. + */ + pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast); + if (drive_fast & 0x02) + pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast & ~0x20); pci_read_config_dword(HWIF(drive)->pci_dev, regtime, ®1); /* detect bus speed by looking at control reg timing: */ switch((reg1 >> 8) & 7) { case 5: - reg2 = pci_bus_clock_list(speed, forty_base); + reg2 = pci_bus_clock_list(speed, direction, forty_base); break; case 9: - reg2 = pci_bus_clock_list(speed, twenty_five_base); + reg2 = pci_bus_clock_list(speed, direction, twenty_five_base); break; default: - printk("hpt366: assuming 33Mhz PCI bus\n"); case 7: - reg2 = pci_bus_clock_list(speed, thirty_three_base); + reg2 = pci_bus_clock_list(speed, direction, thirty_three_base); break; } /* @@ -254,18 +297,56 @@ reg2 &= ~0x80000000; pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2); - err = ide_config_drive_speed(drive, speed); +} +static void hpt370_tune_chipset (ide_drive_t *drive, byte speed, int direction) +{ + byte regfast = (HWIF(drive)->channel) ? 0x55 : 0x51; + byte reg5bh = (speed != XFER_UDMA_5) ? 0x22 : (direction) ? 0x20 : 0x22; + unsigned int list_conf = pci_bus_clock_list(speed, direction, thirty_three_base_hpt370); + unsigned int drive_conf = 0; + unsigned int conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000; + byte drive_pci = 0; + byte drive_fast = 0; + + switch (drive->dn) { + case 0: drive_pci = 0x40; break; + case 1: drive_pci = 0x44; break; + case 2: drive_pci = 0x48; break; + case 3: drive_pci = 0x4c; break; + default: return; + } + /* + * Disable the "fast interrupt" prediction. + */ + pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast); + if (drive_fast & 0x80) + pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast & ~0x80); + + pci_read_config_dword(HWIF(drive)->pci_dev, drive_pci, &drive_conf); + pci_write_config_byte(HWIF(drive)->pci_dev, 0x5b, reg5bh); + + list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask); + /* + * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later) + */ + list_conf &= ~0x80000000; + + pci_write_config_dword(HWIF(drive)->pci_dev, drive_pci, list_conf); +} + +static int hpt3xx_tune_chipset (ide_drive_t *drive, byte speed) +{ if (!drive->init_speed) drive->init_speed = speed; -#if HPT366_DEBUG_DRIVE_INFO - printk("%s: speed=0x%02x(%s), drive%d, old=0x%08x, new=0x%08x, err=0x%04x\n", - drive->name, speed, ide_xfer_verbose(speed), - drive->dn, reg1, reg2, err); -#endif /* HPT366_DEBUG_DRIVE_INFO */ + if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) { + hpt370_tune_chipset(drive, speed, 0); + } else { + hpt366_tune_chipset(drive, speed, 0); + } drive->current_speed = speed; - return(err); + return ((int) ide_config_drive_speed(drive, speed)); } static void config_chipset_for_pio (ide_drive_t *drive) @@ -274,9 +355,6 @@ unsigned short xfer_pio = drive->id->eide_pio_modes; byte timing, speed, pio; -#if HPT366_DEBUG_DRIVE_INFO - printk("%s: config_chipset_for_pio\n", drive->name); -#endif /* HPT366_DEBUG_DRIVE_INFO */ pio = ide_get_best_pio_mode(drive, 255, 5, NULL); if (xfer_pio> 4) @@ -306,13 +384,10 @@ speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW; break; } -#if HPT366_DEBUG_DRIVE_INFO - printk("%s: config_chipset_for_pio: speed=0x%04x\n", drive->name, speed); -#endif /* HPT366_DEBUG_DRIVE_INFO */ - (void) hpt366_tune_chipset(drive, speed); + (void) hpt3xx_tune_chipset(drive, speed); } -static void hpt366_tune_drive (ide_drive_t *drive, byte pio) +static void hpt3xx_tune_drive (ide_drive_t *drive, byte pio) { byte speed; switch(pio) { @@ -322,7 +397,7 @@ case 1: speed = XFER_PIO_1;break; default: speed = XFER_PIO_0;break; } - (void) hpt366_tune_chipset(drive, speed); + (void) hpt3xx_tune_chipset(drive, speed); } #ifdef CONFIG_BLK_DEV_IDEDMA @@ -341,18 +416,24 @@ { struct hd_driveid *id = drive->id; byte speed = 0x00; - byte reg51h = 0; + byte ultra66 = eighty_ninty_three(drive); int rval; - if ((id->dma_ultra & 0x0010) && - (!check_in_drive_lists(drive, bad_ata66_4)) && - (HPT366_ALLOW_ATA66_4) && - (HWIF(drive)->udma_four)) { + if ((id->dma_ultra & 0x0020) && + (!check_in_drive_lists(drive, bad_ata100_5)) && + (HPT370_ALLOW_ATA100_5) && + (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) && + (ultra66)) { + speed = XFER_UDMA_5; + } else if ((id->dma_ultra & 0x0010) && + (!check_in_drive_lists(drive, bad_ata66_4)) && + (HPT366_ALLOW_ATA66_4) && + (ultra66)) { speed = XFER_UDMA_4; } else if ((id->dma_ultra & 0x0008) && (!check_in_drive_lists(drive, bad_ata66_3)) && (HPT366_ALLOW_ATA66_3) && - (HWIF(drive)->udma_four)) { + (ultra66)) { speed = XFER_UDMA_3; } else if (id->dma_ultra && (!check_in_drive_lists(drive, bad_ata33))) { if (id->dma_ultra & 0x0004) { @@ -368,52 +449,56 @@ speed = XFER_MW_DMA_1; } else if (id->dma_mword & 0x0001) { speed = XFER_MW_DMA_0; - } else if (id->dma_1word & 0x0004) { - speed = XFER_SW_DMA_2; - } else if (id->dma_1word & 0x0002) { - speed = XFER_SW_DMA_1; - } else if (id->dma_1word & 0x0001) { - speed = XFER_SW_DMA_0; - } else { -#if HPT366_DEBUG_DRIVE_INFO - printk("%s: config_chipset_for_dma: returning 'ide_dma_off_quietly'\n", drive->name); -#endif /* HPT366_DEBUG_DRIVE_INFO */ + } else { return ((int) ide_dma_off_quietly); } - pci_read_config_byte(HWIF(drive)->pci_dev, 0x51, ®51h); + (void) hpt3xx_tune_chipset(drive, speed); -#ifdef CONFIG_HPT366_FIP - /* - * Some drives prefer/allow for the method of handling interrupts. - */ - if (!(reg51h & 0x80)) - pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, reg51h|0x80); -#else /* ! CONFIG_HPT366_FIP */ - /* - * Disable the "fast interrupt" prediction. - * Instead, always wait for the real interrupt from the drive! - */ - if (reg51h & 0x80) - pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, reg51h & ~0x80); -#endif /* CONFIG_HPT366_FIP */ -#if HPT366_DEBUG_DRIVE_INFO - printk("%s: config_chipset_for_dma: speed=0x%04x\n", drive->name, speed); -#endif /* HPT366_DEBUG_DRIVE_INFO */ - (void) hpt366_tune_chipset(drive, speed); - - rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on : + rval = (int)( ((id->dma_ultra >> 11) & 7) ? ide_dma_on : ((id->dma_ultra >> 8) & 7) ? ide_dma_on : ((id->dma_mword >> 8) & 7) ? ide_dma_on : - ((id->dma_1word >> 8) & 7) ? ide_dma_on : ide_dma_off_quietly); - -#if HPT366_DEBUG_DRIVE_INFO - printk("%s: config_chipset_for_dma: returning %d (%s)\n", drive->name, rval, rval == ide_dma_on ? "dma_on" : "dma_off"); -#endif /* HPT366_DEBUG_DRIVE_INFO */ return rval; } +int hpt3xx_quirkproc (ide_drive_t *drive) +{ + return ((int) check_in_drive_lists(drive, quirk_drives)); +} + +void hpt3xx_intrproc (ide_drive_t *drive) +{ +} + +void hpt3xx_maskproc (ide_drive_t *drive, int mask) +{ + if (drive->quirk_list) { + if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) { + byte reg5a = 0; + pci_read_config_byte(HWIF(drive)->pci_dev, 0x5a, ®5a); + if (((reg5a & 0x10) >> 4) != mask) + pci_write_config_byte(HWIF(drive)->pci_dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10)); + } else { + if (mask) { + disable_irq(HWIF(drive)->irq); + } else { + enable_irq(HWIF(drive)->irq); + } + } + } else { + if (IDE_CONTROL_REG) + OUT_BYTE(mask ? (drive->ctl | 2) : (drive->ctl & ~2), IDE_CONTROL_REG); + } +} + +void hpt370_rw_proc (ide_drive_t *drive, ide_dma_action_t func) +{ + if ((func != ide_dma_write) || (func != ide_dma_read)) + return; + hpt370_tune_chipset(drive, drive->current_speed, (func == ide_dma_write)); +} + static int config_drive_xfer_rate (ide_drive_t *drive) { struct hd_driveid *id = drive->id; @@ -427,7 +512,7 @@ } dma_func = ide_dma_off_quietly; if (id->field_valid & 4) { - if (id->dma_ultra & 0x001F) { + if (id->dma_ultra & 0x002F) { /* Force if Capable UltraDMA */ dma_func = config_chipset_for_dma(drive); if ((id->field_valid & 2) && @@ -436,8 +521,7 @@ } } else if (id->field_valid & 2) { try_dma_modes: - if ((id->dma_mword & 0x0007) || - (id->dma_1word & 0x0007)) { + if (id->dma_mword & 0x0007) { /* Force if Capable regular DMA modes */ dma_func = config_chipset_for_dma(drive); if (dma_func != ide_dma_on) @@ -472,24 +556,39 @@ */ int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { - byte reg50h = 0; + byte reg50h = 0, reg52h = 0, reg5ah = 0; switch (func) { case ide_dma_check: return config_drive_xfer_rate(drive); case ide_dma_lostirq: -#if 0 - pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, ®50h); - pci_write_config_byte(HWIF(drive)->pci_dev, 0x50, reg50h|0x03); pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, ®50h); - /* ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); */ -#endif + pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, ®52h); + pci_read_config_byte(HWIF(drive)->pci_dev, 0x5a, ®5ah); + printk("%s: (%s) reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n", + drive->name, + ide_dmafunc_verbose(func), + reg50h, reg52h, reg5ah); + if (reg5ah & 0x10) + pci_write_config_byte(HWIF(drive)->pci_dev, 0x5a, reg5ah & ~0x10); + break; case ide_dma_timeout: default: break; } return ide_dmaproc(func, drive); /* use standard DMA stuff */ } + +int hpt370_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +{ + switch (func) { + case ide_dma_check: + return config_drive_xfer_rate(drive); + default: + break; + } + return ide_dmaproc(func, drive); /* use standard DMA stuff */ +} #endif /* CONFIG_BLK_DEV_IDEDMA */ unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name) @@ -519,7 +618,7 @@ if (!hpt366_proc) { hpt366_proc = 1; bmide_dev = dev; - if (pci_rev_check_hpt366(dev)) + if (pci_rev_check_hpt3xx(dev)) bmide2_dev = dev; hpt366_display_info = &hpt366_get_info; } @@ -546,14 +645,24 @@ void __init ide_init_hpt366 (ide_hwif_t *hwif) { - if (pci_rev_check_hpt366(hwif->pci_dev)) return; - - hwif->tuneproc = &hpt366_tune_drive; - hwif->speedproc = &hpt366_tune_chipset; + hwif->tuneproc = &hpt3xx_tune_drive; + hwif->speedproc = &hpt3xx_tune_chipset; + hwif->quirkproc = &hpt3xx_quirkproc; + hwif->intrproc = &hpt3xx_intrproc; + hwif->maskproc = &hpt3xx_maskproc; #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { - hwif->dmaproc = &hpt366_dmaproc; + if (pci_rev_check_hpt3xx(hwif->pci_dev)) { + byte reg5ah = 0; + pci_read_config_byte(hwif->pci_dev, 0x5a, ®5ah); + if (reg5ah & 0x10) /* interrupt force enable */ + pci_write_config_byte(hwif->pci_dev, 0x5a, reg5ah & ~0x10); + hwif->dmaproc = &hpt370_dmaproc; + hwif->rwproc = &hpt370_rw_proc; + } else { + hwif->dmaproc = &hpt366_dmaproc; + } hwif->autodma = 1; } else { hwif->autodma = 0; @@ -571,19 +680,16 @@ { byte masterdma = 0, slavedma = 0; byte dma_new = 0, dma_old = inb(dmabase+2); + byte primary = hwif->channel ? 0x4b : 0x43; + byte secondary = hwif->channel ? 0x4f : 0x47; unsigned long flags; - if (pci_rev_check_hpt366(hwif->pci_dev)) { - ide_setup_dma(hwif, dmabase, 8); - return; - } - __save_flags(flags); /* local CPU only */ __cli(); /* local CPU only */ dma_new = dma_old; - pci_read_config_byte(hwif->pci_dev, 0x43, &masterdma); - pci_read_config_byte(hwif->pci_dev, 0x47, &slavedma); + pci_read_config_byte(hwif->pci_dev, primary, &masterdma); + pci_read_config_byte(hwif->pci_dev, secondary, &slavedma); if (masterdma & 0x30) dma_new |= 0x20; if (slavedma & 0x30) dma_new |= 0x40; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/icside.c linux/drivers/ide/icside.c --- v2.4.0-test1/linux/drivers/ide/icside.c Tue May 23 15:31:34 2000 +++ linux/drivers/ide/icside.c Tue Jun 20 07:52:36 2000 @@ -351,7 +351,7 @@ static int icside_set_speed(ide_drive_t *drive, byte speed) { - return ((int) icside_config_if(drive, (int) speed)); + return icside_config_if(drive, speed); } static int @@ -508,9 +508,9 @@ goto failed; } - hwif->dmaproc = &icside_dmaproc; + hwif->speedproc = icside_set_speed; + hwif->dmaproc = icside_dmaproc; hwif->autodma = autodma; - hwif->speedproc = &icside_set_speed; printk(" capable%s\n", autodma ? ", auto-enable" : ""); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/ide-cd.c linux/drivers/ide/ide-cd.c --- v2.4.0-test1/linux/drivers/ide/ide-cd.c Thu May 11 15:30:07 2000 +++ linux/drivers/ide/ide-cd.c Wed Jun 21 22:31:01 2000 @@ -426,11 +426,13 @@ while (hi > lo) { mid = (lo + hi) / 2; - if (packet_command_texts[mid].packet_command == failed_command->c[0]) { + if (packet_command_texts[mid].packet_command == + failed_command->c[0]) { s = packet_command_texts[mid].text; break; } - else if (packet_command_texts[mid].packet_command > failed_command->c[0]) + if (packet_command_texts[mid].packet_command > + failed_command->c[0]) hi = mid; else lo = mid+1; @@ -1524,7 +1526,7 @@ memset(&pc, 0, sizeof(pc)); pc.sense = sense; pc.c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL; - pc.c[4] = lockflag ? 3 : 0; + pc.c[4] = lockflag ? 1 : 0; stat = cdrom_queue_packet_command (drive, &pc); } @@ -1624,7 +1626,8 @@ /* Try to read the entire TOC for the disk into our internal buffer. */ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) { - int stat, ntracks, i; + int minor, stat, ntracks, i; + kdev_t dev; struct cdrom_info *info = drive->driver_data; struct atapi_toc *toc = info->toc; struct { @@ -1663,8 +1666,10 @@ #endif /* not STANDARD_ATAPI */ ntracks = toc->hdr.last_track - toc->hdr.first_track + 1; - if (ntracks <= 0) return -EIO; - if (ntracks > MAX_TRACKS) ntracks = MAX_TRACKS; + if (ntracks <= 0) + return -EIO; + if (ntracks > MAX_TRACKS) + ntracks = MAX_TRACKS; /* Now read the whole schmeer. */ stat = cdrom_read_tocentry(drive, toc->hdr.first_track, 1, 0, @@ -1755,13 +1760,13 @@ toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track); /* Now try to get the total cdrom capacity. */ -#if 0 - stat = cdrom_get_last_written(MKDEV(HWIF(drive)->major, minor), - (long *)&toc->capacity); + minor = (drive->select.b.unit) << PARTN_BITS; + dev = MKDEV(HWIF(drive)->major, minor); + stat = cdrom_get_last_written(dev, (long *)&toc->capacity); if (stat) -#endif - stat = cdrom_read_capacity(drive, &toc->capacity, sense); - if (stat) toc->capacity = 0x1fffff; + stat = cdrom_read_capacity(drive, &toc->capacity, sense); + if (stat) + toc->capacity = 0x1fffff; /* Remember that we've read this stuff. */ CDROM_STATE_FLAGS (drive)->toc_valid = 1; @@ -2194,9 +2199,9 @@ if (!CDROM_CONFIG_FLAGS (drive)->close_tray) devinfo->mask |= CDC_CLOSE_TRAY; - devinfo->de = devfs_register(drive->de, "cd", 2, DEVFS_FL_DEFAULT, + devinfo->de = devfs_register(drive->de, "cd", DEVFS_FL_DEFAULT, HWIF(drive)->major, minor, - S_IFBLK | S_IRUGO | S_IWUGO, 0, 0, + S_IFBLK | S_IRUGO | S_IWUGO, ide_fops, NULL); return register_cdrom(devinfo); @@ -2552,7 +2557,8 @@ { unsigned capacity; - return cdrom_read_capacity(drive, &capacity, NULL) ? 0 : capacity * SECTORS_PER_FRAME; + return cdrom_read_capacity(drive, &capacity, NULL) + ? 0 : capacity * SECTORS_PER_FRAME; } static diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/ide-disk.c linux/drivers/ide/ide-disk.c --- v2.4.0-test1/linux/drivers/ide/ide-disk.c Tue May 23 15:31:34 2000 +++ linux/drivers/ide/ide-disk.c Tue Jun 20 07:52:36 2000 @@ -1,14 +1,13 @@ /* - * linux/drivers/ide/ide-disk.c Version 1.09 April 23, 1999 + * linux/drivers/ide/ide-disk.c Version 1.10 June 9, 2000 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ /* * Mostly written by Mark Lord - * and Gadi Oxman - * - * See linux/MAINTAINERS for address of current maintainer. + * and Gadi Oxman + * and Andre Hedrick * * This is the IDE/ATA disk driver, as evolved from hd.c and ide.c. * @@ -27,9 +26,10 @@ * the entire disk. * Version 1.09 added increment of rq->sector in ide_multwrite * added UDMA 3/4 reporting + * Version 1.10 request queue changes, Ultra DMA 100 */ -#define IDEDISK_VERSION "1.09" +#define IDEDISK_VERSION "1.10" #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -140,11 +140,8 @@ int i; unsigned int msect, nsect; struct request *rq; -#if 0 - if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) { - return ide_error(drive, "read_intr", stat); - } -#else /* new way for dealing with premature shared PCI interrupts */ + + /* new way for dealing with premature shared PCI interrupts */ if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) { if (stat & (ERR_STAT|DRQ_STAT)) { return ide_error(drive, "read_intr", stat); @@ -153,7 +150,6 @@ ide_set_handler(drive, &read_intr, WAIT_CMD, NULL); return ide_started; } -#endif msect = drive->mult_count; read_next: @@ -688,7 +684,6 @@ { if (ide_spin_wait_hwgroup(drive)) return -EBUSY; - drive->nowerr = arg; drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT; spin_unlock_irq(&io_request_lock); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/ide-dma.c linux/drivers/ide/ide-dma.c --- v2.4.0-test1/linux/drivers/ide/ide-dma.c Wed Apr 26 16:34:07 2000 +++ linux/drivers/ide/ide-dma.c Tue Jun 20 07:52:36 2000 @@ -1,7 +1,7 @@ /* - * linux/drivers/ide/ide-dma.c Version 4.09 April 23, 1999 + * linux/drivers/ide/ide-dma.c Version 4.10 June 9, 2000 * - * Copyright (c) 1999 Andre Hedrick + * Copyright (c) 1999-2000 Andre Hedrick * May be copied or modified under the terms of the GNU General Public License */ @@ -70,12 +70,11 @@ * * And, yes, Intel Zappa boards really *do* use both PIIX IDE ports. * - * ACARD ATP850UF Chipset "Modified SCSI Class" with other names - * AEC6210 U/UF - * SIIG's UltraIDE Pro CN-2449 - * TTI HPT343 Chipset "Modified SCSI Class" but reports as an - * unknown storage device. - * NEW check_drive_lists(ide_drive_t *drive, int good_bad) + * check_drive_lists(ide_drive_t *drive, int good_bad) + * + * ATA-66/100 and recovery functions, I forgot the rest...... + * SELECT_READ_WRITE(hwif,drive,func) for active tuning based on IO direction. + * */ #include @@ -358,10 +357,11 @@ { struct hd_driveid *id = drive->id; - if ((id->field_valid & 4) && (id->hw_config & 0x2000) && - (HWIF(drive)->udma_four) && - (id->dma_ultra & (id->dma_ultra >> 11) & 3)) { - if ((id->dma_ultra >> 12) & 1) { + if ((id->field_valid & 4) && (eighty_ninty_three(drive)) && + (id->dma_ultra & (id->dma_ultra >> 11) & 7)) { + if ((id->dma_ultra >> 13) & 1) { + printk(", UDMA(100)"); /* UDMA BIOS-enabled! */ + } else if ((id->dma_ultra >> 12) & 1) { printk(", UDMA(66)"); /* UDMA BIOS-enabled! */ } else { printk(", UDMA(44)"); /* UDMA BIOS-enabled! */ @@ -393,9 +393,9 @@ if (ide_dmaproc(ide_dma_bad_drive, drive)) return hwif->dmaproc(ide_dma_off, drive); - /* Enable DMA on any drive that has UltraDMA (mode 3/4) enabled */ - if ((id->field_valid & 4) && (hwif->udma_four) && (id->hw_config & 0x2000)) - if ((id->dma_ultra & (id->dma_ultra >> 11) & 3)) + /* Enable DMA on any drive that has UltraDMA (mode 3/4/5) enabled */ + if ((id->field_valid & 4) && (eighty_ninty_three(drive))) + if ((id->dma_ultra & (id->dma_ultra >> 11) & 7)) return hwif->dmaproc(ide_dma_on, drive); /* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */ if (id->field_valid & 4) /* UltraDMA */ @@ -413,6 +413,22 @@ } /* + * 1 dmaing, 2 error, 4 intr + */ +static int dma_timer_expiry (ide_drive_t *drive) +{ + byte dma_stat = inb(HWIF(drive)->dma_base+2); + +#ifdef DEBUG + printk("%s: dma_timer_expiry: dma status == 0x%02x\n", drive->name, dma_stat); +#endif /* DEBUG */ + + if (dma_stat & 1) /* DMAing */ + return WAIT_CMD; + return 0; +} + +/* * ide_dmaproc() initiates/aborts DMA read/write operations on a drive. * * The caller is assumed to have selected the drive and programmed the drive's @@ -451,6 +467,7 @@ case ide_dma_read: reading = 1 << 3; case ide_dma_write: + SELECT_READ_WRITE(hwif,drive,func); if (!(count = ide_build_dmatable(drive, func))) return 1; /* try PIO instead of DMA */ outl(hwif->dmatable_dma, dma_base + 4); /* PRD table */ @@ -459,7 +476,7 @@ drive->waiting_for_dma = 1; if (drive->media != ide_disk) return 0; - ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); /* issue cmd to drive */ + ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, dma_timer_expiry); /* issue cmd to drive */ OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); case ide_dma_begin: /* Note that this is done *after* the cmd has @@ -570,8 +587,8 @@ if (hwif->mate && hwif->mate->dma_base) { dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8); } else { - dma_base = dev->resource[4].start; - if (!dma_base || dma_base == PCI_BASE_ADDRESS_IO_MASK) { + dma_base = pci_resource_start(dev, 4); + if (!dma_base) { printk("%s: dma_base is invalid (0x%04lx)\n", name, dma_base); dma_base = 0; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/ide-features.c linux/drivers/ide/ide-features.c --- v2.4.0-test1/linux/drivers/ide/ide-features.c Mon Jun 19 16:31:59 2000 +++ linux/drivers/ide/ide-features.c Tue Jun 20 07:52:36 2000 @@ -1,14 +1,16 @@ /* - * linux/drivers/block/ide-features.c Version 0.03 Feb. 10, 2000 + * linux/drivers/block/ide-features.c Version 0.04 June 9, 2000 * * Copyright (C) 1999-2000 Linus Torvalds & authors (see below) * - * Copyright (C) 1999-2000 Andre Hedrick + * Copyright (C) 1999-2000 Andre Hedrick * * Extracts if ide.c to address the evolving transfer rate code for * the SETFEATURES_XFER callouts. Various parts of any given function * are credited to previous ATA-IDE maintainers. * + * Auto-CRC downgrade for Ultra DMA(ing) + * * May be copied or modified under the terms of the GNU General Public License */ @@ -115,6 +117,10 @@ */ byte ide_auto_reduce_xfer (ide_drive_t *drive) { + if (!drive->crc_count) + return drive->current_speed; + drive->crc_count = 0; + switch(drive->current_speed) { case XFER_UDMA_7: return XFER_UDMA_6; case XFER_UDMA_6: return XFER_UDMA_5; @@ -164,6 +170,7 @@ probe_irq_off(probe_irq_on()); irqs = probe_irq_on(); + SELECT_MASK(HWIF(drive), drive, 1); if (IDE_CONTROL_REG) OUT_BYTE(drive->ctl,IDE_CONTROL_REG); ide_delay_50ms(); @@ -173,17 +180,20 @@ if (0 < (signed long)(jiffies - timeout)) { if (irqs) (void) probe_irq_off(irqs); + SELECT_MASK(HWIF(drive), drive, 0); return 0; /* drive timed-out */ } ide_delay_50ms(); /* give drive a breather */ } while (IN_BYTE(IDE_ALTSTATUS_REG) & BUSY_STAT); ide_delay_50ms(); /* wait for IRQ and DRQ_STAT */ if (!OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) { + SELECT_MASK(HWIF(drive), drive, 0); printk("%s: CHECK for good STATUS\n", drive->name); return 0; } __save_flags(flags); /* local CPU only */ __cli(); /* local CPU only; some systems need this */ + SELECT_MASK(HWIF(drive), drive, 0); id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC); ide_input_data(drive, id, SECTOR_WORDS); (void) GET_STAT(); /* clear drive IRQ */ @@ -214,11 +224,15 @@ (nsect > XFER_UDMA_2) && (feature == SETFEATURES_XFER)) { if (!HWIF(drive)->udma_four) { - printk("%s: Speed warnings UDMA 3/4 is not functional.\n", HWIF(drive)->name); + printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", HWIF(drive)->name); return 1; } +#ifndef CONFIG_IDEDMA_IVB + if ((drive->id->hw_config & 0x6000) == 0) { +#else /* !CONFIG_IDEDMA_IVB */ if ((drive->id->hw_config & 0x2000) == 0) { - printk("%s: Speed warnings UDMA 3/4 is not functional.\n", drive->name); +#endif /* CONFIG_IDEDMA_IVB */ + printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", drive->name); return 1; } } @@ -244,6 +258,18 @@ } /* + * All hosts that use the 80c ribbon mus use! + */ +byte eighty_ninty_three (ide_drive_t *drive) +{ + return ((byte) ((HWIF(drive)->udma_four) && +#ifndef CONFIG_IDEDMA_IVB + (drive->id->hw_config & 0x4000) && +#endif /* CONFIG_IDEDMA_IVB */ + (drive->id->hw_config & 0x2000)) ? 1 : 0); +} + +/* * Similar to ide_wait_stat(), except it never calls ide_error internally. * This is a kludge to handle the new ide_config_drive_speed() function, * and should not otherwise be used anywhere. Eventually, the tuneproc's @@ -260,10 +286,11 @@ int i, error = 1; byte stat; -#ifdef CONFIG_BLK_DEV_IDEDMA_PCI +#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI) byte unit = (drive->select.b.unit & 0x01); outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2); -#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */ +#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */ + /* * Don't use ide_wait_cmd here - it will * attempt to set_geometry and recalibrate, @@ -276,6 +303,7 @@ disable_irq(hwif->irq); /* disable_irq_nosync ?? */ udelay(1); SELECT_DRIVE(HWIF(drive), drive); + SELECT_MASK(HWIF(drive), drive, 0); udelay(1); if (IDE_CONTROL_REG) OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); @@ -315,6 +343,8 @@ } } + SELECT_MASK(HWIF(drive), drive, 0); + enable_irq(hwif->irq); if (error) { @@ -326,13 +356,13 @@ drive->id->dma_mword &= ~0x0F00; drive->id->dma_1word &= ~0x0F00; -#ifdef CONFIG_BLK_DEV_IDEDMA_PCI +#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI) if (speed > XFER_PIO_4) { outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2); } else { outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2); } -#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */ +#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */ switch(speed) { case XFER_UDMA_7: drive->id->dma_ultra |= 0x8080; break; @@ -358,5 +388,5 @@ EXPORT_SYMBOL(ide_driveid_update); EXPORT_SYMBOL(ide_ata66_check); EXPORT_SYMBOL(set_transfer); +EXPORT_SYMBOL(eighty_ninty_three); EXPORT_SYMBOL(ide_config_drive_speed); - diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/ide-geometry.c linux/drivers/ide/ide-geometry.c --- v2.4.0-test1/linux/drivers/ide/ide-geometry.c Mon Jun 19 16:31:59 2000 +++ linux/drivers/ide/ide-geometry.c Tue Jun 20 07:52:36 2000 @@ -3,7 +3,7 @@ */ #include -#if defined(CONFIG_IDE) && !defined(CONFIG_BLK_DEV_HD) +#if defined(CONFIG_IDE) && !defined(CONFIG_BLK_DEV_HD_ONLY) #include #include @@ -211,4 +211,4 @@ drive->bios_cyl, drive->bios_head, drive->bios_sect); return ret; } -#endif /* (CONFIG_IDE) && !(CONFIG_BLK_DEV_HD) */ +#endif /* (CONFIG_IDE) && !(CONFIG_BLK_DEV_HD_ONLY) */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/ide-pci.c linux/drivers/ide/ide-pci.c --- v2.4.0-test1/linux/drivers/ide/ide-pci.c Tue May 23 15:31:34 2000 +++ linux/drivers/ide/ide-pci.c Tue Jun 20 07:52:36 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/ide-pci.c Version 1.04 July 27, 1999 + * linux/drivers/ide/ide-pci.c Version 1.05 June 9, 2000 * * Copyright (c) 1998-2000 Andre Hedrick * @@ -33,10 +33,13 @@ #define DEVID_PIIX4E2 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_1}) #define DEVID_PIIX4U ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_1}) #define DEVID_PIIX4U2 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82372FB_1}) +#define DEVID_PIIX4NX ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX}) +#define DEVID_PIIX4U3 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82820FW_5}) #define DEVID_VIA_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561}) #define DEVID_VP_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1}) #define DEVID_PDC20246 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246}) #define DEVID_PDC20262 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262}) +#define DEVID_PDC20267 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267}) #define DEVID_RZ1000 ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000}) #define DEVID_RZ1001 ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001}) #define DEVID_SAMURAI ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE}) @@ -44,6 +47,7 @@ #define DEVID_CMD643 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_643}) #define DEVID_CMD646 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646}) #define DEVID_CMD648 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_648}) +#define DEVID_CMD649 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_649}) #define DEVID_SIS5513 ((ide_pci_devid_t){PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513}) #define DEVID_OPTI621 ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621}) #define DEVID_OPTI621V ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558}) @@ -65,6 +69,7 @@ #define DEVID_CY82C693 ((ide_pci_devid_t){PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693}) #define DEVID_HINT ((ide_pci_devid_t){0x3388, 0x8013}) #define DEVID_CS5530 ((ide_pci_devid_t){PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE}) +#define DEVID_AMD7403 ((ide_pci_devid_t){PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_COBRA_7403}) #define DEVID_AMD7409 ((ide_pci_devid_t){PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409}) #define IDE_IGNORE ((void *)-1) @@ -288,7 +293,7 @@ typedef struct ide_pci_device_s { ide_pci_devid_t devid; - const char *name; + char *name; unsigned int (*init_chipset)(struct pci_dev *dev, const char *name); unsigned int (*ata66_check)(ide_hwif_t *hwif); void (*init_hwif)(ide_hwif_t *hwif); @@ -307,10 +312,13 @@ {DEVID_PIIX4E2, "PIIX4", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_PIIX4U, "PIIX4", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_PIIX4U2, "PIIX4", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX4NX, "PIIX4", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX4U3, "PIIX4", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_VIA_IDE, "VIA_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_VP_IDE, "VP_IDE", PCI_VIA82CXXX, ATA66_VIA82CXXX,INIT_VIA82CXXX, DMA_VIA82CXXX, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0 }, {DEVID_PDC20246,"PDC20246", PCI_PDC202XX, NULL, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 16 }, {DEVID_PDC20262,"PDC20262", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48 }, + {DEVID_PDC20267,"PDC20267", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48 }, {DEVID_RZ1000, "RZ1000", NULL, NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_RZ1001, "RZ1001", NULL, NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_SAMURAI, "SAMURAI", NULL, NULL, INIT_SAMURAI, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, @@ -320,6 +328,7 @@ {DEVID_CMD643, "CMD643", PCI_CMD64X, NULL, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_CMD646, "CMD646", PCI_CMD64X, NULL, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_CMD648, "CMD648", PCI_CMD64X, ATA66_CMD64X, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_CMD649, "CMD649", PCI_CMD64X, ATA66_CMD64X, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_HT6565, "HT6565", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_OPTI621, "OPTI621", NULL, NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 }, {DEVID_OPTI621X,"OPTI621X", NULL, NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 }, @@ -338,6 +347,7 @@ {DEVID_CY82C693,"CY82C693", PCI_CY82C693, NULL, INIT_CY82C693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_HINT, "HINT_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_CS5530, "CS5530", PCI_CS5530, NULL, INIT_CS5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_AMD7403, "AMD7403", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_AMD7409, "AMD7409", PCI_AMD7409, ATA66_AMD7409, INIT_AMD7409, DMA_AMD7409, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }}; @@ -352,6 +362,7 @@ case PCI_DEVICE_ID_TTI_HPT366: case PCI_DEVICE_ID_PROMISE_20246: case PCI_DEVICE_ID_PROMISE_20262: + case PCI_DEVICE_ID_PROMISE_20267: case PCI_DEVICE_ID_ARTOP_ATP850UF: case PCI_DEVICE_ID_ARTOP_ATP860: case PCI_DEVICE_ID_ARTOP_ATP860R: @@ -510,6 +521,14 @@ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; + + if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)) { + /* see comments in hpt34x.c on why..... */ + char *chipset_names[] = {"HPT343", "HPT345"}; + strcpy(d->name, chipset_names[(pcicmd & PCI_COMMAND_MEMORY)]); + d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD; + } + printk("%s: chipset revision %d\n", d->name, class_rev); /* @@ -541,10 +560,7 @@ printk("%s: 100%% native mode on irq %d\n", d->name, pciirq); #endif } - if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)) { - /* see comments in hpt34x.c on why..... */ - d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD; - } + /* * Set up the IDE ports */ @@ -553,14 +569,14 @@ ide_pci_enablebit_t *e = &(d->enablebits[port]); if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) || (tmp & e->mask) != e->val)) continue; /* port not enabled */ - if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) && (port) && (class_rev != 0x03)) + if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) && (port) && (class_rev < 0x03)) return; if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE || (dev->class & (port ? 4 : 1)) != 0) { ctl = dev->resource[(2*port)+1].start; base = dev->resource[2*port].start; if (!(ctl & PCI_BASE_ADDRESS_IO_MASK) || !(base & PCI_BASE_ADDRESS_IO_MASK)) { - printk("%s: IO baseregs (BIOS) are reported as MEM, report to .\n", d->name); + printk("%s: IO baseregs (BIOS) are reported as MEM, report to .\n", d->name); #if 0 /* FIXME! This really should check that it really gets the IO/MEM part right! */ continue; @@ -603,19 +619,21 @@ goto bypass_umc_dma; } if (hwif->udma_four) { - printk("%s: ATA-66 forced bit set (WARNING)!!\n", d->name); + printk("%s: ATA-66/100 forced bit set (WARNING)!!\n", d->name); } else { hwif->udma_four = (d->ata66_check) ? d->ata66_check(hwif) : 0; } #ifdef CONFIG_BLK_DEV_IDEDMA if (IDE_PCI_DEVID_EQ(d->devid, DEVID_SIS5513) || IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_PIIX4NX) || IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)) autodma = 0; if (autodma) hwif->autodma = 1; if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) || IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20267) || IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) || IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) || IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260R) || @@ -625,6 +643,7 @@ IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) || IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD646) || IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD648) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD649) || ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) { unsigned long dma_base = ide_get_or_set_dma_base(hwif, (!mate && d->extra) ? d->extra : 0, d->name); if (dma_base && !(pcicmd & PCI_COMMAND_MASTER)) { @@ -665,6 +684,7 @@ ide_pci_device_t *d2; unsigned char pin1 = 0, pin2 = 0; unsigned int class_rev; + char *chipset_names[] = {"HPT366", "HPT366", "HPT368", "HPT370", "HPT370A"}; if (PCI_FUNC(dev->devfn) & 1) return; @@ -672,8 +692,13 @@ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; + strcpy(d->name, chipset_names[class_rev]); + switch(class_rev) { - case 3: return; + case 4: + case 3: printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn); + ide_setup_pci_device(dev, d); + return; default: break; } @@ -700,15 +725,6 @@ return; d2 = d; printk("%s: IDE controller on PCI bus %02x dev %02x\n", d2->name, dev2->bus->number, dev2->devfn); - if (hpt363_shared_pin && !hpt363_shared_irq) { - printk("%s: IDE controller run unsupported mode three!!!\n", d2->name); -#ifndef CONFIG_HPT366_MODE3 - printk("%s: IDE controller report to \n", d->name); - return; -#else /* CONFIG_HPT366_MODE3 */ - printk("%s: OVERRIDE IDE controller not advisable this mode!!!\n", d2->name); -#endif /* CONFIG_HPT366_MODE3 */ - } ide_setup_pci_device(dev2, d2); } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/ide-pmac.c linux/drivers/ide/ide-pmac.c --- v2.4.0-test1/linux/drivers/ide/ide-pmac.c Tue May 23 15:31:34 2000 +++ linux/drivers/ide/ide-pmac.c Tue Jun 20 07:52:36 2000 @@ -813,12 +813,6 @@ return 0; } -static int -pmac_ide_tune_chipset(ide_drive_t *drive, byte speed) -{ - return 0; -} - int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/ide-probe.c linux/drivers/ide/ide-probe.c --- v2.4.0-test1/linux/drivers/ide/ide-probe.c Mon Jun 19 16:31:59 2000 +++ linux/drivers/ide/ide-probe.c Tue Jun 20 07:52:36 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/ide-probe.c Version 1.05 July 3, 1999 + * linux/drivers/ide/ide-probe.c Version 1.06 June 9, 2000 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ @@ -7,6 +7,7 @@ /* * Mostly written by Mark Lord * and Gadi Oxman + * and Andre Hedrick * * See linux/MAINTAINERS for address of current maintainer. * @@ -23,6 +24,7 @@ * added ide6/7/8/9 * allowed for secondary flash card to be detectable * with new flag : drive->ata_flash : 1; + * Version 1.06 stream line request queue and prep for cascade project. */ #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -41,6 +43,7 @@ #include #include #include +#include #include #include @@ -167,6 +170,7 @@ } drive->media = ide_disk; printk("ATA DISK drive\n"); + QUIRK_LIST(HWIF(drive),drive); return; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/ide-tape.c linux/drivers/ide/ide-tape.c --- v2.4.0-test1/linux/drivers/ide/ide-tape.c Mon Jun 19 16:31:59 2000 +++ linux/drivers/ide/ide-tape.c Wed Jun 21 22:31:01 2000 @@ -5987,14 +5987,14 @@ idetape_setup (drive, tape, minor); idetape_chrdevs[minor].drive = drive; tape->de_r = - devfs_register (drive->de, "mt", 2, DEVFS_FL_DEFAULT, + devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT, HWIF(drive)->major, minor, - S_IFCHR | S_IRUGO | S_IWUGO, 0, 0, + S_IFCHR | S_IRUGO | S_IWUGO, &idetape_fops, NULL); tape->de_n = - devfs_register (drive->de, "mtn", 3, DEVFS_FL_DEFAULT, + devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT, HWIF(drive)->major, minor + 128, - S_IFCHR | S_IRUGO | S_IWUGO, 0, 0, + S_IFCHR | S_IRUGO | S_IWUGO, &idetape_fops, NULL); devfs_register_tape (tape->de_r); supported++; failed--; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/ide.c linux/drivers/ide/ide.c --- v2.4.0-test1/linux/drivers/ide/ide.c Mon Jun 19 16:31:59 2000 +++ linux/drivers/ide/ide.c Thu Jun 22 07:15:10 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/ide.c Version 6.30 Dec 28, 1999 + * linux/drivers/ide/ide.c Version 6.31 June 9, 2000 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ @@ -7,6 +7,7 @@ /* * Mostly written by Mark Lord * and Gadi Oxman + * and Andre Hedrick * * See linux/MAINTAINERS for address of current maintainer. * @@ -109,6 +110,9 @@ * Version 6.21 Fixing/Fixed SMP spinlock issue with insight from an old * hat that clarified original low level driver design. * Version 6.30 Added SMP support; fixed multmode issues. -ml + * Version 6.31 Debug Share INTR's and request queue streaming + * Native ATA-100 support + * Prep for Cascades Project * * Some additional driver compile-time options are in ./include/linux/ide.h * @@ -117,8 +121,8 @@ * */ -#define REVISION "Revision: 6.30" -#define VERSION "Id: ide.c 6.30 1999/12/28" +#define REVISION "Revision: 6.31" +#define VERSION "Id: ide.c 6.31 2000/06/09" #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -482,7 +486,8 @@ #if 0 udelay(1); /* need to guarantee 400ns since last command was issued */ #endif - if (GET_STAT() & BUSY_STAT) /* Note: this may clear a pending IRQ!! */ +// if (GET_STAT() & BUSY_STAT) /* Note: this may clear a pending IRQ!! */ + if (IN_BYTE(IDE_ALTSTATUS_REG) & BUSY_STAT) return 0; /* drive busy: definitely not interrupting */ return 1; /* drive ready: *might* be interrupting */ } @@ -651,6 +656,19 @@ return ide_stopped; } +static void check_dma_crc (ide_drive_t *drive) +{ + if (drive->crc_count) { + (void) HWIF(drive)->dmaproc(ide_dma_off_quietly, drive); + if ((HWIF(drive)->speedproc) != NULL) + HWIF(drive)->speedproc(drive, ide_auto_reduce_xfer(drive)); + if (drive->current_speed >= XFER_SW_DMA_0) + (void) HWIF(drive)->dmaproc(ide_dma_on, drive); + } else { + (void) HWIF(drive)->dmaproc(ide_dma_off, drive); + } +} + static void pre_reset (ide_drive_t *drive) { if (drive->driver != NULL) @@ -658,12 +676,15 @@ if (!drive->keep_settings) { if (drive->using_dma) { - (void) HWIF(drive)->dmaproc(ide_dma_off, drive); + check_dma_crc(drive); } else { drive->unmask = 0; drive->io_32bit = 0; } + return; } + if (drive->using_dma) + check_dma_crc(drive); } /* @@ -784,7 +805,7 @@ spin_lock_irqsave(&io_request_lock, flags); blkdev_dequeue_request(rq); HWGROUP(drive)->rq = NULL; - rq->rq_status = RQ_INACTIVE; + blkdev_release_request(rq); spin_unlock_irqrestore(&io_request_lock, flags); if (rq->sem != NULL) up(rq->sem); /* inform originator that rq has been serviced */ @@ -902,9 +923,9 @@ if (err == ABRT_ERR) { if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY) return ide_stopped; /* some newer drives don't support WIN_SPECIFY */ - } else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR)) - ; /* UDMA crc error -- just retry the operation */ - else if (err & (BBD_ERR | ECC_ERR)) /* retries won't help these */ + } else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR)) { + drive->crc_count++; /* UDMA crc error -- just retry the operation */ + } else if (err & (BBD_ERR | ECC_ERR)) /* retries won't help these */ rq->errors = ERROR_MAX; else if (err & TRK0_ERR) /* help it find track zero */ rq->errors |= ERROR_RECAL; @@ -941,6 +962,7 @@ ide_set_handler (drive, handler, WAIT_CMD, NULL); if (IDE_CONTROL_REG) OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* clear nIEN */ + SELECT_MASK(HWIF(drive),drive,0); OUT_BYTE(nsect,IDE_NSECTOR_REG); OUT_BYTE(cmd,IDE_COMMAND_REG); } @@ -1298,7 +1320,7 @@ hwif = HWIF(drive); if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif && hwif->io_ports[IDE_CONTROL_OFFSET]) { /* set nIEN for previous hwif */ - OUT_BYTE(hwgroup->drive->ctl|2, hwgroup->hwif->io_ports[IDE_CONTROL_OFFSET]); + SELECT_INTERRUPT(hwif, drive); } hwgroup->hwif = hwif; hwgroup->drive = drive; @@ -1316,13 +1338,13 @@ * happens anyway when any interrupt comes in, IDE or otherwise * -- the kernel masks the IRQ while it is being handled. */ - if (hwif->irq != masked_irq) + if (masked_irq && hwif->irq != masked_irq) disable_irq_nosync(hwif->irq); spin_unlock(&io_request_lock); ide__sti(); /* allow other IRQs while we start this request */ startstop = start_request(drive); spin_lock_irq(&io_request_lock); - if (hwif->irq != masked_irq) + if (masked_irq && hwif->irq != masked_irq) enable_irq(hwif->irq); if (startstop == ide_stopped) hwgroup->busy = 0; @@ -1404,7 +1426,11 @@ */ spin_unlock(&io_request_lock); hwif = HWIF(drive); +#if DISABLE_IRQ_NOSYNC + disable_irq_nosync(hwif->irq); +#else disable_irq(hwif->irq); /* disable_irq_nosync ?? */ +#endif /* DISABLE_IRQ_NOSYNC */ __cli(); /* local CPU only, as if we were handling an interrupt */ if (hwgroup->poll_timeout != 0) { startstop = handler(drive); @@ -2008,12 +2034,12 @@ else hwgroup->hwif = HWIF(hwgroup->drive); -#ifdef CONFIG_BLK_DEV_IDEDMA_PCI +#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI) if (hwif->dma_base) { (void) ide_release_dma(hwif); hwif->dma_base = 0; } -#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */ +#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */ /* * Remove us from the kernel's knowledge @@ -2048,6 +2074,10 @@ hwif->speedproc = old_hwif.speedproc; hwif->selectproc = old_hwif.selectproc; hwif->resetproc = old_hwif.resetproc; + hwif->intrproc = old_hwif.intrproc; + hwif->maskproc = old_hwif.maskproc; + hwif->quirkproc = old_hwif.quirkproc; + hwif->rwproc = old_hwif.rwproc; hwif->dmaproc = old_hwif.dmaproc; hwif->dma_base = old_hwif.dma_base; hwif->dma_extra = old_hwif.dma_extra; @@ -2275,17 +2305,18 @@ unsigned long timeout = jiffies + (3 * HZ); spin_lock_irq(&io_request_lock); + while (hwgroup->busy) { - unsigned long flags; + unsigned long lflags; spin_unlock_irq(&io_request_lock); - __save_flags(flags); /* local CPU only */ + __save_flags(lflags); /* local CPU only */ __sti(); /* local CPU only; needed for jiffies */ if (0 < (signed long)(jiffies - timeout)) { - __restore_flags(flags); + __restore_flags(lflags); /* local CPU only */ printk("%s: channel busy\n", drive->name); return -EBUSY; } - __restore_flags(flags); /* local CPU only */ + __restore_flags(lflags); /* local CPU only */ spin_lock_irq(&io_request_lock); } return 0; @@ -2422,13 +2453,13 @@ */ void ide_delay_50ms (void) { -#if 0 +#ifndef CONFIG_BLK_DEV_IDECS unsigned long timeout = jiffies + ((HZ + 19)/20) + 1; while (0 < (signed long)(timeout - jiffies)); #else __set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/20); -#endif +#endif /* CONFIG_BLK_DEV_IDECS */ } int system_bus_clock (void) @@ -2576,7 +2607,6 @@ err = -EFAULT; return err; } - case HDIO_SCAN_HWIF: { int args[3]; @@ -3266,6 +3296,7 @@ if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) { ide_get_lock(&ide_lock, NULL, NULL); /* for atari only */ disable_irq(ide_hwifs[0].irq); /* disable_irq_nosync ?? */ +// disable_irq_nosync(ide_hwifs[0].irq); } #endif /* __mc68000__ || CONFIG_APUS */ @@ -3619,10 +3650,10 @@ for (index = 0; index < MAX_HWIFS; ++index) { ide_unregister(index); -#ifdef CONFIG_BLK_DEV_IDEDMA_PCI +#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI) if (ide_hwifs[index].dma_base) (void) ide_release_dma(&ide_hwifs[index]); -#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */ +#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */ } #ifdef CONFIG_PROC_FS @@ -3636,6 +3667,7 @@ static int parse_ide_setup (char *line) { parse_options(line); + /* We MUST return 0 as otherwise no subsequent __setup option works... */ return 0; } __setup("", parse_ide_setup); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/ns87415.c linux/drivers/ide/ns87415.c --- v2.4.0-test1/linux/drivers/ide/ns87415.c Wed Apr 26 16:34:07 2000 +++ linux/drivers/ide/ns87415.c Tue Jun 20 07:52:36 2000 @@ -3,7 +3,7 @@ * * Copyright (C) 1997-1998 Mark Lord * Copyright (C) 1998 Eddie C. Dost - * Copyright (C) 1999-2000 Andre Hedrick + * Copyright (C) 1999-2000 Andre Hedrick * * Inspired by an earlier effort from David S. Miller */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/pdc202xx.c linux/drivers/ide/pdc202xx.c --- v2.4.0-test1/linux/drivers/ide/pdc202xx.c Tue May 23 15:31:34 2000 +++ linux/drivers/ide/pdc202xx.c Tue Jun 20 07:52:36 2000 @@ -1,7 +1,7 @@ /* * linux/drivers/ide/pdc202xx.c Version 0.30 Mar. 18, 2000 * - * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com) + * Copyright (C) 1998-2000 Andre Hedrick * May be copied or modified under the terms of the GNU General Public License * * Promise Ultra33 cards with BIOS v1.20 through 1.28 will need this @@ -12,6 +12,8 @@ * Promise Ultra66 cards with BIOS v1.11 this * compiled into the kernel if you have more than one card installed. * + * Promise Ultra100 cards. + * * The latest chipset code will support the following :: * Three Ultra33 controllers and 12 drives. * 8 are UDMA supported and 4 are limited to DMA mode 2 multi-word. @@ -51,6 +53,10 @@ #define DISPLAY_PDC202XX_TIMINGS +#ifndef SPLIT_BYTE +#define SPLIT_BYTE(B,H,L) ((H)=(B>>4), (L)=(B-((B>>4)<<4))) +#endif + #if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) #include #include @@ -99,10 +105,25 @@ { char *p = buffer; - u32 bibma = bmide_dev->resource[4].start; + u32 bibma = pci_resource_start(bmide_dev, 4); u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0; u16 reg50h = 0, pmask = (1<<10), smask = (1<<11); - u8 c0 = 0, c1 = 0; + u8 hi = 0, lo = 0; + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + u8 c0 = inb_p((unsigned short)bibma + 0x02); + u8 c1 = inb_p((unsigned short)bibma + 0x0a); + + u8 sc11 = inb_p((unsigned short)bibma + 0x11); + u8 sc1a = inb_p((unsigned short)bibma + 0x1a); + u8 sc1b = inb_p((unsigned short)bibma + 0x1b); + u8 sc1c = inb_p((unsigned short)bibma + 0x1c); + u8 sc1d = inb_p((unsigned short)bibma + 0x1d); + u8 sc1e = inb_p((unsigned short)bibma + 0x1e); + u8 sc1f = inb_p((unsigned short)bibma + 0x1f); pci_read_config_word(bmide_dev, 0x50, ®50h); pci_read_config_dword(bmide_dev, 0x60, ®60h); @@ -110,14 +131,10 @@ pci_read_config_dword(bmide_dev, 0x68, ®68h); pci_read_config_dword(bmide_dev, 0x6c, ®6ch); - /* - * at that point bibma+0x2 et bibma+0xa are byte registers - * to investigate: - */ - c0 = inb_p((unsigned short)bibma + 0x02); - c1 = inb_p((unsigned short)bibma + 0x0a); - - switch(bmide_dev->device) { + switch(bmide_dev->device) { + case PCI_DEVICE_ID_PROMISE_20267: + p += sprintf(p, "\n PDC20267 Chipset.\n"); + break; case PCI_DEVICE_ID_PROMISE_20262: p += sprintf(p, "\n PDC20262 Chipset.\n"); break; @@ -130,9 +147,40 @@ break; } + p += sprintf(p, "------------------------------- General Status ---------------------------------\n"); + p += sprintf(p, "Burst Mode : %sabled\n", (sc1f & 0x01) ? "en" : "dis"); + p += sprintf(p, "Host Mode : %s\n", (sc1f & 0x08) ? "Tri-Stated" : "Normal"); + p += sprintf(p, "Bus Clocking : %s\n", + ((sc1f & 0xC0) == 0xC0) ? "100 External" : + ((sc1f & 0x80) == 0x80) ? "66 External" : + ((sc1f & 0x40) == 0x40) ? "33 External" : "33 PCI Internal"); + p += sprintf(p, "IO pad select : %s mA\n", + ((sc1c & 0x03) == 0x03) ? "10" : + ((sc1c & 0x02) == 0x02) ? "8" : + ((sc1c & 0x01) == 0x01) ? "6" : + ((sc1c & 0x00) == 0x00) ? "4" : "??"); + SPLIT_BYTE(sc1e, hi, lo); + p += sprintf(p, "Status Polling Period : %d\n", hi); + p += sprintf(p, "Interrupt Check Status Polling Delay : %d\n", lo); p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); - p += sprintf(p, " %sabled %sabled\n", - (c0&0x80)?"dis":" en",(c1&0x80)?"dis":" en"); + p += sprintf(p, " %s %s\n", + (c0&0x80)?"disabled":"enabled ", + (c1&0x80)?"disabled":"enabled "); + p += sprintf(p, "66 Clocking %s %s\n", + (sc11&0x02)?"enabled ":"disabled", + (sc11&0x08)?"enabled ":"disabled"); + p += sprintf(p, " Mode %s Mode %s\n", + (sc1a & 0x01) ? "MASTER" : "PCI ", + (sc1b & 0x01) ? "MASTER" : "PCI "); + p += sprintf(p, " %s %s\n", + (sc1d & 0x08) ? "Error " : + (sc1d & 0x04) ? "Interrupting" : + (sc1d & 0x02) ? "FIFO Full " : + (sc1d & 0x01) ? "FIFO Empty " : "????????????", + (sc1d & 0x80) ? "Error " : + (sc1d & 0x40) ? "Interrupting" : + (sc1d & 0x20) ? "FIFO Full " : + (sc1d & 0x10) ? "FIFO Empty " : "????????????"); p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); p += sprintf(p, "DMA enabled: %s %s %s %s\n", (c0&0x20)?"yes":"no ",(c0&0x40)?"yes":"no ",(c1&0x20)?"yes":"no ",(c1&0x40)?"yes":"no "); @@ -141,9 +189,13 @@ pdc202xx_ultra_verbose(reg64h, (reg50h & pmask)), pdc202xx_ultra_verbose(reg68h, (reg50h & smask)), pdc202xx_ultra_verbose(reg6ch, (reg50h & smask))); - p += sprintf(p, " PIO Mode: %s %s %s %s\n", + p += sprintf(p, "PIO Mode: %s %s %s %s\n", pdc202xx_pio_verbose(reg60h),pdc202xx_pio_verbose(reg64h), pdc202xx_pio_verbose(reg68h),pdc202xx_pio_verbose(reg6ch)); +#if 0 + p += sprintf(p, "--------------- Can ATAPI DMA ---------------\n"); +#endif + return p-buffer; /* => must be less than 4k! */ } #endif /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */ @@ -324,6 +376,7 @@ switch(speed) { #ifdef CONFIG_BLK_DEV_IDEDMA + case XFER_UDMA_5: case XFER_UDMA_4: TB = 0x20; TC = 0x01; break; /* speed 8 == UDMA mode 4 */ case XFER_UDMA_3: TB = 0x40; TC = 0x02; break; /* speed 7 == UDMA mode 3 */ case XFER_UDMA_2: TB = 0x20; TC = 0x01; break; /* speed 6 == UDMA mode 2 */ @@ -408,7 +461,7 @@ struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - unsigned long high_16 = dev->resource[4].start & PCI_BASE_ADDRESS_IO_MASK; + unsigned long high_16 = pci_resource_start(dev, 4); unsigned long dma_base = hwif->dma_base; byte unit = (drive->select.b.unit & 0x01); @@ -418,8 +471,9 @@ byte AP; unsigned short EP; byte CLKSPD = IN_BYTE(high_16 + 0x11); - byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0; byte udma_33 = ultra ? (inb(high_16 + 0x001f) & 1) : 0; + byte udma_66 = ((eighty_ninty_three(drive)) && udma_33) ? 1 : 0; + byte udma_100 = ((dev->device == PCI_DEVICE_ID_PROMISE_20267) && udma_66) ? 1 : 0; /* * Set the control register to use the 66Mhz system @@ -436,11 +490,15 @@ byte mask = hwif->channel ? 0x08 : 0x02; unsigned short c_mask = hwif->channel ? (1<<11) : (1<<10); - byte ultra_66 = ((id->dma_ultra & 0x0010) || (id->dma_ultra & 0x0008)) ? 1 : 0; + byte ultra_66 = ((id->dma_ultra & 0x0010) || + (id->dma_ultra & 0x0008)) ? 1 : 0; + byte ultra_100 = ((id->dma_ultra & 0x0020) || + (id->dma_ultra & 0x0010) || + (id->dma_ultra & 0x0008)) ? 1 : 0; pci_read_config_word(dev, 0x50, &EP); - if ((ultra_66) && (EP & c_mask)) { + if (((ultra_66) || (ultra_100)) && (EP & c_mask)) { #ifdef DEBUG printk("ULTRA66: %s channel of Ultra 66 requires an 80-pin cable for Ultra66 operation.\n", hwif->channel ? "Secondary", "Primary"); printk(" Switching to Ultra33 mode.\n"); @@ -449,13 +507,14 @@ /* Secondary : zero out fourth bit */ OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11)); } else { - if (ultra_66) { + if ((ultra_66) || (ultra_100)) { /* * check to make sure drive on same channel * is u66 capable */ if (hwif->drives[!(drive->dn%2)].id) { - if ((hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0010) || + if ((hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0020) || + (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0010) || (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0008)) { OUT_BYTE(CLKSPD | mask, (high_16 + 0x11)); } else { @@ -517,17 +576,18 @@ if (drive->media == ide_disk) /* PREFETCH_EN */ pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN); - if ((id->dma_ultra & 0x0010) && (udma_66) && (udma_33)) speed = XFER_UDMA_4; - else if ((id->dma_ultra & 0x0008) && (udma_66) && (udma_33)) speed = XFER_UDMA_3; - else if ((id->dma_ultra & 0x0004) && (udma_33)) speed = XFER_UDMA_2; - else if ((id->dma_ultra & 0x0002) && (udma_33)) speed = XFER_UDMA_1; - else if ((id->dma_ultra & 0x0001) && (udma_33)) speed = XFER_UDMA_0; - else if (id->dma_mword & 0x0004) speed = XFER_MW_DMA_2; - else if (id->dma_mword & 0x0002) speed = XFER_MW_DMA_1; - else if (id->dma_mword & 0x0001) speed = XFER_MW_DMA_0; - else if (id->dma_1word & 0x0004) speed = XFER_SW_DMA_2; - else if (id->dma_1word & 0x0002) speed = XFER_SW_DMA_1; - else if (id->dma_1word & 0x0001) speed = XFER_SW_DMA_0; + if ((id->dma_ultra & 0x0020) && (udma_100)) speed = XFER_UDMA_5; + else if ((id->dma_ultra & 0x0010) && (udma_66)) speed = XFER_UDMA_4; + else if ((id->dma_ultra & 0x0008) && (udma_66)) speed = XFER_UDMA_3; + else if ((id->dma_ultra & 0x0004) && (udma_33)) speed = XFER_UDMA_2; + else if ((id->dma_ultra & 0x0002) && (udma_33)) speed = XFER_UDMA_1; + else if ((id->dma_ultra & 0x0001) && (udma_33)) speed = XFER_UDMA_0; + else if (id->dma_mword & 0x0004) speed = XFER_MW_DMA_2; + else if (id->dma_mword & 0x0002) speed = XFER_MW_DMA_1; + else if (id->dma_mword & 0x0001) speed = XFER_MW_DMA_0; + else if (id->dma_1word & 0x0004) speed = XFER_SW_DMA_2; + else if (id->dma_1word & 0x0002) speed = XFER_SW_DMA_1; + else if (id->dma_1word & 0x0001) speed = XFER_SW_DMA_0; else { /* restore original pci-config space */ pci_write_config_dword(dev, drive_pci, drive_conf); @@ -537,7 +597,7 @@ outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); (void) pdc202xx_tune_chipset(drive, speed); - return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_on : + return ((int) ((id->dma_ultra >> 11) & 7) ? ide_dma_on : ((id->dma_ultra >> 8) & 7) ? ide_dma_on : ((id->dma_mword >> 8) & 7) ? ide_dma_on : ((id->dma_1word >> 8) & 7) ? ide_dma_on : @@ -558,7 +618,7 @@ } dma_func = ide_dma_off_quietly; if (id->field_valid & 4) { - if (id->dma_ultra & 0x001F) { + if (id->dma_ultra & 0x002F) { /* Force if Capable UltraDMA */ dma_func = config_chipset_for_dma(drive, 1); if ((id->field_valid & 2) && @@ -603,6 +663,10 @@ switch (func) { case ide_dma_check: return config_drive_xfer_rate(drive); + case ide_dma_lostirq: + case ide_dma_timeout: + if (HWIF(drive)->resetproc != NULL) + HWIF(drive)->resetproc(drive); default: break; } @@ -610,14 +674,29 @@ } #endif /* CONFIG_BLK_DEV_IDEDMA */ +void pdc202xx_reset (ide_drive_t *drive) +{ + unsigned long high_16 = pci_resource_start(HWIF(drive)->pci_dev, 4); + byte udma_speed_flag = inb(high_16 + 0x001f); + int i = 0; + + OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f); + ide_delay_50ms(); + ide_delay_50ms(); + OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f); + for (i = 0; i < 40; i++) + ide_delay_50ms(); +} + unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name) { - unsigned long high_16 = dev->resource[4].start & PCI_BASE_ADDRESS_IO_MASK; + unsigned long high_16 = pci_resource_start(dev, 4); byte udma_speed_flag = inb(high_16 + 0x001f); byte primary_mode = inb(high_16 + 0x001a); byte secondary_mode = inb(high_16 + 0x001b); - if (dev->device == PCI_DEVICE_ID_PROMISE_20262) { + if ((dev->device == PCI_DEVICE_ID_PROMISE_20262) || + (dev->device == PCI_DEVICE_ID_PROMISE_20267)) { int i = 0; /* * software reset - this is required because the bios @@ -646,7 +725,7 @@ byte irq = 0, irq2 = 0; pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2); /* 0xbc */ - if (irq != irq2) { + if ((irq != irq2) && (dev->device != PCI_DEVICE_ID_PROMISE_20267)) { pci_write_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, irq); /* 0xbc */ printk("%s: pci-config space interrupt mirror fixed.\n", name); } @@ -705,8 +784,12 @@ void __init ide_init_pdc202xx (ide_hwif_t *hwif) { - hwif->tuneproc = &pdc202xx_tune_drive; - hwif->speedproc = &pdc202xx_tune_chipset; + hwif->tuneproc = &pdc202xx_tune_drive; + hwif->speedproc = &pdc202xx_tune_chipset; + + if ((hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20262) || + (hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20267)) + hwif->resetproc = &pdc202xx_reset; #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/piix.c linux/drivers/ide/piix.c --- v2.4.0-test1/linux/drivers/ide/piix.c Mon Jun 19 16:31:59 2000 +++ linux/drivers/ide/piix.c Tue Jun 20 07:52:36 2000 @@ -1,8 +1,8 @@ /* - * linux/drivers/ide/piix.c Version 0.31 Mar. 18, 2000 + * linux/drivers/ide/piix.c Version 0.32 June 9, 2000 * * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer - * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com) + * Copyright (C) 1998-2000 Andre Hedrick * May be copied or modified under the terms of the GNU General Public License * * PIO mode setting function for Intel chipsets. @@ -83,7 +83,7 @@ static int piix_get_info (char *buffer, char **addr, off_t offset, int count) { char *p = buffer; - u32 bibma = bmide_dev->resource[4].start; + u32 bibma = pci_resource_start(bmide_dev, 4); u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0; u8 c0 = 0, c1 = 0; u8 reg44 = 0, reg48 = 0, reg4a = 0, reg4b = 0, reg54 = 0, reg55 = 0; @@ -108,10 +108,14 @@ c1 = inb_p((unsigned short)bibma + 0x0a); switch(bmide_dev->device) { + case PCI_DEVICE_ID_INTEL_82820FW_5: + p += sprintf(p, "\n Intel PIIX4 Ultra 100 Chipset.\n"); + break; case PCI_DEVICE_ID_INTEL_82372FB_1: case PCI_DEVICE_ID_INTEL_82801AA_1: p += sprintf(p, "\n Intel PIIX4 Ultra 66 Chipset.\n"); break; + case PCI_DEVICE_ID_INTEL_82451NX: case PCI_DEVICE_ID_INTEL_82801AB_1: case PCI_DEVICE_ID_INTEL_82443MX_1: case PCI_DEVICE_ID_INTEL_82371AB: @@ -142,21 +146,25 @@ (reg48&0x04) ? "yes" : "no ", (reg48&0x08) ? "yes" : "no " ); p += sprintf(p, "UDMA enabled: %s %s %s %s\n", + ((reg54&0x11) && (reg55&0x10) && (reg4a&0x01)) ? "5" : ((reg54&0x11) && (reg4a&0x02)) ? "4" : ((reg54&0x11) && (reg4a&0x01)) ? "3" : (reg4a&0x02) ? "2" : (reg4a&0x01) ? "1" : (reg4a&0x00) ? "0" : "X", + ((reg54&0x22) && (reg55&0x20) && (reg4a&0x10)) ? "5" : ((reg54&0x22) && (reg4a&0x20)) ? "4" : ((reg54&0x22) && (reg4a&0x10)) ? "3" : (reg4a&0x20) ? "2" : (reg4a&0x10) ? "1" : (reg4a&0x00) ? "0" : "X", + ((reg54&0x44) && (reg55&0x40) && (reg4b&0x03)) ? "5" : ((reg54&0x44) && (reg4b&0x02)) ? "4" : ((reg54&0x44) && (reg4b&0x01)) ? "3" : (reg4b&0x02) ? "2" : (reg4b&0x01) ? "1" : (reg4b&0x00) ? "0" : "X", + ((reg54&0x88) && (reg55&0x80) && (reg4b&0x30)) ? "5" : ((reg54&0x88) && (reg4b&0x20)) ? "4" : ((reg54&0x88) && (reg4b&0x10)) ? "3" : (reg4b&0x20) ? "2" : @@ -188,6 +196,7 @@ */ static byte piix_dma_2_pio (byte xfer_rate) { switch(xfer_rate) { + case XFER_UDMA_5: case XFER_UDMA_4: case XFER_UDMA_3: case XFER_UDMA_2: @@ -286,6 +295,7 @@ switch(speed) { case XFER_UDMA_4: case XFER_UDMA_2: u_speed = 2 << (drive->dn * 4); break; + case XFER_UDMA_5: case XFER_UDMA_3: case XFER_UDMA_1: u_speed = 1 << (drive->dn * 4); break; case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break; @@ -298,7 +308,11 @@ if (speed >= XFER_UDMA_0) { if (!(reg48 & u_flag)) pci_write_config_word(dev, 0x48, reg48|u_flag); - pci_write_config_byte(dev, 0x55, (byte) reg55 & ~w_flag); + if (speed == XFER_UDMA_5) { + pci_write_config_byte(dev, 0x55, (byte) reg55|w_flag); + } else { + pci_write_config_byte(dev, 0x55, (byte) reg55 & ~w_flag); + } if (!(reg4a & u_speed)) { pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); pci_write_config_word(dev, 0x4a, reg4a|u_speed); @@ -341,15 +355,20 @@ struct pci_dev *dev = hwif->pci_dev; byte speed; - byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0; - int ultra66 = ((dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) || + byte udma_66 = eighty_ninty_three(drive); + int ultra100 = ((dev->device == PCI_DEVICE_ID_INTEL_82820FW_5)) ? 1 : 0; + int ultra66 = ((ultra100) || + (dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) || (dev->device == PCI_DEVICE_ID_INTEL_82372FB_1)) ? 1 : 0; int ultra = ((ultra66) || (dev->device == PCI_DEVICE_ID_INTEL_82371AB) || (dev->device == PCI_DEVICE_ID_INTEL_82443MX_1) || + (dev->device == PCI_DEVICE_ID_INTEL_82451NX) || (dev->device == PCI_DEVICE_ID_INTEL_82801AB_1)) ? 1 : 0; - if ((id->dma_ultra & 0x0010) && (ultra)) { + if ((id->dma_ultra & 0x0020) && (udma_66) && (ultra100)) { + speed = XFER_UDMA_5; + } else if ((id->dma_ultra & 0x0010) && (ultra)) { speed = ((udma_66) && (ultra66)) ? XFER_UDMA_4 : XFER_UDMA_2; } else if ((id->dma_ultra & 0x0008) && (ultra)) { speed = ((udma_66) && (ultra66)) ? XFER_UDMA_3 : XFER_UDMA_1; @@ -371,7 +390,7 @@ (void) piix_tune_chipset(drive, speed); - return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_on : + return ((int) ((id->dma_ultra >> 11) & 7) ? ide_dma_on : ((id->dma_ultra >> 8) & 7) ? ide_dma_on : ((id->dma_mword >> 8) & 7) ? ide_dma_on : ((id->dma_1word >> 8) & 7) ? ide_dma_on : diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/qd6580.c linux/drivers/ide/qd6580.c --- v2.4.0-test1/linux/drivers/ide/qd6580.c Tue May 23 15:31:34 2000 +++ linux/drivers/ide/qd6580.c Tue Jun 20 07:52:36 2000 @@ -1,16 +1,19 @@ /* - * linux/drivers/ide/qd6580.c Version 0.03 May 13, 2000 + * linux/drivers/ide/qd6580.c Version 0.04 June 4, 2000 * * Copyright (C) 1996-2000 Linus Torvalds & author (see below) */ /* * Version 0.03 Cleaned auto-tune, added probe - * + * Version 0.04 Added second channel tuning + * * QDI QD6580 EIDE controller fast support - * + * * To activate controller support use kernel parameter "ide0=qd6580" * To enable tuning use kernel parameter "ide0=autotune" + * To enable tuning second channel (not really tested), + * use parameter "ide1=autotune" */ /* @@ -36,146 +39,254 @@ #include "ide_modes.h" /* - * I/O ports are 0xb0 0xb1 0xb2 and 0xb3 - * or 0x30 0x31 0x32 and 0x33 + * I/O ports are 0xb0-0xb3 + * or 0x30-0x33 * -- this is a dual IDE interface with I/O chips * * More research on qd6580 being done by willmore@cig.mot.com (David) + * More Information given by Petr Sourcek (petr@ryston.cz) + * http://www.ryston.cz/petr/vlb */ -/* +/* * 0xb0: Timer1 * - * - * 0xb1: Status * - * && 0xf0 is either 0b1010000 or 0b01010000, or else it isn't a qd6580 - * bit 3 & 2: unknown (useless ?) I have 0 & 1, respectively - * bit 1: 1 if qd6580 baseport is 0xb0 - * 0 if qd6580 baseport is 0x30 - * bit 0: 1 if ide baseport is 0x1f0 - * 0 if ide baseport is 0x170 + * 0xb1: Config + * + * bit 0: ide baseport: 1 = 0x1f0 ; 0 = 0x170 * (? Strange: the Dos driver uses it, and then forces baseport to 0x1f0 ?) - * - * + * bit 1: qd baseport: 1 = 0xb0 ; 0 = 0x30 + * bit 2: ID3: bus speed: 1 = <=33MHz ; 0 = >33MHz + * bit 3: 1 for qd6580 + * upper nibble is either 1010 or 0101, or else it isn't a qd6580 + * + * * 0xb2: Timer2 * - * + * * 0xb3: Control * - * bits 0-3 are always set 1 - * bit 6 : if 1, must be set 1 - * bit 1 : if 1, bit 7 must be set 1 - * bit 0 : if 1, drives are independant, we can have two different timers for - * the two drives. - * if 0, we have to take the slowest drive into account, - * but we may tune the second hwif ? + * bits 0-3 must always be set 1 + * bit 4 must be set 1, but is set 0 by dos driver while measuring vlb clock + * bit 0 : 1 = Only primary port enabled : channel 0 for hda, channel 1 for hdb + * 0 = Primary and Secondary ports enabled : channel 0 for hda & hdb + * channel 1 for hdc & hdd + * bit 1 : 1 = only disks on primary port + * 0 = disks & ATAPI devices on primary port + * bit 2-4 : always 0 + * bit 5 : status, but of what ? + * bit 6 : always set 1 by dos driver + * bit 7 : set 1 for non-ATAPI devices (read-ahead and post-write buffer ?) */ +/* truncates a in [b,c] */ +#define IDE_IN(a,b,c) ( ((a)<(b)) ? (b) : ( (a)>(c) ? (c) : (a)) ) + typedef struct ide_hd_timings_s { int active_time; /* Active pulse (ns) minimum */ int recovery_time; /* Recovery pulse (ns) minimum */ } ide_hd_timings_t; static int basePort; /* base port address (0x30 or 0xb0) */ -static byte status; /* status register of qd6580 */ +static byte config; /* config register of qd6580 */ static byte control; /* control register of qd6580 */ -/* truncates a in [b,c] */ -#define IDE_IN(a,b,c) ( ((a)<(b)) ? (b) : ( (a)>(c) ? (c) : (a)) ) - static int bus_clock; /* Vesa local bus clock (ns) */ static int tuned=0; /* to remember whether we've already been tuned */ +static int snd_tuned=0; /* to remember whether we've already been tuned */ +static int nb_disks_prim=0; /* number of disk drives on primary port */ + +/* + * write_reg + * + * writes the specified byte on the specified register + */ + +static void write_reg ( byte content, byte reg ) +{ + unsigned long flags; + + save_flags(flags); /* all CPUs */ + cli(); /* all CPUs */ + outb_p(content,reg); + inb(0x3f6); + restore_flags(flags); /* all CPUs */ +} /* * tune_drive * - * Finds timings for the specified drive, returns it in struc t + * Finds timings for the specified drive, returns it in struct t */ -static void tune_drive ( ide_drive_t *drive, byte pio, ide_hd_timings_t *t) +static void tune_drive ( ide_drive_t *drive, byte pio, ide_hd_timings_t *t ) { ide_pio_data_t d; - t->active_time = 0xaf; - t->recovery_time = 0x19f; /* worst cases values from the dos driver */ + t->active_time = 175; + t->recovery_time = 415; /* worst cases values from the dos driver */ - if (drive->present == 0) { /* not present : free to give any timing */ - t->active_time = 0x0; - t->recovery_time = 0x0; + if (!drive->present) { /* not present : free to give any timing */ + t->active_time = 0; + t->recovery_time = 0; return; } - - pio = ide_get_best_pio_mode(drive, pio, 4, &d); - if (pio) { - - switch (pio) { - case 0: break; - case 3: t->active_time = 0x56; - t->recovery_time = d.cycle_time-0x66; - break; - case 4: t->active_time = 0x46; - t->recovery_time = d.cycle_time-0x3d; - break; - default: if (d.cycle_time >= 0xb4) { - t->active_time = 0x6e; - t->recovery_time = d.cycle_time - 0x78; - } else { - t->active_time = ide_pio_timings[pio].active_time; - t->recovery_time = d.cycle_time - -t->active_time - -ide_pio_timings[pio].setup_time; - } - } - } + pio = ide_get_best_pio_mode(drive, pio, 255, &d); + pio = IDE_MIN(pio,4); + + switch (pio) { + case 0: break; + case 3: + if (d.cycle_time >= 110) { + t->active_time = 86; + t->recovery_time = d.cycle_time-102; + } else { + printk("%s: Strange recovery time !\n",drive->name); + return; + } + break; + case 4: + if (d.cycle_time >= 69) { + t->active_time = 70; + t->recovery_time = d.cycle_time-61; + } else { + printk("%s: Strange recovery time !\n",drive->name); + return; + } + break; + default: + if (d.cycle_time >= 180) { + t->active_time = 110; + t->recovery_time = d.cycle_time - 120; + } else { + t->active_time = ide_pio_timings[pio].active_time; + t->recovery_time = d.cycle_time + -t->active_time; + } + } printk("%s: PIO mode%d, tim1=%dns tim2=%dns\n", drive->name, pio, t->active_time, t->recovery_time); + + if (drive->media == ide_disk) + nb_disks_prim++; + else { +/* need to disable read-ahead FIFO and post-write buffer for ATAPI drives*/ + write_reg(0x5f,basePort+0x03); + printk("%s: Warning: please try to connect this drive to secondary IDE port\nto improve data transfer rate on primary IDE port.\n",drive->name); + } } -/* +/* + * tune_snd_drive + * + * Finds timings for the specified drive, using second channel rules + */ + +static void tune_snd_drive ( ide_drive_t *drive, byte pio, ide_hd_timings_t *t ) +{ + ide_pio_data_t d; + + t->active_time = 175; + t->recovery_time = 415; + + if (!drive->present) { /* not present : free to give any timing */ + t->active_time = 0; + t->recovery_time = 0; + return; + } + + pio = ide_get_best_pio_mode(drive, pio, 255, &d); + + if ((pio) && (d.cycle_time >= 180)) { + t->active_time = 115; + t->recovery_time = d.cycle_time - 115; + } + printk("%s: PIO mode%d, tim1=%dns tim2=%dns\n", drive->name, pio, t->active_time, t->recovery_time); + + if ((drive->media == ide_disk) && (nb_disks_prim<2)) { +/* a disk drive on secondary port while there's room on primary, which is the + * only one that has read-ahead fifo and post-write buffer ? What a waste !*/ + printk("%s: Warning: please try to connect this drive to primary IDE port\nto improve data transfer rate.\n",drive->name); + } +} + +/* + * compute_timing + * + * computes the timing value where + * lower nibble is active time, in count of VLB clocks, 17-(from 2 to 17) + * upper nibble is recovery time, in count of VLB clocks, 15-(from 2 to 15) + */ + +static byte compute_timing ( char name[6], ide_hd_timings_t *t ) +{ + byte active_cycle; + byte recovery_cycle; + byte parameter; + + active_cycle = 17-IDE_IN(t->active_time / bus_clock + 1, 2, 17); + recovery_cycle = 15-IDE_IN(t->recovery_time / bus_clock + 1, 2, 15); + + parameter = active_cycle | (recovery_cycle<<4); + + printk("%s: tim1=%dns tim2=%dns => %#x\n", name, t[0].active_time, t[0].recovery_time, parameter); + return(parameter); +} + +/* * tune_ide * - * Tunes the whole ide, ie tunes each drives, and takes the worst timings - * to tune qd6580 + * Tunes the whole hwif, ie tunes each drives, and in case we have to share, + * takes the worse timings to tune qd6580 */ static void tune_ide ( ide_hwif_t *hwif, byte pio ) { unsigned long flags; ide_hd_timings_t t[2]={{0,0},{0,0}}; - - byte active_cycle; - byte recovery_cycle; - byte parameter; int bus_speed = ide_system_bus_speed (); - + bus_clock = 1000 / bus_speed; - + save_flags(flags); /* all CPUs */ cli(); /* all CPUs */ outb( (bus_clock<30) ? 0x0 : 0x0a, basePort + 0x02); outb( 0x40 | ((control & 0x02) ? 0x9f:0x1f), basePort+0x03); - restore_flags(flags); + restore_flags(flags); tune_drive (&hwif->drives[0], pio, &t[0]); tune_drive (&hwif->drives[1], pio, &t[1]); + if (control & 0x01) { /* only primary port enabled, can tune separately */ + write_reg(compute_timing (hwif->drives[0].name, &t[0]),basePort); + write_reg(compute_timing (hwif->drives[1].name, &t[1]),basePort+0x02); + } else { /* both ports enabled, we have to share */ + + t[0].active_time = IDE_MAX(t[0].active_time, t[1].active_time); + t[0].recovery_time = IDE_MAX(t[0].recovery_time,t[1].recovery_time); + write_reg(compute_timing (hwif->name, &t[0]),basePort); + } +} + +/* + * tune_snd_ide + * + * Tunes the whole secondary hwif, ie tunes each drives, and takes the worse + * timings to tune qd6580 + */ + +static void tune_snd_ide ( ide_hwif_t *hwif, byte pio ) +{ + ide_hd_timings_t t[2]={{0,0},{0,0}}; + + tune_snd_drive (&hwif->drives[0], pio, &t[0]); + tune_snd_drive (&hwif->drives[1], pio, &t[1]); + t[0].active_time = IDE_MAX(t[0].active_time, t[1].active_time); t[0].recovery_time = IDE_MAX(t[0].recovery_time,t[1].recovery_time); - - active_cycle = 17-IDE_IN(t[0].active_time / bus_clock + 1, 2, 17); - recovery_cycle = 15-IDE_IN(t[0].recovery_time / bus_clock + 1, 2, 15); - - parameter=active_cycle | (recovery_cycle<<4); - - printk("%s: tim1=%dns tim2=%dns => %#x\n", hwif->name, t[0].active_time, t[0].recovery_time, parameter); - - save_flags(flags); /* all CPUs */ - cli(); /* all CPUs */ - outb_p(parameter,0xb0); - inb(0x3f6); - restore_flags(flags); /* all CPUs */ - + + write_reg(compute_timing (hwif->name, &t[0]),basePort+0x02); } /* @@ -193,6 +304,20 @@ } /* + * tune_snd_qd6580 + * + * tunes the second hwif if not tuned + */ + +static void tune_snd_qd6580 (ide_drive_t *drive, byte pio) +{ + if (! snd_tuned) { + tune_snd_ide(HWIF(drive), pio); + snd_tuned = 1; + } +} + +/* * testreg * * tests if the given port is a register @@ -203,7 +328,7 @@ byte savereg; byte readreg; unsigned long flags; - + save_flags(flags); /* all CPUs */ cli(); /* all CPUs */ savereg = inb(port); @@ -214,14 +339,15 @@ if (savereg == 0x15) { printk("Outch ! the probe for qd6580 isn't reliable !\n"); - printk("Please contact samuel.thibault@fnac.net to tell about your hardware\n"); - printk("Assuming qd6580 is present"); + printk("Please contact maintainers to tell about your hardware\n"); + printk("Assuming qd6580 is not present.\n"); + return 0; } return (readreg == 0x15); } -/* +/* * trybase: * * tries to find a qd6580 at the given base and save it if found @@ -233,20 +359,20 @@ save_flags(flags); /* all CPUs */ cli(); /* all CPUs */ - status = inb(base+0x01); + config = inb(base+0x01); control = inb(base+0x03); restore_flags(flags); /* all CPUs */ - if (((status & 0xf0) != 0x50) && ((status & 0xf0) != 0xa0)) return(0); - if (! ( ((status & 0x02) == 0x0) == (base == 0x30) ) ) return (0); + if (((config & 0xf0) != 0x50) && ((config & 0xf0) != 0xa0)) return(0); + if (! ( ((config & 0x02) == 0x0) == (base == 0x30) ) ) return (0); /* Seems to be OK, let's use it */ - + basePort = base; return(testreg(base)); } -/* +/* * probe: * * probes qd6580 at 0xb0 (the default) or 0x30 @@ -257,6 +383,11 @@ return (trybase(0xb0) ? 1 : trybase(0x30)); } +/* + * init_qd6580: + * + * called at the very beginning of initialization ; should just probe and link + */ void __init init_qd6580 (void) { @@ -264,13 +395,16 @@ printk("qd6580: not found\n"); return; } - - printk("qd6580: base=%#x, status=%#x, control=%#x\n", basePort, status, control); - + + printk("qd6580: base=%#x, config=%#x, control=%#x\n", basePort, config, control); + ide_hwifs[0].chipset = ide_qd6580; - ide_hwifs[1].chipset = ide_qd6580; ide_hwifs[0].tuneproc = &tune_qd6580; - ide_hwifs[0].mate = &ide_hwifs[1]; - ide_hwifs[1].mate = &ide_hwifs[0]; - ide_hwifs[1].channel = 1; + if (!(control & 0x01)) { + ide_hwifs[1].chipset = ide_qd6580; + ide_hwifs[1].tuneproc = &tune_snd_qd6580; + ide_hwifs[0].mate = &ide_hwifs[1]; + ide_hwifs[1].mate = &ide_hwifs[0]; + ide_hwifs[1].channel = 1; + } } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/sis5513.c linux/drivers/ide/sis5513.c --- v2.4.0-test1/linux/drivers/ide/sis5513.c Tue May 23 15:31:34 2000 +++ linux/drivers/ide/sis5513.c Tue Jun 20 07:52:36 2000 @@ -1,7 +1,7 @@ /* - * linux/drivers/ide/sis5513.c Version 0.10 Mar. 18, 2000 + * linux/drivers/ide/sis5513.c Version 0.11 June 9, 2000 * - * Copyright (C) 1999-2000 Andre Hedrick (andre@suse.com) + * Copyright (C) 1999-2000 Andre Hedrick * May be copied or modified under the terms of the GNU General Public License * * Thanks to SIS Taiwan for direct support and hardware. @@ -111,12 +111,12 @@ extern int (*sis_display_info)(char *, char **, off_t, int); /* ide-proc.c */ static struct pci_dev *bmide_dev; -static char *cable_type[] __initdata = { +static char *cable_type[] = { "80 pins", "40 pins" }; -static char *recovery_time [] __initdata ={ +static char *recovery_time [] ={ "12 PCICLK", "1 PCICLK", "2 PCICLK", "3 PCICLK", "4 PCICLK", "5 PCICLCK", @@ -127,14 +127,14 @@ "15 PCICLK", "15 PCICLK" }; -static char * cycle_time [] __initdata = { +static char * cycle_time [] = { "Undefined", "2 CLCK", "3 CLK", "4 CLK", "5 CLK", "6 CLK", "7 CLK", "8 CLK" }; -static char * active_time [] __initdata = { +static char * active_time [] = { "8 PCICLK", "1 PCICLCK", "2 PCICLK", "2 PCICLK", "4 PCICLK", "5 PCICLK", @@ -185,7 +185,7 @@ p += sprintf(p, " UDMA Cycle Time %s \t UDMA Cycle Time %s\n", cycle_time[(reg & 0x70) >> 4], cycle_time[(reg1 & 0x70) >> 4]); p += sprintf(p, " Data Active Time %s \t Data Active Time %s\n", - active_time[(reg & 0x07)], active_time[(reg &0x07)] ); + active_time[(reg & 0x07)], active_time[(reg1 &0x07)] ); rc = pci_read_config_byte(bmide_dev, 0x40, ®); rc = pci_read_config_byte(bmide_dev, 0x44, ®1); @@ -209,7 +209,7 @@ p += sprintf(p, " UDMA Cycle Time %s \t UDMA Cycle Time %s\n", cycle_time[(reg & 0x70) >> 4], cycle_time[(reg1 & 0x70) >> 4]); p += sprintf(p, " Data Active Time %s \t Data Active Time %s\n", - active_time[(reg & 0x07)], active_time[(reg &0x07)] ); + active_time[(reg & 0x07)], active_time[(reg1 &0x07)] ); rc = pci_read_config_byte(bmide_dev, 0x42, ®); rc = pci_read_config_byte(bmide_dev, 0x46, ®1); @@ -335,7 +335,7 @@ #ifdef CONFIG_BLK_DEV_IDEDMA /* - * ((id->hw_config & 0x2000) && (HWIF(drive)->udma_four)) + * ((id->hw_config & 0x4000|0x2000) && (HWIF(drive)->udma_four)) */ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) { @@ -349,7 +349,7 @@ unsigned long dma_base = hwif->dma_base; byte unit = (drive->select.b.unit & 0x01); byte speed = 0x00, unmask = 0xE0, four_two = 0x00; - byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0; + byte udma_66 = eighty_ninty_three(drive); if (host_dev) { switch(host_dev->device) { @@ -536,7 +536,7 @@ pci_read_config_byte(dev, 0x52, ®52h); if (!(reg52h & 0x04)) { - /* set IDE controller to operate in Compabitility mode obly */ + /* set IDE controller to operate in Compabitility mode only */ pci_write_config_byte(dev, 0x52, reg52h|0x04); } #if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/trm290.c linux/drivers/ide/trm290.c --- v2.4.0-test1/linux/drivers/ide/trm290.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/trm290.c Tue Jun 20 07:52:36 2000 @@ -224,10 +224,10 @@ struct pci_dev *dev = hwif->pci_dev; hwif->chipset = ide_trm290; - cfgbase = dev->resource[4].start; + cfgbase = pci_resource_start(dev, 4); if ((dev->class & 5) && cfgbase) { - hwif->config_data = cfgbase & PCI_BASE_ADDRESS_IO_MASK; + hwif->config_data = cfgbase; printk("TRM290: chip config base at 0x%04lx\n", hwif->config_data); } else { hwif->config_data = 0x3df0; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ide/via82cxxx.c linux/drivers/ide/via82cxxx.c --- v2.4.0-test1/linux/drivers/ide/via82cxxx.c Mon Jun 19 16:31:59 2000 +++ linux/drivers/ide/via82cxxx.c Tue Jun 20 07:52:36 2000 @@ -1,10 +1,10 @@ /* - * linux/drivers/ide/via82cxxx.c Version 0.09 Apr. 02, 2000 + * linux/drivers/ide/via82cxxx.c Version 0.10 June 9, 2000 * * Copyright (C) 1998-99 Michel Aubry, Maintainer * Copyright (C) 1999 Jeff Garzik, MVP4 Support * (jgarzik@mandrakesoft.com) - * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com) + * Copyright (C) 1998-2000 Andre Hedrick * May be copied or modified under the terms of the GNU General Public License * * The VIA MVP-4 is reported OK with UDMA. @@ -101,19 +101,19 @@ struct chipset_bus_clock_list_entry { byte xfer_speed; - byte chipset_settings_25; byte ultra_settings_25; - byte chipset_settings_33; + byte chipset_settings_25; byte ultra_settings_33; - byte chipset_settings_37; + byte chipset_settings_33; byte ultra_settings_37; - byte chipset_settings_41; + byte chipset_settings_37; byte ultra_settings_41; + byte chipset_settings_41; }; static struct chipset_bus_clock_list_entry * via82cxxx_table = NULL; -struct chipset_bus_clock_list_entry via82cxxx_type_one [] = { +static struct chipset_bus_clock_list_entry via82cxxx_type_one [] = { /* speed */ /* 25 */ /* 33 */ /* 37.5 */ /* 41.5 */ #ifdef CONFIG_BLK_DEV_IDEDMA { XFER_UDMA_4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, @@ -134,7 +134,7 @@ { 0, 0x03, 0xA8, 0x03, 0xA8, 0x03, 0xA9, 0x00, 0x00 } }; -struct chipset_bus_clock_list_entry via82cxxx_type_two [] = { +static struct chipset_bus_clock_list_entry via82cxxx_type_two [] = { /* speed */ /* 25 */ /* 33 */ /* 37.5 */ /* 41.5 */ #ifdef CONFIG_BLK_DEV_IDEDMA { XFER_UDMA_4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, @@ -155,7 +155,7 @@ { 0, 0x03, 0xA8, 0x03, 0xA8, 0x03, 0xDB, 0x03, 0xFE } }; -struct chipset_bus_clock_list_entry via82cxxx_type_three [] = { +static struct chipset_bus_clock_list_entry via82cxxx_type_three [] = { /* speed */ /* 25 */ /* 33 */ /* 37.5 */ /* 41.5 */ #ifdef CONFIG_BLK_DEV_IDEDMA { XFER_UDMA_4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, @@ -176,7 +176,7 @@ { 0, 0x03, 0xA8, 0x03, 0xA8, 0x03, 0xDB, 0x03, 0xFE } }; -struct chipset_bus_clock_list_entry via82cxxx_type_four [] = { +static struct chipset_bus_clock_list_entry via82cxxx_type_four [] = { /* speed */ /* 25 */ /* 33 */ /* 37.5 */ /* 41.5 */ #ifdef CONFIG_BLK_DEV_IDEDMA { XFER_UDMA_4, 0x00, 0x00, 0xE0, 0x20, 0xE1, 0x31, 0x00, 0x00 }, @@ -243,20 +243,20 @@ #define arraysize(x) (sizeof(x)/sizeof(*(x))) -#undef DISPLAY_VIA_TIMINGS +#define DISPLAY_VIA_TIMINGS #if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS) #include #include -static char *FIFO_str[] __initdata = { +static char *FIFO_str[] = { " 1 ", "3/4", "1/2", "1/4" }; -static char *control3_str[] __initdata = { +static char *control3_str[] = { "No limitation", "64", "128", @@ -760,11 +760,15 @@ { struct hd_driveid *id = drive->id; byte speed = 0x00; + byte ultra66 = eighty_ninty_three(drive); + byte ultra100 = 0; int rval; - if ((id->dma_ultra & 0x0010) && (HWIF(drive)->udma_four)) { + if ((id->dma_ultra & 0x0020) && (ultra66) && (ultra100)) { + speed = XFER_UDMA_5; + } else if ((id->dma_ultra & 0x0010) && (ultra66)) { speed = XFER_UDMA_4; - } else if ((id->dma_ultra & 0x0008) && (HWIF(drive)->udma_four)) { + } else if ((id->dma_ultra & 0x0008) && (ultra66)) { speed = XFER_UDMA_3; } else if (id->dma_ultra & 0x0004) { speed = XFER_UDMA_2; @@ -778,12 +782,6 @@ speed = XFER_MW_DMA_1; } else if (id->dma_mword & 0x0001) { speed = XFER_MW_DMA_0; - } else if (id->dma_1word & 0x0004) { - speed = XFER_SW_DMA_2; - } else if (id->dma_1word & 0x0002) { - speed = XFER_SW_DMA_1; - } else if (id->dma_1word & 0x0001) { - speed = XFER_SW_DMA_0; } else { return ((int) ide_dma_off_quietly); } @@ -793,7 +791,6 @@ rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on : ((id->dma_ultra >> 8) & 7) ? ide_dma_on : ((id->dma_mword >> 8) & 7) ? ide_dma_on : - ((id->dma_1word >> 8) & 7) ? ide_dma_on : ide_dma_off_quietly); return rval; } @@ -811,7 +808,7 @@ } dma_func = ide_dma_off_quietly; if (id->field_valid & 4) { - if (id->dma_ultra & 0x001F) { + if (id->dma_ultra & 0x002F) { /* Force if Capable UltraDMA */ dma_func = config_chipset_for_dma(drive); if ((id->field_valid & 2) && @@ -820,8 +817,7 @@ } } else if (id->field_valid & 2) { try_dma_modes: - if ((id->dma_mword & 0x0007) || - (id->dma_1word & 0x0007)) { + if (id->dma_mword & 0x0007) { /* Force if Capable regular DMA modes */ dma_func = config_chipset_for_dma(drive); if (dma_func != ide_dma_on) @@ -870,7 +866,7 @@ byte revision = 0; for (i = 0; i < arraysize (ApolloHostChipInfo) && !host_dev; i++) { - host = pci_find_device (PCI_VENDOR_ID_VIA, + host = pci_find_device (ApolloHostChipInfo[i].vendor_id, ApolloHostChipInfo[i].host_id, NULL); if (!host) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ieee1394/Makefile linux/drivers/ieee1394/Makefile --- v2.4.0-test1/linux/drivers/ieee1394/Makefile Fri Jan 21 18:19:16 2000 +++ linux/drivers/ieee1394/Makefile Mon Jun 19 17:59:40 2000 @@ -25,15 +25,13 @@ OX_OBJS := ifeq ($(CONFIG_IEEE1394),y) -L_OBJS += ieee1394.o hosts.o highlevel.o csr.o -O_TARGET = ieee1394.o -O_OBJS += ieee1394_core.o ieee1394_transactions.o -OX_OBJS += ieee1394_syms.o +L_OBJS += ieee1394_core.o ieee1394_transactions.o hosts.o highlevel.o csr.o guid.o +LX_OBJS += ieee1394_syms.o else ifeq ($(CONFIG_IEEE1394),m) M_OBJS += ieee1394.o O_TARGET = ieee1394.o - O_OBJS += ieee1394_core.o ieee1394_transactions.o hosts.o highlevel.o csr.o + O_OBJS += ieee1394_core.o ieee1394_transactions.o hosts.o highlevel.o csr.o guid.o OX_OBJS += ieee1394_syms.o endif endif diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ieee1394/aic5800.c linux/drivers/ieee1394/aic5800.c --- v2.4.0-test1/linux/drivers/ieee1394/aic5800.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/ieee1394/aic5800.c Mon Jun 19 17:59:40 2000 @@ -723,14 +723,17 @@ static int add_card(struct pci_dev *dev) { -#define FAIL(fmt, args...) \ +#define FAIL(fmt, args...) do {\ PRINT_G(KERN_ERR, fmt , ## args); \ num_of_cards--; \ remove_card(aic); \ - return 1; + return 1; } while (0) struct aic5800 *aic; /* shortcut to currently handled device */ unsigned long page; + + if (pci_enable_device(dev)) + return 1; if (num_of_cards == MAX_AIC5800_CARDS) { PRINT_G(KERN_WARNING, "cannot handle more than %d cards. " diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ieee1394/guid.c linux/drivers/ieee1394/guid.c --- v2.4.0-test1/linux/drivers/ieee1394/guid.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/ieee1394/guid.c Mon Jun 19 17:59:40 2000 @@ -0,0 +1,226 @@ +/* + * IEEE 1394 for Linux + * + * GUID collection and management + * + * Copyright (C) 2000 Andreas E. Bombe + */ + +#include +#include +#include +#include +#include + +#include "ieee1394_types.h" +#include "ieee1394.h" +#include "hosts.h" +#include "ieee1394_transactions.h" +#include "highlevel.h" +#include "csr.h" + + +static atomic_t outstanding_requests; + +static LIST_HEAD(guid_list); +rwlock_t guid_lock = RW_LOCK_UNLOCKED; + +struct guid_entry { + struct list_head list; + atomic_t refcount; + + u64 guid; + + struct hpsb_host *host; + nodeid_t node_id; + + atomic_t generation; +}; + +struct guid_req { + struct hpsb_packet *pkt; + struct tq_struct tq; +}; + + +static struct guid_entry *create_guid_entry(void) +{ + struct guid_entry *ge; + unsigned long flags; + + ge = kmalloc(sizeof(struct guid_entry), SLAB_ATOMIC); + if (!ge) return NULL; + + INIT_LIST_HEAD(&ge->list); + atomic_set(&ge->refcount, 0); + ge->guid = (u64) -1; + ge->host = NULL; + ge->node_id = 0; + atomic_set(&ge->generation, -1); + + write_lock_irqsave(&guid_lock, flags); + list_add_tail(&ge->list, &guid_list); + write_unlock_irqrestore(&guid_lock, flags); + + return ge; +} + +static struct guid_entry *find_entry(u64 guid) +{ + struct list_head *lh; + struct guid_entry *ge; + + lh = guid_list.next; + while (lh != &guid_list) { + ge = list_entry(lh, struct guid_entry, list); + if (ge->guid == guid) return ge; + lh = lh->next; + } + + return NULL; +} + +static void associate_guid(struct hpsb_host *host, nodeid_t nodeid, u64 guid) +{ + struct guid_entry *ge; + unsigned long flags; + + HPSB_DEBUG("node %d on host 0x%p has GUID 0x%08x%08x", + nodeid & NODE_MASK, host, (unsigned int)(guid >> 32), + (unsigned int)(guid & 0xffffffff)); + + read_lock_irqsave(&guid_lock, flags); + ge = find_entry(guid); + read_unlock_irqrestore(&guid_lock, flags); + + if (!ge) ge = create_guid_entry(); + if (!ge) return; + + ge->host = host; + ge->node_id = nodeid; + ge->guid = guid; + + atomic_set(&ge->generation, get_hpsb_generation()); +} + +static void pkt_complete(struct guid_req *req) +{ + struct hpsb_packet *pkt = req->pkt; + int rcode = (pkt->header[1] >> 12) & 0xf; + + if (pkt->ack_code == ACK_PENDING && rcode == RCODE_COMPLETE) { + if (*(char *)pkt->data > 1) { + associate_guid(pkt->host, pkt->node_id, + ((u64)be32_to_cpu(pkt->data[3]) << 32) + | be32_to_cpu(pkt->data[4])); + } else { + HPSB_DEBUG("minimal ROM on node %d", + pkt->node_id & NODE_MASK); + } + } else { + HPSB_DEBUG("guid transaction error: ack %d, rcode %d", + pkt->ack_code, rcode); + } + + free_tlabel(pkt->host, pkt->node_id, pkt->tlabel); + free_hpsb_packet(pkt); + kfree(req); + + if (atomic_dec_and_test(&outstanding_requests)) { + /* FIXME: free unreferenced and inactive GUID entries. */ + } +} + + +static void host_reset(struct hpsb_host *host) +{ + struct guid_req *greq; + struct hpsb_packet *pkt; + struct selfid *sid = (struct selfid *)host->topology_map; + int nodecount = host->node_count; + nodeid_t nodeid = LOCAL_BUS; + + for (; nodecount; nodecount--, nodeid++, sid++) { + while (sid->extended) sid++; + if (!sid->link_active) continue; + if (nodeid == host->node_id) continue; + + greq = kmalloc(sizeof(struct guid_req), SLAB_ATOMIC); + if (!greq) { + HPSB_ERR("out of memory in GUID processing"); + return; + } + + pkt = hpsb_make_readbpacket(host, nodeid, + CSR_REGISTER_BASE + CSR_CONFIG_ROM, + 20); + if (!pkt) { + kfree(greq); + HPSB_ERR("out of memory in GUID processing"); + return; + } + + greq->tq.next = NULL; + greq->tq.sync = 0; + greq->tq.routine = (void (*)(void*))pkt_complete; + greq->tq.data = greq; + greq->pkt = pkt; + + queue_task(&greq->tq, &pkt->complete_tq); + + if (!hpsb_send_packet(pkt)) { + free_tlabel(pkt->host, pkt->node_id, pkt->tlabel); + free_hpsb_packet(pkt); + kfree(greq); + HPSB_NOTICE("failed to send packet in GUID processing"); + } + + HPSB_INFO("GUID request sent to node %d", nodeid & NODE_MASK); + atomic_inc(&outstanding_requests); + } +} + + +struct guid_entry *hpsb_guid_get_handle(u64 guid) +{ + unsigned long flags; + struct guid_entry *ge; + + read_lock_irqsave(&guid_lock, flags); + ge = find_entry(guid); + if (ge) atomic_inc(&ge->refcount); + read_unlock_irqrestore(&guid_lock, flags); + + return ge; +} + +struct hpsb_host *hpsb_guid_localhost(struct guid_entry *ge) +{ + if (atomic_read(&ge->generation) != get_hpsb_generation()) return NULL; + if (ge->node_id == ge->host->node_id) return ge->host; + return NULL; +} + +int hpsb_guid_fill_packet(struct guid_entry *ge, struct hpsb_packet *pkt) +{ + if (atomic_read(&ge->generation) != get_hpsb_generation()) return 0; + + pkt->host = ge->host; + pkt->node_id = ge->node_id; + pkt->generation = atomic_read(&ge->generation); + return 1; +} + + +static struct hpsb_highlevel_ops guid_ops = { + host_reset: host_reset, +}; + +void init_ieee1394_guid(void) +{ + atomic_set(&outstanding_requests, 0); + + if (!hpsb_register_highlevel("GUID manager", &guid_ops)) { + HPSB_ERR("out of memory during ieee1394 initialization"); + } +} diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ieee1394/guid.h linux/drivers/ieee1394/guid.h --- v2.4.0-test1/linux/drivers/ieee1394/guid.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/ieee1394/guid.h Mon Jun 19 17:59:40 2000 @@ -0,0 +1,54 @@ + +#ifndef _IEEE1394_GUID_H +#define _IEEE1394_GUID_H + + +/* + * General information: Finding out which GUID belongs to which node is done by + * sending packets and therefore waiting for the answers. Wherever it is + * mentioned that a node is inaccessible this could just as well mean that we + * just don't know yet (usually, bus reset handlers can't rely on GUIDs being + * associated with current nodes). + */ + +struct guid_entry; +typedef struct guid_entry *hpsb_guid_t; + + +/* + * Returns a guid handle (which has its reference count incremented) or NULL if + * there is the GUID in question is not known of. Getting a valid handle does + * not mean that the node with this GUID is currently accessible (might not be + * plugged in or powered down). + */ +hpsb_guid_t hpsb_guid_get_handle(u64 guid); + +/* + * If the handle refers to a local host, this function will return the pointer + * to the hpsb_host structure. It will return NULL otherwise. Once you have + * established it is a local host, you can use that knowledge from then on (the + * GUID won't wander to an external node). + * + * Note that the local GUID currently isn't collected, so this will always + * return NULL. + */ +struct hpsb_host *hpsb_guid_localhost(hpsb_guid_t handle); + +/* + * This will fill in the given, pre-initialised hpsb_packet with the current + * information from the GUID handle (host, node ID, generation number). It will + * return false if the node owning the GUID is not accessible (and not modify the + * hpsb_packet) and return true otherwise. + * + * Note that packet sending may still fail in hpsb_send_packet if a bus reset + * happens while you are trying to set up the packet (due to obsolete generation + * number). It will at least reliably fail so that you don't accidentally and + * unknowingly send your packet to the wrong node. + */ +int hpsb_guid_fill_packet(hpsb_guid_t handle, struct hpsb_packet *pkt); + + +void init_ieee1394_guid(void); + + +#endif /* _IEEE1394_GUID_H */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ieee1394/ieee1394_core.c linux/drivers/ieee1394/ieee1394_core.c --- v2.4.0-test1/linux/drivers/ieee1394/ieee1394_core.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ieee1394/ieee1394_core.c Mon Jun 19 17:59:40 2000 @@ -25,6 +25,7 @@ #include "highlevel.h" #include "ieee1394_transactions.h" #include "csr.h" +#include "guid.h" atomic_t hpsb_generation = ATOMIC_INIT(0); @@ -45,6 +46,26 @@ } +/** + * alloc_hpsb_packet - allocate new packet structure + * @data_size: size of the data block to be allocated + * + * This function allocates, initializes and returns a new &struct hpsb_packet. + * It can be used in interrupt context. A header block is always included, its + * size is big enough to contain all possible 1394 headers. The data block is + * only allocated when @data_size is not zero. + * + * For packets for which responses will be received the @data_size has to be big + * enough to contain the response's data block since no further allocation + * occurs at response matching time. + * + * The packet's generation value will be set to the current generation number + * for ease of use. Remember to overwrite it with your own recorded generation + * number if you can not be sure that your code will not race with a bus reset. + * + * Return value: A pointer to a &struct hpsb_packet or NULL on allocation + * failure. + */ struct hpsb_packet *alloc_hpsb_packet(size_t data_size) { struct hpsb_packet *packet = NULL; @@ -83,6 +104,14 @@ return packet; } + +/** + * free_hpsb_packet - free packet and data associated with it + * @packet: packet to free (is NULL safe) + * + * This function will free packet->data, packet->header and finally the packet + * itself. + */ void free_hpsb_packet(struct hpsb_packet *packet) { if (packet == NULL) { @@ -336,6 +365,20 @@ queue_task(&host->timeout_tq, &tq_timer); } +/** + * hpsb_send_packet - transmit a packet on the bus + * @packet: packet to send + * + * The packet is sent through the host specified in the packet->host field. + * Before sending, the packet's transmit speed is automatically determined using + * the local speed map. + * + * Possibilities for failure are that host is either not initialized, in bus + * reset, the packet's generation number doesn't match the current generation + * number or the host reports a transmit error. + * + * Return value: False (0) on failure, true (1) otherwise. + */ int hpsb_send_packet(struct hpsb_packet *packet) { struct hpsb_host *host = packet->host; @@ -721,47 +764,6 @@ } -#if 0 -int hpsb_host_thread(void *hostPointer) -{ - struct hpsb_host *host = (struct hpsb_host *)hostPointer; - - /* I don't understand why, but I just want to be on the safe side. */ - lock_kernel(); - - HPSB_INFO(__FUNCTION__ " starting for one %s adapter", - host->template->name); - - exit_mm(current); - exit_files(current); - exit_fs(current); - - strcpy(current->comm, "ieee1394 thread"); - - /* ... but then again, I think the following is safe. */ - unlock_kernel(); - - for (;;) { - siginfo_t info; - unsigned long signr; - - if (signal_pending(current)) { - spin_lock_irq(¤t->sigmask_lock); - signr = dequeue_signal(¤t->blocked, &info); - spin_unlock_irq(¤t->sigmask_lock); - - break; - } - - abort_timedouts(host); - } - - HPSB_INFO(__FUNCTION__ " exiting"); - return 0; -} -#endif - - #ifndef MODULE void __init ieee1394_init(void) @@ -769,6 +771,7 @@ register_builtin_lowlevels(); init_hpsb_highlevel(); init_csr(); + init_ieee1394_guid(); } #else @@ -777,6 +780,8 @@ { init_hpsb_highlevel(); init_csr(); + init_ieee1394_guid(); + return 0; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ieee1394/ieee1394_syms.c linux/drivers/ieee1394/ieee1394_syms.c --- v2.4.0-test1/linux/drivers/ieee1394/ieee1394_syms.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/ieee1394/ieee1394_syms.c Mon Jun 19 17:59:40 2000 @@ -8,6 +8,7 @@ #include #include +#include #include "ieee1394_types.h" #include "hosts.h" @@ -15,6 +16,7 @@ #include "ieee1394_transactions.h" /* #include "events.h" */ #include "highlevel.h" +#include "guid.h" EXPORT_SYMBOL(hpsb_register_lowlevel); EXPORT_SYMBOL(hpsb_unregister_lowlevel); @@ -52,3 +54,7 @@ EXPORT_SYMBOL(highlevel_write); EXPORT_SYMBOL(highlevel_lock); EXPORT_SYMBOL(highlevel_lock64); + +EXPORT_SYMBOL(hpsb_guid_get_handle); +EXPORT_SYMBOL(hpsb_guid_localhost); +EXPORT_SYMBOL(hpsb_guid_fill_packet); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ieee1394/ieee1394_transactions.c linux/drivers/ieee1394/ieee1394_transactions.c --- v2.4.0-test1/linux/drivers/ieee1394/ieee1394_transactions.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ieee1394/ieee1394_transactions.c Mon Jun 19 17:59:40 2000 @@ -132,6 +132,26 @@ } +/** + * get_tlabel - allocate a transaction label + * @host: host to be used for transmission + * @nodeid: the node ID of the transmission target + * @wait: whether to sleep if no tlabel is available + * + * Every asynchronous transaction on the 1394 bus needs a transaction label to + * match the response to the request. This label has to be different from any + * other transaction label in an outstanding request to the same node to make + * matching possible without ambiguity. + * + * There are 64 different tlabels, so an allocated tlabel has to be freed with + * free_tlabel() after the transaction is complete (unless it's reused again for + * the same target node). + * + * @wait must not be set to true if you are calling from interrupt context. + * + * Return value: The allocated transaction label or -1 if there was no free + * tlabel and @wait is false. + */ int get_tlabel(struct hpsb_host *host, nodeid_t nodeid, int wait) { unsigned long flags; @@ -166,6 +186,18 @@ } } +/** + * free_tlabel - free an allocated transaction label + * @host: host to be used for transmission + * @nodeid: the node ID of the transmission target + * @tlabel: the transaction label to free + * + * Frees the transaction label allocated with get_tlabel(). The tlabel has to + * be freed after the transaction is complete (i.e. response was received for a + * split transaction or packet was sent for a unified transaction). + * + * A tlabel must not be freed twice. + */ void free_tlabel(struct hpsb_host *host, nodeid_t nodeid, int tlabel) { unsigned long flags; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ieee1394/ieee1394_types.h linux/drivers/ieee1394/ieee1394_types.h --- v2.4.0-test1/linux/drivers/ieee1394/ieee1394_types.h Mon Mar 27 08:08:24 2000 +++ linux/drivers/ieee1394/ieee1394_types.h Mon Jun 19 17:59:40 2000 @@ -27,7 +27,19 @@ #define __constant_cpu_to_be32(x) __constant_htonl((x)) -#endif +#define set_current_state(state_value) \ + do { current->state = (state_value); } while (0) + +#include +inline static int pci_enable_device(struct pci_dev *dev) +{ + u16 cmd; + pci_read_config_word(dev, PCI_COMMAND, &cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd | PCI_COMMAND_MEMORY); + return 0; +} + +#endif /* Linux version < 2.3 */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) #include @@ -39,6 +51,9 @@ #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif typedef __u32 quadlet_t; typedef __u64 octlet_t; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ieee1394/ohci1394.c linux/drivers/ieee1394/ohci1394.c --- v2.4.0-test1/linux/drivers/ieee1394/ohci1394.c Thu May 11 15:30:07 2000 +++ linux/drivers/ieee1394/ohci1394.c Mon Jun 19 17:59:40 2000 @@ -38,15 +38,25 @@ * . Self-id are sometimes not received properly * if card is initialized with no other nodes * on the bus + * . SONY CXD3222 chip is not working properly + * . Apple PowerBook detected but not working yet */ /* * Acknowledgments: * * Emilie Chung - * .Tip on Async Request Filter + * . Tip on Async Request Filter * Pascal Drolet - * .Various tips for optimization and functionnalities + * . Various tips for optimization and functionnalities + * Robert Ficklin + * . Loop in irq_handler + * James Goodwin + * . Various tips on initialization, self-id reception, etc. + * Albrecht Dress + * . Apple PowerBook detection + * Daniel Kobras + * . Reset the board properly before leaving */ #include @@ -65,6 +75,7 @@ #include #include #include +#include #include #include @@ -118,6 +129,7 @@ { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_UPD72862 }, { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_UPD72870 }, { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_UPD72871 }, + { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_FW }, { -1, -1 } }; @@ -128,7 +140,619 @@ static void remove_card(struct ti_ohci *ohci); static int init_driver(void); static void dma_trm_bh(void *data); +static void dma_rcv_bh(void *data); static void dma_trm_reset(struct dma_trm_ctx *d); +static void stop_context(struct ti_ohci *ohci, int reg, char *msg); + +#ifdef _VIDEO_1394_H + +/* Taken from bttv.c */ +/*******************************/ +/* Memory management functions */ +/*******************************/ + +#define MDEBUG(x) do { } while(0) /* Debug memory management */ + +/* [DaveM] I've recoded most of this so that: + * 1) It's easier to tell what is happening + * 2) It's more portable, especially for translating things + * out of vmalloc mapped areas in the kernel. + * 3) Less unnecessary translations happen. + * + * The code used to assume that the kernel vmalloc mappings + * existed in the page tables of every process, this is simply + * not guarenteed. We now use pgd_offset_k which is the + * defined way to get at the kernel page tables. + */ + +/* Given PGD from the address space's page table, return the kernel + * virtual mapping of the physical memory mapped at ADR. + */ +static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) +{ + unsigned long ret = 0UL; + pmd_t *pmd; + pte_t *ptep, pte; + + if (!pgd_none(*pgd)) { + pmd = pmd_offset(pgd, adr); + if (!pmd_none(*pmd)) { + ptep = pte_offset(pmd, adr); + pte = *ptep; + if(pte_present(pte)) + ret = (pte_page(pte)|(adr&(PAGE_SIZE-1))); + } + } + MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret)); + return ret; +} + +static inline unsigned long uvirt_to_bus(unsigned long adr) +{ + unsigned long kva, ret; + + kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr); + ret = virt_to_bus((void *)kva); + MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret)); + return ret; +} + +static inline unsigned long kvirt_to_bus(unsigned long adr) +{ + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = virt_to_bus((void *)kva); + MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret)); + return ret; +} + +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the + * area and marking the pages as reserved. + */ +static inline unsigned long kvirt_to_pa(unsigned long adr) +{ + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = __pa(kva); + MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); + return ret; +} + +static void * rvmalloc(unsigned long size) +{ + void * mem; + unsigned long adr, page; + + mem=vmalloc(size); + if (mem) + { + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr=(unsigned long) mem; + while (size > 0) + { + page = kvirt_to_pa(adr); + mem_map_reserve(MAP_NR(__va(page))); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + } + return mem; +} + +static void rvfree(void * mem, unsigned long size) +{ + unsigned long adr, page; + + if (mem) + { + adr=(unsigned long) mem; + while (size > 0) + { + page = kvirt_to_pa(adr); + mem_map_unreserve(MAP_NR(__va(page))); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + vfree(mem); + } +} + +static int free_dma_fbuf_ctx(struct dma_fbuf_ctx **d) +{ + int i; + struct ti_ohci *ohci; + + if ((*d)==NULL) return -1; + + ohci = (struct ti_ohci *)(*d)->ohci; + + DBGMSG(ohci->id, "Freeing dma_fbuf_ctx %d", (*d)->ctx); + + stop_context(ohci, (*d)->ctrlClear, NULL); + + if ((*d)->buf) rvfree((void *)(*d)->buf, + (*d)->num_desc * (*d)->buf_size); + + if ((*d)->prg) { + for (i=0;i<(*d)->num_desc;i++) + if ((*d)->prg[i]) kfree((*d)->prg[i]); + kfree((*d)->prg); + } + + if ((*d)->buffer_status) + kfree((*d)->buffer_status); + + kfree(*d); + *d = NULL; + + return 0; +} + +static struct dma_fbuf_ctx * +alloc_dma_fbuf_ctx(struct ti_ohci *ohci, int ctx, int num_desc, + int buf_size, int channel) +{ + struct dma_fbuf_ctx *d=NULL; + int i; + + d = (struct dma_fbuf_ctx *)kmalloc(sizeof(struct dma_fbuf_ctx), + GFP_KERNEL); + + if (d==NULL) { + PRINT(KERN_ERR, ohci->id, "failed to allocate dma_fbuf_ctx"); + return NULL; + } + + d->ohci = (void *)ohci; + d->ctx = ctx; + d->channel = channel; + d->num_desc = num_desc; + d->frame_size = buf_size; + if (buf_size%PAGE_SIZE) + d->buf_size = buf_size + PAGE_SIZE - (buf_size%PAGE_SIZE); + else + d->buf_size = buf_size; + d->ctrlSet = OHCI1394_IrRcvContextControlSet+32*d->ctx; + d->ctrlClear = OHCI1394_IrRcvContextControlClear+32*d->ctx; + d->cmdPtr = OHCI1394_IrRcvCommandPtr+32*d->ctx; + d->ctxMatch = OHCI1394_IrRcvContextMatch+32*d->ctx; + d->nb_cmd = d->buf_size / PAGE_SIZE + 1; + d->last_buffer = 0; + d->buf = NULL; + d->prg = NULL; + init_waitqueue_head(&d->waitq); + + d->buf = rvmalloc(d->num_desc * d->buf_size); + + if (d->buf == NULL) { + PRINT(KERN_ERR, ohci->id, "failed to allocate dma fbuffer"); + free_dma_fbuf_ctx(&d); + return NULL; + } + memset(d->buf, 0, d->num_desc * d->buf_size); + + d->prg = kmalloc(d->num_desc * sizeof(struct dma_cmd *), + GFP_KERNEL); + + if (d->prg == NULL) { + PRINT(KERN_ERR, ohci->id, "failed to allocate dma fbuf prg"); + free_dma_fbuf_ctx(&d); + return NULL; + } + memset(d->prg, 0, d->num_desc * sizeof(struct dma_cmd *)); + + for (i=0;inum_desc;i++) { + d->prg[i] = kmalloc(d->nb_cmd * sizeof(struct dma_cmd), + GFP_KERNEL); + if (d->prg[i] == NULL) { + PRINT(KERN_ERR, ohci->id, + "failed to allocate dma fbuf prg"); + free_dma_fbuf_ctx(&d); + return NULL; + } + } + + d->buffer_status = kmalloc(d->num_desc * sizeof(unsigned int), + GFP_KERNEL); + + if (d->buffer_status == NULL) { + PRINT(KERN_ERR, ohci->id, "failed to allocate dma fbuf prg"); + free_dma_fbuf_ctx(&d); + return NULL; + } + memset(d->buffer_status, 0, d->num_desc * sizeof(unsigned int)); + + PRINT(KERN_INFO, ohci->id, "Iso DMA to User's Space: %d buffers " + "of size %d allocated for a frame size %d, each with %d prgs", + d->num_desc, d->buf_size, d->frame_size, d->nb_cmd); + + return d; +} + +static void initialize_dma_fbuf_prg(struct dma_cmd *prg, int n, + int frame_size, unsigned long buf) +{ + int i; + int leftsize = (frame_size%PAGE_SIZE) ? + frame_size%PAGE_SIZE : PAGE_SIZE; + + /* the first descriptor will sync and read only 4 bytes */ + prg[0].control = (0x280F << 16) | 4; + prg[0].address = kvirt_to_bus(buf); + prg[0].branchAddress = (virt_to_bus(&(prg[1].control)) + & 0xfffffff0) | 0x1; + prg[0].status = 0; + + /* the second descriptor will read PAGE_SIZE-4 bytes */ + prg[1].control = (0x280C << 16) | (PAGE_SIZE-4); + prg[1].address = kvirt_to_bus(buf+4); + prg[1].branchAddress = (virt_to_bus(&(prg[2].control)) + & 0xfffffff0) | 0x1; + prg[1].status = 0; + + for (i=2;iohci; + int i; + + stop_context(ohci, d->ctrlClear, NULL); + + for (i=0;inum_desc;i++) { + initialize_dma_fbuf_prg(d->prg[i], d->nb_cmd, d->frame_size, + (unsigned long)d->buf+i*d->buf_size); + } + + /* Set bufferFill, no header */ + reg_write(ohci, d->ctrlSet, 0x80000000); + + /* Set the context match register to match on all tags, + sync for sync tag, and listen to d->channel */ + reg_write(ohci, d->ctxMatch, 0xf0000000|((tag&0xf)<<8)|d->channel); + + /* Set up isoRecvIntMask to generate interrupts */ + reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1<ctx); +} + +/* find which context is listening to this channel */ +int fbuf_ctx_listening(struct ti_ohci *ohci, int channel) +{ + int i; + for (i=0;inb_iso_ctx-1;i++) + if (ohci->fbuf_context[i]) { + if (ohci->fbuf_context[i]->channel==channel) + return i; + } + + PRINT(KERN_ERR, ohci->id, + "no iso context is listening to channel %d", + channel); + return -1; +} + +static int ohci_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct ti_ohci *ohci=&cards[MINOR(inode->i_rdev)]; + + switch(cmd) + { + case VIDEO1394_LISTEN_CHANNEL: + { + struct video1394_mmap v; + int i; + + if(copy_from_user(&v, (void *)arg, sizeof(v))) + return -EFAULT; + if (v.channel<0 || v.channel>(ISO_CHANNELS-1)) { + PRINT(KERN_ERR, ohci->id, + "iso channel %d out of bound", v.channel); + return -EFAULT; + } + if (test_and_set_bit(v.channel, &ohci->IR_channel_usage)) { + PRINT(KERN_ERR, ohci->id, + "channel %d is already taken", v.channel); + return -EFAULT; + } + + /* find a free iso context */ + for (i=0;inb_iso_ctx-1;i++) + if (ohci->fbuf_context[i]==NULL) break; + + if (i==(ohci->nb_iso_ctx-1)) { + PRINT(KERN_ERR, ohci->id, "no iso context available"); + return -EFAULT; + } + + if (v.nb_buffers * v.buf_size > VIDEO1394_MAX_SIZE) { + PRINT(KERN_ERR, ohci->id, + "%d buffers of size %d bytes is too big", + v.nb_buffers, v.buf_size); + return -EFAULT; + } + + ohci->fbuf_context[i] = + alloc_dma_fbuf_ctx(ohci, i+1, v.nb_buffers, + v.buf_size, v.channel); + + if (ohci->fbuf_context[i] == NULL) { + PRINT(KERN_ERR, ohci->id, + "Couldn't allocate fbuf context"); + return -EFAULT; + } + initialize_dma_fbuf_ctx(ohci->fbuf_context[i], v.sync_tag); + + ohci->current_fbuf_ctx = ohci->fbuf_context[i]; + + v.buf_size = ohci->fbuf_context[i]->buf_size; + + PRINT(KERN_INFO, ohci->id, + "iso context %d listen on channel %d", i+1, + v.channel); + + if(copy_to_user((void *)arg, &v, sizeof(v))) + return -EFAULT; + + return 0; + } + case VIDEO1394_UNLISTEN_CHANNEL: + { + int channel; + int i; + + if(copy_from_user(&channel, (void *)arg, sizeof(int))) + return -EFAULT; + + if (!test_and_clear_bit(channel, &ohci->IR_channel_usage)) { + PRINT(KERN_ERR, ohci->id, + "channel %d is not being used", channel); + return -EFAULT; + } + + i = fbuf_ctx_listening(ohci, channel); + if (i<0) return -EFAULT; + + free_dma_fbuf_ctx(&ohci->fbuf_context[i]); + + PRINT(KERN_INFO, ohci->id, + "iso context %d stop listening on channel %d", + i+1, channel); + + return 0; + } + case VIDEO1394_QUEUE_BUFFER: + { + struct video1394_wait v; + struct dma_fbuf_ctx *d; + int i; + + if(copy_from_user(&v, (void *)arg, sizeof(v))) + return -EFAULT; + + i = fbuf_ctx_listening(ohci, v.channel); + if (i<0) return -EFAULT; + d = ohci->fbuf_context[i]; + + if ((v.buffer<0) || (v.buffer>d->num_desc)) { + PRINT(KERN_ERR, ohci->id, + "buffer %d out of range",v.buffer); + return -EFAULT; + } + + if (d->buffer_status[v.buffer]!=VIDEO1394_BUFFER_FREE) { + PRINT(KERN_ERR, ohci->id, + "buffer %d is already used",v.buffer); + return -EFAULT; + } + + d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED; + + d->prg[d->last_buffer][d->nb_cmd-1].branchAddress = + (virt_to_bus(&(d->prg[v.buffer][0].control)) + & 0xfffffff0) | 0x1; + + d->last_buffer = v.buffer; + + if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) + { + DBGMSG(ohci->id, "Starting iso DMA ctx=%d",d->ctx); + + /* Tell the controller where the first program is */ + reg_write(ohci, d->cmdPtr, + virt_to_bus(&(d->prg[v.buffer][0])) | 0x1 ); + + /* Run IR context */ + reg_write(ohci, d->ctrlSet, 0x8000); + } + else { + /* Wake up dma context if necessary */ + if (!(reg_read(ohci, d->ctrlSet) & 0x400)) { + PRINT(KERN_INFO, ohci->id, + "Waking up iso dma ctx=%d", d->ctx); + reg_write(ohci, d->ctrlSet, 0x1000); + } + } + return 0; + + } + case VIDEO1394_WAIT_BUFFER: + { + struct video1394_wait v; + struct dma_fbuf_ctx *d; + int i; + + if(copy_from_user(&v, (void *)arg, sizeof(v))) + return -EFAULT; + + i = fbuf_ctx_listening(ohci, v.channel); + if (i<0) return -EFAULT; + d = ohci->fbuf_context[i]; + + if ((v.buffer<0) || (v.buffer>d->num_desc)) { + PRINT(KERN_ERR, ohci->id, + "buffer %d out of range",v.buffer); + return -EFAULT; + } + + switch(d->buffer_status[v.buffer]) { + case VIDEO1394_BUFFER_READY: + d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE; + return 0; + case VIDEO1394_BUFFER_QUEUED: + while(d->buffer_status[v.buffer]!= + VIDEO1394_BUFFER_READY) { + interruptible_sleep_on(&d->waitq); + if(signal_pending(current)) return -EINTR; + } + d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE; + return 0; + default: + PRINT(KERN_ERR, ohci->id, + "buffer %d is not queued",v.buffer); + return -EFAULT; + } + } + default: + return -EINVAL; + } +} + +/* + * This maps the vmalloced and reserved fbuffer to user space. + * + * FIXME: + * - PAGE_READONLY should suffice!? + * - remap_page_range is kind of inefficient for page by page remapping. + * But e.g. pte_alloc() does not work in modules ... :-( + */ + +static int do_fbuf_mmap(struct ti_ohci *ohci, struct dma_fbuf_ctx *d, + const char *adr, unsigned long size) +{ + unsigned long start=(unsigned long) adr; + unsigned long page,pos; + + if (size>d->num_desc * d->buf_size) { + PRINT(KERN_ERR, ohci->id, + "fbuf context %d buf size is different from mmap size", + d->ctx); + return -EINVAL; + } + if (!d->buf) { + PRINT(KERN_ERR, ohci->id, + "fbuf context %d is not allocated", d->ctx); + return -EINVAL; + } + + pos=(unsigned long) d->buf; + while (size > 0) { + page = kvirt_to_pa(pos); + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) + return -EAGAIN; + start+=PAGE_SIZE; + pos+=PAGE_SIZE; + size-=PAGE_SIZE; + } + return 0; +} + +int ohci_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct ti_ohci *ohci=&cards[MINOR(file->f_dentry->d_inode->i_rdev)]; + PRINT(KERN_INFO, ohci->id, "mmap"); + if (ohci->current_fbuf_ctx == NULL) { + PRINT(KERN_ERR, ohci->id, "current fbuf context not set"); + return -EINVAL; + } + + return do_fbuf_mmap(ohci, ohci->current_fbuf_ctx, + (char *)vma->vm_start, + (unsigned long)(vma->vm_end-vma->vm_start)); + return 0; +} + +static int ohci_open(struct inode *inode, struct file *file) +{ + struct ti_ohci *ohci=&cards[MINOR(inode->i_rdev)]; + PRINT(KERN_INFO, ohci->id, "open"); + return 0; +} + +static int ohci_release(struct inode *inode, struct file *file) +{ + struct ti_ohci *ohci=&cards[MINOR(inode->i_rdev)]; + int i; + + PRINT(KERN_INFO, ohci->id, "release"); + for (i=0;inb_iso_ctx-1;i++) + if (ohci->fbuf_context[i]) { + if (!test_and_clear_bit(ohci->fbuf_context[i]->channel, + &ohci->IR_channel_usage)) { + PRINT(KERN_ERR, ohci->id, + "channel %d is not being used", + ohci->fbuf_context[i]->channel); + } + PRINT(KERN_INFO, ohci->id, + "iso context %d stop listening on channel %d", + i+1, ohci->fbuf_context[i]->channel); + free_dma_fbuf_ctx(&ohci->fbuf_context[i]); + } + return 0; +} + +static struct file_operations ohci_fops= +{ + owner: THIS_MODULE, + ioctl: ohci_ioctl, + mmap: ohci_mmap, + open: ohci_open, + release: ohci_release +}; + +int wakeup_dma_fbuf_ctx(struct ti_ohci *ohci, struct dma_fbuf_ctx *d) +{ + int i; + + if (d==NULL) { + PRINT(KERN_ERR, ohci->id, "Iso receive event received but " + "context not allocated"); + return -EFAULT; + } + + for (i=0;inum_desc;i++) { + if (d->prg[i][d->nb_cmd-1].status) { + d->prg[i][d->nb_cmd-1].status=0; + d->buffer_status[i] = VIDEO1394_BUFFER_READY; + } + } + if (waitqueue_active(&d->waitq)) wake_up_interruptible(&d->waitq); + return 0; +} + +#endif + + /*********************************** * IEEE-1394 functionality section * @@ -220,6 +844,22 @@ "Error in reception of self-id packets" "Self-id count: %08x q[0]: %08x", self_id_count, q[0]); + + /* + * Tip by James Goodwin : + * We had an error, generate another bus reset in response. + * TODO. Actually read the current value in the phy before + * generating a bus reset (read modify write). This way + * we don't stomp any current gap count settings, etc. + */ + if (ohci->self_id_errorsself_id_errors++; + } + else { + PRINT(KERN_ERR, ohci->id, + "Timeout on self-id error reception"); + } return -1; } @@ -411,15 +1051,34 @@ spin_lock_init(&ohci->phy_reg_lock); + /* + * Tip by James Goodwin : + * We need to add delays after the soft reset, setting LPS, and + * enabling our link. This might fixes the self-id reception + * problem at initialization. + */ + /* Soft reset */ if ((retval=ohci_soft_reset(ohci))<0) return retval; - - /* Set the bus number */ - reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0); + /* + *Delay aftger soft reset to make sure everything has settled + * down (sanity) + */ + mdelay(100); + /* Set Link Power Status (LPS) */ reg_write(ohci, OHCI1394_HCControlSet, 0x00080000); + /* + * Delay after setting LPS in order to make sure link/phy + * communication is established + */ + mdelay(100); + + /* Set the bus number */ + reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0); + /* Enable posted writes */ reg_write(ohci, OHCI1394_HCControlSet, 0x00040000); @@ -464,9 +1123,6 @@ /* Don't accept phy packets into AR request context */ reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400); - /* Enable link */ - reg_write(ohci, OHCI1394_HCControlSet, 0x00020000); - /* Initialize IR dma */ ohci->nb_iso_ctx = get_nb_iso_ctx(ohci); PRINT(KERN_INFO, ohci->id, "%d iso contexts available", @@ -477,7 +1133,18 @@ reg_write(ohci, OHCI1394_IrRcvContextMatch+32*i, 0); reg_write(ohci, OHCI1394_IrRcvCommandPtr+32*i, 0); } - +#ifdef _VIDEO_1394_H + ohci->fbuf_context = (struct dma_fbuf_ctx **) + kmalloc((ohci->nb_iso_ctx-1)*sizeof(struct dma_fbuf_ctx *), + GFP_KERNEL); + if (ohci->fbuf_context) + memset(ohci->fbuf_context, 0, + (ohci->nb_iso_ctx-1)*sizeof(struct dma_fbuf_ctx *)); + else { + PRINT(KERN_ERR, ohci->id, "Cannot allocate fbuf_context"); + return -1; + } +#endif /* Set bufferFill, isochHeader, multichannel for IR context */ reg_write(ohci, OHCI1394_IrRcvContextControlSet, 0xd0000000); @@ -495,16 +1162,6 @@ (thanks to Michael Greger for seeing that I forgot this) */ reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 0x00000001); - initialize_dma_rcv_ctx(ohci->ir_context); - - /* Initialize AR dma */ - initialize_dma_rcv_ctx(ohci->ar_req_context); - initialize_dma_rcv_ctx(ohci->ar_resp_context); - - /* Initialize AT dma */ - initialize_dma_trm_ctx(ohci->at_req_context); - initialize_dma_trm_ctx(ohci->at_resp_context); - /* * Accept AT requests from all nodes. This probably * will have to be controlled from the subsystem @@ -539,6 +1196,20 @@ OHCI1394_isochRx ); + /* Enable link */ + reg_write(ohci, OHCI1394_HCControlSet, 0x00020000); + + /* Initialize AR dma */ + initialize_dma_rcv_ctx(ohci->ar_req_context); + initialize_dma_rcv_ctx(ohci->ar_resp_context); + + /* Initialize AT dma */ + initialize_dma_trm_ctx(ohci->at_req_context); + initialize_dma_trm_ctx(ohci->at_resp_context); + + /* Initialize IR dma */ + initialize_dma_rcv_ctx(ohci->ir_context); + return 1; } @@ -619,7 +1290,7 @@ struct ti_ohci *ohci = host->hostdata; struct dma_trm_ctx *d; unsigned char tcode; - int i=50; + int timeout=50; if (packet->data_size >= ohci->max_packet_size) { PRINT(KERN_ERR, ohci->id, @@ -642,8 +1313,9 @@ } while (d->free_prgs<1) { spin_unlock(&d->lock); - schedule(); - if (i-- <0) { + interruptible_sleep_on(&d->waitq); + if(signal_pending(current)) return -EINTR; + if (timeout--<0) { stop_context(ohci, d->ctrlClear, "AT DMA runaway loop... bailing out"); return 0; @@ -687,7 +1359,7 @@ switch (cmd) { case RESET_BUS: - host->attempt_root=1; + host->attempt_root=1; PRINT(KERN_INFO, ohci->id, "resetting bus on request%s", (host->attempt_root ? " and attempting to become root" : "")); @@ -743,6 +1415,11 @@ spin_lock_irqsave(&ohci->IR_channel_lock, flags); +#if 0 + PRINT(KERN_INFO, ohci->id, "!!! try listen on channel %d !!!", + arg); +#endif + if (!test_and_set_bit(arg, &ohci->IR_channel_usage)) { PRINT(KERN_INFO, ohci->id, "listening enabled on channel %d", arg); @@ -845,137 +1522,179 @@ struct ti_ohci *ohci = (struct ti_ohci *)dev_id; struct hpsb_host *host = ohci->host; int phyid = -1, isroot = 0; + int timeout = 255; - /* read the interrupt event register */ - event=reg_read(ohci, OHCI1394_IntEventSet); - -#if 0 - /* - * clear the interrupt event register, except for the - * bus reset event interrupt (if any). This is an - * attempt to comply with ohci spec 7.2.3.2 - */ - reg_write(ohci, OHCI1394_IntEventClear, event & (~OHCI1394_busReset)); + do { + /* read the interrupt event register */ + event=reg_read(ohci, OHCI1394_IntEventClear); + + DBGMSG(ohci->id, "IntEvent: %08x",event); + + if (!event) return; + + /* clear the interrupt event register */ + reg_write(ohci, OHCI1394_IntEventClear, event); + + if (event & OHCI1394_busReset) { + if (!host->in_bus_reset) { + PRINT(KERN_INFO, ohci->id, "Bus reset"); + + /* Wait for the AT fifo to be flushed */ + dma_trm_reset(ohci->at_req_context); + dma_trm_reset(ohci->at_resp_context); + + /* Subsystem call */ + hpsb_bus_reset(ohci->host); + + ohci->NumBusResets++; + } + } + /* + * Problem: How can I ensure that the AT bottom half will be + * executed before the AR bottom half (both events may have + * occured within a single irq event) + * Quick hack: just launch it within the IRQ handler + */ + if (event & OHCI1394_reqTxComplete) { + struct dma_trm_ctx *d = ohci->at_req_context; + DBGMSG(ohci->id, "Got reqTxComplete interrupt " + "status=0x%08X", reg_read(ohci, d->ctrlSet)); + if (reg_read(ohci, d->ctrlSet) & 0x800) + stop_context(ohci, d->ctrlClear, + "reqTxComplete"); + else + dma_trm_bh((void *)d); + } + if (event & OHCI1394_respTxComplete) { + struct dma_trm_ctx *d = ohci->at_resp_context; + DBGMSG(ohci->id, "Got respTxComplete interrupt " + "status=0x%08X", reg_read(ohci, d->ctrlSet)); + if (reg_read(ohci, d->ctrlSet) & 0x800) + stop_context(ohci, d->ctrlClear, + "respTxComplete"); + else + dma_trm_bh((void *)d); + } + if (event & OHCI1394_RQPkt) { + struct dma_rcv_ctx *d = ohci->ar_req_context; + DBGMSG(ohci->id, "Got RQPkt interrupt status=0x%08X", + reg_read(ohci, d->ctrlSet)); + if (reg_read(ohci, d->ctrlSet) & 0x800) + stop_context(ohci, d->ctrlClear, "RQPkt"); + else { +#if 1 + queue_task(&d->task, &tq_immediate); + mark_bh(IMMEDIATE_BH); #else - /* The above attempt doesn't work */ - reg_write(ohci, OHCI1394_IntEventClear, event); + dma_rcv_bh((void *)d); #endif - if (event & OHCI1394_busReset) { - if (!host->in_bus_reset) { - PRINT(KERN_INFO, ohci->id, "Bus reset"); - - /* Wait for the AT fifo to be flushed */ - dma_trm_reset(ohci->at_req_context); - dma_trm_reset(ohci->at_resp_context); - -#if 0 - /* clear the bus reset event */ - reg_write(ohci, OHCI1394_IntEventClear, - OHCI1394_busReset); -#endif - /* Subsystem call */ - hpsb_bus_reset(ohci->host); - - ohci->NumBusResets++; + } } - } - /* - * Problem: How can I ensure that the AT bottom half will be - * executed before the AR bottom half (both events may have - * occured within a single irq event) - * Quick hack: just launch it within the IRQ handler - */ - if (event & OHCI1394_reqTxComplete) { - struct dma_trm_ctx *d = ohci->at_req_context; - DBGMSG(ohci->id, "Got reqTxComplete interrupt status=0x%08X", - reg_read(ohci, d->ctrlSet)); - if (reg_read(ohci, d->ctrlSet) & 0x800) - stop_context(ohci, d->ctrlClear, "reqTxComplete"); - else - dma_trm_bh((void *)d); - } - if (event & OHCI1394_respTxComplete) { - struct dma_trm_ctx *d = ohci->at_resp_context; - DBGMSG(ohci->id, "Got respTxComplete interrupt status=0x%08X", - reg_read(ohci, d->ctrlSet)); - if (reg_read(ohci, d->ctrlSet) & 0x800) - stop_context(ohci, d->ctrlClear, "respTxComplete"); - else - dma_trm_bh((void *)d); - } - if (event & OHCI1394_RQPkt) { - struct dma_rcv_ctx *d = ohci->ar_req_context; - DBGMSG(ohci->id, "Got RQPkt interrupt status=0x%08X", - reg_read(ohci, d->ctrlSet)); - if (reg_read(ohci, d->ctrlSet) & 0x800) - stop_context(ohci, d->ctrlClear, "RQPkt"); - else { - queue_task(&d->task, &tq_immediate); - mark_bh(IMMEDIATE_BH); + if (event & OHCI1394_RSPkt) { + struct dma_rcv_ctx *d = ohci->ar_resp_context; + DBGMSG(ohci->id, "Got RSPkt interrupt status=0x%08X", + reg_read(ohci, d->ctrlSet)); + if (reg_read(ohci, d->ctrlSet) & 0x800) + stop_context(ohci, d->ctrlClear, "RSPkt"); + else { +#if 1 + queue_task(&d->task, &tq_immediate); + mark_bh(IMMEDIATE_BH); +#else + dma_rcv_bh((void *)d); +#endif + } } - } - if (event & OHCI1394_RSPkt) { - struct dma_rcv_ctx *d = ohci->ar_resp_context; - DBGMSG(ohci->id, "Got RSPkt interrupt status=0x%08X", - reg_read(ohci, d->ctrlSet)); - if (reg_read(ohci, d->ctrlSet) & 0x800) - stop_context(ohci, d->ctrlClear, "RSPkt"); - else { - queue_task(&d->task, &tq_immediate); - mark_bh(IMMEDIATE_BH); + if (event & OHCI1394_isochRx) { + quadlet_t isoRecvIntEvent; + struct dma_rcv_ctx *d = ohci->ir_context; +#ifdef _VIDEO_1394_H + int i; +#endif + isoRecvIntEvent = + reg_read(ohci, OHCI1394_IsoRecvIntEventSet); + reg_write(ohci, OHCI1394_IsoRecvIntEventClear, + isoRecvIntEvent); + DBGMSG(ohci->id, "Got isochRx interrupt " + "status=0x%08X isoRecvIntEvent=%08x", + reg_read(ohci, d->ctrlSet), isoRecvIntEvent); + if (isoRecvIntEvent & 0x1) { + if (reg_read(ohci, d->ctrlSet) & 0x800) + stop_context(ohci, d->ctrlClear, + "isochRx"); + else { +#if 1 + queue_task(&d->task, &tq_immediate); + mark_bh(IMMEDIATE_BH); +#else + dma_rcv_bh((void *)d); +#endif + } + } +#ifdef _VIDEO_1394_H + for (i=0;inb_iso_ctx-1;i++) + if (isoRecvIntEvent & (1<<(i+1))) + wakeup_dma_fbuf_ctx( + ohci,ohci->fbuf_context[i]); +#endif } - } - if (event & OHCI1394_isochRx) { - quadlet_t isoRecvIntEvent; - struct dma_rcv_ctx *d = ohci->ir_context; - isoRecvIntEvent = reg_read(ohci, OHCI1394_IsoRecvIntEventSet); - reg_write(ohci, OHCI1394_IsoRecvIntEventClear, - isoRecvIntEvent); - DBGMSG(ohci->id, "Got reqTxComplete interrupt status=0x%08X", - reg_read(ohci, d->ctrlSet)); - if (reg_read(ohci, d->ctrlSet) & 0x800) - stop_context(ohci, d->ctrlClear, "isochRx"); - else { - queue_task(&d->task, &tq_immediate); - mark_bh(IMMEDIATE_BH); + if (event & OHCI1394_selfIDComplete) { + if (host->in_bus_reset) { + node_id = reg_read(ohci, OHCI1394_NodeID); + if (node_id & 0x80000000) { /* NodeID valid */ + phyid = node_id & 0x0000003f; + isroot = (node_id & 0x40000000) != 0; + + PRINT(KERN_INFO, ohci->id, + "SelfID process finished " + "(phyid %d, %s)", phyid, + (isroot ? "root" : "not root")); + + handle_selfid(ohci, host, + phyid, isroot); + } + else + PRINT(KERN_ERR, ohci->id, + "SelfID process finished but " + "NodeID not valid: %08X", + node_id); + + /* Accept Physical requests from all nodes. */ + reg_write(ohci,OHCI1394_AsReqFilterHiSet, + 0xffffffff); + reg_write(ohci,OHCI1394_AsReqFilterLoSet, + 0xffffffff); + /* + * Tip by James Goodwin + * Turn on phys dma reception. We should + * probably manage the filtering somehow, + * instead of blindly turning it on. + */ + reg_write(ohci,OHCI1394_PhyReqFilterHiSet, + 0xffffffff); + reg_write(ohci,OHCI1394_PhyReqFilterLoSet, + 0xffffffff); + reg_write(ohci,OHCI1394_PhyUpperBound, + 0xffff0000); + } + else PRINT(KERN_ERR, ohci->id, + "self-id received outside of bus reset" + "sequence"); } - } - if (event & OHCI1394_selfIDComplete) { - if (host->in_bus_reset) { - node_id = reg_read(ohci, OHCI1394_NodeID); - if (node_id & 0x80000000) { /* NodeID valid */ - phyid = node_id & 0x0000003f; - isroot = (node_id & 0x40000000) != 0; - - PRINT(KERN_INFO, ohci->id, - "SelfID process finished (phyid %d, %s)", - phyid, (isroot ? "root" : "not root")); - - handle_selfid(ohci, host, phyid, isroot); + if (event & OHCI1394_phyRegRcvd) { +#if 1 + if (host->in_bus_reset) { + PRINT(KERN_INFO, ohci->id, "PhyControl: %08X", + reg_read(ohci, OHCI1394_PhyControl)); } - else - PRINT(KERN_ERR, ohci->id, - "SelfID process finished but NodeID" - " not valid: %08X",node_id); - - /* Accept Physical requests from all nodes. */ - reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0xffffffff); - reg_write(ohci,OHCI1394_AsReqFilterLoSet, 0xffffffff); - } - else PRINT(KERN_INFO, ohci->id, - "phy reg received without reset\n"); - } - if (event & OHCI1394_phyRegRcvd) { -#if 0 - if (host->in_bus_reset) { - PRINT(KERN_INFO, ohci->id, "PhyControl: %08X", - reg_read(ohci, OHCI1394_PhyControl)); - } else - PRINT(KERN_ERR, ohci->id, - "phy reg received without reset"); + else PRINT(KERN_ERR, ohci->id, + "phy reg received outside of bus reset" + "sequence"); #endif - } + } + } while (--timeout); + PRINT(KERN_ERR, ohci->id, "irq_handler timeout event=0x%08x", event); } /* Put the buffer back into the dma context */ @@ -1119,6 +1838,17 @@ buf_ptr += offset/4; } + /* + * Tip by James Goodwin + * We need to handle write requests that are received + * to our middle address space (posted writes). + * In this case, the hardware generates an + * ack_complete... but, if we pass the packet up to + * the subsystem, it will try and send a response + * (which it shouldn't), because it assumes we + * returned ack_pending. + */ + /* * We get one phy packet for each bus reset. * we know that from now on the bus topology may @@ -1132,6 +1862,20 @@ (d->spb[length/4-1]>>16)&0x1f, (d->spb[length/4-1]>>21)&0x3, tcode, length, d->spb[3], d->ctx); + + /* + * Tip by James Goodwin + * Handle case of posted writes. If we receive + * an ack_complete, we should not send a + * response. Fake out upper layers by turning + * the packet into a broadcast packet... we + * should really modify the core stack to + * accept an ack received argument and figure + * out whether to reply. + */ + if (((d->spb[length/4-1]>>16)&0x1f) == 0x11) { + d->spb[0] |= (ALL_NODES<<16); + } hpsb_packet_received(ohci->host, d->spb, length); } @@ -1154,6 +1898,20 @@ (buf_ptr[length/4-1]>>16)&0x1f, (buf_ptr[length/4-1]>>21)&0x3, tcode, length, buf_ptr[3], d->ctx); + + /* + * Tip by James Goodwin + * Handle case of posted writes. If we receive + * an ack_complete, we should not send a + * response. Fake out upper layers by turning + * the packet into a broadcast packet... we + * should really modify the core stack to + * accept an ack received argument and figure + * out whether to reply. + */ + if (((d->spb[length/4-1]>>16)&0x1f) == 0x11) { + buf_ptr[0] |= (ALL_NODES<<16); + } hpsb_packet_received(ohci->host, buf_ptr, length); } @@ -1207,32 +1965,42 @@ d->sent_ind = (d->sent_ind+1)%d->num_desc; d->free_prgs++; spin_unlock(&d->lock); - + + if (waitqueue_active(&d->waitq)) wake_up_interruptible(&d->waitq); + DBGMSG(ohci->id, "Packet sent to node %d ack=0x%X spd=%d ctx=%d", (packet->header[0]>>16)&0x3f, ack&0x1f, (ack>>5)&0x3, d->ctx); hpsb_packet_sent(ohci->host, packet, ack&0xf); } -static int free_dma_rcv_ctx(struct dma_rcv_ctx *d) +static int free_dma_rcv_ctx(struct dma_rcv_ctx **d) { int i; + struct ti_ohci *ohci; - if (d==NULL) return -1; + if (*d==NULL) return -1; - if (d->buf) { - for (i=0; inum_desc; i++) - if (d->buf[i]) kfree(d->buf[i]); - kfree(d->buf); - } - if (d->prg) { - for (i=0; inum_desc; i++) - if (d->prg[i]) kfree(d->prg[i]); - kfree(d->prg); - } - if (d->spb) kfree(d->spb); + ohci = (struct ti_ohci *)(*d)->ohci; + + DBGMSG(ohci->id, "Freeing dma_rcv_ctx %d",(*d)->ctx); - kfree(d); + stop_context(ohci, (*d)->ctrlClear, NULL); + + if ((*d)->buf) { + for (i=0; i<(*d)->num_desc; i++) + if ((*d)->buf[i]) kfree((*d)->buf[i]); + kfree((*d)->buf); + } + if ((*d)->prg) { + for (i=0; i<(*d)->num_desc; i++) + if ((*d)->prg[i]) kfree((*d)->prg[i]); + kfree((*d)->prg); + } + if ((*d)->spb) kfree((*d)->spb); + kfree(*d); + *d = NULL; + return 0; } @@ -1270,7 +2038,7 @@ if (d->buf == NULL) { PRINT(KERN_ERR, ohci->id, "failed to allocate dma buffer"); - free_dma_rcv_ctx(d); + free_dma_rcv_ctx(&d); return NULL; } memset(d->buf, 0, d->num_desc * sizeof(quadlet_t*)); @@ -1279,7 +2047,7 @@ if (d->prg == NULL) { PRINT(KERN_ERR, ohci->id, "failed to allocate dma prg"); - free_dma_rcv_ctx(d); + free_dma_rcv_ctx(&d); return NULL; } memset(d->prg, 0, d->num_desc * sizeof(struct dma_cmd*)); @@ -1288,7 +2056,7 @@ if (d->spb == NULL) { PRINT(KERN_ERR, ohci->id, "failed to allocate split buffer"); - free_dma_rcv_ctx(d); + free_dma_rcv_ctx(&d); return NULL; } @@ -1300,7 +2068,7 @@ } else { PRINT(KERN_ERR, ohci->id, "failed to allocate dma buffer"); - free_dma_rcv_ctx(d); + free_dma_rcv_ctx(&d); return NULL; } @@ -1311,7 +2079,7 @@ } else { PRINT(KERN_ERR, ohci->id, "failed to allocate dma prg"); - free_dma_rcv_ctx(d); + free_dma_rcv_ctx(&d); return NULL; } } @@ -1319,17 +2087,29 @@ spin_lock_init(&d->lock); /* initialize bottom handler */ + d->task.sync = 0; + d->task.next = NULL; d->task.routine = dma_rcv_bh; d->task.data = (void*)d; return d; } -static int free_dma_trm_ctx(struct dma_trm_ctx *d) +static int free_dma_trm_ctx(struct dma_trm_ctx **d) { - if (d==NULL) return -1; - if (d->prg) kfree(d->prg); - kfree(d); + struct ti_ohci *ohci; + + if (*d==NULL) return -1; + + ohci = (struct ti_ohci *)(*d)->ohci; + + DBGMSG(ohci->id, "Freeing dma_trm_ctx %d",(*d)->ctx); + + stop_context(ohci, (*d)->ctrlClear, NULL); + + if ((*d)->prg) kfree((*d)->prg); + kfree(*d); + *d = NULL; return 0; } @@ -1359,7 +2139,7 @@ if (d->prg == NULL) { PRINT(KERN_ERR, ohci->id, "failed to allocate at dma prg"); - free_dma_trm_ctx(d); + free_dma_trm_ctx(&d); return NULL; } memset(d->prg, 0, d->num_desc * sizeof(struct at_dma_prg)); @@ -1370,6 +2150,8 @@ d->task.routine = dma_trm_bh; d->task.data = (void*)d; + init_waitqueue_head(&d->waitq); + return d; } @@ -1385,10 +2167,12 @@ return 1; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) - /* XXX check return value */ - pci_enable_device(dev); -#endif + if (pci_enable_device(dev)) { + PRINT_G(KERN_NOTICE, "failed to enable OHCI hardware %d", + num_of_cards); + return 1; + } + pci_set_master(dev); ohci = &cards[num_of_cards++]; @@ -1397,13 +2181,6 @@ ohci->state = 0; - if (!request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ, - OHCI1394_DRIVER_NAME, ohci)) { - PRINT(KERN_INFO, ohci->id, "allocated interrupt %d", dev->irq); - } else { - FAIL("failed to allocate shared interrupt %d", dev->irq); - } - /* csr_config rom allocation */ ohci->csr_config_rom = kmalloc(1024, GFP_KERNEL); if (ohci->csr_config_rom == NULL) { @@ -1437,7 +2214,9 @@ OHCI1394_AsRspRcvContextControlClear, OHCI1394_AsRspRcvCommandPtr); - if (ohci->ar_resp_context == NULL) return 1; + if (ohci->ar_resp_context == NULL) { + FAIL("failed to allocate AR Resp context"); + } ohci->at_req_context = alloc_dma_trm_ctx(ohci, 0, AT_REQ_NUM_DESC, @@ -1445,7 +2224,9 @@ OHCI1394_AsReqTrContextControlClear, OHCI1394_AsReqTrCommandPtr); - if (ohci->at_req_context == NULL) return 1; + if (ohci->at_req_context == NULL) { + FAIL("failed to allocate AT Req context"); + } ohci->at_resp_context = alloc_dma_trm_ctx(ohci, 1, AT_RESP_NUM_DESC, @@ -1453,7 +2234,9 @@ OHCI1394_AsRspTrContextControlClear, OHCI1394_AsRspTrCommandPtr); - if (ohci->at_resp_context == NULL) return 1; + if (ohci->at_resp_context == NULL) { + FAIL("failed to allocate AT Resp context"); + } ohci->ir_context = alloc_dma_rcv_ctx(ohci, 2, IR_NUM_DESC, @@ -1462,7 +2245,9 @@ OHCI1394_IrRcvContextControlClear, OHCI1394_IrRcvCommandPtr); - if (ohci->ir_context == NULL) return 1; + if (ohci->ir_context == NULL) { + FAIL("failed to allocate IR context"); + } ohci->IR_channel_usage= 0x0000000000000000; spin_lock_init(&ohci->IR_channel_lock); @@ -1482,6 +2267,13 @@ PRINT(KERN_INFO, ohci->id, "remapped memory spaces reg 0x%p", ohci->registers); + if (!request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ, + OHCI1394_DRIVER_NAME, ohci)) { + PRINT(KERN_INFO, ohci->id, "allocated interrupt %d", dev->irq); + } else { + FAIL("failed to allocate shared interrupt %d", dev->irq); + } + return 0; #undef FAIL } @@ -1507,6 +2299,10 @@ int i; struct dma_rcv_ctx *d=NULL; struct dma_trm_ctx *dt=NULL; +#ifdef _VIDEO_1394_H + int j; + struct dma_fbuf_ctx *f=ohci->fbuf_context[0]; +#endif p += sprintf(p,"IEEE-1394 OHCI Driver status report:\n"); p += sprintf(p," bus number: 0x%x Node ID: 0x%x\n", @@ -1535,6 +2331,27 @@ host->is_busmgr ? "bus_mgr" : ""); p += sprintf(p,"\n---Iso Receive DMA---\n"); + +#ifdef _VIDEO_1394_H + +#if 0 + if (f!=NULL) { + for (i=0; inum_desc; i++) { + for (j=0;jnb_cmd;j++) { + p += sprintf(p, + "prg[%d][%d]: %p %08x %08x %08x %08x\n", + i,j,virt_to_bus(&(f->prg[i][j])), + f->prg[i][j].control, + f->prg[i][j].address, + f->prg[i][j].branchAddress, + f->prg[i][j].status); + } + } + } +#endif + +#else + d = ohci->ir_context; #if 0 for (i=0; inum_desc; i++) { @@ -1621,7 +2438,8 @@ dt->branchAddrPtr); p += sprintf(p, "AT resp queue: first: %p last: %p\n", dt->first, dt->last); - +#endif + /* ----- Register Dump ----- */ p += sprintf(p,"\n### HC Register dump ###\n"); SR("Version : %08x GUID_ROM : %08x ATRetries : %08x\n", @@ -1736,19 +2554,34 @@ static void remove_card(struct ti_ohci *ohci) { - if (ohci->registers) - iounmap(ohci->registers); +#ifdef _VIDEO_1394_H + int i; +#endif /* Free AR dma */ - free_dma_rcv_ctx(ohci->ar_req_context); - free_dma_rcv_ctx(ohci->ar_resp_context); + free_dma_rcv_ctx(&ohci->ar_req_context); + free_dma_rcv_ctx(&ohci->ar_resp_context); /* Free AT dma */ - free_dma_trm_ctx(ohci->at_req_context); - free_dma_trm_ctx(ohci->at_resp_context); + free_dma_trm_ctx(&ohci->at_req_context); + free_dma_trm_ctx(&ohci->at_resp_context); /* Free IR dma */ - free_dma_rcv_ctx(ohci->ir_context); + free_dma_rcv_ctx(&ohci->ir_context); + +#ifdef _VIDEO_1394_H + /* Free the frame buffer context */ + if (ohci->fbuf_context) + for (i=0;inb_iso_ctx-1;i++) { + free_dma_fbuf_ctx(&ohci->fbuf_context[i]); + } +#endif + + /* + * Reset the board properly before leaving + * Daniel Kobras + */ + ohci_soft_reset(ohci); /* Free self-id buffer */ if (ohci->self_id_buffer) @@ -1761,6 +2594,9 @@ /* Free the IRQ */ free_irq(ohci->dev->irq, ohci); + if (ohci->registers) + iounmap(ohci->registers); + ohci->state = 0; } @@ -1858,16 +2694,30 @@ proc_unregister(&proc_root, ohci_proc_entry.low_ino); #endif #endif + +#ifdef _VIDEO_1394_H + unregister_chrdev(OHCI1394_MAJOR, "ohci1394"); +#endif + PRINT_G(KERN_INFO, "removed " OHCI1394_DRIVER_NAME " module\n"); } int init_module(void) { - + memset(cards, 0, MAX_OHCI1394_CARDS * sizeof (struct ti_ohci)); + if (hpsb_register_lowlevel(get_ohci_template())) { PRINT_G(KERN_ERR, "registering failed\n"); return -ENXIO; } else { +#ifdef _VIDEO_1394_H + if (register_chrdev(OHCI1394_MAJOR, "ohci1394", &ohci_fops)) + { + printk("ohci1394: unable to get major %d\n", + OHCI1394_MAJOR); + return -EIO; + } +#endif return 0; } } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ieee1394/ohci1394.h linux/drivers/ieee1394/ohci1394.h --- v2.4.0-test1/linux/drivers/ieee1394/ohci1394.h Mon Mar 27 08:08:24 2000 +++ linux/drivers/ieee1394/ohci1394.h Mon Jun 19 17:59:40 2000 @@ -1,8 +1,29 @@ +/* + * ohci1394.h - driver for OHCI 1394 boards + * Copyright (C)1999,2000 Sebastien Rougeaux + * Gord Peters + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 _OHCI1394_H #define _OHCI1394_H #include "ieee1394_types.h" +/* include this for the video frame grabber */ +/* #include "video1394.h" */ #define OHCI1394_DRIVER_NAME "ohci1394" @@ -46,11 +67,16 @@ #define PCI_DEVICE_ID_NEC_UPD72871 0x00ce #endif +#ifndef PCI_DEVICE_ID_APPLE_UNI_N_FW +#define PCI_DEVICE_ID_APPLE_UNI_N_FW 0x0018 +#endif + #define MAX_OHCI1394_CARDS 4 #define OHCI1394_MAX_AT_REQ_RETRIES 0x2 #define OHCI1394_MAX_AT_RESP_RETRIES 0x2 #define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8 +#define OHCI1394_MAX_SELF_ID_ERRORS 16 #define AR_REQ_NUM_DESC 4 /* number of AR req descriptors */ #define AR_REQ_BUF_SIZE 4096 /* size of AR req buffers */ @@ -116,8 +142,34 @@ int ctrlClear; int ctrlSet; int cmdPtr; + wait_queue_head_t waitq; }; +#ifdef _VIDEO_1394_H + +#define OHCI1394_MAJOR 172 +#define ISO_CHANNELS 64 + +struct dma_fbuf_ctx { + void *ohci; + int ctx; + int channel; + int last_buffer; + unsigned int num_desc; + unsigned int buf_size; + unsigned int frame_size; + unsigned int nb_cmd; + unsigned char *buf; + struct dma_cmd **prg; + unsigned int *buffer_status; + int ctrlClear; + int ctrlSet; + int cmdPtr; + int ctxMatch; + wait_queue_head_t waitq; +}; +#endif + struct ti_ohci { int id; /* sequential card number */ @@ -147,6 +199,12 @@ spinlock_t IR_channel_lock; int nb_iso_ctx; +#ifdef _VIDEO_1394_H + /* frame buffer context */ + struct dma_fbuf_ctx **fbuf_context; + struct dma_fbuf_ctx *current_fbuf_ctx; +#endif + /* IEEE-1394 part follows */ struct hpsb_host *host; @@ -154,6 +212,7 @@ spinlock_t phy_reg_lock; + int self_id_errors; int NumBusResets; }; @@ -328,8 +387,8 @@ #define OHCI1394_RSPkt 0x00000020 #define OHCI1394_isochTx 0x00000040 #define OHCI1394_isochRx 0x00000080 -#define OHCI1394_postedWriteErr 0x00001000 -#define OHCI1394_lockRespErr 0x00002000 +#define OHCI1394_postedWriteErr 0x00000100 +#define OHCI1394_lockRespErr 0x00000200 #define OHCI1394_selfIDComplete 0x00010000 #define OHCI1394_busReset 0x00020000 #define OHCI1394_phy 0x00080000 diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ieee1394/pcilynx.c linux/drivers/ieee1394/pcilynx.c --- v2.4.0-test1/linux/drivers/ieee1394/pcilynx.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ieee1394/pcilynx.c Mon Jun 19 17:59:40 2000 @@ -99,6 +99,8 @@ return -1; } + +#if 0 static void free_pcl(struct ti_lynx *lynx, pcl_t pclid) { int off, bit; @@ -145,6 +147,7 @@ get_pcl(lynx, pclid, &pcl); pretty_print_pcl(&pcl); } +#endif static int add_card(struct pci_dev *dev); @@ -486,7 +489,8 @@ put_pcl(lynx, lynx->iso_rcv.pcl_start, &pcl); /* 85 bytes for each FIFO - FIXME - optimize or make configurable */ - reg_write(lynx, FIFO_SIZES, 0x00555555); + /* reg_write(lynx, FIFO_SIZES, 0x00555555); */ + reg_write(lynx, FIFO_SIZES, 0x002020c0); /* 20 byte threshold before triggering PCI transfer */ reg_write(lynx, DMA_GLOBAL_REGISTER, 0x2<<24); /* 69 byte threshold on both send FIFOs before transmitting */ @@ -597,15 +601,16 @@ } else { arg = 1 << 6; } - + + retval = get_phy_reg(lynx, 1); + arg |= (retval == -1 ? 63 : retval); + retval = 0; + PRINT(KERN_INFO, lynx->id, "resetting bus on request%s", (host->attempt_root ? " and attempting to become root" : "")); - spin_lock_irqsave(&lynx->phy_reg_lock, flags); - reg_write(lynx, LINK_PHY, LINK_PHY_WRITE | LINK_PHY_ADDR(1) - | LINK_PHY_WDATA(arg)); - spin_unlock_irqrestore(&lynx->phy_reg_lock, flags); + set_phy_reg(lynx, 1, arg); break; case GET_CYCLE_COUNTER: @@ -705,6 +710,7 @@ static struct file_operations aux_ops = { + owner: THIS_MODULE, /* FIXME: should have custom llseek with bounds checking */ read: mem_read, write: mem_write, @@ -717,61 +723,10 @@ static void aux_setup_pcls(struct ti_lynx *lynx) { struct ti_pcl pcl; - unsigned long membufbus = virt_to_bus(lynx->mem_dma_buffer); - int i; - /* This pcl is used to start any aux transfers, the pointer to next - points to itself to avoid a dummy pcl (the PCL engine only executes - the next pcl on startup. The real chain is done by branch */ - pcl.next = pcl_bus(lynx, lynx->mem_pcl.start); - pcl.buffer[0].control = PCL_CMD_BRANCH | PCL_COND_DMARDY_SET; - pcl.buffer[0].pointer = pcl_bus(lynx, lynx->mem_pcl.max); - pcl.buffer[1].control = PCL_CMD_BRANCH | PCL_COND_DMARDY_CLEAR; - pcl.buffer[1].pointer = pcl_bus(lynx, lynx->mem_pcl.cmd); - put_pcl(lynx, lynx->mem_pcl.start, &pcl); - - /* let maxpcl transfer exactly 32kB */ - pcl.next = PCL_NEXT_INVALID; - for (i=0; i<8; i++) { - pcl.buffer[i].control = 4000; - pcl.buffer[i].pointer = membufbus + i * 4000; - } - pcl.buffer[0].control |= PCL_CMD_LBUS_TO_PCI /*| PCL_GEN_INTR*/; - pcl.buffer[8].control = 768 | PCL_LAST_BUFF; - pcl.buffer[8].pointer = membufbus + 8 * 4000; - put_pcl(lynx, lynx->mem_pcl.max, &pcl); - - - /* magic stuff - self and modpcl modifying pcl */ - pcl.next = pcl_bus(lynx, lynx->mem_pcl.mod); - pcl.user_data = 4000; - pcl.buffer[0].control = PCL_CMD_LOAD; - pcl.buffer[0].pointer = pcl_bus(lynx, lynx->mem_pcl.cmd) - + pcloffs(user_data); - pcl.buffer[1].control = PCL_CMD_STOREQ; - pcl.buffer[1].pointer = pcl_bus(lynx, lynx->mem_pcl.mod) - + pcloffs(buffer[1].control); - pcl.buffer[2].control = PCL_CMD_LOAD; - pcl.buffer[2].pointer = membufbus; - pcl.buffer[3].control = PCL_CMD_STOREQ; - pcl.buffer[3].pointer = pcl_bus(lynx, lynx->mem_pcl.cmd) - + pcloffs(buffer[1].pointer); - pcl.buffer[4].control = PCL_CMD_STOREQ; - pcl.buffer[4].pointer = pcl_bus(lynx, lynx->mem_pcl.cmd) - + pcloffs(buffer[6].pointer); - pcl.buffer[5].control = PCL_CMD_LOAD; - pcl.buffer[5].pointer = membufbus + 4; - pcl.buffer[6].control = PCL_CMD_STOREQ | PCL_LAST_CMD; - put_pcl(lynx, lynx->mem_pcl.cmd, &pcl); - - /* modified by cmdpcl when actual transfer occurs */ pcl.next = PCL_NEXT_INVALID; - pcl.buffer[0].control = PCL_CMD_LBUS_TO_PCI; /* null transfer */ - for (i=1; i<13; i++) { - pcl.buffer[i].control = 4000; - pcl.buffer[i].pointer = membufbus + (i-1) * 4000; - } - put_pcl(lynx, lynx->mem_pcl.mod, &pcl); + pcl.user_data = pcl_bus(lynx, lynx->dmem_pcl); + put_pcl(lynx, lynx->dmem_pcl, &pcl); } static int mem_open(struct inode *inode, struct file *file) @@ -779,24 +734,19 @@ int cid = MINOR(inode->i_rdev); enum { rom, aux, ram } type; struct memdata *md; - - MOD_INC_USE_COUNT; if (cid < PCILYNX_MINOR_AUX_START) { /* just for completeness */ - MOD_DEC_USE_COUNT; return -ENXIO; } else if (cid < PCILYNX_MINOR_ROM_START) { cid -= PCILYNX_MINOR_AUX_START; if (cid >= num_of_cards || !cards[cid].aux_port) { - MOD_DEC_USE_COUNT; return -ENXIO; } type = aux; } else if (cid < PCILYNX_MINOR_RAM_START) { cid -= PCILYNX_MINOR_ROM_START; if (cid >= num_of_cards || !cards[cid].local_rom) { - MOD_DEC_USE_COUNT; return -ENXIO; } type = rom; @@ -805,7 +755,6 @@ * It is currently used inside the driver! */ cid -= PCILYNX_MINOR_RAM_START; if (cid >= num_of_cards || !cards[cid].local_ram) { - MOD_DEC_USE_COUNT; return -ENXIO; } type = ram; @@ -813,7 +762,6 @@ md = (struct memdata *)vmalloc(sizeof(struct memdata)); if (md == NULL) { - MOD_DEC_USE_COUNT; return -ENOMEM; } @@ -828,7 +776,8 @@ md->type = ram; break; case aux: - md->aux_intr_last_seen = atomic_read(&cards[cid].aux_intr_seen); + atomic_set(&md->aux_intr_last_seen, + atomic_read(&cards[cid].aux_intr_seen)); md->type = aux; break; } @@ -844,7 +793,6 @@ vfree(md); - MOD_DEC_USE_COUNT; return 0; } @@ -862,11 +810,9 @@ poll_wait(file, &cards[cid].aux_intr_wait, pt); intr_seen = atomic_read(&cards[cid].aux_intr_seen); - if (md->aux_intr_last_seen != intr_seen) { + if (atomic_read(&md->aux_intr_last_seen) != intr_seen) { mask |= POLLPRI; - /* md->aux_intr_last_seen = intr_seen; */ - md->aux_intr_last_seen++; /* don't miss interrupts */ - /* FIXME - make ioctl for configuring this */ + atomic_inc(&md->aux_intr_last_seen); } } @@ -882,38 +828,104 @@ short mem_mindma = 2400; MODULE_PARM(mem_mindma, "h"); +static ssize_t mem_dmaread(struct memdata *md, u32 physbuf, ssize_t count, + int offset) +{ + pcltmp_t pcltmp; + struct ti_pcl *pcl; + size_t retval; + int i; + DECLARE_WAITQUEUE(wait, current); + + //printk("buf 0x%08x %x count %d offset %d\n", physbuf, physbuf % 3, count, offset); + + count &= ~3; + count = MIN(count, 53196); + retval = count; + + if (reg_read(md->lynx, DMA_CHAN_CTRL(CHANNEL_LOCALBUS)) + & DMA_CHAN_CTRL_BUSY) { + PRINT(KERN_WARNING, md->lynx->id, "DMA ALREADY ACTIVE!"); + } + + switch (md->type) { + case rom: + reg_write(md->lynx, LBUS_ADDR, LBUS_ADDR_SEL_ROM | offset); + break; + case ram: + reg_write(md->lynx, LBUS_ADDR, LBUS_ADDR_SEL_RAM | offset); + break; + case aux: + reg_write(md->lynx, LBUS_ADDR, LBUS_ADDR_SEL_AUX | offset); + break; + } + + pcl = edit_pcl(md->lynx, md->lynx->dmem_pcl, &pcltmp); + pcl->buffer[0].control = PCL_CMD_LBUS_TO_PCI | MIN(count, 4092); + pcl->buffer[0].pointer = physbuf; + count -= 4092; + + i = 0; + while (count > 0) { + i++; + pcl->buffer[i].control = MIN(count, 4092); + pcl->buffer[i].pointer = physbuf + i * 4092; + count -= 4092; + } + pcl->buffer[i].control |= PCL_LAST_BUFF; + commit_pcl(md->lynx, md->lynx->dmem_pcl, &pcltmp); + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&md->lynx->mem_dma_intr_wait, &wait); + run_sub_pcl(md->lynx, md->lynx->dmem_pcl, 2, CHANNEL_LOCALBUS); + + schedule(); + while (reg_read(md->lynx, DMA_CHAN_CTRL(CHANNEL_LOCALBUS)) + & DMA_CHAN_CTRL_BUSY) { + if (signal_pending(current)) { + retval = -EINTR; + break; + } + schedule(); + } + + reg_write(md->lynx, DMA_CHAN_CTRL(CHANNEL_LOCALBUS), 0); + remove_wait_queue(&md->lynx->mem_dma_intr_wait, &wait); + + if (reg_read(md->lynx, DMA_CHAN_CTRL(CHANNEL_LOCALBUS)) + & DMA_CHAN_CTRL_BUSY) { + PRINT(KERN_ERR, md->lynx->id, "DMA STILL ACTIVE!"); + } + + return retval; +} + static ssize_t mem_read(struct file *file, char *buffer, size_t count, loff_t *offset) { struct memdata *md = (struct memdata *)file->private_data; - size_t bcount; + ssize_t bcount; size_t alignfix; int off = (int)*offset; /* avoid useless 64bit-arithmetic */ + ssize_t retval; void *membase; - DECLARE_WAITQUEUE(wait, current); - - if ((off + count) > PCILYNX_MAX_MEMORY+1) { - count = PCILYNX_MAX_MEMORY+1 - off; + if ((off + count) > PCILYNX_MAX_MEMORY + 1) { + count = PCILYNX_MAX_MEMORY + 1 - off; } if (count <= 0) { return 0; } - down(&md->lynx->mem_dma_mutex); - switch (md->type) { case rom: - reg_write(md->lynx, LBUS_ADDR, LBUS_ADDR_SEL_ROM | off); membase = md->lynx->local_rom; break; case ram: - reg_write(md->lynx, LBUS_ADDR, LBUS_ADDR_SEL_RAM | off); membase = md->lynx->local_ram; break; case aux: - reg_write(md->lynx, LBUS_ADDR, LBUS_ADDR_SEL_AUX | off); membase = md->lynx->aux_port; break; default: @@ -921,89 +933,49 @@ md->lynx->id, md->type); } + down(&md->lynx->mem_dma_mutex); + if (count < mem_mindma) { memcpy_fromio(md->lynx->mem_dma_buffer, membase+off, count); - copy_to_user(buffer, md->lynx->mem_dma_buffer, count); - bcount = 0; - goto done; + goto out; } - + bcount = count; alignfix = 4 - (off % 4); if (alignfix != 4) { if (bcount < alignfix) { alignfix = bcount; } - memcpy_fromio(md->lynx->mem_dma_buffer, membase+off, alignfix); - copy_to_user(buffer, md->lynx->mem_dma_buffer, alignfix); + memcpy_fromio(md->lynx->mem_dma_buffer, membase+off, + alignfix); if (bcount == alignfix) { - goto done; + goto out; } bcount -= alignfix; - buffer += alignfix; off += alignfix; } - if (reg_read(md->lynx, DMA0_CHAN_CTRL) & DMA_CHAN_CTRL_BUSY) { - PRINT(KERN_WARNING, md->lynx->id, "DMA ALREADY ACTIVE!"); - } - - add_wait_queue(&md->lynx->mem_dma_intr_wait, &wait); - - if (bcount > 32768) { - current->state = TASK_INTERRUPTIBLE; - - reg_write(md->lynx, DMA0_READY, 1); /* select maxpcl */ - run_pcl(md->lynx, md->lynx->mem_pcl.start, 0); - - while (reg_read(md->lynx, DMA0_CHAN_CTRL) - & DMA_CHAN_CTRL_BUSY) { - if (signal_pending(current)) { - reg_write(md->lynx, DMA0_CHAN_CTRL, 0); - goto rmwait_done; - } - schedule(); - } - - copy_to_user(buffer, md->lynx->mem_dma_buffer, 32768); - buffer += 32768; - bcount -= 32768; - } - - *(u32 *)(md->lynx->mem_dma_buffer) = - pcl_bus(md->lynx, md->lynx->mem_pcl.mod) - + pcloffs(buffer[bcount/4000+1].control); - *(u32 *)(md->lynx->mem_dma_buffer+4) = PCL_LAST_BUFF | (bcount % 4000); - - current->state = TASK_INTERRUPTIBLE; + while (bcount >= 4) { + retval = mem_dmaread(md, virt_to_phys(md->lynx->mem_dma_buffer) + + count - bcount, bcount, off); + if (retval < 0) return retval; - reg_write(md->lynx, DMA0_READY, 0); - run_pcl(md->lynx, md->lynx->mem_pcl.start, 0); - - while (reg_read(md->lynx, DMA0_CHAN_CTRL) & DMA_CHAN_CTRL_BUSY) { - if (signal_pending(current)) { - reg_write(md->lynx, DMA0_CHAN_CTRL, 0); - goto rmwait_done; - } - schedule(); + bcount -= retval; + off += retval; } - copy_to_user(buffer, md->lynx->mem_dma_buffer, bcount); - bcount = 0; - - if (reg_read(md->lynx, DMA0_CHAN_CTRL) & DMA_CHAN_CTRL_BUSY) { - PRINT(KERN_ERR, md->lynx->id, "DMA STILL ACTIVE!"); + if (bcount) { + memcpy_fromio(md->lynx->mem_dma_buffer + count - bcount, + membase+off, bcount); } - rmwait_done: - reg_write(md->lynx, DMA0_CHAN_CTRL, 0); - remove_wait_queue(&md->lynx->mem_dma_intr_wait, &wait); - done: + out: + retval = copy_to_user(buffer, md->lynx->mem_dma_buffer, count); up(&md->lynx->mem_dma_mutex); - count -= bcount; + if (retval < 0) return retval; *offset += count; - return (count ? count : -EINTR); + return count; } @@ -1200,6 +1172,12 @@ data = lynx->iso_rcv.page[idx / ISORCV_PER_PAGE] + (idx % ISORCV_PER_PAGE) * MAX_ISORCV_SIZE; + if ((*data >> 16) + 4 != (lynx->iso_rcv.stat[idx] & 0x1fff)) { + PRINT(KERN_ERR, lynx->id, + "iso length mismatch 0x%08x/0x%08x", *data, + lynx->iso_rcv.stat[idx]); + } + if (lynx->iso_rcv.stat[idx] & (DMA_CHAN_STAT_PCIERR | DMA_CHAN_STAT_PKTERR)) { PRINT(KERN_INFO, lynx->id, @@ -1224,11 +1202,12 @@ static int add_card(struct pci_dev *dev) { -#define FAIL(fmt, args...) \ +#define FAIL(fmt, args...) do { \ PRINT_G(KERN_ERR, fmt , ## args); \ num_of_cards--; \ remove_card(lynx); \ - return 1 + return 1; \ + } while (0) struct ti_lynx *lynx; /* shortcut to currently handled device */ unsigned long page; @@ -1246,6 +1225,9 @@ lynx->id = num_of_cards-1; lynx->dev = dev; + if (pci_enable_device(dev)) { + FAIL("failed to enable PCILynx hardware %d", lynx->id); + } pci_set_master(dev); if (!request_irq(dev->irq, lynx_irq_handler, SA_SHIRQ, @@ -1271,7 +1253,7 @@ } #endif - lynx->mem_dma_buffer = kmalloc(32768, GFP_KERNEL); + lynx->mem_dma_buffer = kmalloc(65536, GFP_KERNEL); if (lynx->mem_dma_buffer != NULL) { lynx->state = have_aux_buf; } else { @@ -1301,15 +1283,15 @@ lynx->local_ram = ioremap(dev->base_address[1], PCILYNX_MAX_MEMORY); lynx->aux_port = ioremap(dev->base_address[2], PCILYNX_MAX_MEMORY); #else - lynx->registers = ioremap_nocache(dev->resource[0].start, + lynx->registers = ioremap_nocache(pci_resource_start(dev,0), PCILYNX_MAX_REGISTER); - lynx->local_ram = ioremap(dev->resource[1].start, PCILYNX_MAX_MEMORY); - lynx->aux_port = ioremap(dev->resource[2].start, PCILYNX_MAX_MEMORY); + lynx->local_ram = ioremap(pci_resource_start(dev,1), PCILYNX_MAX_MEMORY); + lynx->aux_port = ioremap(pci_resource_start(dev,2), PCILYNX_MAX_MEMORY); #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,15) lynx->local_rom = ioremap(dev->rom_address, PCILYNX_MAX_MEMORY); #else - lynx->local_rom = ioremap(dev->resource[PCI_ROM_RESOURCE].start, + lynx->local_rom = ioremap(pci_resource_start(dev,PCI_ROM_RESOURCE), PCILYNX_MAX_MEMORY); #endif lynx->state = have_iomappings; @@ -1328,12 +1310,8 @@ /* alloc_pcl return values are not checked, it is expected that the * provided PCL space is sufficient for the initial allocations */ if (lynx->aux_port != NULL) { - lynx->mem_pcl.start = alloc_pcl(lynx); - lynx->mem_pcl.cmd = alloc_pcl(lynx); - lynx->mem_pcl.mod = alloc_pcl(lynx); - lynx->mem_pcl.max = alloc_pcl(lynx); + lynx->dmem_pcl = alloc_pcl(lynx); aux_setup_pcls(lynx); - sema_init(&lynx->mem_dma_mutex, 1); } lynx->rcv_pcl = alloc_pcl(lynx); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ieee1394/pcilynx.h linux/drivers/ieee1394/pcilynx.h --- v2.4.0-test1/linux/drivers/ieee1394/pcilynx.h Mon Mar 27 08:08:24 2000 +++ linux/drivers/ieee1394/pcilynx.h Mon Jun 19 17:59:40 2000 @@ -19,7 +19,7 @@ #define ISORCV_PER_PAGE (PAGE_SIZE / MAX_ISORCV_SIZE) #define ISORCV_PAGES (NUM_ISORCV_PCL / ISORCV_PER_PAGE) -/* only iso rcv uses these definitions so far */ +/* only iso rcv and localbus use these definitions so far */ #define CHANNEL_LOCALBUS 0 #define CHANNEL_ASYNC_RCV 1 #define CHANNEL_ISO_RCV 2 @@ -70,9 +70,7 @@ #endif /* PCLs for local mem / aux transfers */ - struct { - pcl_t start, cmd, mod, max; - } mem_pcl; + pcl_t dmem_pcl; /* IEEE-1394 part follows */ struct hpsb_host *host; @@ -105,7 +103,7 @@ struct memdata { struct ti_lynx *lynx; int cid; - int aux_intr_last_seen; + atomic_t aux_intr_last_seen; enum { rom, aux, ram } type; }; @@ -415,6 +413,38 @@ #endif /* CONFIG_IEEE1394_PCILYNX_LOCALRAM */ +#if defined (CONFIG_IEEE1394_PCILYNX_LOCALRAM) || defined (__BIG_ENDIAN) +typedef struct ti_pcl pcltmp_t; + +inline static struct ti_pcl *edit_pcl(const struct ti_lynx *lynx, pcl_t pclid, + pcltmp_t *tmp) +{ + get_pcl(lynx, pclid, tmp); + return tmp; +} + +inline static void commit_pcl(const struct ti_lynx *lynx, pcl_t pclid, + pcltmp_t *tmp) +{ + put_pcl(lynx, pclid, tmp); +} + +#else +typedef int pcltmp_t; /* just a dummy */ + +inline static struct ti_pcl *edit_pcl(const struct ti_lynx *lynx, pcl_t pclid, + pcltmp_t *tmp) +{ + return lynx->pcl_mem + pclid * sizeof(struct ti_pcl); +} + +inline static void commit_pcl(const struct ti_lynx *lynx, pcl_t pclid, + pcltmp_t *tmp) +{ +} +#endif + + inline static void run_sub_pcl(const struct ti_lynx *lynx, pcl_t pclid, int idx, int dmachan) { @@ -464,73 +494,73 @@ #define _(x) (__constant_cpu_to_be32(x)) -quadlet_t lynx_csr_rom[] = { - /* bus info block */ - _(0x04040000), /* info/CRC length, CRC */ - _(0x31333934), /* 1394 magic number */ - _(0xf064a000), /* misc. settings */ - _(0x08002850), /* vendor ID, chip ID high */ - _(0x0000ffff), /* chip ID low */ - /* root directory */ - _(0x00090000), /* CRC length, CRC */ - _(0x03080028), /* vendor ID (Texas Instr.) */ - _(0x81000009), /* offset to textual ID */ - _(0x0c000200), /* node capabilities */ - _(0x8d00000e), /* offset to unique ID */ - _(0xc7000010), /* offset to module independent info */ - _(0x04000000), /* module hardware version */ - _(0x81000026), /* offset to textual ID */ - _(0x09000000), /* node hardware version */ - _(0x81000026), /* offset to textual ID */ - /* module vendor ID textual */ - _(0x00080000), /* CRC length, CRC */ - _(0x00000000), - _(0x00000000), - _(0x54455841), /* "Texas Instruments" */ - _(0x5320494e), - _(0x53545255), - _(0x4d454e54), - _(0x53000000), - /* node unique ID leaf */ - _(0x00020000), /* CRC length, CRC */ - _(0x08002850), /* vendor ID, chip ID high */ - _(0x0000ffff), /* chip ID low */ - /* module dependent info */ - _(0x00060000), /* CRC length, CRC */ - _(0xb8000006), /* offset to module textual ID */ - _(0x81000004), /* ??? textual descriptor */ - _(0x39010000), /* SRAM size */ - _(0x3a010000), /* AUXRAM size */ - _(0x3b000000), /* AUX device */ - /* module textual ID */ - _(0x00050000), /* CRC length, CRC */ - _(0x00000000), - _(0x00000000), - _(0x54534231), /* "TSB12LV21" */ - _(0x324c5632), - _(0x31000000), - /* part number */ - _(0x00060000), /* CRC length, CRC */ - _(0x00000000), - _(0x00000000), - _(0x39383036), /* "9806000-0001" */ - _(0x3030342d), - _(0x30303431), - _(0x20000001), - /* module hardware version textual */ - _(0x00050000), /* CRC length, CRC */ - _(0x00000000), - _(0x00000000), - _(0x5453424b), /* "TSBKPCITST" */ - _(0x50434954), - _(0x53540000), - /* node hardware version textual */ - _(0x00050000), /* CRC length, CRC */ - _(0x00000000), - _(0x00000000), - _(0x54534232), /* "TSB21LV03" */ - _(0x313c5630), - _(0x33000000) +static quadlet_t lynx_csr_rom[] = { +/* bus info block offset (hex) */ + _(0x04040000), /* info/CRC length, CRC 400 */ + _(0x31333934), /* 1394 magic number 404 */ + _(0xf064a000), /* misc. settings 408 */ + _(0x08002850), /* vendor ID, chip ID high 40c */ + _(0x0000ffff), /* chip ID low 410 */ +/* root directory */ + _(0x00090000), /* directory length, CRC 414 */ + _(0x03080028), /* vendor ID (Texas Instr.) 418 */ + _(0x81000008), /* offset to textual ID 41c */ + _(0x0c000200), /* node capabilities 420 */ + _(0x8d00000e), /* offset to unique ID 424 */ + _(0xc7000010), /* offset to module independent info 428 */ + _(0x04000000), /* module hardware version 42c */ + _(0x81000014), /* offset to textual ID 430 */ + _(0x09000000), /* node hardware version 434 */ + _(0x81000018), /* offset to textual ID 438 */ + /* module vendor ID textual */ + _(0x00070000), /* CRC length, CRC 43c */ + _(0x00000000), /* 440 */ + _(0x00000000), /* 444 */ + _(0x54455841), /* "Texas Instruments" 448 */ + _(0x5320494e), /* 44c */ + _(0x53545255), /* 450 */ + _(0x4d454e54), /* 454 */ + _(0x53000000), /* 458 */ +/* node unique ID leaf */ + _(0x00020000), /* CRC length, CRC 45c */ + _(0x08002850), /* vendor ID, chip ID high 460 */ + _(0x0000ffff), /* chip ID low 464 */ +/* module dependent info */ + _(0x00050000), /* CRC length, CRC 468 */ + _(0x81000012), /* offset to module textual ID 46c */ + _(0x81000017), /* textual descriptor 470 */ + _(0x39010000), /* SRAM size 474 */ + _(0x3a010000), /* AUXRAM size 478 */ + _(0x3b000000), /* AUX device 47c */ +/* module textual ID */ + _(0x00050000), /* CRC length, CRC 480 */ + _(0x00000000), /* 484 */ + _(0x00000000), /* 488 */ + _(0x54534231), /* "TSB12LV21" 48c */ + _(0x324c5632), /* 490 */ + _(0x31000000), /* 494 */ +/* part number */ + _(0x00060000), /* CRC length, CRC 498 */ + _(0x00000000), /* 49c */ + _(0x00000000), /* 4a0 */ + _(0x39383036), /* "9806000-0001" 4a4 */ + _(0x3030302d), /* 4a8 */ + _(0x30303031), /* 4ac */ + _(0x20000001), /* 4b0 */ +/* module hardware version textual */ + _(0x00050000), /* CRC length, CRC 4b4 */ + _(0x00000000), /* 4b8 */ + _(0x00000000), /* 4bc */ + _(0x5453424b), /* "TSBKPCITST" 4c0 */ + _(0x50434954), /* 4c4 */ + _(0x53540000), /* 4c8 */ +/* node hardware version textual */ + _(0x00050000), /* CRC length, CRC 4d0 */ + _(0x00000000), /* 4d4 */ + _(0x00000000), /* 4d8 */ + _(0x54534232), /* "TSB21LV03" 4dc */ + _(0x314c5630), /* 4e0 */ + _(0x33000000) /* 4e4 */ }; #undef _ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ieee1394/raw1394.c linux/drivers/ieee1394/raw1394.c --- v2.4.0-test1/linux/drivers/ieee1394/raw1394.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ieee1394/raw1394.c Mon Jun 19 17:59:40 2000 @@ -575,8 +575,8 @@ break; case RAW1394_REQ_LOCK: - if ((req->req.misc != EXTCODE_FETCH_ADD) - && (req->req.misc != EXTCODE_LITTLE_ADD)) { + if ((req->req.misc == EXTCODE_FETCH_ADD) + || (req->req.misc == EXTCODE_LITTLE_ADD)) { if (req->req.length != 4) { req->req.error = RAW1394_ERROR_INVALID_ARG; break; @@ -667,8 +667,8 @@ break; case RAW1394_REQ_LOCK: - if ((req->req.misc != EXTCODE_FETCH_ADD) - && (req->req.misc != EXTCODE_LITTLE_ADD)) { + if ((req->req.misc == EXTCODE_FETCH_ADD) + || (req->req.misc == EXTCODE_LITTLE_ADD)) { if (req->req.length != 4) { req->req.error = RAW1394_ERROR_INVALID_ARG; break; @@ -690,6 +690,7 @@ break; } + req->data = packet->data; req->req.length = 4; break; @@ -716,6 +717,7 @@ if (!hpsb_send_packet(packet)) { req->req.error = RAW1394_ERROR_SEND_ERROR; req->req.length = 0; + free_tlabel(packet->host, packet->node_id, packet->tlabel); queue_complete_req(req); } return sizeof(struct raw1394_request); @@ -843,7 +845,6 @@ file->private_data = fi; - MOD_INC_USE_COUNT; return 0; } @@ -897,7 +898,6 @@ kfree(fi); - MOD_DEC_USE_COUNT; return 0; } @@ -910,6 +910,7 @@ }; static struct file_operations file_ops = { + owner: THIS_MODULE, read: dev_read, write: dev_write, poll: dev_poll, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/ieee1394/video1394.h linux/drivers/ieee1394/video1394.h --- v2.4.0-test1/linux/drivers/ieee1394/video1394.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/ieee1394/video1394.h Mon Jun 19 17:59:40 2000 @@ -0,0 +1,50 @@ +/* + * video1394.h - driver for OHCI 1394 boards + * Copyright (C)1999,2000 Sebastien Rougeaux + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 _VIDEO_1394_H +#define _VIDEO_1394_H + +#define VIDEO1394_MAX_SIZE 0x400000 + +enum { + VIDEO1394_BUFFER_FREE = 0, + VIDEO1394_BUFFER_QUEUED, + VIDEO1394_BUFFER_READY +}; + +enum { + VIDEO1394_LISTEN_CHANNEL = 0, + VIDEO1394_UNLISTEN_CHANNEL, + VIDEO1394_QUEUE_BUFFER, + VIDEO1394_WAIT_BUFFER +}; + +struct video1394_mmap { + int channel; + int sync_tag; + int nb_buffers; + int buf_size; +}; + +struct video1394_wait { + int channel; + int buffer; +}; + +#endif diff -u --recursive --new-file v2.4.0-test1/linux/drivers/isdn/avmb1/b1pci.c linux/drivers/isdn/avmb1/b1pci.c --- v2.4.0-test1/linux/drivers/isdn/avmb1/b1pci.c Wed Apr 26 16:34:07 2000 +++ linux/drivers/isdn/avmb1/b1pci.c Mon Jun 19 17:59:40 2000 @@ -466,12 +466,15 @@ struct capicardparams param; int retval; - if (dev->resource[ 2].start & PCI_BASE_ADDRESS_IO_MASK) { /* B1 PCI V4 */ + if (pci_enable_device(dev)) + return 0; /* return failure */ + + if (pci_resource_flags(dev, 2) & IORESOURCE_IO) { /* B1 PCI V4 */ #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 driver = &b1pciv4_driver; #endif - param.membase = dev->resource[ 0].start & PCI_BASE_ADDRESS_MEM_MASK; - param.port = dev->resource[ 2].start & PCI_BASE_ADDRESS_IO_MASK; + param.membase = pci_resource_start (dev, 0); + param.port = pci_resource_start (dev, 2); param.irq = dev->irq; printk(KERN_INFO "%s: PCI BIOS reports AVM-B1 V4 at i/o %#x, irq %d, mem %#x\n", @@ -488,7 +491,7 @@ } } else { param.membase = 0; - param.port = dev->resource[ 1].start & PCI_BASE_ADDRESS_IO_MASK; + param.port = pci_resource_start (dev, 1); param.irq = dev->irq; printk(KERN_INFO "%s: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n", diff -u --recursive --new-file v2.4.0-test1/linux/drivers/isdn/avmb1/c4.c linux/drivers/isdn/avmb1/c4.c --- v2.4.0-test1/linux/drivers/isdn/avmb1/c4.c Wed Apr 26 16:34:07 2000 +++ linux/drivers/isdn/avmb1/c4.c Mon Jun 19 17:59:40 2000 @@ -1333,9 +1333,12 @@ PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C4, dev))) { struct capicardparams param; - param.port = dev->resource[ 1].start & PCI_BASE_ADDRESS_IO_MASK; + if (pci_enable_device(dev)) + continue; + + param.port = pci_resource_start (dev, 1); param.irq = dev->irq; - param.membase = dev->resource[ 0].start & PCI_BASE_ADDRESS_MEM_MASK; + param.membase = pci_resource_start (dev, 0); printk(KERN_INFO "%s: PCI BIOS reports AVM-C4 at i/o %#x, irq %d, mem %#x\n", diff -u --recursive --new-file v2.4.0-test1/linux/drivers/isdn/avmb1/capi.c linux/drivers/isdn/avmb1/capi.c --- v2.4.0-test1/linux/drivers/isdn/avmb1/capi.c Wed Apr 26 16:34:07 2000 +++ linux/drivers/isdn/avmb1/capi.c Wed Jun 21 22:31:01 2000 @@ -653,6 +653,7 @@ datahandle, skb->len); #endif mp->tty->ldisc.receive_buf(mp->tty, skb->data, 0, skb->len); + kfree_skb(skb); return 0; } else if (mp->file) { @@ -1197,7 +1198,6 @@ if ((file->private_data = capidev_alloc(file)) == 0) return -ENOMEM; - MOD_INC_USE_COUNT; #ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capi_open %d\n", GET_USE_COUNT(THIS_MODULE)); #endif @@ -1211,7 +1211,6 @@ capincci_free(cdev, 0xffffffff); capidev_free(cdev); - MOD_DEC_USE_COUNT; #ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capi_release %d\n", GET_USE_COUNT(THIS_MODULE)); #endif @@ -1220,6 +1219,7 @@ static struct file_operations capi_fops = { + owner: THIS_MODULE, llseek: capi_llseek, read: capi_read, write: capi_write, @@ -1407,18 +1407,14 @@ struct file_operations capinc_raw_fops = { - capinc_raw_llseek, - capinc_raw_read, - capinc_raw_write, - NULL, /* capi_readdir */ - capinc_raw_poll, - capinc_raw_ioctl, - NULL, /* capi_mmap */ - capinc_raw_open, - NULL, /* capi_flush */ - capinc_raw_release, - NULL, /* capi_fsync */ - NULL, /* capi_fasync */ + owner: THIS_MODULE, + llseek: capinc_raw_llseek, + read: capinc_raw_read, + write: capinc_raw_write, + poll: capinc_raw_poll, + ioctl: capinc_raw_ioctl, + open: capinc_raw_open, + release: capinc_raw_release, }; /* -------- tty_operations for capincci ----------------------------- */ @@ -1879,7 +1875,7 @@ *eof = 1; if (off >= len+begin) return 0; - *start = page + (begin-off); + *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off); } @@ -2057,11 +2053,11 @@ devfs_register_series (NULL, "capi/r%u", CAPINC_NR_PORTS, DEVFS_FL_DEFAULT, capi_rawmajor, 0, - S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR, &capinc_raw_fops, NULL); #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ - devfs_register (NULL, "isdn/capi20", 0, DEVFS_FL_DEFAULT, - capi_major, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + devfs_register (NULL, "isdn/capi20", DEVFS_FL_DEFAULT, + capi_major, 0, S_IFCHR | S_IRUSR | S_IWUSR, &capi_fops, NULL); printk(KERN_NOTICE "capi20: started up with major %d\n", capi_major); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/isdn/avmb1/capifs.c linux/drivers/isdn/avmb1/capifs.c --- v2.4.0-test1/linux/drivers/isdn/avmb1/capifs.c Wed Apr 26 16:34:07 2000 +++ linux/drivers/isdn/avmb1/capifs.c Wed Jun 21 07:25:16 2000 @@ -209,7 +209,7 @@ dentry->d_inode = np->inode; if ( dentry->d_inode ) - dentry->d_inode->i_count++; + atomic_inc(&dentry->d_inode->i_count); d_add(dentry, dentry->d_inode); @@ -228,9 +228,9 @@ for ( i = 0 ; i < sbi->max_ncci ; i++ ) { if ( (inode = sbi->nccis[i].inode) ) { - if ( inode->i_count != 1 ) + if ( atomic_read(&inode->i_count) != 1 ) printk("capifs_put_super: badness: entry %d count %d\n", - i, inode->i_count); + i, atomic_read(&inode->i_count)); inode->i_nlink--; iput(inode); } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/isdn/avmb1/kcapi.c linux/drivers/isdn/avmb1/kcapi.c --- v2.4.0-test1/linux/drivers/isdn/avmb1/kcapi.c Tue May 23 15:31:34 2000 +++ linux/drivers/isdn/avmb1/kcapi.c Mon Jun 19 17:59:40 2000 @@ -354,7 +354,7 @@ *eof = 1; if (off >= len+begin) return 0; - *start = page + (begin-off); + *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off); } @@ -385,7 +385,7 @@ *eof = 1; if (off >= len+begin) return 0; - *start = page + (begin-off); + *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off); } @@ -422,7 +422,7 @@ *eof = 1; if (off >= len+begin) return 0; - *start = page + (begin-off); + *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off); } @@ -459,7 +459,7 @@ *eof = 1; if (off >= len+begin) return 0; - *start = page + (begin-off); + *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off); } @@ -496,7 +496,7 @@ *eof = 1; if (off >= len+begin) return 0; - *start = page + (begin-off); + *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off); } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/isdn/avmb1/t1pci.c linux/drivers/isdn/avmb1/t1pci.c --- v2.4.0-test1/linux/drivers/isdn/avmb1/t1pci.c Thu May 11 15:30:07 2000 +++ linux/drivers/isdn/avmb1/t1pci.c Mon Jun 19 17:59:40 2000 @@ -305,11 +305,12 @@ while ((dev = pci_find_device(PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_T1, dev))) { struct capicardparams param; + if (pci_enable_device(dev)) + continue; + param.port = pci_resource_start (dev, 1); param.irq = dev->irq; param.membase = pci_resource_start (dev, 0); - - pci_enable_device (dev); /* XXX check return */ printk(KERN_INFO "%s: PCI BIOS reports AVM-T1-PCI at i/o %#x, irq %d, mem %#x\n", diff -u --recursive --new-file v2.4.0-test1/linux/drivers/isdn/eicon/eicon_pci.c linux/drivers/isdn/eicon/eicon_pci.c --- v2.4.0-test1/linux/drivers/isdn/eicon/eicon_pci.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/eicon/eicon_pci.c Mon Jun 19 17:59:40 2000 @@ -148,6 +148,8 @@ } } + pci_enable_device(pdev); /* XXX handle error return */ + pci_akt = 0; switch(pci_type) { @@ -156,8 +158,8 @@ aparms->type = EICON_CTYPE_MAESTRA; aparms->irq = pdev->irq; - preg = pdev->resource[ 2].start & 0xfffffffc; - pcfg = pdev->resource[ 1].start & 0xffffff80; + preg = pci_resource_start(pdev, 2); + pcfg = pci_resource_start(pdev, 1); #ifdef EICON_PCI_DEBUG printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq); @@ -178,9 +180,9 @@ printk(KERN_INFO "Eicon: DIVA Server PRI/PCI detected !\n"); aparms->type = EICON_CTYPE_MAESTRAP; /*includes 9M,30M*/ aparms->irq = pdev->irq; - pram = pdev->resource[ 0].start & 0xfffff000; - preg = pdev->resource[ 2].start & 0xfffff000; - pcfg = pdev->resource[ 4].start & 0xfffff000; + pram = pci_resource_start(pdev, 0); + preg = pci_resource_start(pdev, 2); + pcfg = pci_resource_start(pdev, 4); #ifdef EICON_PCI_DEBUG printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/isdn/hisax/avm_pci.c linux/drivers/isdn/hisax/avm_pci.c --- v2.4.0-test1/linux/drivers/isdn/hisax/avm_pci.c Sat Feb 26 22:31:45 2000 +++ linux/drivers/isdn/hisax/avm_pci.c Mon Jun 19 17:59:40 2000 @@ -820,11 +820,12 @@ PCI_FRITZPCI_ID, dev_avm))) { cs->irq = dev_avm->irq; if (!cs->irq) { - printk(KERN_WARNING "FritzPCI: No IRQ for PCI card found\n"); + printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n"); return(0); } - cs->hw.avm.cfg_reg = dev_avm->resource[ 1].start & - PCI_BASE_ADDRESS_IO_MASK; + if (pci_enable_device(dev_avm)) + return(0); + cs->hw.avm.cfg_reg = pci_resource_start (dev_avm, 1); if (!cs->hw.avm.cfg_reg) { printk(KERN_WARNING "FritzPCI: No IO-Adr for PCI card found\n"); return(0); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/isdn/hisax/bkm_a4t.c linux/drivers/isdn/hisax/bkm_a4t.c --- v2.4.0-test1/linux/drivers/isdn/hisax/bkm_a4t.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hisax/bkm_a4t.c Mon Jun 19 17:59:40 2000 @@ -319,11 +319,13 @@ if ((dev_a4t = pci_find_device(I20_VENDOR_ID, I20_DEVICE_ID, dev_a4t))) { u_int sub_sys_id = 0; + if (pci_enable_device(dev_a4t)) + return (0); pci_read_config_dword(dev_a4t, PCI_SUBSYSTEM_VENDOR_ID, &sub_sys_id); if (sub_sys_id == ((A4T_SUBSYS_ID << 16) | A4T_SUBVEN_ID)) { found = 1; - pci_memaddr = dev_a4t->resource[ 0].start; + pci_memaddr = pci_resource_start (dev_a4t, 0); cs->irq = dev_a4t->irq; } } @@ -339,7 +341,6 @@ printk(KERN_WARNING "HiSax: %s: No Memory base address\n", CardType[card->typ]); return (0); } - pci_memaddr &= PCI_BASE_ADDRESS_MEM_MASK; cs->hw.ax.base = (u_int) ioremap(pci_memaddr, 4096); /* Check suspecious address */ pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/isdn/hisax/diva.c linux/drivers/isdn/hisax/diva.c --- v2.4.0-test1/linux/drivers/isdn/hisax/diva.c Sat Feb 26 22:31:45 2000 +++ linux/drivers/isdn/hisax/diva.c Mon Jun 19 17:59:40 2000 @@ -936,26 +936,28 @@ cs->subtyp = 0; if ((dev_diva = pci_find_device(PCI_VENDOR_EICON_DIEHL, PCI_DIVA20_ID, dev_diva))) { + if (pci_enable_device(dev_diva)) + return (0); cs->subtyp = DIVA_PCI; cs->irq = dev_diva->irq; - cs->hw.diva.cfg_reg = dev_diva->resource[ 2].start - & PCI_BASE_ADDRESS_IO_MASK; + cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2); } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_EICON_DIEHL, PCI_DIVA20_U_ID, dev_diva_u))) { + if (pci_enable_device(dev_diva_u)) + return (0); cs->subtyp = DIVA_PCI; cs->irq = dev_diva_u->irq; - cs->hw.diva.cfg_reg = dev_diva_u->resource[ 2].start - & PCI_BASE_ADDRESS_IO_MASK; + cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2); } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_EICON_DIEHL, PCI_DIVA_201, dev_diva201))) { + if (pci_enable_device(dev_diva201)) + return (0); cs->subtyp = DIVA_IPAC_PCI; cs->irq = dev_diva201->irq; cs->hw.diva.pci_cfg = - (ulong) ioremap((dev_diva201->resource[ 0].start - & PCI_BASE_ADDRESS_IO_MASK), 4096); + (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096); cs->hw.diva.cfg_reg = - (ulong) ioremap((dev_diva201->resource[ 1].start - & PCI_BASE_ADDRESS_IO_MASK), 4096); + (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096); } else { printk(KERN_WARNING "Diva: No PCI card found\n"); return(0); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/isdn/hisax/elsa.c linux/drivers/isdn/hisax/elsa.c --- v2.4.0-test1/linux/drivers/isdn/hisax/elsa.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hisax/elsa.c Mon Jun 19 17:59:40 2000 @@ -1058,20 +1058,20 @@ cs->subtyp = 0; if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ELSA, PCI_QS1000_ID, dev_qs1000))) { - cs->subtyp = ELSA_QS1000PCI; + if (pci_enable_device(dev_qs1000)) + return (0); + cs->subtyp = ELSA_QS1000PCI; cs->irq = dev_qs1000->irq; - cs->hw.elsa.cfg = dev_qs1000->resource[ 1].start & - PCI_BASE_ADDRESS_IO_MASK; - cs->hw.elsa.base = dev_qs1000->resource[ 3].start & - PCI_BASE_ADDRESS_IO_MASK; + cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1); + cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3); } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ELSA, PCI_QS3000_ID, dev_qs3000))) { + if (pci_enable_device(dev_qs1000)) + return (0); cs->subtyp = ELSA_QS3000PCI; cs->irq = dev_qs3000->irq; - cs->hw.elsa.cfg = dev_qs3000->resource[ 1].start & - PCI_BASE_ADDRESS_IO_MASK; - cs->hw.elsa.base = dev_qs3000->resource[ 3].start & - PCI_BASE_ADDRESS_IO_MASK; + cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1); + cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3); } else { printk(KERN_WARNING "Elsa: No PCI card found\n"); return(0); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/isdn/hisax/gazel.c linux/drivers/isdn/hisax/gazel.c --- v2.4.0-test1/linux/drivers/isdn/hisax/gazel.c Thu Nov 11 20:11:37 1999 +++ linux/drivers/isdn/hisax/gazel.c Mon Jun 19 13:30:56 2000 @@ -589,7 +589,8 @@ seekcard = GAZEL_R685; for (nbseek = 0; nbseek < 3; nbseek++) { if ((dev_tel = pci_find_device(GAZEL_MANUFACTURER, seekcard, dev_tel))) { - + if (pci_enable_device(dev_tel)) + return 1; pci_irq = dev_tel->irq; pci_ioaddr0 = dev_tel->resource[ 1].start; pci_ioaddr1 = dev_tel->resource[ 2].start; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/isdn/hisax/hfc_pci.c linux/drivers/isdn/hisax/hfc_pci.c --- v2.4.0-test1/linux/drivers/isdn/hisax/hfc_pci.c Sat Feb 26 22:31:45 2000 +++ linux/drivers/isdn/hisax/hfc_pci.c Mon Jun 19 13:30:56 2000 @@ -1738,7 +1738,9 @@ dev_hfcpci); i++; if (tmp_hfcpci) { - if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->resource[ 0].start & PCI_BASE_ADDRESS_IO_MASK))) + if (pci_enable_device(tmp_hfcpci)) + continue; + if ((card->para[0]) && (card->para[0] != pci_resource_start(tmp_hfcpci, 0))) continue; else break; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/isdn/hisax/netjet.c linux/drivers/isdn/hisax/netjet.c --- v2.4.0-test1/linux/drivers/isdn/hisax/netjet.c Sat Feb 26 22:31:46 2000 +++ linux/drivers/isdn/hisax/netjet.c Mon Jun 19 13:30:56 2000 @@ -1130,13 +1130,14 @@ } if ((dev_netjet = pci_find_device(PCI_VENDOR_TRAVERSE_TECH, PCI_NETJET_ID, dev_netjet))) { + if (pci_enable_device(dev_netjet)) + return (0); cs->irq = dev_netjet->irq; if (!cs->irq) { printk(KERN_WARNING "NETjet: No IRQ for PCI card found\n"); return(0); } - cs->hw.njet.base = dev_netjet->resource[ 0].start - & PCI_BASE_ADDRESS_IO_MASK; + cs->hw.njet.base = pci_resource_start(dev_netjet, 0); if (!cs->hw.njet.base) { printk(KERN_WARNING "NETjet: No IO-Adr for PCI card found\n"); return(0); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/isdn/hisax/niccy.c linux/drivers/isdn/hisax/niccy.c --- v2.4.0-test1/linux/drivers/isdn/hisax/niccy.c Wed Apr 26 16:34:07 2000 +++ linux/drivers/isdn/hisax/niccy.c Mon Jun 19 13:30:56 2000 @@ -313,6 +313,8 @@ cs->subtyp = 0; if ((niccy_dev = pci_find_device(PCI_VENDOR_DR_NEUHAUS, PCI_NICCY_ID, niccy_dev))) { + if (pci_enable_device(niccy_dev)) + return (0); /* get IRQ */ if (!niccy_dev->irq) { printk(KERN_WARNING "Niccy: No IRQ for PCI card found\n"); @@ -323,12 +325,12 @@ printk(KERN_WARNING "Niccy: No IO-Adr for PCI cfg found\n"); return(0); } - cs->hw.niccy.cfg_reg = niccy_dev->resource[ 0].start & PCI_BASE_ADDRESS_IO_MASK; + cs->hw.niccy.cfg_reg = pci_resource_start(niccy_dev, 0); if (!niccy_dev->resource[ 1].start) { printk(KERN_WARNING "Niccy: No IO-Adr for PCI card found\n"); return(0); } - pci_ioaddr = niccy_dev->resource[ 1].start & PCI_BASE_ADDRESS_IO_MASK; + pci_ioaddr = pci_resource_start(niccy_dev, 1); cs->subtyp = NICCY_PCI; } else { printk(KERN_WARNING "Niccy: No PCI card found\n"); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/isdn/hisax/sedlbauer.c linux/drivers/isdn/hisax/sedlbauer.c --- v2.4.0-test1/linux/drivers/isdn/hisax/sedlbauer.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hisax/sedlbauer.c Mon Jun 19 13:30:56 2000 @@ -641,23 +641,22 @@ } if ((dev_sedl = pci_find_device(PCI_VENDOR_SEDLBAUER, PCI_SPEEDPCI_ID, dev_sedl))) { + if (pci_enable_device(dev_sedl)) + return (0); cs->irq = dev_sedl->irq; if (!cs->irq) { printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n"); return(0); } - cs->hw.sedl.cfg_reg = dev_sedl->resource[ 0].start & - PCI_BASE_ADDRESS_IO_MASK; + cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0); } else { printk(KERN_WARNING "Sedlbauer: No PCI card found\n"); return(0); } cs->irq_flags |= SA_SHIRQ; cs->hw.sedl.bus = SEDL_BUS_PCI; - pci_read_config_word(dev_sedl, PCI_SUBSYSTEM_VENDOR_ID, - &sub_vendor_id); - pci_read_config_word(dev_sedl, PCI_SUBSYSTEM_ID, - &sub_id); + sub_vendor_id = dev_sedl->subsystem_vendor; + sub_id = dev_sedl->subsystem_device; printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n", sub_vendor_id, sub_id); printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n", diff -u --recursive --new-file v2.4.0-test1/linux/drivers/isdn/hisax/telespci.c linux/drivers/isdn/hisax/telespci.c --- v2.4.0-test1/linux/drivers/isdn/hisax/telespci.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hisax/telespci.c Mon Jun 19 13:30:56 2000 @@ -325,6 +325,8 @@ return(0); } if ((dev_tel = pci_find_device (0x11DE, 0x6120, dev_tel))) { + if (pci_enable_device(dev_tel)) + return (0); cs->irq = dev_tel->irq; if (!cs->irq) { printk(KERN_WARNING "Teles: No IRQ for PCI card found\n"); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/isdn/hisax/w6692.c linux/drivers/isdn/hisax/w6692.c --- v2.4.0-test1/linux/drivers/isdn/hisax/w6692.c Mon Mar 27 08:08:25 2000 +++ linux/drivers/isdn/hisax/w6692.c Mon Jun 19 13:30:56 2000 @@ -1009,8 +1009,11 @@ dev_w6692 = pci_find_device(id_list[id_idx].vendor_id, id_list[id_idx].device_id, dev_w6692); - if (dev_w6692) + if (dev_w6692) { + if (pci_enable_device(dev_w6692)) + continue; break; + } id_idx++; } if (dev_w6692) { @@ -1018,7 +1021,7 @@ pci_irq = dev_w6692->irq; /* I think address 0 is allways the configuration area */ /* and address 1 is the real IO space KKe 03.09.99 */ - pci_ioaddr = dev_w6692->resource[ 1].start; + pci_ioaddr = pci_resource_start(dev_w6692, 1); } if (!found) { printk(KERN_WARNING "W6692: No PCI card found\n"); @@ -1029,7 +1032,6 @@ printk(KERN_WARNING "W6692: No IRQ for PCI card found\n"); return (0); } - pci_ioaddr &= PCI_BASE_ADDRESS_IO_MASK; if (!pci_ioaddr) { printk(KERN_WARNING "W6692: NO I/O Base Address found\n"); return (0); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/isdn/hysdn/hysdn_init.c linux/drivers/isdn/hysdn/hysdn_init.c --- v2.4.0-test1/linux/drivers/isdn/hysdn/hysdn_init.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hysdn/hysdn_init.c Mon Jun 19 13:30:56 2000 @@ -84,7 +84,8 @@ card_last = NULL; while ((akt_pcidev = pci_find_device(PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_PLX, akt_pcidev)) != NULL) { - + if (pci_enable_device(akt_pcidev)) + continue; if (!(card = kmalloc(sizeof(hysdn_card), GFP_KERNEL))) { printk(KERN_ERR "HYSDN: unable to alloc device mem \n"); return; @@ -93,12 +94,11 @@ card->myid = cardmax; /* set own id */ card->bus = akt_pcidev->bus->number; card->devfn = akt_pcidev->devfn; /* slot + function */ - pcibios_read_config_word(card->bus, card->devfn, PCI_SUBSYSTEM_ID, &card->subsysid); - pcibios_read_config_byte(card->bus, card->devfn, PCI_INTERRUPT_LINE, &irq); - card->irq = irq; - card->iobase = akt_pcidev->resource[ PCI_REG_PLX_IO_BASE].start & PCI_BASE_ADDRESS_IO_MASK; - card->plxbase = akt_pcidev->resource[ PCI_REG_PLX_MEM_BASE].start; - card->membase = akt_pcidev->resource[ PCI_REG_MEMORY_BASE].start; + card->subsysid = akt_pcidev->subsystem_device; + card->irq = akt_pcidev->irq; + card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE); + card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE); + card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE); card->brdtype = BD_NONE; /* unknown */ card->debug_flags = DEF_DEB_FLAGS; /* set default debug */ card->faxchans = 0; /* default no fax channels */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/isdn/isdn_audio.c linux/drivers/isdn/isdn_audio.c --- v2.4.0-test1/linux/drivers/isdn/isdn_audio.c Mon Mar 27 08:08:25 2000 +++ linux/drivers/isdn/isdn_audio.c Mon Jun 19 13:30:56 2000 @@ -307,8 +307,10 @@ : "0"((long) table), "1"(n), "2"((long) buff), "3"((long) buff) : "memory", "ax"); #else + unsigned char* b = (unsigned char*) buff; + unsigned char* t = (unsigned char*) table; while (n--) - *buff++ = table[*(unsigned char *)buff]; + *b++ = t[*b]; #endif } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c --- v2.4.0-test1/linux/drivers/isdn/isdn_common.c Thu May 11 15:30:07 2000 +++ linux/drivers/isdn/isdn_common.c Wed Jun 21 22:31:01 2000 @@ -2581,14 +2581,14 @@ sprintf (buf, "isdn%d", k); dev->devfs_handle_isdnX[k] = - devfs_register (devfs_handle, buf, 0, DEVFS_FL_DEFAULT, - ISDN_MAJOR, ISDN_MINOR_B + k,0600 | S_IFCHR, 0, 0, + devfs_register (devfs_handle, buf, DEVFS_FL_DEFAULT, + ISDN_MAJOR, ISDN_MINOR_B + k,0600 | S_IFCHR, &isdn_fops, NULL); sprintf (buf, "isdnctrl%d", k); dev->devfs_handle_isdnctrlX[k] = - devfs_register (devfs_handle, buf, 0, DEVFS_FL_DEFAULT, + devfs_register (devfs_handle, buf, DEVFS_FL_DEFAULT, ISDN_MAJOR, ISDN_MINOR_CTRL + k, 0600 | S_IFCHR, - 0, 0, &isdn_fops, NULL); + &isdn_fops, NULL); } static void isdn_unregister_devfs(int k) @@ -2610,19 +2610,19 @@ sprintf (buf, "ippp%d", i); dev->devfs_handle_ipppX[i] = - devfs_register (devfs_handle, buf, 0, DEVFS_FL_DEFAULT, + devfs_register (devfs_handle, buf, DEVFS_FL_DEFAULT, ISDN_MAJOR, ISDN_MINOR_PPP + i, - 0600 | S_IFCHR, 0, 0, &isdn_fops, NULL); + 0600 | S_IFCHR, &isdn_fops, NULL); } # endif dev->devfs_handle_isdninfo = - devfs_register (devfs_handle, "isdninfo", 0, DEVFS_FL_DEFAULT, + devfs_register (devfs_handle, "isdninfo", DEVFS_FL_DEFAULT, ISDN_MAJOR, ISDN_MINOR_STATUS, 0600 | S_IFCHR, - 0, 0, &isdn_fops, NULL); + &isdn_fops, NULL); dev->devfs_handle_isdnctrl = - devfs_register (devfs_handle, "isdnctrl", 0, DEVFS_FL_DEFAULT, - ISDN_MAJOR, ISDN_MINOR_CTRL, 0600 | S_IFCHR, 0, 0, + devfs_register (devfs_handle, "isdnctrl", DEVFS_FL_DEFAULT, + ISDN_MAJOR, ISDN_MINOR_CTRL, 0600 | S_IFCHR, &isdn_fops, NULL); } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c --- v2.4.0-test1/linux/drivers/isdn/isdn_tty.c Sat Feb 26 22:31:46 2000 +++ linux/drivers/isdn/isdn_tty.c Mon Jun 19 13:30:56 2000 @@ -381,8 +381,14 @@ #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 + static int bit2si[8] = {1, 5, 7, 7, 7, 7, 7, 7}; static int si2bit[8] = diff -u --recursive --new-file v2.4.0-test1/linux/drivers/macintosh/adb.c linux/drivers/macintosh/adb.c --- v2.4.0-test1/linux/drivers/macintosh/adb.c Tue May 23 15:31:34 2000 +++ linux/drivers/macintosh/adb.c Wed Jun 21 22:31:01 2000 @@ -674,8 +674,8 @@ if (devfs_register_chrdev(ADB_MAJOR, "adb", &adb_fops)) printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR); else - devfs_register (NULL, "adb", 0, DEVFS_FL_NONE, + devfs_register (NULL, "adb", DEVFS_FL_DEFAULT, ADB_MAJOR, 0, - S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR, &adb_fops, NULL); } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/macintosh/mac_keyb.c linux/drivers/macintosh/mac_keyb.c --- v2.4.0-test1/linux/drivers/macintosh/mac_keyb.c Tue May 23 15:31:34 2000 +++ linux/drivers/macintosh/mac_keyb.c Tue Jun 20 13:58:42 2000 @@ -225,7 +225,7 @@ static void kbd_repeat(unsigned long); -static struct timer_list repeat_timer = { NULL, NULL, 0, 0, kbd_repeat }; +static struct timer_list repeat_timer = { function: kbd_repeat }; static int last_keycode; static void mackeyb_probe(void); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/macintosh/nvram.c linux/drivers/macintosh/nvram.c --- v2.4.0-test1/linux/drivers/macintosh/nvram.c Tue May 23 15:31:34 2000 +++ linux/drivers/macintosh/nvram.c Tue Jun 20 13:58:42 2000 @@ -70,24 +70,11 @@ return p - buf; } -static int nvram_open(struct inode *inode, struct file *file) -{ - MOD_INC_USE_COUNT; - return 0; -} - -static int nvram_release(struct inode *inode, struct file *file) -{ - MOD_DEC_USE_COUNT; - return 0; -} - struct file_operations nvram_fops = { + owner: THIS_MODULE, llseek: nvram_llseek, read: read_nvram, write: write_nvram, - open: nvram_open, - release: nvram_release, }; static struct miscdevice nvram_dev = { diff -u --recursive --new-file v2.4.0-test1/linux/drivers/macintosh/via-pmu.c linux/drivers/macintosh/via-pmu.c --- v2.4.0-test1/linux/drivers/macintosh/via-pmu.c Tue May 23 15:31:34 2000 +++ linux/drivers/macintosh/via-pmu.c Tue Jun 20 14:14:50 2000 @@ -1290,7 +1290,11 @@ sti(); - set_context(current->mm->context); + /* The PGD is only a placeholder until Dan finds a way to make + * this work properly on the 8xx processors. It is only used on + * 8xx processors, it is ignored here. + */ + set_context(current->mm->context, current->mm->pgd); /* Restore L2 cache */ if (save_l2cr) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/3c503.c linux/drivers/net/3c503.c --- v2.4.0-test1/linux/drivers/net/3c503.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/3c503.c Mon Jun 19 13:30:56 2000 @@ -99,7 +99,7 @@ if (base_addr > 0x1ff) /* Check a single specified location. */ return el2_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ - return ENXIO; + return -ENXIO; for (addr = addrs; *addr; addr++) { int i; @@ -118,7 +118,7 @@ #if ! defined(no_probe_nonshared_memory) && ! defined (HAVE_DEVLIST) return el2_pio_probe(dev); #else - return ENODEV; + return -ENODEV; #endif } @@ -134,7 +134,7 @@ if (base_addr > 0x1ff) /* Check a single specified location. */ return el2_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ - return ENXIO; + return -ENXIO; for (i = 0; netcard_portlist[i]; i++) { int ioaddr = netcard_portlist[i]; @@ -144,7 +144,7 @@ return 0; } - return ENODEV; + return -ENODEV; } #endif @@ -161,7 +161,7 @@ /* Reset and/or avoid any lurking NE2000 */ if (inb(ioaddr + 0x408) == 0xff) { mdelay(1); - return ENODEV; + return -ENODEV; } /* We verify that it's a 3C503 board by checking the first three octets @@ -171,7 +171,7 @@ /* ASIC location registers should be 0 or have only a single bit set. */ if ( (iobase_reg & (iobase_reg - 1)) || (membase_reg & (membase_reg - 1))) { - return ENODEV; + return -ENODEV; } saved_406 = inb_p(ioaddr + 0x406); outb_p(ECNTRL_RESET|ECNTRL_THIN, ioaddr + 0x406); /* Reset it... */ @@ -183,12 +183,9 @@ if ((vendor_id != OLD_3COM_ID) && (vendor_id != NEW_3COM_ID)) { /* Restore the register we frobbed. */ outb(saved_406, ioaddr + 0x406); - return ENODEV; + return -ENODEV; } - if (load_8390_module("3c503.c")) - return -ENOSYS; - /* We should have a "dev" from Space.c or the static module table. */ if (dev == NULL) { printk("3c503.c: Passed a NULL device.\n"); @@ -645,6 +642,9 @@ { int this_dev, found = 0; + if (load_8390_module("3c503.c")) + return -ENOSYS; + for (this_dev = 0; this_dev < MAX_EL2_CARDS; this_dev++) { struct net_device *dev = &dev_el2[this_dev]; dev->irq = irq[this_dev]; @@ -658,14 +658,13 @@ if (register_netdev(dev) != 0) { printk(KERN_WARNING "3c503.c: No 3c503 card found (i/o = 0x%x).\n", io[this_dev]); if (found != 0) { /* Got at least one. */ - lock_8390_module(); return 0; } + unload_8390_module(); return -ENXIO; } found++; } - lock_8390_module(); return 0; } @@ -684,7 +683,7 @@ kfree(priv); } } - unlock_8390_module(); + unload_8390_module(); } #endif /* MODULE */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/3c507.c linux/drivers/net/3c507.c --- v2.4.0-test1/linux/drivers/net/3c507.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/3c507.c Mon Jun 19 13:30:56 2000 @@ -315,7 +315,7 @@ if (base_addr > 0x1ff) /* Check a single specified location. */ return el16_probe1(dev, base_addr); else if (base_addr != 0) - return ENXIO; /* Don't probe at all. */ + return -ENXIO; /* Don't probe at all. */ for (i = 0; netcard_portlist[i]; i++) { int ioaddr = netcard_portlist[i]; @@ -325,7 +325,7 @@ return 0; } - return ENODEV; + return -ENODEV; } static int __init el16_probe1(struct net_device *dev, int ioaddr) @@ -351,7 +351,7 @@ && inb(ioaddr+2) == 'C' && inb(ioaddr+3) == 'O') ; else - return ENODEV; + return -ENODEV; /* Allocate a new 'dev' if needed. */ if (dev == NULL) @@ -370,7 +370,7 @@ irqval = request_irq(irq, &el16_interrupt, 0, "3c507", dev); if (irqval) { printk ("unable to get IRQ %d (irqval=%d).\n", irq, irqval); - return EAGAIN; + return -EAGAIN; } /* We've committed to using the board, and can start filling in *dev. */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/3c515.c linux/drivers/net/3c515.c --- v2.4.0-test1/linux/drivers/net/3c515.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/3c515.c Mon Jun 19 13:30:56 2000 @@ -448,7 +448,7 @@ goto no_pnp; for(i=0; corkscrew_isapnp_adapters[i].vendor != 0; i++) { struct pci_dev *idev = NULL; - int irq, j; + int irq; while((idev = isapnp_find_dev(NULL, corkscrew_isapnp_adapters[i].vendor, corkscrew_isapnp_adapters[i].function, @@ -1427,7 +1427,7 @@ entry = (++vp->cur_rx) % RX_RING_SIZE; } /* Refill the Rx ring buffers. */ - for (; vp->dirty_rx < vp->cur_rx; vp->dirty_rx++) { + for (; vp->cur_rx - vp->dirty_rx > 0; vp->dirty_rx++) { struct sk_buff *skb; entry = vp->dirty_rx % RX_RING_SIZE; if (vp->rx_skbuff[entry] == NULL) { diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/3c523.c linux/drivers/net/3c523.c --- v2.4.0-test1/linux/drivers/net/3c523.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/3c523.c Mon Jun 19 13:30:56 2000 @@ -417,7 +417,7 @@ unsigned int size = 0; if (MCA_bus == 0) { - return ENODEV; + return -ENODEV; } /* search through the slots for the 3c523. */ slot = mca_find_adapter(ELMC_MCA_ID, 0); @@ -519,7 +519,7 @@ printk(KERN_ERR "%s: memprobe, Can't find memory at 0x%lx!\n", dev->name, dev->mem_start); release_region(dev->base_addr, ELMC_IO_EXTENT); - return ENODEV; + return -ENODEV; } dev->mem_end = dev->mem_start + size; /* set mem_end showed by 'ifconfig' */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c --- v2.4.0-test1/linux/drivers/net/3c59x.c Tue May 23 15:31:34 2000 +++ linux/drivers/net/3c59x.c Mon Jun 19 13:30:57 2000 @@ -9,7 +9,7 @@ Members of the series include Fast EtherLink 3c590/3c592/3c595/3c597 and the EtherLink XL 3c900 and 3c905 cards. - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O + The author may be reached as becker@scyld.com, or C/O Center of Excellence in Space Data and Information Sciences Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 @@ -53,7 +53,7 @@ - Increased the loop counter in wait_for_completion from 2,000 to 4,000. LK1.1.5 28 April 2000, andrewm - - Added powerpc defines + - Added powerpc defines (John Daniel said these work...) - Some extra diagnostics - In vortex_error(), reset the Tx on maxCollisions. Otherwise most chips usually get a Tx timeout. @@ -63,6 +63,20 @@ - In vortex_up(), don't make Wn3_config initialisation dependent upon has_nway (this came across from 3c575_cb). + LK1.1.6 06 Jun 2000, andrewm + - Backed out the PPC defines. + - Use del_timer_sync(), mod_timer(). + - Fix wrapped ulong comparison in boomerang_rx() + - Add IS_TORNADO, use it to suppress 3c905C checksum error msg + (Donald Becker, I Lee Hetherington ) + - Replace union wn3_config with BFINS/BFEXT manipulation for + sparc64 (Pete Zaitcev, Peter Jones) + - In vortex_error, do_tx_reset and vortex_tx_timeout(Vortex): + do a netif_wake_queue() to better recover from errors. (Anders Pedersen, + Donald Becker) + - Print a warning on out-of-memory (rate limited to 1 per 10 secs) + - Added two more Cardbus 575 NICs: 5b57 and 6564 (Paul Wagland) + - See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 for more details. */ @@ -75,6 +89,12 @@ * elimination of all the tests and reduced cache footprint. */ +/* A few values that may be tweaked. */ +/* Keep the ring sizes a power of two for efficiency. */ +#define TX_RING_SIZE 16 +#define RX_RING_SIZE 32 +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ + /* "Knobs" that adjust features and parameters. */ /* Set the copy breakpoint for the copy-only-tiny-frames scheme. Setting to > 1512 effectively disables this feature. */ @@ -85,6 +105,8 @@ static int max_interrupt_work = 32; /* Give the NIC an extra reset at the end of vortex_up() */ static int extra_reset = 0; +/* Tx timeout interval (millisecs) */ +static int watchdog = 400; /* Allow aggregation of Tx interrupts. Saves CPU load at the cost * of possible Tx stalls if the system is blocking interrupts @@ -92,6 +114,7 @@ * AKPM 26 April 2000: enabling this still gets vestigial Tx timeouts * in a heavily loaded (collision-prone) 10BaseT LAN. Should be OK with * switched Ethernet. + * AKPM 24May00: vestigial timeouts have been removed by later fixes. */ #define tx_interrupt_mitigation 1 @@ -107,15 +130,6 @@ debugging. */ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits; -/* A few values that may be tweaked. */ -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT ((400*HZ)/1000) - -/* Keep the ring sizes a power of two for efficiency. */ -#define TX_RING_SIZE 16 -#define RX_RING_SIZE 32 -#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ - #ifndef __OPTIMIZE__ #error You must compile this file with the correct options! #error See the last lines of the source file. @@ -141,12 +155,6 @@ #include #include -/* John Daniel said these work... */ -#ifdef __powerpc__ -#define outsl outsl_ns -#define insl insl_ns -#endif - /* Kernel compatibility defines, some common to David Hinds' PCMCIA package. This is only in the support-all-kernels source code. */ @@ -155,9 +163,9 @@ #include static char version[] __devinitdata = -"3c59x.c:v0.99L+LK1.1.5 30 Apr 2000 Donald Becker and others http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html " "$Revision: 1.78 $\n"; +"3c59x.c:v0.99L+LK1.1.6 28 May 2000 Donald Becker and others. http://www.scyld.com/network/vortex.html " "$Revision: 1.97 $\n"; -MODULE_AUTHOR("Donald Becker "); +MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("3Com 3c59x/3c90x/3c575 series Vortex/Boomerang/Cyclone driver"); MODULE_PARM(debug, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(8) "i"); @@ -168,6 +176,7 @@ MODULE_PARM(compaq_ioaddr, "i"); MODULE_PARM(compaq_irq, "i"); MODULE_PARM(compaq_device_id, "i"); +MODULE_PARM(watchdog, "i"); /* Operational parameter that usually are not changed. */ @@ -271,9 +280,9 @@ PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3, }; -enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, - EEPROM_230=8, /* AKPM: Uses 0x230 as the base bitmpas for EEPROM reads */ - HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, }; +enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, IS_TORNADO=8, + EEPROM_230=0x10, /* AKPM: Uses 0x230 as the base bitmaps for EEPROM reads */ + HAS_PWR_CTRL=0x20, HAS_MII=0x40, HAS_NWAY=0x80, HAS_CB_FNS=0x100, }; enum vortex_chips { @@ -284,31 +293,33 @@ CH_3C595_2, CH_3C595_3, - CH_VORTEX, CH_3C900_1, CH_3C900_2, CH_3C900_3, - CH_3C900_4, + CH_3C900_5, CH_3C900B_FL, CH_3C905_1, CH_3C905_2, - CH_3C905B_1, + CH_3C905B_2, CH_3C905B_FX, CH_3C905C, CH_3C980, + CH_3C9805, CH_3CSOHO100_TX, CH_3C555, + CH_3C575, CH_3C575_1, CH_3CCFE575, - CH_3CCFE575CT, + CH_3CCFE575CT, CH_3CCFE656, CH_3CCFEM656, + CH_3CCFEM656_1, CH_3C450, }; @@ -323,6 +334,7 @@ int drv_flags; int io_size; } vortex_info_tbl[] __devinitdata = { +#define EISA_TBL_OFFSET 0 /* Offset of this entry for vortex_eisa_init */ {"3c590 Vortex 10Mbps", PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, {"3c592 EISA 10mbps Demon/Vortex", /* AKPM: from Don's 3c59x_cb.c 0.49H */ @@ -336,18 +348,15 @@ {"3c595 Vortex 100base-MII", PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, -#define EISA_TBL_OFFSET 6 /* Offset of this entry for vortex_eisa_init */ - {"3Com Vortex", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, {"3c900 Boomerang 10baseT", PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, {"3c900 Boomerang 10Mbps Combo", PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, {"3c900 Cyclone 10Mbps TPO", /* AKPM: from Don's 0.99M */ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, - {"3c900 Cyclone 10Mbps Combo", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + {"3c900 Cyclone 10Mbps TPC", /* AKPM: from Don's 0.99M */ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, {"3c900B-FL Cyclone 10base-FL", @@ -356,35 +365,42 @@ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, }, {"3c905 Boomerang 100baseT4", PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, }, - {"3c905B Cyclone 100baseTx", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, }, + {"3c905B Cyclone 10/100/BNC", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, }, {"3c905B-FX Cyclone 100baseFx", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, {"3c905C Tornado", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY, 128, }, {"3c980 Cyclone", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + {"3c980 10/100 Base-TX NIC(Python-T)", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, {"3cSOHO100-TX Hurricane", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, {"3c555 Laptop Hurricane", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + {"3c575 [Megahertz] 10/100 LAN CardBus", + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_230, 128, }, {"3c575 Boomerang CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_230, 64, }, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_230, 128, }, {"3CCFE575 Cyclone CardBus", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, }, + {"3CCFE575CT Cyclone CardBus", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, }, - {"3CCFE656 Cyclone CardBus", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, }, {"3CCFEM656 Cyclone CardBus", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, }, - {"3c450 Cyclone/unknown", /* AKPM: from Don's 0.99N */ - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, }, + {"3CCFEM656 Cyclone CardBus(0x6564)", /* From pcmcia-cs-3.1.5 */ + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, }, + {"3c450 HomePNA Tornado", /* AKPM: from Don's 0.99Q */ + PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY, 128, }, + {0,}, /* 0 terminated list. */ }; @@ -397,32 +413,35 @@ { 0x10B7, 0x5951, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_2 }, { 0x10B7, 0x5952, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_3 }, - { 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VORTEX }, { 0x10B7, 0x9000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_1 }, { 0x10B7, 0x9001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_2 }, { 0x10B7, 0x9004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_3 }, - { 0x10B7, 0x9005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_4 }, + { 0x10B7, 0x9006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_5 }, { 0x10B7, 0x900A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900B_FL }, { 0x10B7, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_1 }, { 0x10B7, 0x9051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_2 }, - { 0x10B7, 0x9055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_1 }, + { 0x10B7, 0x9058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_2 }, { 0x10B7, 0x905A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_FX }, { 0x10B7, 0x9200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905C }, { 0x10B7, 0x9800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C980 }, + { 0x10B7, 0x9805, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C9805 }, { 0x10B7, 0x7646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CSOHO100_TX }, { 0x10B7, 0x5055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C555 }, + { 0x10B7, 0x5b57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575 }, { 0x10B7, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_1 }, { 0x10B7, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575 }, - { 0x10B7, 0x5257, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575CT }, + { 0x10B7, 0x5257, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575CT }, { 0x10B7, 0x6560, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE656 }, { 0x10B7, 0x6562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656 }, + { 0x10B7, 0x6564, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656_1 }, { 0x10B7, 0x4500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C450 }, + {0,} /* 0 terminated list. */ }; MODULE_DEVICE_TABLE(pci, vortex_pci_tbl); @@ -501,15 +520,21 @@ enum Window3 { /* Window 3: MAC/config bits. */ Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8, }; -union wn3_config { - int i; - struct w3_config_fields { - unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2; - int pad8:8; - unsigned int ram_split:2, pad18:2, xcvr:4, autoselect:1; - int pad24:7; - } u; -}; + +#define BFEXT(value, offset, bitcount) \ + ((((unsigned long)(value)) >> (offset)) & ((1 << (bitcount)) - 1)) + +#define BFINS(lhs, rhs, offset, bitcount) \ + (((lhs) & ~((((1 << (bitcount)) - 1)) << (offset))) | \ + (((rhs) & ((1 << (bitcount)) - 1)) << (offset))) + +#define RAM_SIZE(v) BFEXT(v, 0, 3) +#define RAM_WIDTH(v) BFEXT(v, 3, 1) +#define RAM_SPEED(v) BFEXT(v, 4, 2) +#define ROM_SIZE(v) BFEXT(v, 6, 2) +#define RAM_SPLIT(v) BFEXT(v, 16, 2) +#define XCVR(v) BFEXT(v, 20, 4) +#define AUTOSELECT(v) BFEXT(v, 24, 1) enum Window4 { /* Window 4: Xcvr/media bits. */ Wn4_FIFODiag = 4, Wn4_NetDiag = 6, Wn4_PhysicalMgmt=8, Wn4_Media = 10, @@ -532,7 +557,8 @@ /* The Rx and Tx descriptor lists. Caution Alpha hackers: these types are 32 bits! Note also the 8 byte alignment contraint on tx_ring[] and rx_ring[]. */ -#define LAST_FRAG 0x80000000 /* Last Addr/Len pair in descriptor. */ +#define LAST_FRAG 0x80000000 /* Last Addr/Len pair in descriptor. */ +#define DN_COMPLETE 0x00010000 /* This packet has been downloaded */ struct boom_rx_desc { u32 next; /* Last entry points to 0. */ s32 status; @@ -785,6 +811,7 @@ struct net_device *dev; static int printed_version = 0; int retval; + struct vortex_chip_info * const vci = &vortex_info_tbl[chip_idx]; if (!printed_version) { printk (KERN_INFO "%s", version); @@ -801,7 +828,7 @@ printk(KERN_INFO "%s: 3Com %s %s at 0x%lx, ", dev->name, pdev ? "PCI" : "EISA", - vortex_info_tbl[chip_idx].name, + vci->name, ioaddr); /* private struct aligned and zeroed by init_etherdev */ @@ -809,8 +836,8 @@ dev->base_addr = ioaddr; dev->irq = irq; dev->mtu = mtu; - vp->has_nway = (vortex_info_tbl[chip_idx].drv_flags & HAS_NWAY) ? 1 : 0; - vp->io_size = vortex_info_tbl[chip_idx].io_size; + vp->has_nway = (vci->drv_flags & HAS_NWAY) ? 1 : 0; + vp->io_size = vci->io_size; /* module list only for EISA devices */ if (pdev == NULL) { @@ -821,10 +848,9 @@ /* PCI-only startup logic */ if (pdev) { /* EISA resources already marked, so only PCI needs to do this here */ - if (!request_region (ioaddr, vortex_info_tbl[chip_idx].io_size, - dev->name)) { + if (!request_region (ioaddr, vci->io_size, dev->name)) { printk (KERN_ERR "%s: Cannot reserve I/O resource 0x%x @ 0x%lx, aborting\n", - dev->name, vortex_info_tbl[chip_idx].io_size, ioaddr); + dev->name, vci->io_size, ioaddr); retval = -EBUSY; goto free_dev; } @@ -836,7 +862,7 @@ } /* enable bus-mastering if necessary */ - if (vortex_info_tbl[chip_idx].flags & PCI_USES_MASTER) + if (vci->flags & PCI_USES_MASTER) pci_set_master (pdev); } @@ -891,7 +917,7 @@ /* Read the station address from the EEPROM. */ EL3WINDOW(0); { - int base = (vortex_info_tbl[chip_idx].drv_flags & EEPROM_230) ? 0x230 : EEPROM_Read; + int base = (vci->drv_flags & EEPROM_230) ? 0x230 : EEPROM_Read; for (i = 0; i < 0x40; i++) { int timer; outw(base + i, ioaddr + Wn0EepromCmd); @@ -912,7 +938,7 @@ checksum ^= eeprom[i++]; checksum = (checksum ^ (checksum >> 8)) & 0xff; } - if (checksum != 0x00) + if ((checksum != 0x00) && !(vci->drv_flags & IS_TORNADO)) printk(" ***INVALID CHECKSUM %4.4x*** ", checksum); for (i = 0; i < 3; i++) ((u16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]); @@ -932,7 +958,7 @@ dev->irq); #endif - if (pdev && vortex_info_tbl[chip_idx].drv_flags & HAS_CB_FNS) { + if (pdev && vci->drv_flags & HAS_CB_FNS) { u32 fn_st_addr; /* Cardbus function status space */ fn_st_addr = pci_resource_start (pdev, 2); if (fn_st_addr) @@ -960,24 +986,24 @@ { static const char * ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; - union wn3_config config; + unsigned int config; EL3WINDOW(3); vp->available_media = inw(ioaddr + Wn3_Options); if ((vp->available_media & 0xff) == 0) /* Broken 3c916 */ vp->available_media = 0x40; - config.i = inl(ioaddr + Wn3_Config); + config = inl(ioaddr + Wn3_Config); if (vortex_debug > 1) printk(KERN_DEBUG " Internal config register is %4.4x, " - "transceivers %#x.\n", config.i, inw(ioaddr + Wn3_Options)); + "transceivers %#x.\n", config, inw(ioaddr + Wn3_Options)); printk(KERN_INFO " %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n", - 8 << config.u.ram_size, - config.u.ram_width ? "word" : "byte", - ram_split[config.u.ram_split], - config.u.autoselect ? "autoselect/" : "", - config.u.xcvr > XCVR_ExtMII ? "" : - media_tbl[config.u.xcvr].name); - vp->default_media = config.u.xcvr; - vp->autoselect = config.u.autoselect; + 8 << RAM_SIZE(config), + RAM_WIDTH(config) ? "word" : "byte", + ram_split[RAM_SPLIT(config)], + AUTOSELECT(config) ? "autoselect/" : "", + XCVR(config) > XCVR_ExtMII ? "" : + media_tbl[XCVR(config)].name); + vp->default_media = XCVR(config); + vp->autoselect = AUTOSELECT(config); } if (vp->media_override != 7) { @@ -1037,12 +1063,12 @@ dev->do_ioctl = &vortex_ioctl; dev->set_multicast_list = &set_rx_mode; dev->tx_timeout = &vortex_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; + dev->watchdog_timeo = (watchdog * HZ) / 1000; return 0; free_region: - release_region (ioaddr, vortex_info_tbl[chip_idx].io_size); + release_region (ioaddr, vci->io_size); free_dev: unregister_netdev(dev); kfree (dev); @@ -1070,7 +1096,7 @@ { long ioaddr = dev->base_addr; struct vortex_private *vp = (struct vortex_private *)dev->priv; - union wn3_config config; + unsigned int config; int i, device_id; if (vp->pdev) @@ -1080,7 +1106,7 @@ /* Before initializing select the active media port. */ EL3WINDOW(3); - config.i = inl(ioaddr + Wn3_Config); + config = inl(ioaddr + Wn3_Config); if (vp->media_override != 7) { if (vortex_debug > 1) @@ -1118,13 +1144,13 @@ dev->name, media_tbl[dev->if_port].name); vp->full_duplex = vp->force_fd; - config.u.xcvr = dev->if_port; + config = BFINS(config, dev->if_port, 20, 4); //AKPM if (!vp->has_nway) { if (vortex_debug > 6) printk(KERN_DEBUG "vortex_up(): writing 0x%x to InternalConfig\n", - config.i); - outl(config.i, ioaddr + Wn3_Config); + config); + outl(config, ioaddr + Wn3_Config); } if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) { @@ -1151,7 +1177,7 @@ if (vortex_debug > 1) { printk(KERN_DEBUG "%s: vortex_up() InternalConfig %8.8x.\n", - dev->name, config.i); + dev->name, config); } wait_for_completion(dev, TxReset); @@ -1233,8 +1259,6 @@ set_rx_mode(dev); outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ - netif_start_queue (dev); - outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ /* Allow status bits to be seen. */ @@ -1264,6 +1288,7 @@ } outw(TxEnable, ioaddr + EL3_CMD); } + netif_start_queue (dev); } static int @@ -1321,9 +1346,11 @@ int ok = 0; int media_status, mii_status, old_window; - if (vortex_debug > 1) + if (vortex_debug > 1) { printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n", dev->name, media_tbl[dev->if_port].name); + printk(KERN_DEBUG "dev->watchdog_timeo=%d\n", dev->watchdog_timeo); + } disable_irq(dev->irq); old_window = inw(ioaddr + EL3_CMD) >> 13; @@ -1383,7 +1410,7 @@ ok = 1; } if ( ! ok) { - union wn3_config config; + unsigned int config; do { dev->if_port = media_tbl[dev->if_port].next; @@ -1405,14 +1432,14 @@ media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media); EL3WINDOW(3); - config.i = inl(ioaddr + Wn3_Config); - config.u.xcvr = dev->if_port; - outl(config.i, ioaddr + Wn3_Config); + config = inl(ioaddr + Wn3_Config); + config = BFINS(config, dev->if_port, 20, 4); + outl(config, ioaddr + Wn3_Config); outw(dev->if_port == XCVR_10base2 ? StartCoax : StopCoax, ioaddr + EL3_CMD); if (vortex_debug > 1) - printk(KERN_DEBUG "wrote 0x%08x to Wn3_Config\n", config.i); + printk(KERN_DEBUG "wrote 0x%08x to Wn3_Config\n", config); /* AKPM: FIXME: Should reset Rx & Tx here. P60 of 3c90xc.pdf */ } EL3WINDOW(old_window); @@ -1422,10 +1449,10 @@ printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n", dev->name, media_tbl[dev->if_port].name); - vp->timer.expires = RUN_AT(next_tick); - add_timer(&vp->timer); + mod_timer(&vp->timer, RUN_AT(next_tick)); if (vp->deferred) outw(FakeIntr, ioaddr + EL3_CMD); + timer_exit(&vp->timer); return; } @@ -1437,6 +1464,7 @@ printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n", dev->name, inb(ioaddr + TxStatus), inw(ioaddr + EL3_STATUS)); + /* Slight code bloat to be user friendly. */ if ((inb(ioaddr + TxStatus) & 0x88) == 0x88) printk(KERN_ERR "%s: Transmitter encountered 16 collisions --" @@ -1460,7 +1488,7 @@ } } - if (vortex_debug > 1) + if (vortex_debug > 0) dump_tx_ring(dev); wait_for_completion(dev, TxReset); @@ -1481,8 +1509,10 @@ netif_stop_queue (dev); outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); outw(DownUnstall, ioaddr + EL3_CMD); - } else + } else { vp->stats.tx_dropped++; + netif_wake_queue(dev); + } /* Issue Tx Enable */ outw(TxEnable, ioaddr + EL3_CMD); @@ -1607,6 +1637,7 @@ } else { wait_for_completion(dev, TxReset); outw(TxEnable, ioaddr + EL3_CMD); + netif_wake_queue(dev); } } } @@ -1875,9 +1906,15 @@ outw(AckIntr | DownComplete, ioaddr + EL3_CMD); while (vp->cur_tx - dirty_tx > 0) { int entry = dirty_tx % TX_RING_SIZE; +#if 1 /* AKPM: the latter is faster, but cyclone-only */ if (inl(ioaddr + DownListPtr) == vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc)) break; /* It still hasn't been processed. */ +#else + if ((vp->tx_ring[entry].status & DN_COMPLETE) == 0) + break; /* It still hasn't been processed. */ +#endif + if (vp->tx_skbuff[entry]) { struct sk_buff *skb = vp->tx_skbuff[entry]; @@ -1899,8 +1936,6 @@ netif_wake_queue (dev); } } - if (vp->tx_full) - netif_stop_queue (dev); /* Check for all uncommon interrupts at once. */ if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) @@ -1925,7 +1960,7 @@ if (vp->cb_fn_base) /* The PCMCIA people are idiots. */ writel(0x8000, vp->cb_fn_base + 4); - } while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete)); + } while ((status = inw(ioaddr + EL3_STATUS)) & IntLatch); if (vortex_debug > 4) printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n", @@ -2041,8 +2076,7 @@ /* Check if the packet is long enough to just accept without copying to a properly sized skbuff. */ - if (pkt_len < rx_copybreak - && (skb = dev_alloc_skb(pkt_len + 2)) != 0) { + if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != 0) { skb->dev = dev; skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ pci_dma_sync_single(vp->pdev, dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); @@ -2076,13 +2110,19 @@ entry = (++vp->cur_rx) % RX_RING_SIZE; } /* Refill the Rx ring buffers. */ - for (; vp->dirty_rx < vp->cur_rx; vp->dirty_rx++) { + for (; vp->cur_rx - vp->dirty_rx > 0; vp->dirty_rx++) { struct sk_buff *skb; entry = vp->dirty_rx % RX_RING_SIZE; if (vp->rx_skbuff[entry] == NULL) { skb = dev_alloc_skb(PKT_BUF_SZ); - if (skb == NULL) + if (skb == NULL) { + static unsigned long last_jif; + if ((jiffies - last_jif) > 10 * HZ) { + printk(KERN_WARNING "%s: memory shortage\n", dev->name); + last_jif = jiffies; + } break; /* Bad news! */ + } skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ vp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE)); @@ -2102,7 +2142,7 @@ netif_stop_queue (dev); - del_timer(&vp->timer); + del_timer_sync(&vp->timer); /* Turn off statistics ASAP. We update vp->stats below. */ outw(StatsDisable, ioaddr + EL3_CMD); @@ -2184,16 +2224,16 @@ int stalled = inl(ioaddr + PktStatus) & 0x04; /* Possible racy. But it's only debug stuff */ wait_for_completion(dev, DownStall); - printk(KERN_DEBUG " Flags; bus-master %d, full %d; dirty %d(%d) " + printk(KERN_ERR " Flags; bus-master %d, full %d; dirty %d(%d) " "current %d(%d).\n", vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->dirty_tx % TX_RING_SIZE, vp->cur_tx, vp->cur_tx % TX_RING_SIZE); - printk(KERN_DEBUG " Transmit list %8.8x vs. %p.\n", + printk(KERN_ERR " Transmit list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr), &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]); for (i = 0; i < TX_RING_SIZE; i++) { - printk(KERN_DEBUG " %d: @%p length %8.8x status %8.8x\n", i, + printk(KERN_ERR " %d: @%p length %8.8x status %8.8x\n", i, &vp->tx_ring[i], le32_to_cpu(vp->tx_ring[i].length), le32_to_cpu(vp->tx_ring[i].status)); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/8139too.c linux/drivers/net/8139too.c --- v2.4.0-test1/linux/drivers/net/8139too.c Tue May 23 15:31:35 2000 +++ linux/drivers/net/8139too.c Mon Jun 19 13:30:57 2000 @@ -97,7 +97,7 @@ #include -#define RTL8139_VERSION "0.9.5" +#define RTL8139_VERSION "0.9.7" #define RTL8139_MODULE_NAME "8139too" #define RTL8139_DRIVER_NAME RTL8139_MODULE_NAME " Fast Ethernet driver " RTL8139_VERSION #define PFX RTL8139_MODULE_NAME ": " @@ -232,6 +232,7 @@ IntrMask = 0x3C, IntrStatus = 0x3E, TxConfig = 0x40, + ChipVersion = 0x43, RxConfig = 0x44, Timer = 0x48, /* A general-purpose counter. */ RxMissed = 0x4C, /* 24 bits valid, write clears. */ @@ -392,8 +393,8 @@ typedef enum { CH_8139 = 0, + CH_8139_K, CH_8139A, - CH_8139A_G, CH_8139B, CH_8130, CH_8139C, @@ -403,36 +404,36 @@ /* directly indexed by chip_t, above */ const static struct { const char *name; - u32 version; /* from RTL8139C docs */ + u8 version; /* from RTL8139C docs */ u32 RxConfigMask; /* should clear the bits supported by this chip */ } rtl_chip_info[] = { { "RTL-8139", - 0x60000000, + 0x40, 0xf0fe0040, /* XXX copied from RTL8139A, verify */ }, - { "RTL-8139A", - 0x70000000, - 0xf0fe0040, + { "RTL-8139 rev K", + 0x60, + 0xf0fe0040, /* XXX copied from RTL8139A, verify */ }, - { "RTL-8139A rev. G", - 0x70800000, + { "RTL-8139A", + 0x70, 0xf0fe0040, }, { "RTL-8139B", - 0x78000000, + 0x78, 0xf0fc0040 }, { "RTL-8130", - 0x7C000000, + 0x7C, 0xf0fe0040, /* XXX copied from RTL8139A, verify */ }, { "RTL-8139C", - 0x74000000, + 0x74, 0xf0fc0040, /* XXX copied from RTL8139B, verify */ }, @@ -672,7 +673,7 @@ } /* identify chip attached to board */ - tmp = RTL_R32 (TxConfig) & TxVersionMask; + tmp = RTL_R8 (ChipVersion); for (i = arraysize (rtl_chip_info) - 1; i >= 0; i--) if (tmp == rtl_chip_info[i].version) { tp->chipset = i; @@ -686,10 +687,8 @@ tp->chipset = 0; match: - DPRINTK ("chipset id (%d/%d/%d) == %d, '%s'\n", - CH_8139, - CH_8139A, - CH_8139B, + DPRINTK ("chipset id (%d) == index %d, '%s'\n", + tmp, tp->chipset, rtl_chip_info[tp->chipset].name); @@ -1144,19 +1143,6 @@ RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0))); RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4))); - /* unlock Config[01234] and BMCR register writes */ - RTL_W8_F (Cfg9346, Cfg9346_Unlock); - udelay (100); - - tp->cur_rx = 0; - - /* init Rx ring buffer DMA address */ - RTL_W32_F (RxBuf, tp->rx_ring_dma); - - /* init Tx buffer DMA addresses */ - for (i = 0; i < NUM_TX_DESC; i++) - RTL_W32_F (TxAddr0 + (i * 4), tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs)); - /* Must enable Tx/Rx before setting transfer thresholds! */ RTL_W8_F (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdRxEnb | CmdTxEnb); @@ -1168,47 +1154,43 @@ /* Check this value: the documentation for IFG contradicts ifself. */ RTL_W32 (TxConfig, (TX_DMA_BURST << 8)); -#if 0 - /* if link status not ok... */ - if ((RTL_R16 (BasicModeStatus) & (1<<2)) == 0) { - printk (KERN_INFO "%s: no link, starting NWay\n", dev->name); - - /* Reset N-Way to chipset defaults */ - RTL_W16 (BasicModeCtrl, RTL_R16 (BasicModeCtrl) | (1<<15)); - for (i = 1000; i > 0; i--) - if ((RTL_R8 (BasicModeCtrl) & (1<<15)) == 0) - break; - - /* Set N-Way to sane defaults */ - RTL_W16_F (FIFOTMS, RTL_R16 (FIFOTMS) & ~(1<<7)); - RTL_W16_F (NWayAdvert, RTL_R16 (NWayAdvert) | - (1<<13)|(1<<8)|(1<<7)|(1<<6)|(1<<5)|(1<<0)); - RTL_W16_F (BasicModeCtrl, RTL_R16 (BasicModeCtrl) | - (1<<13)|(1<<12)|(1<<9)|(1<<8)); - RTL_W8_F (MediaStatus, RTL_R8 (MediaStatus) | (1<<7) | (1<<6)); - - /* check_duplex() here. */ - /* XXX writing Config1 here is flat out wrong */ - /* RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); */ - } -#endif + /* unlock Config[01234] and BMCR register writes */ + RTL_W8_F (Cfg9346, Cfg9346_Unlock); + udelay (10); + + tp->cur_rx = 0; - if (tp->chipset > CH_8139) { + if (tp->chipset >= CH_8139A) { tmp = RTL_R8 (Config1) & Config1Clear; + tmp |= Cfg1_Driver_Load; tmp |= (tp->chipset == CH_8139B) ? 3 : 1; /* Enable PM/VPD */ RTL_W8_F (Config1, tmp); + } else { + u8 foo = RTL_R8 (Config1) & Config1Clear; + RTL_W8 (Config1, tp->full_duplex ? (foo|0x60) : (foo|0x20)); } - if (tp->chipset == CH_8139B) { + if (tp->chipset >= CH_8139B) { tmp = RTL_R8 (Config4) & ~(1<<2); /* chip will clear Rx FIFO overflow automatically */ tmp |= (1<<7); RTL_W8 (Config4, tmp); - } - /* disable magic packet scanning, which is enabled - * when PM is enabled above (Config1) */ - RTL_W8 (Config3, RTL_R8 (Config3) & ~(1<<5)); + /* disable magic packet scanning, which is enabled + * when PM is enabled above (Config1) */ + RTL_W8 (Config3, RTL_R8 (Config3) & ~(1<<5)); + } + + /* Lock Config[01234] and BMCR register writes */ + RTL_W8_F (Cfg9346, Cfg9346_Lock); + udelay (10); + + /* init Rx ring buffer DMA address */ + RTL_W32_F (RxBuf, tp->rx_ring_dma); + + /* init Tx buffer DMA addresses */ + for (i = 0; i < NUM_TX_DESC; i++) + RTL_W32_F (TxAddr0 + (i * 4), tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs)); RTL_W32_F (RxMissed, 0); @@ -1217,6 +1199,10 @@ /* no early-rx interrupts */ RTL_W16 (MultiIntr, RTL_R16 (MultiIntr) & MultiIntrClear); + /* make sure RxTx has started */ + RTL_W8_F (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | + CmdRxEnb | CmdTxEnb); + /* Enable all known interrupts by setting the interrupt mask. */ RTL_W16_F (IntrMask, rtl8139_intr_mask); @@ -1354,6 +1340,7 @@ mii_reg5 = mdio_read (dev, tp->phys[0], 5); +#if 0 if (!tp->duplex_lock && mii_reg5 != 0xffff) { int duplex = (mii_reg5 & 0x0100) || (mii_reg5 & 0x01C0) == 0x0040; @@ -1366,8 +1353,10 @@ tp->phys[0], mii_reg5); RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); + RTL_W8 (Cfg9346, Cfg9346_Lock); } } +#endif rtl8139_tune_twister (dev, tp); @@ -1703,8 +1692,8 @@ } else { eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], - rx_size, 0); - skb_put (skb, rx_size); + rx_size - 4, 0); + skb_put (skb, rx_size - 4); } skb->protocol = eth_type_trans (skb, dev); netif_rx (skb); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/8390.c linux/drivers/net/8390.c --- v2.4.0-test1/linux/drivers/net/8390.c Wed Apr 26 16:34:07 2000 +++ linux/drivers/net/8390.c Mon Jun 19 13:30:57 2000 @@ -1152,17 +1152,13 @@ EXPORT_SYMBOL(ethdev_init); EXPORT_SYMBOL(NS8390_init); -struct module *NS8390_module = NULL; - int init_module(void) { - NS8390_module = &__this_module; return 0; } void cleanup_module(void) { - NS8390_module = NULL; } #endif /* MODULE */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/8390.h linux/drivers/net/8390.h --- v2.4.0-test1/linux/drivers/net/8390.h Wed Aug 18 11:36:45 1999 +++ linux/drivers/net/8390.h Fri Jun 23 21:31:19 2000 @@ -53,24 +53,49 @@ #if defined(LOAD_8390_BY_KMOD) && defined(MODULE) && !defined(NS8390_CORE) /* Function pointers to be mapped onto the 8390 core support */ -static int (*S_ethdev_init)(struct net_device *dev); -static void (*S_NS8390_init)(struct net_device *dev, int startp); -static int (*S_ei_open)(struct net_device *dev); -static int (*S_ei_close)(struct net_device *dev); -static void (*S_ei_interrupt)(int irq, void *dev_id, struct pt_regs *regs); +static int (*S_ethdev_init)(struct net_device *dev) = NULL; +static void (*S_NS8390_init)(struct net_device *dev, int startp) = NULL; +static int (*S_ei_open)(struct net_device *dev) = NULL; +static int (*S_ei_close)(struct net_device *dev) = NULL; +static void (*S_ei_interrupt)(int irq, void *dev_id, struct pt_regs *regs) = NULL; - -#define NS8390_KSYSMS_PRESENT ( \ - get_module_symbol(NULL, "ethdev_init") != 0 && \ - get_module_symbol(NULL, "NS8390_init") != 0 && \ - get_module_symbol(NULL, "ei_open") != 0 && \ - get_module_symbol(NULL, "ei_close") != 0 && \ - get_module_symbol(NULL, "ei_interrupt") != 0) +extern __inline__ void unload_8390_module(void) +{ + if (S_ethdev_init) { + put_module_symbol((unsigned long)S_ethdev_init); + S_ethdev_init = NULL; + } + if (S_NS8390_init) { + put_module_symbol((unsigned long)S_NS8390_init); + S_NS8390_init = NULL; + } + if (S_ei_open) { + put_module_symbol((unsigned long)S_ei_open); + S_ei_open = NULL; + } + if (S_ei_close) { + put_module_symbol((unsigned long)S_ei_close); + S_ei_close = NULL; + } + if (S_ei_interrupt) { + put_module_symbol((unsigned long)S_ei_interrupt); + S_ei_interrupt = NULL; + } +} extern __inline__ int load_8390_module(const char *driver) { + /* Do we actually need to handle this case? */ + if (S_ethdev_init) { + printk(KERN_DEBUG "%s: load_8390_module called when pointers already present\n", driver); + return 0; + } + + /* Attempt to get the first symbol */ + S_ethdev_init = (void *)get_module_symbol(NULL, "ethdev_init"); - if (! NS8390_KSYSMS_PRESENT) { + if (!S_ethdev_init) { + /* It failed. See if we have request_module() */ int (*request_mod)(const char *module_name); if (get_module_symbol("", "request_module") == 0) { @@ -80,52 +105,34 @@ return -ENOSYS; } + /* OK - we have request_module() - try it */ request_mod = (void*)get_module_symbol("", "request_module"); if (request_mod("8390")) { printk("%s: request to load the 8390 module failed.\n", driver); return -ENOSYS; } - /* Check if module really loaded and is valid */ - if (! NS8390_KSYSMS_PRESENT) { - printk("%s: 8390.o not found/invalid or failed to load.\n", driver); - return -ENOSYS; - } - printk(KERN_INFO "%s: auto-loaded 8390 module.\n", driver); + + /* Retry getting ethdev_init */ + S_ethdev_init = (void *)get_module_symbol(NULL, "ethdev_init"); } - /* Map the functions into place */ - S_ethdev_init = (void*)get_module_symbol(0, "ethdev_init"); + /* Get addresses for the other functions */ S_NS8390_init = (void*)get_module_symbol(0, "NS8390_init"); S_ei_open = (void*)get_module_symbol(0, "ei_open"); S_ei_close = (void*)get_module_symbol(0, "ei_close"); S_ei_interrupt = (void*)get_module_symbol(0, "ei_interrupt"); - return 0; -} - -/* - * Since a kmod aware driver won't explicitly show a dependence on the - * exported 8390 functions (due to the mapping above), the 8390 module - * (if present, and not in-kernel) needs to be protected from garbage - * collection. NS8390_module is only defined for a modular 8390 core. - */ - -extern __inline__ void lock_8390_module(void) -{ - struct module **mod = (struct module**)get_module_symbol(0, "NS8390_module"); - - if (mod != NULL && *mod != NULL) - __MOD_INC_USE_COUNT(*mod); + /* Check if module really loaded and is valid */ + if (!S_ethdev_init || !S_NS8390_init || !S_ei_open || !S_ei_close + || !S_ei_interrupt) { + unload_8390_module(); + printk("%s: 8390.o not found/invalid or failed to load.\n", driver); + return -ENOSYS; } -extern __inline__ void unlock_8390_module(void) -{ - struct module **mod = (struct module**)get_module_symbol(0, "NS8390_module"); - - if (mod != NULL && *mod != NULL) - __MOD_DEC_USE_COUNT(*mod); + return 0; } /* @@ -141,8 +148,7 @@ #else /* not a module or kmod support not wanted */ #define load_8390_module(driver) 0 -#define lock_8390_module() do { } while (0) -#define unlock_8390_module() do { } while (0) +#define unload_8390_module() do { } while (0) extern int ethdev_init(struct net_device *dev); extern void NS8390_init(struct net_device *dev, int startp); extern int ei_open(struct net_device *dev); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.4.0-test1/linux/drivers/net/Config.in Tue May 23 15:31:35 2000 +++ linux/drivers/net/Config.in Fri Jun 23 21:06:58 2000 @@ -49,7 +49,7 @@ tristate ' MIPS JAZZ onboard SONIC Ethernet support' CONFIG_MIPS_JAZZ_SONIC fi if [ "$CONFIG_SGI_IP27" = "y" ]; then - bool ' SGI IOC3 Ethernet' CONFIG_SGI_IOC3_ETH + bool ' SGI IOC3 Ethernet' CONFIG_SGI_IOC3_ETH fi if [ "$CONFIG_SUPERH" = "y" -a "$CONFIG_SH_SOLUTION_ENGINE" = "y" ]; then tristate ' National DP83902AV support' CONFIG_STNIC @@ -60,14 +60,14 @@ tristate ' 3c503 "EtherLink II" support' CONFIG_EL2 tristate ' 3c505 "EtherLink Plus" support' CONFIG_ELPLUS if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate ' 3c507 support (EXPERIMENTAL)' CONFIG_EL16 + tristate ' 3c507 "EtherLink 16" support (EXPERIMENTAL)' CONFIG_EL16 fi tristate ' 3c509/3c529 (MCA)/3c579 "EtherLink III" support' CONFIG_EL3 - tristate ' 3c515 ISA Fast EtherLink' CONFIG_3C515 + tristate ' 3c515 ISA "Fast EtherLink"' CONFIG_3C515 if [ "$CONFIG_MCA" = "y" ]; then - tristate ' 3c523 EtherLinkMC support' CONFIG_ELMC + tristate ' 3c523 "EtherLink/MC" support' CONFIG_ELMC if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate ' 3c527 EtherLink/MC 32 support (EXPERIMENTAL)' CONFIG_ELMC_II + tristate ' 3c527 "EtherLink/MC 32" support (EXPERIMENTAL)' CONFIG_ELMC_II fi fi tristate ' 3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX @@ -104,7 +104,7 @@ tristate ' EtherWORKS 3 (DE203, DE204, DE205) support' CONFIG_EWRK3 fi tristate ' EtherExpress 16 support' CONFIG_EEXPRESS - tristate ' EtherExpressPro support' CONFIG_EEXPRESS_PRO + tristate ' EtherExpressPro support/EtherExpress 10 (i82595) support' CONFIG_EEXPRESS_PRO if [ "$CONFIG_OBSOLETE" = "y" ]; then tristate ' FMV-181/182/183/184 support' CONFIG_FMV18X fi @@ -121,6 +121,7 @@ if [ "$CONFIG_MCA" = "y" ]; then tristate ' SKnet MCA support' CONFIG_SKMC tristate ' NE/2 (ne2000 MCA version) support' CONFIG_NE2_MCA + tristate ' IBM LAN Adapter/A support' CONFIG_IBMLANA fi bool ' EISA, VLB, PCI and on board controllers' CONFIG_NET_PCI if [ "$CONFIG_NET_PCI" = "y" ]; then @@ -182,20 +183,21 @@ mainmenu_option next_comment comment 'Ethernet (1000 Mbit)' - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - # tristate 'Packet Engines Hamachi GNIC-II support (EXPERIMENTAL)' CONFIG_HAMACHI - tristate 'Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN - fi - tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC - if [ "$CONFIG_ACENIC" != "n" ]; then - bool ' Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I - fi - tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + # tristate 'Packet Engines Hamachi GNIC-II support (EXPERIMENTAL)' CONFIG_HAMACHI + tristate 'Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN +fi +tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC +if [ "$CONFIG_ACENIC" != "n" ]; then + bool ' Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I +fi +tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN + endmenu bool 'FDDI driver support' CONFIG_FDDI if [ "$CONFIG_FDDI" = "y" ]; then - dep_tristate ' Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX $CONFIG_FDDI + tristate ' Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX tristate ' SysKonnect FDDI PCI support' CONFIG_SKFP fi @@ -223,7 +225,7 @@ dep_tristate ' PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP dep_tristate ' PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP $CONFIG_PPP if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate ' PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP + dep_tristate ' PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP fi fi diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.4.0-test1/linux/drivers/net/Makefile Tue May 23 15:31:35 2000 +++ linux/drivers/net/Makefile Mon Jun 19 13:30:57 2000 @@ -83,16 +83,8 @@ endif endif -ifeq ($(CONFIG_ISDN),y) - ifeq ($(CONFIG_ISDN_PPP),y) - obj-y += slhc.o ppp_deflate.o - endif -else - ifeq ($(CONFIG_ISDN),m) - ifeq ($(CONFIG_ISDN_PPP),y) - obj-m += slhc.o ppp_deflate.o - endif - endif +ifeq ($(CONFIG_ISDN_PPP),y) + obj-$(CONFIG_ISDN) += slhc.o endif ifeq ($(CONFIG_ARCNET),y) @@ -240,6 +232,7 @@ obj-$(CONFIG_EL16) += 3c507.o obj-$(CONFIG_ELMC) += 3c523.o obj-$(CONFIG_SKMC) += sk_mca.o +obj-$(CONFIG_IBMLANA) += ibmlana.o obj-$(CONFIG_ELMC_II) += 3c527.o obj-$(CONFIG_EL3) += 3c509.o obj-$(CONFIG_3C515) += 3c515.o diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v2.4.0-test1/linux/drivers/net/Space.c Tue May 23 15:31:35 2000 +++ linux/drivers/net/Space.c Mon Jun 19 13:30:57 2000 @@ -86,8 +86,6 @@ extern int sgiseeq_probe(struct net_device *); extern int atarilance_probe(struct net_device *); extern int sun3lance_probe(struct net_device *); -extern int a2065_probe(struct net_device *); -extern int ariadne_probe(struct net_device *); extern int ariadne2_probe(struct net_device *); extern int hydra_probe(struct net_device *); extern int apne_probe(struct net_device *); @@ -330,12 +328,6 @@ #endif #ifdef CONFIG_SUN3LANCE /* sun3 onboard Lance chip */ {sun3lance_probe, 0}, -#endif -#ifdef CONFIG_A2065 /* Commodore/Ameristar A2065 Ethernet Board */ - {a2065_probe, 0}, -#endif -#ifdef CONFIG_ARIADNE /* Village Tronic Ariadne Ethernet Board */ - {ariadne_probe, 0}, #endif #ifdef CONFIG_ARIADNE2 /* Village Tronic Ariadne II Ethernet Board */ {ariadne2_probe, 0}, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/a2065.c linux/drivers/net/a2065.c --- v2.4.0-test1/linux/drivers/net/a2065.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/a2065.c Mon Jun 19 13:30:57 2000 @@ -132,8 +132,14 @@ int burst_sizes; /* ledma SBus burst sizes */ #endif struct timer_list multicast_timer; + struct net_device *dev; /* Backpointer */ + struct lance_private *next_module; }; +#ifdef MODULE +static struct lance_private *root_a2065_dev = NULL; +#endif + #define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\ lp->tx_old+lp->tx_ring_mod_mask-lp->tx_new:\ lp->tx_old - lp->tx_new-1) @@ -714,18 +720,14 @@ static int __init a2065_probe(void) { - struct net_device *dev = NULL; - static int called = 0; struct zorro_dev *z = NULL; - - if (called) - return -ENODEV; - called++; + struct net_device *dev; + struct lance_private *priv; + int res = -ENODEV; while ((z = zorro_find_device(ZORRO_WILDCARD, z))) { - unsigned long board, base_addr, ram_start; + unsigned long board, base_addr, mem_start; int is_cbm; - struct lance_private *priv; if (z->id == ZORRO_PROD_CBM_A2065_1 || z->id == ZORRO_PROD_CBM_A2065_2) @@ -737,12 +739,12 @@ board = z->resource.start; base_addr = board+A2065_LANCE; - ram_start = board+A2065_RAM; + mem_start = board+A2065_RAM; if (!request_mem_region(base_addr, sizeof(struct lance_regs), "Am7990")) continue; - if (!request_mem_region(ram_start, A2065_RAM_SIZE, "RAM")) { + if (!request_mem_region(mem_start, A2065_RAM_SIZE, "RAM")) { release_mem_region(base_addr, sizeof(struct lance_regs)); continue; @@ -754,18 +756,18 @@ if (dev == NULL) { release_mem_region(base_addr, sizeof(struct lance_regs)); - release_mem_region(ram_start, A2065_RAM_SIZE); + release_mem_region(mem_start, A2065_RAM_SIZE); return -ENOMEM; } priv = (struct lance_private *)dev->priv; memset(priv, 0, sizeof(struct lance_private)); + priv->dev = dev; + dev->dev_addr[0] = 0x00; if (is_cbm) { /* Commodore */ - dev->dev_addr[0] = 0x00; dev->dev_addr[1] = 0x80; dev->dev_addr[2] = 0x10; } else { /* Ameristar */ - dev->dev_addr[0] = 0x00; dev->dev_addr[1] = 0x00; dev->dev_addr[2] = 0x9f; } @@ -778,7 +780,7 @@ dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); dev->base_addr = ZTWO_VADDR(base_addr); - dev->mem_start = ZTWO_VADDR(ram_start); + dev->mem_start = ZTWO_VADDR(mem_start); dev->mem_end = dev->mem_start+A2065_RAM_SIZE; priv->ll = (volatile struct lance_regs *)dev->base_addr; @@ -801,28 +803,38 @@ dev->set_multicast_list = &lance_set_multicast; dev->dma = 0; +#ifdef MODULE + priv->next_module = root_a2065_dev; + root_a2065_dev = priv; +#endif ether_setup(dev); init_timer(&priv->multicast_timer); priv->multicast_timer.data = (unsigned long) dev; priv->multicast_timer.function = (void (*)(unsigned long)) &lance_set_multicast; - return(0); + res = 0; } - return(-ENODEV); + return res; } static void __exit a2065_cleanup(void) { #ifdef MODULE - struct lance_private *priv = (struct lance_private *)a2065_dev.priv; + struct lance_private *next; + struct net_device *dev; - unregister_netdev(&a2065_dev); - release_mem_region(ZTWO_PADDR(a2065_dev.base_addr), - sizeof(struct lance_regs)); - release_mem_region(ZTWO_PADDR(a2065_dev.mem_start), A2065_RAM_SIZE); - kfree(priv); + while (root_a2065_dev) { + next = root_a2065_dev->next_module; + dev = root_a2065_dev->dev; + unregister_netdev(dev); + release_mem_region(ZTWO_PADDR(dev->base_addr), + sizeof(struct lance_regs)); + release_mem_region(ZTWO_PADDR(dev->mem_start), A2065_RAM_SIZE); + kfree(dev); + root_a2065_dev = next; + } #endif } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/ac3200.c linux/drivers/net/ac3200.c --- v2.4.0-test1/linux/drivers/net/ac3200.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/ac3200.c Mon Jun 19 13:30:57 2000 @@ -102,10 +102,10 @@ if (ioaddr > 0x1ff) /* Check a single specified location. */ return ac_probe1(ioaddr, dev); else if (ioaddr > 0) /* Don't probe at all. */ - return ENXIO; + return -ENXIO; if ( ! EISA_bus) - return ENXIO; + return -ENXIO; for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { if (check_region(ioaddr, AC_IO_EXTENT)) @@ -114,7 +114,7 @@ return 0; } - return ENODEV; + return -ENODEV; } static int __init ac_probe1(int ioaddr, struct net_device *dev) @@ -151,7 +151,7 @@ || inb(ioaddr + AC_SA_PROM + 1) != AC_ADDR1 || inb(ioaddr + AC_SA_PROM + 2) != AC_ADDR2 ) { printk(", not found (invalid prefix).\n"); - return ENODEV; + return -ENODEV; } #endif @@ -174,7 +174,7 @@ printk (" nothing! Unable to get IRQ %d.\n", dev->irq); kfree(dev->priv); dev->priv = NULL; - return EAGAIN; + return -EAGAIN; } printk(" IRQ %d, %s port\n", dev->irq, port_name[dev->if_port]); @@ -213,7 +213,7 @@ free_irq(dev->irq, dev); kfree(dev->priv); dev->priv = NULL; - return EINVAL; + return -EINVAL; } dev->mem_start = (unsigned long)ioremap(dev->mem_start, AC_STOP_PG*0x100); if (dev->mem_start == 0) { @@ -223,7 +223,7 @@ free_irq(dev->irq, dev); kfree(dev->priv); dev->priv = NULL; - return EAGAIN; + return -EAGAIN; } ei_status.reg0 = 1; /* Use as remap flag */ printk("ac3200.c: remapped %dkB card memory to virtual address %#lx\n", @@ -365,6 +365,9 @@ { int this_dev, found = 0; + if (load_8390_module("ac3200.c")) + return -ENOSYS; + for (this_dev = 0; this_dev < MAX_AC32_CARDS; this_dev++) { struct net_device *dev = &dev_ac32[this_dev]; dev->irq = irq[this_dev]; @@ -376,14 +379,13 @@ if (register_netdev(dev) != 0) { printk(KERN_WARNING "ac3200.c: No ac3200 card found (i/o = 0x%x).\n", io[this_dev]); if (found != 0) { /* Got at least one. */ - lock_8390_module(); return 0; } + unload_8390_module(); return -ENXIO; } found++; } - lock_8390_module(); return 0; } @@ -405,7 +407,7 @@ kfree(priv); } } - unlock_8390_module(); + unload_8390_module(); } #endif /* MODULE */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/aironet4500_card.c linux/drivers/net/aironet4500_card.c --- v2.4.0-test1/linux/drivers/net/aironet4500_card.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/aironet4500_card.c Mon Jun 19 13:30:57 2000 @@ -98,6 +98,8 @@ pdev = pci_find_slot(awc_pci_bus, awc_pci_dev); if (!pdev) continue; + if (pci_enable_device(pdev)) + continue; vendor = pdev->vendor; device = pdev->device; pci_irq_line = pdev->irq; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/am79c961a.c linux/drivers/net/am79c961a.c --- v2.4.0-test1/linux/drivers/net/am79c961a.c Tue May 23 15:31:35 2000 +++ linux/drivers/net/am79c961a.c Mon Jun 19 13:30:57 2000 @@ -39,8 +39,6 @@ #include "am79c961a.h" static void am79c961_interrupt (int irq, void *dev_id, struct pt_regs *regs); -static void am79c961_rx (struct net_device *dev, struct dev_priv *priv); -static void am79c961_tx (struct net_device *dev, struct dev_priv *priv); static unsigned int net_debug = NET_DEBUG; @@ -57,11 +55,21 @@ " : : "r" (val), "r" (reg), "r" (0xf0000464)); } +static inline unsigned short +read_rreg (unsigned int base_addr, unsigned int reg) +{ + unsigned short v; + __asm__("str%?h %1, [%2] @ NET_RAP + ldr%?h %0, [%2, #-4] @ NET_RDP + " : "=r" (v): "r" (reg), "r" (0xf0000464)); + return v; +} + static inline void write_ireg (unsigned long base, unsigned int reg, unsigned short val) { __asm__("str%?h %1, [%2] @ NET_RAP - str%?h %0, [%2, #8] @ NET_RDP + str%?h %0, [%2, #8] @ NET_IDP " : : "r" (val), "r" (reg), "r" (0xf0000464)); } @@ -70,7 +78,7 @@ "r" ((val) & 0xffff), "r" (0xe0000000 + ((off) << 1))); static inline void -am_writebuffer(struct net_device *dev, unsigned int offset, unsigned char *buf, unsigned int length) +am_writebuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length) { offset = 0xe0000000 + (offset << 1); length = (length + 1) & ~1; @@ -102,18 +110,11 @@ } } -static inline unsigned short -read_rreg (unsigned int base_addr, unsigned int reg) -{ - unsigned short v; - __asm__("str%?h %1, [%2] @ NET_RAP - ldr%?h %0, [%2, #-4] @ NET_IDP - " : "=r" (v): "r" (reg), "r" (0xf0000464)); - return v; -} - -static inline unsigned short -am_readword (struct net_device *dev, unsigned long off) +/* + * This reads a 16-bit quantity in little-endian + * mode from the am79c961 buffer. + */ +static inline unsigned short am_readword(struct net_device *dev, u_int off) { unsigned long address = 0xe0000000 + (off << 1); unsigned short val; @@ -123,7 +124,7 @@ } static inline void -am_readbuffer(struct net_device *dev, unsigned int offset, unsigned char *buf, unsigned int length) +am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length) { offset = 0xe0000000 + (offset << 1); length = (length + 1) & ~1; @@ -198,18 +199,35 @@ am79c961_init_for_open(struct net_device *dev) { struct dev_priv *priv = (struct dev_priv *)dev->priv; - unsigned long hdr_addr, first_free_addr; unsigned long flags; unsigned char *p; + u_int hdr_addr, first_free_addr; int i; save_flags_cli (flags); - - write_ireg (dev->base_addr, 2, 0x4000); /* autoselect media */ write_rreg (dev->base_addr, CSR0, CSR0_BABL|CSR0_CERR|CSR0_MISS|CSR0_MERR|CSR0_TINT|CSR0_RINT|CSR0_STOP); - restore_flags (flags); + write_ireg (dev->base_addr, 5, 0x00a0); /* Receive address LED */ + write_ireg (dev->base_addr, 6, 0x0081); /* Collision LED */ + write_ireg (dev->base_addr, 7, 0x0090); /* XMIT LED */ + write_ireg (dev->base_addr, 2, 0x0000); /* MODE register selects media */ + + for (i = LADRL; i <= LADRH; i++) + write_rreg (dev->base_addr, i, 0); + + for (i = PADRL, p = dev->dev_addr; i <= PADRH; i++, p += 2) + write_rreg (dev->base_addr, i, p[0] | (p[1] << 8)); + + i = MODE_PORT_10BT; + if (dev->flags & IFF_PROMISC) + i |= MODE_PROMISC; + + write_rreg (dev->base_addr, MODE, i); + write_rreg (dev->base_addr, POLLINT, 0); + write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS); + write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS); + first_free_addr = RX_BUFFERS * 8 + TX_BUFFERS * 8 + 16; hdr_addr = 0; @@ -232,31 +250,17 @@ for (i = 0; i < TX_BUFFERS; i++) { priv->txbuffer[i] = first_free_addr; am_writeword (dev, hdr_addr, first_free_addr); - am_writeword (dev, hdr_addr + 2, 0); - am_writeword (dev, hdr_addr + 4, 0); + am_writeword (dev, hdr_addr + 2, TMD_STP|TMD_ENP); + am_writeword (dev, hdr_addr + 4, 0xf000); am_writeword (dev, hdr_addr + 6, 0); first_free_addr += 1600; hdr_addr += 8; } - for (i = LADRL; i <= LADRH; i++) - write_rreg (dev->base_addr, i, 0); - - for (i = PADRL, p = dev->dev_addr; i <= PADRH; i++, p += 2) - write_rreg (dev->base_addr, i, p[0] | (p[1] << 8)); - - i = MODE_PORT0; - if (dev->flags & IFF_PROMISC) - i |= MODE_PROMISC; - - write_rreg (dev->base_addr, MODE, i); write_rreg (dev->base_addr, BASERXL, priv->rxhdr); write_rreg (dev->base_addr, BASERXH, 0); write_rreg (dev->base_addr, BASETXL, priv->txhdr); write_rreg (dev->base_addr, BASERXH, 0); - write_rreg (dev->base_addr, POLLINT, 0); - write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS); - write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS); write_rreg (dev->base_addr, CSR0, CSR0_STOP); write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM|CSR3_DXSUFLO); write_rreg (dev->base_addr, CSR0, CSR0_IENA|CSR0_STRT); @@ -303,7 +307,6 @@ save_flags_cli (flags); - write_ireg (dev->base_addr, 2, 0x4000); /* autoselect media */ write_rreg (dev->base_addr, CSR0, CSR0_STOP); write_rreg (dev->base_addr, CSR3, CSR3_MASKALL); @@ -369,7 +372,7 @@ unsigned short multi_hash[4], mode; int i, stopped; - mode = MODE_PORT0; + mode = MODE_PORT_10BT; if (dev->flags & IFF_PROMISC) { mode |= MODE_PROMISC; @@ -466,54 +469,32 @@ dev->trans_start = jiffies; restore_flags (flags); - if (!(am_readword (dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN)) + /* + * If the next packet is owned by the ethernet device, + * then the tx ring is full and we can't add another + * packet. + */ + if (am_readword(dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN) { + printk(KERN_DEBUG"tx ring full, stopping queue\n"); netif_stop_queue(dev); + } dev_kfree_skb(skb); return 0; } -static void -am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct net_device *dev = (struct net_device *)dev_id; - struct dev_priv *priv = (struct dev_priv *)dev->priv; - unsigned int status; - -#if NET_DEBUG > 1 - if(net_debug & DEBUG_INT) - printk(KERN_DEBUG "am79c961irq: %d ", irq); -#endif - - status = read_rreg (dev->base_addr, CSR0); - write_rreg (dev->base_addr, CSR0, status & (CSR0_TINT|CSR0_RINT|CSR0_MISS|CSR0_IENA)); - - if (status & CSR0_RINT) /* Got a packet(s). */ - am79c961_rx (dev, priv); - if (status & CSR0_TINT) /* Packets transmitted */ - am79c961_tx (dev, priv); - if (status & CSR0_MISS) - priv->stats.rx_dropped ++; - -#if NET_DEBUG > 1 - if(net_debug & DEBUG_INT) - printk("done\n"); -#endif -} - /* * If we have a good packet(s), get it/them out of the buffers. */ static void am79c961_rx(struct net_device *dev, struct dev_priv *priv) { - unsigned long hdraddr; - unsigned long pktaddr; - do { - unsigned long status; struct sk_buff *skb; + u_int hdraddr; + u_int pktaddr; + u_int status; int len; hdraddr = priv->rxhdr + (priv->rxtail << 3); @@ -540,20 +521,19 @@ continue; } - len = am_readword (dev, hdraddr + 6); - skb = dev_alloc_skb (len + 2); + len = am_readword(dev, hdraddr + 6); + skb = dev_alloc_skb(len + 2); if (skb) { - unsigned char *buf; - skb->dev = dev; - skb_reserve (skb, 2); - buf = skb_put (skb, len); + skb_reserve(skb, 2); - am_readbuffer (dev, pktaddr, buf, len); - am_writeword (dev, hdraddr + 2, RMD_OWN); + am_readbuffer(dev, pktaddr, skb_put(skb, len), len); + am_writeword(dev, hdraddr + 2, RMD_OWN); skb->protocol = eth_type_trans(skb, dev); - netif_rx (skb); + netif_rx(skb); + dev->last_rx = jiffies; + priv->stats.rx_bytes += len; priv->stats.rx_packets ++; } else { am_writeword (dev, hdraddr + 2, RMD_OWN); @@ -571,9 +551,11 @@ am79c961_tx(struct net_device *dev, struct dev_priv *priv) { do { - unsigned long hdraddr; - unsigned long status; + u_int hdraddr; + u_int status; +int bufnum; +bufnum = priv->txtail; hdraddr = priv->txhdr + (priv->txtail << 3); status = am_readword (dev, hdraddr + 2); if (status & TMD_OWN) @@ -584,11 +566,15 @@ priv->txtail = 0; if (status & TMD_ERR) { - unsigned long status2; + u_int status2; priv->stats.tx_errors ++; status2 = am_readword (dev, hdraddr + 6); + + /* + * Clear the error byte + */ am_writeword (dev, hdraddr + 6, 0); if (status2 & TST_RTRY) @@ -607,6 +593,24 @@ netif_wake_queue(dev); } +static void +am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct dev_priv *priv = (struct dev_priv *)dev->priv; + u_int status; + + status = read_rreg(dev->base_addr, CSR0); + write_rreg(dev->base_addr, CSR0, status & (CSR0_TINT|CSR0_RINT|CSR0_MISS|CSR0_IENA)); + + if (status & CSR0_RINT) + am79c961_rx(dev, priv); + if (status & CSR0_TINT) + am79c961_tx(dev, priv); + if (status & CSR0_MISS) + priv->stats.rx_dropped ++; +} + static int am79c961_hw_init(struct net_device *dev) { @@ -617,7 +621,6 @@ save_flags_cli (flags); - write_ireg (dev->base_addr, 2, 0x4000); /* autoselect media */ write_rreg (dev->base_addr, CSR0, CSR0_STOP); write_rreg (dev->base_addr, CSR3, CSR3_MASKALL); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/apne.c linux/drivers/net/apne.c --- v2.4.0-test1/linux/drivers/net/apne.c Wed Aug 18 11:36:41 1999 +++ linux/drivers/net/apne.c Mon Jun 19 13:30:57 2000 @@ -178,9 +178,6 @@ 8, 9+GAYLE_ODD, 0xa, 0xb+GAYLE_ODD, 0xc, 0xd+GAYLE_ODD, 0xe, 0xf+GAYLE_ODD }; - if (load_8390_module("apne.c")) - return -ENOSYS; - /* We should have a "dev" from Space.c or the static module table. */ if (dev == NULL) { printk(KERN_ERR "apne.c: Passed a NULL device.\n"); @@ -271,7 +268,7 @@ stop_page = (wordlength == 2) ? 0x40 : 0x20; } else { printk(" not found.\n"); - return ENXIO; + return -ENXIO; } @@ -572,12 +569,16 @@ int init_module(void) { int err; + + if (load_8390_module("apne.c")) + return -ENOSYS; + if ((err = register_netdev(&apne_dev))) { if (err == -EIO) printk("No PCMCIA NEx000 ethernet card found.\n"); + unload_8390_module(); return (err); } - lock_8390_module(); return (0); } @@ -591,7 +592,7 @@ pcmcia_reset(); - unlock_8390_module(); + unload_8390_module(); apne_owned = 0; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/appletalk/ltpc.c linux/drivers/net/appletalk/ltpc.c --- v2.4.0-test1/linux/drivers/net/appletalk/ltpc.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/appletalk/ltpc.c Mon Jun 19 13:30:57 2000 @@ -224,6 +224,7 @@ #include #include #include +#include #include #include diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/ariadne.c linux/drivers/net/ariadne.c --- v2.4.0-test1/linux/drivers/net/ariadne.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/net/ariadne.c Mon Jun 19 13:30:57 2000 @@ -104,7 +104,8 @@ int dirty_tx; /* The ring entries to be free()ed. */ struct net_device_stats stats; char tx_full; - unsigned long lock; + struct net_device *dev; /* Backpointer */ + struct ariadne_private *next_module; }; @@ -119,11 +120,16 @@ u_short rx_buff[RX_RING_SIZE][PKT_BUF_SIZE/sizeof(u_short)]; }; +#ifdef MODULE +static struct ariadne_private *root_ariadne_dev = NULL; +#endif static int ariadne_open(struct net_device *dev); static void ariadne_init_ring(struct net_device *dev); static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev); +static void ariadne_tx_timeout(struct net_device *dev); static int ariadne_rx(struct net_device *dev); +static void ariadne_reset(struct net_device *dev); static void ariadne_interrupt(int irq, void *data, struct pt_regs *fp); static int ariadne_close(struct net_device *dev); static struct net_device_stats *ariadne_get_stats(struct net_device *dev); @@ -143,19 +149,22 @@ } -int __init ariadne_probe(struct net_device *dev) +static int __init ariadne_probe(void) { struct zorro_dev *z = NULL; + struct net_device *dev; + struct ariadne_private *priv; + int res = -ENODEV; while ((z = zorro_find_device(ZORRO_PROD_VILLAGE_TRONIC_ARIADNE, z))) { unsigned long board = z->resource.start; unsigned long base_addr = board+ARIADNE_LANCE; - unsigned long ram_start = board+ARIADNE_RAM; + unsigned long mem_start = board+ARIADNE_RAM; if (!request_mem_region(base_addr, sizeof(struct Am79C960), "Am79C960")) continue; - if (!request_mem_region(ram_start, ARIADNE_RAM_SIZE, "RAM")) { + if (!request_mem_region(mem_start, ARIADNE_RAM_SIZE, "RAM")) { release_mem_region(base_addr, sizeof(struct Am79C960)); continue; } @@ -165,35 +174,43 @@ if (dev == NULL) { release_mem_region(base_addr, sizeof(struct Am79C960)); - release_mem_region(ram_start, ARIADNE_RAM_SIZE); + release_mem_region(mem_start, ARIADNE_RAM_SIZE); return -ENOMEM; } - memset(dev->priv, 0, sizeof(struct ariadne_private)); + priv = (struct ariadne_private *)dev->priv; + memset(priv, 0, sizeof(struct ariadne_private)); + priv->dev = dev; dev->dev_addr[0] = 0x00; dev->dev_addr[1] = 0x60; dev->dev_addr[2] = 0x30; - dev->dev_addr[3] = (z->rom.er_SerialNumber>>16)&0xff; - dev->dev_addr[4] = (z->rom.er_SerialNumber>>8)&0xff; - dev->dev_addr[5] = z->rom.er_SerialNumber&0xff; + dev->dev_addr[3] = (z->rom.er_SerialNumber>>16) & 0xff; + dev->dev_addr[4] = (z->rom.er_SerialNumber>>8) & 0xff; + dev->dev_addr[5] = z->rom.er_SerialNumber & 0xff; printk("%s: Ariadne at 0x%08lx, Ethernet Address " "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, board, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); dev->base_addr = ZTWO_VADDR(base_addr); - dev->mem_start = ZTWO_VADDR(ram_start); + dev->mem_start = ZTWO_VADDR(mem_start); dev->mem_end = dev->mem_start+ARIADNE_RAM_SIZE; dev->open = &ariadne_open; dev->stop = &ariadne_close; dev->hard_start_xmit = &ariadne_start_xmit; + dev->tx_timeout = &ariadne_tx_timeout; + dev->watchdog_timeo = 5*HZ; dev->get_stats = &ariadne_get_stats; dev->set_multicast_list = &set_multicast_list; - return 0; +#ifdef MODULE + priv->next_module = root_ariadne_dev; + root_ariadne_dev = priv; +#endif + res = 0; } - return -ENODEV; + return res; } @@ -217,12 +234,12 @@ version |= swapw(lance->RDP)<<16; if ((version & 0x00000fff) != 0x00000003) { printk("ariadne_open: Couldn't find AMD Ethernet Chip\n"); - return(-EAGAIN); + return -EAGAIN; } if ((version & 0x0ffff000) != 0x00003000) { printk("ariadne_open: Couldn't find Am79C960 (Wrong part number = %ld)\n", (version & 0x0ffff000)>>12); - return(-EAGAIN); + return -EAGAIN; } #if 0 printk("ariadne_open: Am79C960 (PCnet-ISA) Revision %ld\n", @@ -289,20 +306,18 @@ lance->RAP = ISACSR7; /* LED3 Status */ lance->IDP = PSE|RCVE; - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + netif_start_queue(dev); if (request_irq(IRQ_AMIGA_PORTS, ariadne_interrupt, SA_SHIRQ, "Ariadne Ethernet", dev)) - return(-EAGAIN); + return -EAGAIN; lance->RAP = CSR0; /* PCnet-ISA Controller Status */ lance->RDP = INEA|STRT; MOD_INC_USE_COUNT; - return(0); + return 0; } @@ -312,7 +327,9 @@ volatile struct lancedata *lancedata = (struct lancedata *)dev->mem_start; int i; - priv->lock = 0, priv->tx_full = 0; + netif_stop_queue(dev); + + priv->tx_full = 0; priv->cur_rx = priv->cur_tx = 0; priv->dirty_tx = 0; @@ -355,8 +372,7 @@ struct ariadne_private *priv = (struct ariadne_private *)dev->priv; volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; - dev->start = 0; - dev->tbusy = 1; + netif_stop_queue(dev); lance->RAP = CSR112; /* Missed Frame Count */ priv->stats.rx_missed_errors = swapw(lance->RDP); @@ -376,7 +392,19 @@ MOD_DEC_USE_COUNT; - return(0); + return 0; +} + + +static inline void ariadne_reset(struct net_device *dev) +{ + volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; + + lance->RAP = CSR0; /* PCnet-ISA Controller Status */ + lance->RDP = STOP; + ariadne_init_ring(dev); + lance->RDP = INEA|STRT; + netif_start_queue(dev); } @@ -397,11 +425,6 @@ if (!(lance->RDP & INTR)) /* Check if any interrupt has been */ return; /* generated by the board. */ - if (dev->interrupt) - printk("%s: Re-entering the interrupt handler.\n", dev->name); - - dev->interrupt = 1; - priv = (struct ariadne_private *)dev->priv; boguscnt = 10; @@ -500,12 +523,11 @@ } #endif - if (priv->tx_full && dev->tbusy && + if (priv->tx_full && netif_queue_stopped(dev) && dirty_tx > priv->cur_tx - TX_RING_SIZE + 2) { - /* The ring is no longer full, clear tbusy. */ + /* The ring is no longer full. */ priv->tx_full = 0; - dev->tbusy = 0; - mark_bh(NET_BH); + netif_wake_queue(dev); } priv->dirty_tx = dirty_tx; @@ -533,12 +555,21 @@ printk("%s: exiting interrupt, csr%d=%#4.4x.\n", dev->name, lance->RAP, lance->RDP); #endif - - dev->interrupt = 0; return; } +static void ariadne_tx_timeout(struct net_device *dev) +{ + volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; + + printk(KERN_ERR "%s: transmit timed out, status %4.4x, resetting.\n", + dev->name, lance->RDP); + ariadne_reset(dev); + netif_wake_queue(dev); +} + + static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ariadne_private *priv = (struct ariadne_private *)dev->priv; @@ -546,45 +577,6 @@ int entry; unsigned long flags; - /* Transmitter timeout, serious problems. */ - if (dev->tbusy) { - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 20) - return(1); - lance->RAP = CSR0; /* PCnet-ISA Controller Status */ - printk("%s: transmit timed out, status %4.4x, resetting.\n", dev->name, - lance->RDP); - lance->RDP = STOP; - priv->stats.tx_errors++; -#ifndef final_version - { - int i; - printk(" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.", - priv->dirty_tx, priv->cur_tx, priv->tx_full ? " (full)" : "", - priv->cur_rx); - for (i = 0 ; i < RX_RING_SIZE; i++) - printk("%s %08x %04x %04x", i & 0x3 ? "" : "\n ", - (swapw((priv->rx_ring[i]->RMD1))<<16) | - swapw(priv->rx_ring[i]->RMD0), - swapw(-priv->rx_ring[i]->RMD2), - swapw(priv->rx_ring[i]->RMD3)); - for (i = 0 ; i < TX_RING_SIZE; i++) - printk("%s %08x %04x %04x", i & 0x3 ? "" : "\n ", - (swapw((priv->tx_ring[i]->TMD1))<<16) | - swapw(priv->tx_ring[i]->TMD0), - swapw(-priv->tx_ring[i]->TMD2), priv->tx_ring[i]->TMD3); - printk("\n"); - } -#endif - ariadne_init_ring(dev); - lance->RDP = INEA|STRT; - - dev->tbusy = 0; - dev->trans_start = jiffies; - - return(0); - } - #if 0 if (ariadne_debug > 3) { lance->RAP = CSR0; /* PCnet-ISA Controller Status */ @@ -594,20 +586,6 @@ } #endif - /* Block a timer-based transmit from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - printk("%s: Transmitter access conflict.\n", dev->name); - return(1); - } - - if (test_and_set_bit(0, (void*)&priv->lock) != 0) { - if (ariadne_debug > 0) - printk("%s: tx queue lock!.\n", dev->name); - /* don't clear dev->tbusy flag. */ - return(1); - } - /* Fill in a Tx ring entry */ #if 0 @@ -638,7 +616,8 @@ priv->tx_ring[entry]->TMD2 = swapw((u_short)-skb->len); priv->tx_ring[entry]->TMD3 = 0x0000; - memcpyw(priv->tx_buff[entry], (u_short *)skb->data, skb->len); + memcpyw(priv->tx_buff[entry], (u_short *)skb->data, + skb->len <= ETH_ZLEN ? ETH_ZLEN : skb->len); #if 0 { @@ -681,14 +660,13 @@ dev->trans_start = jiffies; - priv->lock = 0; - if (lowb(priv->tx_ring[(entry+1) % TX_RING_SIZE]->TMD1) == 0) - dev->tbusy = 0; - else + if (lowb(priv->tx_ring[(entry+1) % TX_RING_SIZE]->TMD1) != 0) { + netif_stop_queue(dev); priv->tx_full = 1; + } restore_flags(flags); - return(0); + return 0; } @@ -776,7 +754,7 @@ /* We should check that at least two ring entries are free. If not, we should free one and mark stats->rx_dropped++. */ - return(0); + return 0; } @@ -795,7 +773,7 @@ lance->RAP = saved_addr; restore_flags(flags); - return(&priv->stats); + return &priv->stats; } @@ -809,6 +787,11 @@ { volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; + if (!netif_running(dev)) + return; + + netif_stop_queue(dev); + /* We take the simple way out and always enable promiscuous mode. */ lance->RAP = CSR0; /* PCnet-ISA Controller Status */ lance->RDP = STOP; /* Temporarily stop the lance. */ @@ -836,41 +819,28 @@ lance->RAP = CSR0; /* PCnet-ISA Controller Status */ lance->RDP = INEA|STRT|IDON; /* Resume normal operation. */ -} + netif_wake_queue(dev); +} -#ifdef MODULE -static char devicename[9] = { 0, }; - -static struct net_device ariadne_dev = -{ - devicename, /* filled in by register_netdev() */ - 0, 0, 0, 0, /* memory */ - 0, 0, /* base, irq */ - 0, 0, 0, NULL, ariadne_probe, -}; -int init_module(void) +static void __exit ariadne_cleanup(void) { - int err; +#ifdef MODULE + struct ariadne_private *next; + struct net_device *dev; - if ((err = register_netdev(&ariadne_dev))) { - if (err == -EIO) - printk("No Ariadne board found. Module not loaded.\n"); - return(err); + while (root_ariadne_dev) { + next = root_ariadne_dev->next_module; + dev = root_ariadne_dev->dev; + unregister_netdev(dev); + release_mem_region(ZTWO_PADDR(dev->base_addr), sizeof(struct Am79C960)); + release_mem_region(ZTWO_PADDR(dev->mem_start), ARIADNE_RAM_SIZE); + kfree(dev); + root_ariadne_dev = next; } - return(0); -} - -void cleanup_module(void) -{ - struct ariadne_private *priv = (struct ariadne_private *)ariadne_dev.priv; - - unregister_netdev(&ariadne_dev); - release_mem_region(ZTWO_PADDR(ariadne_dev.base_addr), - sizeof(struct Am79C960)); - release_mem_region(ZTWO_PADDR(ariadne_dev.mem_start), ARIADNE_RAM_SIZE); - kfree(priv); +#endif } -#endif /* MODULE */ +module_init(ariadne_probe); +module_exit(ariadne_cleanup); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/ariadne2.c linux/drivers/net/ariadne2.c --- v2.4.0-test1/linux/drivers/net/ariadne2.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/net/ariadne2.c Mon Jun 19 13:30:57 2000 @@ -113,9 +113,6 @@ }; unsigned long ioaddr = board+ARIADNE2_BASE*2; - if (load_8390_module("ariadne2.c")) - return -ENOSYS; - /* We should have a "dev" from Space.c or the static module table. */ if (dev == NULL) { printk(KERN_ERR "ariadne2.c: Passed a NULL device.\n"); @@ -273,8 +270,8 @@ /* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) { printk("%s: DMAing conflict in ne_get_8390_hdr " - "[DMAstat:%d][irqlock:%d][intr:%ld].\n", dev->name, ei_status.dmaing, - ei_status.irqlock, dev->interrupt); + "[DMAstat:%d][irqlock:%d].\n", dev->name, ei_status.dmaing, + ei_status.irqlock); return; } @@ -314,9 +311,8 @@ /* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) { printk("%s: DMAing conflict in ne_block_input " - "[DMAstat:%d][irqlock:%d][intr:%ld].\n", - dev->name, ei_status.dmaing, ei_status.irqlock, - dev->interrupt); + "[DMAstat:%d][irqlock:%d].\n", + dev->name, ei_status.dmaing, ei_status.irqlock); return; } ei_status.dmaing |= 0x01; @@ -355,8 +351,8 @@ /* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) { printk("%s: DMAing conflict in ne_block_output." - "[DMAstat:%d][irqlock:%d][intr:%ld]\n", dev->name, ei_status.dmaing, - ei_status.irqlock, dev->interrupt); + "[DMAstat:%d][irqlock:%d]\n", dev->name, ei_status.dmaing, + ei_status.irqlock); return; } ei_status.dmaing |= 0x01; @@ -405,12 +401,16 @@ int init_module(void) { int err; + + if (load_8390_module("ariadne2.c")) + return -ENOSYS; + if ((err = register_netdev(&ariadne2_dev))) { if (err == -EIO) printk("No AriadNE2 ethernet card found.\n"); + unload_8390_module(); return err; } - lock_8390_module(); return 0; } @@ -419,7 +419,7 @@ free_irq(IRQ_AMIGA_PORTS, &ariadne2_dev); release_mem_region(ZTWO_PADDR(ariadne2_dev.base_addr), NE_IO_EXTENT*2); unregister_netdev(&ariadne2_dev); - unlock_8390_module(); + unload_8390_module(); } #endif /* MODULE */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/arlan.c linux/drivers/net/arlan.c --- v2.4.0-test1/linux/drivers/net/arlan.c Fri Mar 10 16:40:42 2000 +++ linux/drivers/net/arlan.c Mon Jun 19 13:30:57 2000 @@ -1091,14 +1091,14 @@ { if (lastFoundAt == 0xbe000) printk(KERN_ERR "arlan: No Arlan devices found \n"); - return ENODEV; + return -ENODEV; } else return 0; ARLAN_DEBUG_EXIT("arlan_probe_everywhere"); - return ENODEV; + return -ENODEV; } int __init arlan_find_devices(void) @@ -1975,7 +1975,7 @@ printk("Arlan driver %s\n", arlan_version); if (arlan_probe_everywhere(dev)) - return ENODEV; + return -ENODEV; arlans_found++; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/at1700.c linux/drivers/net/at1700.c --- v2.4.0-test1/linux/drivers/net/at1700.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/at1700.c Mon Jun 19 13:30:57 2000 @@ -206,7 +206,7 @@ if (base_addr > 0x1ff) /* Check a single specified location. */ return at1700_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ - return ENXIO; + return -ENXIO; for (i = 0; at1700_probe_list[i]; i++) { int ioaddr = at1700_probe_list[i]; @@ -215,7 +215,7 @@ if (at1700_probe1(dev, ioaddr) == 0) return 0; } - return ENODEV; + return -ENODEV; } #endif diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/atari_bionet.c linux/drivers/net/atari_bionet.c --- v2.4.0-test1/linux/drivers/net/atari_bionet.c Wed Aug 18 11:36:41 1999 +++ linux/drivers/net/atari_bionet.c Mon Jun 19 13:30:57 2000 @@ -332,7 +332,7 @@ int i; if (!MACH_IS_ATARI || no_more_found) - return ENODEV; + return -ENODEV; printk("Probing for BioNet 100 Adapter...\n"); @@ -350,12 +350,12 @@ || station_addr[2] != 'O' ) { no_more_found = 1; printk( "No BioNet 100 found.\n" ); - return ENODEV; + return -ENODEV; } if (dev == NULL) - return ENODEV; + return -ENODEV; if (bionet_debug > 0 && version_printed++ == 0) printk(version); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/atari_pamsnet.c linux/drivers/net/atari_pamsnet.c --- v2.4.0-test1/linux/drivers/net/atari_pamsnet.c Wed Aug 18 11:36:41 1999 +++ linux/drivers/net/atari_pamsnet.c Mon Jun 19 13:30:57 2000 @@ -574,7 +574,7 @@ static int no_more_found = 0; if (no_more_found) - return ENODEV; + return -ENODEV; no_more_found = 1; @@ -619,7 +619,7 @@ printk("No PAM's Net/GK found.\n"); if ((dev == NULL) || (lance_target < 0)) - return ENODEV; + return -ENODEV; if (pamsnet_debug > 0 && version_printed++ == 0) printk(version); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/atp.c linux/drivers/net/atp.c --- v2.4.0-test1/linux/drivers/net/atp.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/atp.c Mon Jun 19 13:30:57 2000 @@ -162,7 +162,7 @@ if (base_addr > 0x1ff) /* Check a single specified location. */ return atp_probe1(dev, base_addr); else if (base_addr == 1) /* Don't probe at all. */ - return ENXIO; + return -ENXIO; for (port = ports; *port; port++) { int ioaddr = *port; @@ -173,7 +173,7 @@ return 0; } - return ENODEV; + return -ENODEV; } static int __init atp_probe1(struct net_device *dev, short ioaddr) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/bonding.c linux/drivers/net/bonding.c --- v2.4.0-test1/linux/drivers/net/bonding.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/bonding.c Mon Jun 19 13:30:57 2000 @@ -85,35 +85,49 @@ return 0; } -static int bond_close(struct net_device *master) +static void release_one_slave(struct net_device *master, slave_t *slave) { bonding_t *bond = master->priv; - slave_t *slave; - while ((slave = bond->next) != (slave_t*)bond) { + spin_lock_bh(&master->xmit_lock); + if (bond->current_slave == slave) + bond->current_slave = slave->next; + slave->next->prev = slave->prev; + slave->prev->next = slave->next; + spin_unlock_bh(&master->xmit_lock); - spin_lock_bh(&master->xmit_lock); - slave->next->prev = slave->prev; - slave->prev->next = slave->next; - bond->current_slave = (slave_t*)bond; - spin_unlock_bh(&master->xmit_lock); + netdev_set_master(slave->dev, NULL); - netdev_set_master(slave->dev, NULL); + dev_put(slave->dev); + kfree(slave); + MOD_DEC_USE_COUNT; +} - kfree(slave); - } +static int bond_close(struct net_device *master) +{ + bonding_t *bond = master->priv; + slave_t *slave; + + while ((slave = bond->next) != (slave_t*)bond) + release_one_slave(master, slave); MOD_DEC_USE_COUNT; return 0; } -/* Fake multicast ability. - - NB. It is possible and necessary to make it true one, otherwise - the device is not functional. - */ -static void bond_set_multicast_list(struct net_device *dev) +static void bond_set_multicast_list(struct net_device *master) { + bonding_t *bond = master->priv; + slave_t *slave; + + for (slave = bond->next; slave != (slave_t*)bond; slave = slave->next) { + slave->dev->mc_list = master->mc_list; + slave->dev->mc_count = master->mc_count; + slave->dev->flags = master->flags; + slave->dev->set_multicast_list(slave->dev); + } + + return 0; } static int bond_enslave(struct net_device *master, struct net_device *dev) @@ -161,20 +175,9 @@ if (dev->master != master) return -EINVAL; - netdev_set_master(dev, NULL); - for (slave = bond->next; slave != (slave_t*)bond; slave = slave->next) { if (slave->dev == dev) { - spin_lock_bh(&master->xmit_lock); - if (bond->current_slave == slave) - bond->current_slave = slave->next; - slave->next->prev = slave->prev; - slave->prev->next = slave->next; - spin_unlock_bh(&master->xmit_lock); - - kfree(slave); - dev_put(dev); - MOD_DEC_USE_COUNT; + release_one_slave(master, slave); break; } } @@ -281,7 +284,7 @@ if (slave == (slave_t*)bond) continue; - if (netif_running(slave->dev) && netif_carrier_ok(dev)) { + if (netif_running(slave->dev) && netif_carrier_ok(slave->dev)) { bond->current_slave = slave->next; skb->dev = slave->dev; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c --- v2.4.0-test1/linux/drivers/net/cs89x0.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/cs89x0.c Mon Jun 19 13:30:57 2000 @@ -238,7 +238,7 @@ if (base_addr > 0x1ff) /* Check a single specified location. */ return cs89x0_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ - return ENXIO; + return -ENXIO; for (i = 0; netcard_portlist[i]; i++) { int ioaddr = netcard_portlist[i]; @@ -248,7 +248,7 @@ return 0; } printk(KERN_WARNING "cs89x0: no cs8900 or cs8920 detected. Be sure to disable PnP with SETUP\n"); - return ENODEV; + return -ENODEV; } extern int inline @@ -366,7 +366,7 @@ if (ioaddr & 1) { ioaddr &= ~1; if ((inw(ioaddr + ADD_PORT) & ADD_MASK) != ADD_SIG) - return ENODEV; + return -ENODEV; outw(PP_ChipID, ioaddr + ADD_PORT); } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/daynaport.c linux/drivers/net/daynaport.c --- v2.4.0-test1/linux/drivers/net/daynaport.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/net/daynaport.c Mon Jun 19 13:30:57 2000 @@ -633,6 +633,7 @@ static int ns8390_open(struct net_device *dev) { + MOD_INC_USE_COUNT; ei_open(dev); /* At least on my card (a Focus Enhancements PDS card) I start */ @@ -644,10 +645,9 @@ if (request_irq(dev->irq, ei_interrupt, 0, "8390 Ethernet", dev)) { printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq); - return EAGAIN; + MOD_DEC_USE_COUNT; + return -EAGAIN; } - - MOD_INC_USE_COUNT; return 0; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c --- v2.4.0-test1/linux/drivers/net/de4x5.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/de4x5.c Mon Jun 19 13:30:57 2000 @@ -2229,7 +2229,7 @@ lp->chipset = device; /* Get the board I/O address (64 bits on sparc64) */ - iobase = pdev->resource[0].start; + iobase = pci_resource_start(pdev, 0); /* Fetch the IRQ to be used */ irq = pdev->irq; @@ -2318,7 +2318,7 @@ lp->chipset = device; /* Get the board I/O address (64 bits on sparc64) */ - iobase = this_dev->resource[0].start; + iobase = pci_resource_start(this_dev, 0); /* Fetch the IRQ to be used */ irq = this_dev->irq; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/de600.c linux/drivers/net/de600.c --- v2.4.0-test1/linux/drivers/net/de600.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/de600.c Mon Jun 19 13:30:57 2000 @@ -650,7 +650,7 @@ de600_put_command(STOP_RESET); if (de600_read_status(dev) & 0xf0) { printk(": not at I/O %#3x.\n", DATA_PORT); - return ENODEV; + return -ENODEV; } /* @@ -675,13 +675,13 @@ dev->dev_addr[3] |= 0x70; } else { printk(" not identified in the printer port\n"); - return ENODEV; + return -ENODEV; } #if 0 /* Not yet */ if (check_region(DE600_IO, 3)) { printk(", port 0x%x busy\n", DE600_IO); - return EBUSY; + return -EBUSY; } #endif request_region(DE600_IO, 3, "de600"); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/de620.c linux/drivers/net/de620.c --- v2.4.0-test1/linux/drivers/net/de620.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/de620.c Mon Jun 19 13:30:57 2000 @@ -834,13 +834,13 @@ if ((checkbyte != 0xa5) || (read_eeprom(dev) != 0)) { printk(" not identified in the printer port\n"); - return ENODEV; + return -ENODEV; } #if 0 /* Not yet */ if (check_region(dev->base_addr, 3)) { printk(", port 0x%x busy\n", dev->base_addr); - return EBUSY; + return -EBUSY; } #endif request_region(dev->base_addr, 3, "de620"); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/defxx.c linux/drivers/net/defxx.c --- v2.4.0-test1/linux/drivers/net/defxx.c Tue Apr 11 15:09:17 2000 +++ linux/drivers/net/defxx.c Mon Jun 19 13:30:57 2000 @@ -500,6 +500,9 @@ printk(version); /* we only display this string ONCE */ } + if (pci_enable_device(pdev)) + continue; + /* Verify that I/O enable bit is set (PCI slot is enabled) */ pci_read_config_word(pdev, PCI_COMMAND, &command); @@ -515,7 +518,7 @@ /* Get I/O base address from PCI Configuration Space */ - port = pdev->resource[1].start; + port = pci_resource_start (pdev, 1); /* Verify port address range is not already being used */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/dgrs.c linux/drivers/net/dgrs.c --- v2.4.0-test1/linux/drivers/net/dgrs.c Mon Jun 19 16:31:59 2000 +++ linux/drivers/net/dgrs.c Mon Jun 19 13:30:58 2000 @@ -4,7 +4,7 @@ * The RightSwitch is a 4 (EISA) or 6 (PCI) port etherswitch and * a NIC on an internal board. * - * Author: Rick Richardson, rick@dgii.com, rick_richardson@dgii.com + * Author: Rick Richardson, rick@remotepoint.com * Derived from the SVR4.2 (UnixWare) driver for the same card. * * Copyright 1995-1996 Digi International Inc. @@ -73,7 +73,7 @@ * */ -static char *version = "$Id: dgrs.c,v 1.12 1996/12/21 13:43:58 rick Exp $"; +static char *version = "$Id: dgrs.c,v 1.13 2000/06/06 04:07:00 rick Exp $"; #include #include @@ -206,7 +206,7 @@ I596_RFD *rfdp; /* Current RFD list */ I596_RBD *rbdp; /* Current RBD list */ - int intrcnt; /* Count of interrupts */ + volatile int intrcnt; /* Count of interrupts */ /* * SE-4 (EISA) board variables @@ -1184,7 +1184,7 @@ */ if (priv->plxreg) OUTL(dev->base_addr + PLX_LCL2PCI_DOORBELL, 1); - rc = request_irq(dev->irq, &dgrs_intr, 0, "RightSwitch", dev); + rc = request_irq(dev->irq, &dgrs_intr, SA_SHIRQ, "RightSwitch", dev); if (rc) return (rc); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/dmfe.c linux/drivers/net/dmfe.c --- v2.4.0-test1/linux/drivers/net/dmfe.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/dmfe.c Wed Jun 21 09:32:44 2000 @@ -1,8 +1,9 @@ /* - dmfe.c: Version 1.28 01/18/2000 + dmfe.c: Version 1.30 06/11/2000 A Davicom DM9102(A)/DM9132/DM9801 fast ethernet driver for Linux. Copyright (C) 1997 Sten Wang + (C)Copyright 1997-1998 DAVICOM Semiconductor,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 @@ -46,20 +47,29 @@ Made it compile in 2.3 (device to net_device) Alan Cox : + Cleaned up for kernel merge. Removed the back compatibility support Reformatted, fixing spelling etc as I went Removed IRQ 0-15 assumption - + + Jeff Garzik : + Updated to use new PCI driver API. + Resource usage cleanups. + Report driver version to user. + TODO - + + Implement pci_driver::suspend() and pci_driver::resume() + power management methods. + Check and fix on 64bit and big endian boxes. - Sort out the PCI latency. - - (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved. - - Cleaned up for kernel merge by Alan Cox (alan@redhat.com) + + Test and make sure PCI latency is now correct for all cases. + */ +#define DMFE_VERSION "1.30 (June 11, 2000)" + #include #include @@ -118,7 +128,7 @@ #define DMFE_AUTO 8 #define DMFE_TIMER_WUT jiffies+(HZ*2)/2 /* timer wakeup time : 1 second */ -#define DMFE_TX_TIMEOUT HZ*1.5 /* tx packet time-out time 1.5 s" */ +#define DMFE_TX_TIMEOUT ((HZ*3)/2) /* tx packet time-out time 1.5 s" */ #define DMFE_DBUG(dbug_now, msg, vaule) if (dmfe_debug || dbug_now) printk("DBUG: %s %x\n", msg, vaule) @@ -142,7 +152,9 @@ #define SROM_CLK_WRITE(data, ioaddr) outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);DELAY_5US;outl(data|CR9_SROM_READ|CR9_SRCS|CR9_SRCLK,ioaddr);DELAY_5US;outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);DELAY_5US; -#define CHK_IO_SIZE(pci_id, dev_rev) ( (pci_id==PCI_DM9132_ID) || (dev_rev >= 0x02000030) ) ? DM9102A_IO_SIZE: DM9102_IO_SIZE +#define __CHK_IO_SIZE(pci_id, dev_rev) ( ((pci_id)==PCI_DM9132_ID) || ((dev_rev) >= 0x02000030) ) ? DM9102A_IO_SIZE: DM9102_IO_SIZE +#define CHK_IO_SIZE(pci_dev, dev_rev) \ + __CHK_IO_SIZE(((pci_dev)->device << 16) | (pci_dev)->vendor, dev_rev) /* Structure/enum declaration ------------------------------- */ @@ -164,7 +176,7 @@ struct dmfe_board_info { u32 chip_id; /* Chip vendor/Device ID */ - u32 chip_revesion; /* Chip revesion */ + u32 chip_revision; /* Chip revision */ struct net_device *next_dev; /* next device */ struct pci_dev *net_dev; /* PCI device */ @@ -221,7 +233,6 @@ /* Global variable declaration ----------------------------- */ static int dmfe_debug = 0; static unsigned char dmfe_media_mode = 8; -static struct net_device *dmfe_root_dev = NULL; /* First device */ static u32 dmfe_cr6_user_set = 0; /* For module input parameter */ @@ -299,7 +310,6 @@ }; /* function declaration ------------------------------------- */ -static int dmfe_probe(void); static int dmfe_open(struct net_device *); static int dmfe_start_xmit(struct sk_buff *, struct net_device *); static int dmfe_stop(struct net_device *); @@ -333,111 +343,117 @@ * Search DM910X board, allocate space and register it */ -static int __init dmfe_probe(void) + +static int __init dmfe_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) { unsigned long pci_iobase; - u16 dm9102_count = 0; u8 pci_irqline; - static int index = 0; /* For multiple call */ struct dmfe_board_info *db; /* Point a board information structure */ int i; - struct pci_dev *net_dev = NULL; struct net_device *dev; + u32 dev_rev; DMFE_DBUG(0, "dmfe_probe()", 0); - if (!pci_present()) - return -ENODEV; + pci_iobase = pci_resource_start(pdev, 0); + pci_irqline = pdev->irq; - index = 0; - while ((net_dev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, net_dev))) - { - u32 pci_id; - u32 dev_rev; - - index++; - if (pci_read_config_dword(net_dev, PCI_VENDOR_ID, &pci_id) != DMFE_SUCC) - continue; - - if ((pci_id != PCI_DM9102_ID) && (pci_id != PCI_DM9132_ID)) - continue; - - pci_iobase = net_dev->resource[0].start; - pci_irqline = net_dev->irq; - - /* Enable Master/IO access, Disable memory access */ - - pci_enable_device (net_dev); /* XXX check return val */ - pci_set_master(net_dev); - - /* Set Latency Timer 80h */ - - /* FIXME: setting values > 32 breaks some SiS 559x stuff. - Need a PCI quirk.. */ - - pci_write_config_byte(net_dev, PCI_LATENCY_TIMER, 0x80); + /* Interrupt check */ + if (pci_irqline == 0) { + printk(KERN_ERR "dmfe: Interrupt wrong : IRQ=%d\n", + pci_irqline); + goto err_out; + } - /* Read Chip revesion */ - pci_read_config_dword(net_dev, PCI_REVISION_ID, &dev_rev); - - /* IO range check */ - if (check_region(pci_iobase, CHK_IO_SIZE(pci_id, dev_rev))) { - printk(KERN_ERR "dmfe: I/O conflict : IO=%lx Range=%x\n", pci_iobase, CHK_IO_SIZE(pci_id, dev_rev)); - continue; - } - /* Interrupt check */ - if (pci_irqline == 0) { - printk(KERN_ERR "dmfe: Interrupt wrong : IRQ=%d\n", pci_irqline); - continue; - } + /* iobase check */ + if (pci_iobase == 0) { + printk(KERN_ERR "dmfe: I/O base is zero\n"); + goto err_out; + } - /* Found DM9102 card and PCI resource allocated OK */ - dm9102_count++; /* Found a DM9102 card */ + /* Enable Master/IO access, Disable memory access */ + if (pci_enable_device(pdev)) + goto err_out; + pci_set_master(pdev); - /* Init network device */ - dev = init_etherdev(NULL, sizeof(*db)); - if (dev == NULL) - continue; - - db = dev->priv; +#if 0 /* pci_{enable_device,set_master} sets minimum latency for us now */ - memset(db, 0, sizeof(*db)); - db->next_dev = dmfe_root_dev; - dmfe_root_dev = dev; + /* Set Latency Timer 80h */ + /* FIXME: setting values > 32 breaks some SiS 559x stuff. + Need a PCI quirk.. */ - db->chip_id = pci_id; /* keep Chip vandor/Device ID */ - db->ioaddr = pci_iobase; - db->chip_revesion = dev_rev; + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80); +#endif - db->net_dev = net_dev; + /* Read Chip revision */ + pci_read_config_dword(pdev, PCI_REVISION_ID, &dev_rev); - dev->base_addr = pci_iobase; - dev->irq = pci_irqline; - dev->open = &dmfe_open; - dev->hard_start_xmit = &dmfe_start_xmit; - dev->stop = &dmfe_stop; - dev->get_stats = &dmfe_get_stats; - dev->set_multicast_list = &dmfe_set_filter_mode; - dev->do_ioctl = &dmfe_do_ioctl; + /* Init network device */ + dev = init_etherdev(NULL, sizeof(*db)); + if (dev == NULL) + goto err_out; - request_region(pci_iobase, CHK_IO_SIZE(pci_id, dev_rev), dev->name); + /* IO range check */ + if (!request_region(pci_iobase, CHK_IO_SIZE(pdev, dev_rev), dev->name)) { + printk(KERN_ERR "dmfe: I/O conflict : IO=%lx Range=%x\n", + pci_iobase, CHK_IO_SIZE(pdev, dev_rev)); + goto err_out_netdev; + } - /* read 64 word srom data */ - for (i = 0; i < 64; i++) - ((u16 *) db->srom)[i] = read_srom_word(pci_iobase, i); + db = dev->priv; + pdev->driver_data = dev; - /* Set Node address */ - for (i = 0; i < 6; i++) - dev->dev_addr[i] = db->srom[20 + i]; + db->chip_id = ent->driver_data; + db->ioaddr = pci_iobase; + db->chip_revision = dev_rev; - } + db->net_dev = pdev; + + dev->base_addr = pci_iobase; + dev->irq = pci_irqline; + dev->open = &dmfe_open; + dev->hard_start_xmit = &dmfe_start_xmit; + dev->stop = &dmfe_stop; + dev->get_stats = &dmfe_get_stats; + dev->set_multicast_list = &dmfe_set_filter_mode; + dev->do_ioctl = &dmfe_do_ioctl; - if (!dm9102_count) - printk(KERN_WARNING "dmfe: Can't find DM910X board\n"); + /* read 64 word srom data */ + for (i = 0; i < 64; i++) + ((u16 *) db->srom)[i] = read_srom_word(pci_iobase, i); - return dm9102_count ? 0 : -ENODEV; + /* Set Node address */ + for (i = 0; i < 6; i++) + dev->dev_addr[i] = db->srom[20 + i]; + + return 0; + +err_out_netdev: + unregister_netdev(dev); + kfree(dev); +err_out: + return -ENODEV; +} + + +static void __exit dmfe_remove_one (struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + struct dmfe_board_info *db; + + DMFE_DBUG(0, "dmfe_remove_one()", 0); + + db = dev->priv; + + unregister_netdev(dev); + release_region(dev->base_addr, CHK_IO_SIZE(pdev, db->chip_revision)); + kfree(dev); /* free board information */ + + DMFE_DBUG(0, "dmfe_remove_one() exit", 0); } + /* * Open the interface. * The interface is opened whenever "ifconfig" actives it. @@ -482,7 +498,7 @@ db->in_reset_state = 0; db->rx_error_cnt = 0; - if (!chkmode || (db->chip_id == PCI_DM9132_ID) || (db->chip_revesion >= 0x02000030)) { + if (!chkmode || (db->chip_id == PCI_DM9132_ID) || (db->chip_revision >= 0x02000030)) { //db->cr6_data &= ~CR6_SFT; /* Used Tx threshold */ //db->cr6_data |= CR6_NO_PURGE; /* No purge if rx unavailable */ db->cr0_data = 0xc00000; /* TX/RX desc burst mode */ @@ -933,8 +949,8 @@ else tmp_cr12 = inb(db->ioaddr + DCR12); /* DM9102/DM9102A */ - if (((db->chip_id == PCI_DM9102_ID) && (db->chip_revesion == 0x02000030)) || - ((db->chip_id == PCI_DM9132_ID) && (db->chip_revesion == 0x02000010))) { + if (((db->chip_id == PCI_DM9102_ID) && (db->chip_revision == 0x02000030)) || + ((db->chip_id == PCI_DM9132_ID) && (db->chip_revision == 0x02000010))) { /* DM9102A Chip */ if (tmp_cr12 & 2) tmp_cr12 = 0x0; /* Link failed */ @@ -1532,6 +1548,21 @@ } +static struct pci_device_id dmfe_pci_tbl[] __initdata = { + { 0x1282, 0x9132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9132_ID }, + { 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9102_ID }, + { 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9100_ID }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, dmfe_pci_tbl); + +static struct pci_driver dmfe_driver = { + name: "dmfe", + id_table: dmfe_pci_tbl, + probe: dmfe_init_one, + remove: dmfe_remove_one, +}; + MODULE_AUTHOR("Sten Wang, sten_wang@davicom.com.tw"); MODULE_DESCRIPTION("Davicom DM910X fast ethernet driver"); MODULE_PARM(debug, "i"); @@ -1546,6 +1577,8 @@ static int __init dmfe_init_module(void) { + int rc; + DMFE_DBUG(0, "init_module() ", debug); if (debug) @@ -1565,32 +1598,26 @@ break; } - return dmfe_probe(); /* search board and register */ + rc = pci_register_driver(&dmfe_driver); + if (rc < 0) + return rc; + if (rc > 0) { + printk (KERN_INFO "Davicom DM91xx net driver loaded, version " + DMFE_VERSION "\n"); + return 0; + } + return -ENODEV; } /* * Description: * when user used rmmod to delete module, system invoked clean_module() - * to un-register device. + * to un-register all registered services. */ static void __exit dmfe_cleanup_module(void) { - struct net_device *next_dev; - struct dmfe_board_info *db; - - DMFE_DBUG(0, "clean_module()", 0); - - while (dmfe_root_dev) { - db = dmfe_root_dev->priv; - next_dev = db->next_dev; - unregister_netdev(dmfe_root_dev); - release_region(dmfe_root_dev->base_addr, CHK_IO_SIZE(db->chip_id, db->chip_revesion)); - kfree(db); /* free board information */ - kfree(dmfe_root_dev); /* free device structure */ - dmfe_root_dev = next_dev; - } - DMFE_DBUG(0, "clean_module() exit", 0); + pci_unregister_driver(&dmfe_driver); } module_init(dmfe_init_module); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/dummy.c linux/drivers/net/dummy.c --- v2.4.0-test1/linux/drivers/net/dummy.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/dummy.c Thu Jun 22 07:23:26 2000 @@ -110,12 +110,12 @@ static int dummy_xmit(struct sk_buff *skb, struct net_device *dev) { struct net_device_stats *stats; - dev_kfree_skb(skb); stats = (struct net_device_stats *)dev->priv; stats->tx_packets++; stats->tx_bytes+=skb->len; + dev_kfree_skb(skb); return 0; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/e2100.c linux/drivers/net/e2100.c --- v2.4.0-test1/linux/drivers/net/e2100.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/e2100.c Mon Jun 19 13:30:58 2000 @@ -125,7 +125,7 @@ if (base_addr > 0x1ff) /* Check a single specified location. */ return e21_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ - return ENXIO; + return -ENXIO; for (port = e21_probe_list; *port; port++) { if (check_region(*port, E21_IO_EXTENT)) @@ -134,7 +134,7 @@ return 0; } - return ENODEV; + return -ENODEV; } int __init e21_probe1(struct net_device *dev, int ioaddr) @@ -147,14 +147,14 @@ if (inb(ioaddr + E21_SAPROM + 0) != 0x00 || inb(ioaddr + E21_SAPROM + 1) != 0x00 || inb(ioaddr + E21_SAPROM + 2) != 0x1d) - return ENODEV; + return -ENODEV; /* Verify by making certain that there is a 8390 at there. */ outb(E8390_NODMA + E8390_STOP, ioaddr); udelay(1); /* we want to delay one I/O cycle - which is 2MHz */ status = inb(ioaddr); if (status != 0x21 && status != 0x23) - return ENODEV; + return -ENODEV; /* Read the station address PROM. */ for (i = 0; i < 6; i++) @@ -163,9 +163,6 @@ inb(ioaddr + E21_MEDIA); /* Point to media selection. */ outb(0, ioaddr + E21_ASIC); /* and disable the secondary interface. */ - if (load_8390_module("e2100.c")) - return -ENOSYS; - if (ei_debug && version_printed++ == 0) printk(version); @@ -194,7 +191,7 @@ } if (i >= 8) { printk(" unable to get IRQ %d.\n", dev->irq); - return EAGAIN; + return -EAGAIN; } } else if (dev->irq == 2) /* Fixup luser bogosity: IRQ2 is really IRQ9 */ dev->irq = 9; @@ -259,7 +256,7 @@ short ioaddr = dev->base_addr; if (request_irq(dev->irq, ei_interrupt, 0, "e2100", dev)) { - return EBUSY; + return -EBUSY; } /* Set the interrupt line and memory base on the hardware. */ @@ -410,6 +407,9 @@ { int this_dev, found = 0; + if (load_8390_module("e2100.c")) + return -ENOSYS; + for (this_dev = 0; this_dev < MAX_E21_CARDS; this_dev++) { struct net_device *dev = &dev_e21[this_dev]; dev->irq = irq[this_dev]; @@ -424,14 +424,13 @@ if (register_netdev(dev) != 0) { printk(KERN_WARNING "e2100.c: No E2100 card found (i/o = 0x%x).\n", io[this_dev]); if (found != 0) { /* Got at least one. */ - lock_8390_module(); return 0; } + unload_8390_module(); return -ENXIO; } found++; } - lock_8390_module(); return 0; } @@ -450,7 +449,7 @@ kfree(priv); } } - unlock_8390_module(); + unload_8390_module(); } #endif /* MODULE */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/eepro.c linux/drivers/net/eepro.c --- v2.4.0-test1/linux/drivers/net/eepro.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/eepro.c Mon Jun 19 13:30:58 2000 @@ -23,6 +23,8 @@ This is a compatibility hardware problem. Versions: + 0.12a port of version 0.12a of 2.2.x kernels to 2.3.x + (aris (aris@conectiva.com.br), 05/19/2000) 0.11e some tweaks about multiple cards support (PdP, jul/aug 1999) 0.11d added __initdata, __init stuff; call spin_lock_init in eepro_probe1. Replaced "eepro" by dev->name. Augmented @@ -93,7 +95,7 @@ */ static const char *version = - "eepro.c: v0.11d 08/12/1998 dupuis@lei.ucl.ac.be\n"; + "eepro.c: v0.12a 04/26/2000 aris@conectiva.com.br\n"; #include @@ -174,6 +176,7 @@ #define LAN595 0 #define LAN595TX 1 #define LAN595FX 2 +#define LAN595FX_10ISA 3 /* Information that need to be kept for each board. */ struct eepro_local { @@ -293,7 +296,7 @@ static void set_multicast_list(struct net_device *dev); static void eepro_tx_timeout (struct net_device *dev); -static int read_eeprom(int ioaddr, int location); +static int read_eeprom(int ioaddr, int location, struct net_device *dev); static void hardware_send_packet(struct net_device *dev, void *buf, short length); static int eepro_grab_irq(struct net_device *dev); @@ -327,18 +330,32 @@ buffer (transmit-buffer = 32K - receive-buffer). */ -#define RAM_SIZE 0x8000 -#define RCV_HEADER 8 -#define RCV_RAM 0x6000 /* 24KB default for RCV buffer */ -#define RCV_LOWER_LIMIT 0x00 /* 0x0000 */ -/* #define RCV_UPPER_LIMIT ((RCV_RAM - 2) >> 8) */ /* 0x5ffe */ -#define RCV_UPPER_LIMIT (((rcv_ram) - 2) >> 8) -/* #define XMT_RAM (RAM_SIZE - RCV_RAM) */ /* 8KB for XMT buffer */ -#define XMT_RAM (RAM_SIZE - (rcv_ram)) /* 8KB for XMT buffer */ -/* #define XMT_LOWER_LIMIT (RCV_RAM >> 8) */ /* 0x6000 */ -#define XMT_LOWER_LIMIT ((rcv_ram) >> 8) -#define XMT_UPPER_LIMIT ((RAM_SIZE - 2) >> 8) /* 0x7ffe */ -#define XMT_HEADER 8 +/* now this section could be used by both boards: the oldies and the ee10: + * ee10 uses tx buffer before of rx buffer and the oldies the inverse. + * (aris) + */ +#define RAM_SIZE 0x8000 + +#define RCV_HEADER 8 +#define RCV_DEFAULT_RAM 0x6000 +#define RCV_RAM rcv_ram + +static unsigned rcv_ram = RCV_DEFAULT_RAM; + +#define XMT_HEADER 8 +#define XMT_RAM (RAM_SIZE - RCV_RAM) + +#define XMT_START ((rcv_start + RCV_RAM) % RAM_SIZE) + +#define RCV_LOWER_LIMIT (rcv_start >> 8) +#define RCV_UPPER_LIMIT (((rcv_start + RCV_RAM) - 2) >> 8) +#define XMT_LOWER_LIMIT (XMT_START >> 8) +#define XMT_UPPER_LIMIT (((XMT_START + XMT_RAM) - 2) >> 8) + +#define RCV_START_PRO 0x00 +#define RCV_START_10 XMT_RAM + /* by default the old driver */ +static unsigned rcv_start = RCV_START_PRO; #define RCV_DONE 0x0008 #define RX_OK 0x2000 @@ -384,7 +401,11 @@ #define IO_32_BIT 0x10 #define RCV_BAR 0x04 /* The following are word (16-bit) registers */ #define RCV_STOP 0x06 -#define XMT_BAR 0x0a + +#define XMT_BAR_PRO 0x0a +#define XMT_BAR_10 0x0b +static unsigned xmt_bar = XMT_BAR_PRO; + #define HOST_ADDRESS_REG 0x0c #define IO_PORT 0x0e #define IO_PORT_32_BIT 0x0c @@ -396,8 +417,13 @@ #define INT_NO_REG 0x02 #define RCV_LOWER_LIMIT_REG 0x08 #define RCV_UPPER_LIMIT_REG 0x09 -#define XMT_LOWER_LIMIT_REG 0x0a -#define XMT_UPPER_LIMIT_REG 0x0b + +#define XMT_LOWER_LIMIT_REG_PRO 0x0a +#define XMT_UPPER_LIMIT_REG_PRO 0x0b +#define XMT_LOWER_LIMIT_REG_10 0x0b +#define XMT_UPPER_LIMIT_REG_10 0x0a +static unsigned xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_PRO; +static unsigned xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_PRO; /* Bank 2 registers */ #define XMT_Chain_Int 0x20 /* Interrupt at the end of the transmit chain */ @@ -420,12 +446,68 @@ #define I_ADD_REG4 0x08 #define I_ADD_REG5 0x09 -#define EEPROM_REG 0x0a +#define EEPROM_REG_PRO 0x0a +#define EEPROM_REG_10 0x0b +static unsigned eeprom_reg = EEPROM_REG_PRO; + #define EESK 0x01 #define EECS 0x02 #define EEDI 0x04 #define EEDO 0x08 +/* do a full reset */ +#define eepro_reset(ioaddr) outb(RESET_CMD, ioaddr) + +/* do a nice reset */ +#define eepro_sel_reset(ioaddr) { \ + outb(SEL_RESET_CMD, ioaddr); \ + SLOW_DOWN; \ + SLOW_DOWN; \ + } + +/* disable all interrupts */ +#define eepro_dis_int(ioaddr) outb(ALL_MASK, ioaddr + INT_MASK_REG) + +/* clear all interrupts */ +#define eepro_clear_int(ioaddr) outb(ALL_MASK, ioaddr + STATUS_REG) + +/* enable tx/rx */ +#define eepro_en_int(ioaddr) outb(ALL_MASK & ~(RX_MASK | TX_MASK), \ + ioaddr + INT_MASK_REG) + +/* enable exec event interrupt */ +#define eepro_en_intexec(ioaddr) outb(ALL_MASK & ~(EXEC_MASK), ioaddr + INT_MASK_REG) + +/* enable rx */ +#define eepro_en_rx(ioaddr) outb(RCV_ENABLE_CMD, ioaddr) + +/* disable rx */ +#define eepro_dis_rx(ioaddr) outb(RCV_DISABLE_CMD, ioaddr) + +/* switch bank */ +#define eepro_sw2bank0(ioaddr) outb(BANK0_SELECT, ioaddr) +#define eepro_sw2bank1(ioaddr) outb(BANK1_SELECT, ioaddr) +#define eepro_sw2bank2(ioaddr) outb(BANK2_SELECT, ioaddr) + +/* enable interrupt line */ +#define eepro_en_intline(ioaddr) outb(inb(ioaddr + REG1) | INT_ENABLE,\ + ioaddr + REG1) + +/* disable interrupt line */ +#define eepro_dis_intline(ioaddr) outb(inb(ioaddr + REG1) & 0x7f, \ + ioaddr + REG1); + +/* set diagnose flag */ +#define eepro_diag(ioaddr) outb(DIAGNOSE_CMD, ioaddr) + +/* ack for rx/tx int */ +#define eepro_ack_rxtx(ioaddr) outb (RX_INT | TX_INT, ioaddr + STATUS_REG) + +/* ack for rx int */ +#define eepro_ack_rx(ioaddr) outb (RX_INT, ioaddr + STATUS_REG) + +/* ack for tx int */ +#define eepro_ack_tx(ioaddr) outb (TX_INT, ioaddr + STATUS_REG) /* Check for a network adaptor of this type, and return '0' if one exists. If dev->base_addr == 0, probe all likely locations. @@ -478,7 +560,7 @@ return eepro_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ - return ENXIO; + return -ENXIO; for (i = 0; eepro_portlist[i]; i++) { @@ -490,20 +572,20 @@ return 0; } - return ENODEV; + return -ENODEV; } #endif -void printEEPROMInfo(short ioaddr) +void printEEPROMInfo(short ioaddr, struct net_device *dev) { unsigned short Word; int i,j; for (i=0, j=ee_Checksum; i>ee_IO0)<<4); if (net_debug>4) { - Word=read_eeprom(ioaddr, 1); + Word=read_eeprom(ioaddr, 1, dev); printk(KERN_DEBUG "Word1:\n"); printk(KERN_DEBUG " INT: %d\n", Word & ee_IntMask); printk(KERN_DEBUG " LI: %d\n", GetBit(Word,ee_LI)); @@ -522,7 +604,7 @@ printk(KERN_DEBUG " Duplex: %d\n", GetBit(Word,ee_Duplex)); } - Word=read_eeprom(ioaddr, 5); + Word=read_eeprom(ioaddr, 5, dev); printk(KERN_DEBUG "Word5:\n"); printk(KERN_DEBUG " BNC: %d\n",GetBit(Word,ee_BNC_TPE)); printk(KERN_DEBUG " NumConnectors: %d\n",GetBit(Word,ee_NumConn)); @@ -532,12 +614,12 @@ if (GetBit(Word,ee_PortAUI)) printk("AUI "); printk("port(s) \n"); - Word=read_eeprom(ioaddr, 6); + Word=read_eeprom(ioaddr, 6, dev); printk(KERN_DEBUG "Word6:\n"); printk(KERN_DEBUG " Stepping: %d\n",Word & ee_StepMask); printk(KERN_DEBUG " BoardID: %d\n",Word>>ee_BoardID); - Word=read_eeprom(ioaddr, 7); + Word=read_eeprom(ioaddr, 7, dev); printk(KERN_DEBUG "Word7:\n"); printk(KERN_DEBUG " INT to IRQ:\n"); @@ -557,7 +639,8 @@ { unsigned short station_addr[6], id, counter; int i,j, irqMask; - int eepro; + int eepro = 0; + struct eepro_local *lp; const char *ifmap[] = {"AUI", "10Base2", "10BaseT"}; enum iftype { AUI=0, BNC=1, TPE=2 }; @@ -566,9 +649,6 @@ id=inb(ioaddr + ID_REG); - printk(KERN_DEBUG " id: %#x ",id); - printk(" io: %#x ",ioaddr); - if (((id) & ID_REG_MASK) == ID_REG_SIG) { /* We seem to have the 82595 signature, let's @@ -580,19 +660,45 @@ (counter + 0x40)) { /* Yes, the 82595 has been found */ + printk(KERN_DEBUG " id: %#x ",id); + printk(" io: %#x ",ioaddr); + + /* Initialize the device structure */ + dev->priv = kmalloc(sizeof(struct eepro_local), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct eepro_local)); + + lp = (struct eepro_local *)dev->priv; /* Now, get the ethernet hardware address from the EEPROM */ - station_addr[0] = read_eeprom(ioaddr, 2); - station_addr[1] = read_eeprom(ioaddr, 3); - station_addr[2] = read_eeprom(ioaddr, 4); + station_addr[0] = read_eeprom(ioaddr, 2, dev); - /* Check the station address for the manufacturer's code */ - if (net_debug>3) - printEEPROMInfo(ioaddr); - - if (read_eeprom(ioaddr,7)== ee_FX_INT2IRQ) { /* int to IRQ Mask */ + /* FIXME - find another way to know that we've found + * an Etherexpress 10 + */ + if (station_addr[0] == 0x0000 || + station_addr[0] == 0xffff) { + eepro = 3; + lp->eepro = LAN595FX_10ISA; + eeprom_reg = EEPROM_REG_10; + rcv_start = RCV_START_10; + xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_10; + xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_10; + + station_addr[0] = read_eeprom(ioaddr, 2, dev); + } + + station_addr[1] = read_eeprom(ioaddr, 3, dev); + station_addr[2] = read_eeprom(ioaddr, 4, dev); + + if (eepro) { + printk("%s: Intel EtherExpress 10 ISA\n at %#x,", + dev->name, ioaddr); + } else if (read_eeprom(ioaddr,7,dev)== ee_FX_INT2IRQ) { + /* int to IRQ Mask */ eepro = 2; printk("%s: Intel EtherExpress Pro/10+ ISA\n at %#x,", dev->name, ioaddr); @@ -615,13 +721,21 @@ dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i]; printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]); } + + dev->mem_start = (RCV_LOWER_LIMIT << 8); if ((dev->mem_end & 0x3f) < 3 || /* RX buffer must be more than 3K */ (dev->mem_end & 0x3f) > 29) /* and less than 29K */ - dev->mem_end = RCV_RAM; /* or it will be set to 24K */ - else dev->mem_end = 1024*dev->mem_end; /* Maybe I should shift << 10 */ + dev->mem_end = (RCV_UPPER_LIMIT << 8); + else { + dev->mem_end = (dev->mem_end * 1024) + + (RCV_LOWER_LIMIT << 8); + rcv_ram = dev->mem_end - (RCV_LOWER_LIMIT << 8); + } - /* From now on, dev->mem_end contains the actual size of rx buffer */ + /* From now on, dev->mem_end - dev->mem_start contains + * the actual size of rx buffer + */ if (net_debug > 3) printk(", %dK RCV buffer", (int)(dev->mem_end)/1024); @@ -629,7 +743,7 @@ /* ............... */ - if (GetBit( read_eeprom(ioaddr, 5),ee_BNC_TPE)) + if (GetBit( read_eeprom(ioaddr, 5, dev),ee_BNC_TPE)) dev->if_port = BNC; else dev->if_port = TPE; @@ -637,8 +751,8 @@ if ((dev->irq < 2) && (eepro!=0)) { - i = read_eeprom(ioaddr, 1); - irqMask = read_eeprom(ioaddr, 7); + i = read_eeprom(ioaddr, 1, dev); + irqMask = read_eeprom(ioaddr, 7, dev); i &= 0x07; /* Mask off INT number */ for (j=0; ((j<16) && (i>=0)); j++) { @@ -650,15 +764,13 @@ i--; /* count bits set in irqMask */ } } - if (dev -> irq<2) { + if (dev->irq < 2) { printk(" Duh! illegal interrupt vector stored in EEPROM.\n"); - return ENODEV; + return -ENODEV; } else - if (dev->irq==2) dev->irq = 9; - - else if (dev->irq == 2) - dev->irq = 9; + if (dev->irq==2) + dev->irq = 9; } if (dev->irq > 2) { @@ -671,7 +783,7 @@ net_debug = dev->mem_start & 7; /* still useful or not */ if (net_debug > 3) { - i = read_eeprom(ioaddr, 5); + i = read_eeprom(ioaddr, 5, dev); if (i & 0x2000) /* bit 13 of EEPROM word 5 */ printk(KERN_DEBUG "%s: Concurrent Processing is enabled but not used!\n", dev->name); @@ -683,12 +795,6 @@ /* Grab the region so we can find another board if autoIRQ fails. */ request_region(ioaddr, EEPRO_IO_EXTENT, dev->name); - /* Initialize the device structure */ - dev->priv = kmalloc(sizeof(struct eepro_local), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct eepro_local)); - ((struct eepro_local *)dev->priv)->lock = SPIN_LOCK_UNLOCKED; dev->open = eepro_open; @@ -704,15 +810,20 @@ ether_setup(dev); - outb(RESET_CMD, ioaddr); /* RESET the 82595 */ + /* Check the station address for the manufacturer's code */ + if (net_debug>3) + printEEPROMInfo(ioaddr, dev); + + /* RESET the 82595 */ + eepro_reset(ioaddr); return 0; } - else return ENODEV; + else return -ENODEV; } else if (net_debug > 3) printk ("EtherExpress Pro probed failed!\n"); - return ENODEV; + return -ENODEV; } /* Open/initialize the board. This is called (in the current kernel) @@ -730,55 +841,54 @@ int irqlist[] = { 3, 4, 5, 7, 9, 10, 11, 12, 0 }; int *irqp = irqlist, temp_reg, ioaddr = dev->base_addr; - outb(BANK1_SELECT, ioaddr); /* be CAREFUL, BANK 1 now */ + eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */ /* Enable the interrupt line. */ - temp_reg = inb(ioaddr + REG1); - outb(temp_reg | INT_ENABLE, ioaddr + REG1); + eepro_en_intline(ioaddr); + + /* be CAREFUL, BANK 0 now */ + eepro_sw2bank0(ioaddr); - outb(BANK0_SELECT, ioaddr); /* be CAREFUL, BANK 0 now */ - /* clear all interrupts */ - outb(ALL_MASK, ioaddr + STATUS_REG); + eepro_clear_int(ioaddr); /* Let EXEC event to interrupt */ - outb(ALL_MASK & ~(EXEC_MASK), ioaddr + INT_MASK_REG); + eepro_en_intexec(ioaddr); do { - outb(BANK1_SELECT, ioaddr); /* be CAREFUL, BANK 1 now */ + eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */ temp_reg = inb(ioaddr + INT_NO_REG); outb((temp_reg & 0xf8) | irqrmap[*irqp], ioaddr + INT_NO_REG); - outb(BANK0_SELECT, ioaddr); /* Switch back to Bank 0 */ + eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */ if (request_irq (*irqp, NULL, 0, "bogus", dev) != EBUSY) { /* Twinkle the interrupt, and check if it's seen */ autoirq_setup(0); - outb(DIAGNOSE_CMD, ioaddr); /* RESET the 82595 */ + eepro_diag(ioaddr); /* RESET the 82595 */ if (*irqp == autoirq_report(2)) /* It's a good IRQ line */ break; /* clear all interrupts */ - outb(ALL_MASK, ioaddr + STATUS_REG); + eepro_clear_int(ioaddr); } } while (*++irqp); - outb(BANK1_SELECT, ioaddr); /* Switch back to Bank 1 */ + eepro_sw2bank1(ioaddr); /* Switch back to Bank 1 */ /* Disable the physical interrupt line. */ - temp_reg = inb(ioaddr + REG1); - outb(temp_reg & 0x7f, ioaddr + REG1); + eepro_dis_intline(ioaddr); - outb(BANK0_SELECT, ioaddr); /* Switch back to Bank 0 */ + eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */ /* Mask all the interrupts. */ - outb(ALL_MASK, ioaddr + INT_MASK_REG); + eepro_dis_int(ioaddr); /* clear all interrupts */ - outb(ALL_MASK, ioaddr + STATUS_REG); + eepro_clear_int(ioaddr); return dev->irq; } @@ -787,13 +897,18 @@ { unsigned short temp_reg, old8, old9; int irqMask; - int i, ioaddr = dev->base_addr, rcv_ram = dev->mem_end; + int i, ioaddr = dev->base_addr; struct eepro_local *lp = (struct eepro_local *)dev->priv; if (net_debug > 3) printk(KERN_DEBUG "%s: entering eepro_open routine.\n", dev->name); - if ((irqMask=read_eeprom(ioaddr,7))== ee_FX_INT2IRQ) /* INT to IRQ Mask */ + irqMask = read_eeprom(ioaddr,7,dev); + + if (lp->eepro == LAN595FX_10ISA) { + if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 3;\n"); + } + else if (irqMask == ee_FX_INT2IRQ) /* INT to IRQ Mask */ { lp->eepro = 2; /* Yes, an Intel EtherExpress Pro/10+ */ if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 2;\n"); @@ -831,8 +946,8 @@ /* Initialize the 82595. */ - outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */ - temp_reg = inb(ioaddr + EEPROM_REG); + eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */ + temp_reg = inb(ioaddr + eeprom_reg); lp->stepping = temp_reg >> 5; /* Get the stepping number of the 595 */ @@ -840,7 +955,7 @@ printk(KERN_DEBUG "The stepping of the 82595 is %d\n", lp->stepping); if (temp_reg & 0x10) /* Check the TurnOff Enable bit */ - outb(temp_reg & 0xef, ioaddr + EEPROM_REG); + outb(temp_reg & 0xef, ioaddr + eeprom_reg); for (i=0; i < 6; i++) outb(dev->dev_addr[i] , ioaddr + I_ADD_REG0 + i); @@ -855,17 +970,17 @@ outb(temp_reg & 0x3f, ioaddr + REG3); /* clear test mode */ /* Set the receiving mode */ - outb(BANK1_SELECT, ioaddr); /* be CAREFUL, BANK 1 now */ + eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */ /* Set the interrupt vector */ temp_reg = inb(ioaddr + INT_NO_REG); - if (lp->eepro == 2) + if (lp->eepro == 2 || lp->eepro == LAN595FX_10ISA) outb((temp_reg & 0xf8) | irqrmap2[dev->irq], ioaddr + INT_NO_REG); else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG); temp_reg = inb(ioaddr + INT_NO_REG); - if (lp->eepro == 2) + if (lp->eepro == 2 || lp->eepro == LAN595FX_10ISA) outb((temp_reg & 0xf0) | irqrmap2[dev->irq] | 0x08,ioaddr+INT_NO_REG); else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG); @@ -876,20 +991,20 @@ /* Initialize the RCV and XMT upper and lower limits */ outb(RCV_LOWER_LIMIT, ioaddr + RCV_LOWER_LIMIT_REG); outb(RCV_UPPER_LIMIT, ioaddr + RCV_UPPER_LIMIT_REG); - outb(XMT_LOWER_LIMIT, ioaddr + XMT_LOWER_LIMIT_REG); - outb(XMT_UPPER_LIMIT, ioaddr + XMT_UPPER_LIMIT_REG); + outb(XMT_LOWER_LIMIT, ioaddr + xmt_lower_limit_reg); + outb(XMT_UPPER_LIMIT, ioaddr + xmt_upper_limit_reg); /* Enable the interrupt line. */ - temp_reg = inb(ioaddr + REG1); - outb(temp_reg | INT_ENABLE, ioaddr + REG1); + eepro_en_intline(ioaddr); - outb(BANK0_SELECT, ioaddr); /* Switch back to Bank 0 */ + /* Switch back to Bank 0 */ + eepro_sw2bank0(ioaddr); /* Let RX and TX events to interrupt */ - outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); + eepro_en_int(ioaddr); /* clear all interrupts */ - outb(ALL_MASK, ioaddr + STATUS_REG); + eepro_clear_int(ioaddr); /* Initialize RCV */ outw(RCV_LOWER_LIMIT << 8, ioaddr + RCV_BAR); @@ -897,7 +1012,7 @@ outw((RCV_UPPER_LIMIT << 8) | 0xfe, ioaddr + RCV_STOP); /* Initialize XMT */ - outw(XMT_LOWER_LIMIT << 8, ioaddr + XMT_BAR); + outw(XMT_LOWER_LIMIT << 8, ioaddr + xmt_bar); /* Check for the i82595TX and i82595FX */ old8 = inb(ioaddr + 8); @@ -927,12 +1042,12 @@ if (dev->if_port != TPE) { /* Hopefully, this will fix the problem of using Pentiums and pro/10 w/ BNC. */ - outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */ + eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */ temp_reg = inb(ioaddr + REG13); /* disable the full duplex mode since it is not applicable with the 10Base2 cable. */ outb(temp_reg & ~(FDX | A_N_ENABLE), REG13); - outb(BANK0_SELECT, ioaddr); /* be CAREFUL, BANK 0 now */ + eepro_sw2bank0(ioaddr); /* be CAREFUL, BANK 0 now */ } } else if (net_debug > 3) { @@ -941,13 +1056,9 @@ } } - outb(SEL_RESET_CMD, ioaddr); + eepro_sel_reset(ioaddr); - /* We are supposed to wait for 2 us after a SEL_RESET */ - SLOW_DOWN; - SLOW_DOWN; - - lp->tx_start = lp->tx_end = XMT_LOWER_LIMIT << 8; /* or = RCV_RAM */ + lp->tx_start = lp->tx_end = XMT_LOWER_LIMIT << 8; lp->tx_last = 0; netif_start_queue(dev); @@ -955,7 +1066,8 @@ if (net_debug > 3) printk(KERN_DEBUG "%s: exiting eepro_open routine.\n", dev->name); - outb(RCV_ENABLE_CMD, ioaddr); + /* enabling rx */ + eepro_en_rx(ioaddr); MOD_INC_USE_COUNT; return 0; @@ -965,7 +1077,6 @@ { struct eepro_local *lp = (struct eepro_local *) dev->priv; int ioaddr = dev->base_addr; - int rcv_ram = dev->mem_end; /* if (net_debug > 1) */ printk (KERN_ERR "%s: transmit timed out, %s?\n", dev->name, @@ -977,19 +1088,20 @@ lp->stats.tx_errors++; /* Try to restart the adaptor. */ - outb (SEL_RESET_CMD, ioaddr); - /* We are supposed to wait for 2 us after a SEL_RESET */ - SLOW_DOWN; - SLOW_DOWN; - + eepro_sel_reset(ioaddr); + /* Do I also need to flush the transmit buffers here? YES? */ - lp->tx_start = lp->tx_end = rcv_ram; + lp->tx_start = lp->tx_end = XMT_LOWER_LIMIT; lp->tx_last = 0; dev->trans_start = jiffies; netif_wake_queue (dev); - outb (RCV_ENABLE_CMD, ioaddr); + /* enabling interrupts */ + eepro_en_int(ioaddr); + + /* enabling rx */ + eepro_en_rx(ioaddr); } @@ -1012,6 +1124,7 @@ lp->stats.tx_bytes+=skb->len; hardware_send_packet(dev, buf, length); + dev->trans_start = jiffies; } @@ -1053,31 +1166,34 @@ ioaddr = dev->base_addr; - do { - status = inb(ioaddr + STATUS_REG); - + while (((status = inb(ioaddr + STATUS_REG)) & 0x06) && (boguscount--)) + { + switch (status & (RX_INT | TX_INT)) { + case (RX_INT | TX_INT): + eepro_ack_rxtx(ioaddr); + break; + case RX_INT: + eepro_ack_rx(ioaddr); + break; + case TX_INT: + eepro_ack_tx(ioaddr); + break; + } if (status & RX_INT) { if (net_debug > 4) - printk(KERN_DEBUG "%s: packet received interrupt.\n", dev->name); + printk(KERN_DEBUG "%s: packet received interrupt.\n", dev->name); - /* Acknowledge the RX_INT */ - outb(RX_INT, ioaddr + STATUS_REG); /* Get the received packets */ eepro_rx(dev); } - - else if (status & TX_INT) { + if (status & TX_INT) { if (net_debug > 4) - printk(KERN_DEBUG "%s: packet transmit interrupt.\n", dev->name); - - /* Acknowledge the TX_INT */ - outb(TX_INT, ioaddr + STATUS_REG); + printk(KERN_DEBUG "%s: packet transmit interrupt.\n", dev->name); /* Process the status of transmitted packets */ eepro_transmit_interrupt(dev); } - - } while ((boguscount-- > 0) && (status & 0x06)); + } if (net_debug > 5) printk(KERN_DEBUG "%s: exiting eepro_interrupt routine.\n", dev->name); @@ -1090,32 +1206,31 @@ { struct eepro_local *lp = (struct eepro_local *)dev->priv; int ioaddr = dev->base_addr; - int rcv_ram = dev->mem_end; short temp_reg; netif_stop_queue(dev); - outb(BANK1_SELECT, ioaddr); /* Switch back to Bank 1 */ + eepro_sw2bank1(ioaddr); /* Switch back to Bank 1 */ /* Disable the physical interrupt line. */ temp_reg = inb(ioaddr + REG1); outb(temp_reg & 0x7f, ioaddr + REG1); - outb(BANK0_SELECT, ioaddr); /* Switch back to Bank 0 */ + eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */ /* Flush the Tx and disable Rx. */ outb(STOP_RCV_CMD, ioaddr); - lp->tx_start = lp->tx_end = rcv_ram ; + lp->tx_start = lp->tx_end = (XMT_LOWER_LIMIT << 8); lp->tx_last = 0; /* Mask all the interrupts. */ - outb(ALL_MASK, ioaddr + INT_MASK_REG); + eepro_dis_int(ioaddr); /* clear all interrupts */ - outb(ALL_MASK, ioaddr + STATUS_REG); + eepro_clear_int(ioaddr); /* Reset the 82595 */ - outb(RESET_CMD, ioaddr); + eepro_reset(ioaddr); /* release the interrupt */ free_irq(dev->irq, dev); @@ -1126,10 +1241,6 @@ /* Update the statistics here. What statistics? */ - /* We are supposed to wait for 200 us after a RESET */ - SLOW_DOWN; - SLOW_DOWN; /* May not be enough? */ - MOD_DEC_USE_COUNT; return 0; } @@ -1164,23 +1275,23 @@ */ dev->flags|=IFF_PROMISC; - outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */ + eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */ mode = inb(ioaddr + REG2); outb(mode | PRMSC_Mode, ioaddr + REG2); mode = inb(ioaddr + REG3); outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */ - outb(BANK0_SELECT, ioaddr); /* Return to BANK 0 now */ + eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */ printk("%s: promiscuous mode enabled.\n", dev->name); } else if (dev->mc_count==0 ) { - outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */ + eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */ mode = inb(ioaddr + REG2); outb(mode & 0xd6, ioaddr + REG2); /* Turn off Multi-IA and PRMSC_Mode bits */ mode = inb(ioaddr + REG3); outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */ - outb(BANK0_SELECT, ioaddr); /* Return to BANK 0 now */ + eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */ } else @@ -1191,14 +1302,14 @@ /* Disable RX and TX interrupts. Necessary to avoid corruption of the HOST_ADDRESS_REG by interrupt service routines. */ - outb(ALL_MASK, ioaddr + INT_MASK_REG); + eepro_dis_int(ioaddr); - outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */ + eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */ mode = inb(ioaddr + REG2); outb(mode | Multi_IA, ioaddr + REG2); mode = inb(ioaddr + REG3); outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */ - outb(BANK0_SELECT, ioaddr); /* Return to BANK 0 now */ + eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */ outw(lp->tx_end, ioaddr + HOST_ADDRESS_REG); outw(MC_SETUP, ioaddr + IO_PORT); outw(0, ioaddr + IO_PORT); @@ -1218,7 +1329,7 @@ outw(eaddrs[0], ioaddr + IO_PORT); outw(eaddrs[1], ioaddr + IO_PORT); outw(eaddrs[2], ioaddr + IO_PORT); - outw(lp->tx_end, ioaddr + XMT_BAR); + outw(lp->tx_end, ioaddr + xmt_bar); outb(MC_SETUP, ioaddr); /* Update the transmit queue */ @@ -1262,10 +1373,9 @@ } while (++boguscount < 100); /* Re-enable RX and TX interrupts */ - outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); - + eepro_en_int(ioaddr); } - outb(RCV_ENABLE_CMD, ioaddr); + eepro_en_rx(ioaddr); } /* The horrible routine to read a word from the serial EEPROM. */ @@ -1276,15 +1386,25 @@ #define EE_READ_CMD (6 << 6) int -read_eeprom(int ioaddr, int location) +read_eeprom(int ioaddr, int location, struct net_device *dev) { int i; unsigned short retval = 0; - short ee_addr = ioaddr + EEPROM_REG; + short ee_addr = ioaddr + eeprom_reg; + struct eepro_local *lp = (struct eepro_local *)dev->priv; int read_cmd = location | EE_READ_CMD; short ctrl_val = EECS ; + + /* XXXX - this is not the final version. We must test this on other + * boards other than eepro10. I think that it won't let other + * boards to fail. (aris) + */ + if (lp->eepro == LAN595FX_10ISA) { + eepro_sw2bank1(ioaddr); + outb(0x00, ioaddr + STATUS_REG); + } - outb(BANK2_SELECT, ioaddr); + eepro_sw2bank2(ioaddr); outb(ctrl_val, ee_addr); /* Shift the read command bits out. */ @@ -1311,7 +1431,7 @@ eeprom_delay(); outb(ctrl_val, ee_addr); eeprom_delay(); - outb(BANK0_SELECT, ioaddr); + eepro_sw2bank0(ioaddr); return retval; } @@ -1320,7 +1440,6 @@ { struct eepro_local *lp = (struct eepro_local *)dev->priv; short ioaddr = dev->base_addr; - int rcv_ram = dev->mem_end; unsigned status, tx_available, last, end, boguscount = 100; if (net_debug > 5) @@ -1331,7 +1450,7 @@ /* Disable RX and TX interrupts. Necessary to avoid corruption of the HOST_ADDRESS_REG by interrupt service routines. */ - outb(ALL_MASK, ioaddr + INT_MASK_REG); + eepro_dis_int(ioaddr); /* determine how much of the transmit buffer space is available */ if (lp->tx_end > lp->tx_start) @@ -1346,26 +1465,24 @@ eepro_transmit_interrupt(dev); /* Clean up the transmiting queue */ /* Enable RX and TX interrupts */ - outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); + eepro_en_int(ioaddr); continue; } last = lp->tx_end; end = last + (((length + 3) >> 1) << 1) + XMT_HEADER; - if (end >= RAM_SIZE) { /* the transmit buffer is wrapped around */ - - if ((RAM_SIZE - last) <= XMT_HEADER) { + if (end >= (XMT_UPPER_LIMIT << 8)) { /* the transmit buffer is wrapped around */ + if (((XMT_UPPER_LIMIT << 8) - last) <= XMT_HEADER) { /* Arrrr!!!, must keep the xmt header together, several days were lost to chase this one down. */ - last = rcv_ram; + last = (XMT_LOWER_LIMIT << 8); end = last + (((length + 3) >> 1) << 1) + XMT_HEADER; } - else end = rcv_ram + (end - RAM_SIZE); + else end = (XMT_LOWER_LIMIT << 8) + (end - XMT_RAM); } - outw(last, ioaddr + HOST_ADDRESS_REG); outw(XMT_CMD, ioaddr + IO_PORT); outw(0, ioaddr + IO_PORT); @@ -1385,7 +1502,7 @@ status = inw(ioaddr + IO_PORT); if (lp->tx_start == lp->tx_end) { - outw(last, ioaddr + XMT_BAR); + outw(last, ioaddr + xmt_bar); outb(XMT_CMD, ioaddr); lp->tx_start = last; /* I don't like to change tx_start here */ } @@ -1411,15 +1528,22 @@ if (netif_queue_stopped(dev)) netif_wake_queue(dev); + + /* now we are serializing tx. queue won't come back until + * the tx interrupt + */ + if (lp->eepro == LAN595FX_10ISA) + netif_stop_queue(dev); /* Enable RX and TX interrupts */ - outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); + eepro_en_int(ioaddr); if (net_debug > 5) printk(KERN_DEBUG "%s: exiting hardware_send_packet routine.\n", dev->name); return; } - + eepro_en_int(ioaddr); + netif_stop_queue(dev); if (net_debug > 5) printk(KERN_DEBUG "%s: exiting hardware_send_packet routine.\n", dev->name); @@ -1429,13 +1553,16 @@ eepro_rx(struct net_device *dev) { struct eepro_local *lp = (struct eepro_local *)dev->priv; - short ioaddr = dev->base_addr, rcv_ram = dev->mem_end; + short ioaddr = dev->base_addr; short boguscount = 20; - short rcv_car = lp->rx_start; + unsigned rcv_car = lp->rx_start; unsigned rcv_event, rcv_status, rcv_next_frame, rcv_size; if (net_debug > 5) printk(KERN_DEBUG "%s: entering eepro_rx routine.\n", dev->name); + + /* clear all interrupts */ + eepro_clear_int(ioaddr); /* Set the read pointer to the start of the RCV */ outw(rcv_car, ioaddr + HOST_ADDRESS_REG); @@ -1515,6 +1642,9 @@ if (net_debug > 5) printk(KERN_DEBUG "%s: exiting eepro_rx routine.\n", dev->name); + + /* enable tx/rx interrupts */ + eepro_en_int(ioaddr); } static void @@ -1523,7 +1653,7 @@ struct eepro_local *lp = (struct eepro_local *)dev->priv; short ioaddr = dev->base_addr; short boguscount = 20; - short xmt_status; + unsigned xmt_status; /* if (dev->tbusy == 0) { @@ -1533,31 +1663,67 @@ dev->name); } */ + while (lp->tx_start != lp->tx_end && boguscount) { - while (lp->tx_start != lp->tx_end) { - outw(lp->tx_start, ioaddr + HOST_ADDRESS_REG); xmt_status = inw(ioaddr+IO_PORT); - if ((xmt_status & TX_DONE_BIT) == 0) break; + if ((xmt_status & TX_DONE_BIT) == 0) { + udelay(40); + boguscount--; + continue; + } xmt_status = inw(ioaddr+IO_PORT); lp->tx_start = inw(ioaddr+IO_PORT); + if (lp->eepro == LAN595FX_10ISA) { + lp->tx_start = (XMT_LOWER_LIMIT << 8); + lp->tx_end = lp->tx_start; + + /* yeah, black magic :( */ + eepro_sw2bank0(ioaddr); + eepro_en_int(ioaddr); + + /* disabling rx */ + eepro_dis_rx(ioaddr); + + /* enabling rx */ + eepro_en_rx(ioaddr); + } + netif_wake_queue (dev); if (xmt_status & 0x2000) lp->stats.tx_packets++; else { lp->stats.tx_errors++; - if (xmt_status & 0x0400) + if (xmt_status & 0x0400) { lp->stats.tx_carrier_errors++; - printk("%s: XMT status = %#x\n", - dev->name, xmt_status); - printk(KERN_DEBUG "%s: XMT status = %#x\n", - dev->name, xmt_status); + printk(KERN_DEBUG "%s: carrier error\n", + dev->name); + printk(KERN_DEBUG "%s: XMT status = %#x\n", + dev->name, xmt_status); + } + else { + printk(KERN_DEBUG "%s: XMT status = %#x\n", + dev->name, xmt_status); + printk(KERN_DEBUG "%s: XMT status = %#x\n", + dev->name, xmt_status); + } + if (lp->eepro == LAN595FX_10ISA) { + /* Try to restart the adaptor. */ + /* We are supposed to wait for 2 us after a SEL_RESET */ + eepro_sel_reset(ioaddr); + + /* first enable interrupts */ + eepro_sw2bank0(ioaddr); + outb(ALL_MASK & ~(RX_INT | TX_INT), ioaddr + STATUS_REG); + + /* enabling rx */ + eepro_en_rx(ioaddr); + } } - if (xmt_status & 0x000f) { lp->stats.collisions += (xmt_status & 0x000f); } @@ -1566,25 +1732,19 @@ lp->stats.tx_heartbeat_errors++; } - if (--boguscount == 0) - break; + boguscount--; } } #define MAX_EEPRO 8 static struct net_device dev_eepro[MAX_EEPRO]; -static int io[MAX_EEPRO] = { -#ifdef PnPWakeup - 0x210, /*: default for PnP enabled FX chips */ -#else - 0x200, /* Why? */ -#endif - [1 ... MAX_EEPRO - 1] = -1 }; +static int io[MAX_EEPRO]; static int irq[MAX_EEPRO] = { [0 ... MAX_EEPRO-1] = 0 }; static int mem[MAX_EEPRO] = { /* Size of the rx buffer in KB */ - [0 ... MAX_EEPRO-1] = RCV_RAM/1024 + [0 ... MAX_EEPRO-1] = RCV_DEFAULT_RAM/1024 }; +static int autodetect; static int n_eepro = 0; /* For linux 2.1.xx */ @@ -1594,19 +1754,30 @@ MODULE_PARM(io, "1-" __MODULE_STRING(MAX_EEPRO) "i"); MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_EEPRO) "i"); MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_EEPRO) "i"); +MODULE_PARM(autodetect, "1-" __MODULE_STRING(1) "i"); #ifdef MODULE int init_module(void) { - if (io[0] == 0) - printk("eepro_init_module: You should not use auto-probing with insmod!\n"); + int i; + if (io[0] == 0 && autodetect == 0) { + printk("eepro_init_module: Probe is very dangerous in ISA boards!\n"); + printk("eepro_init_module: Please add \"autodetect=1\" to force probe\n"); + return 1; + } + else if (autodetect) { + /* if autodetect is set then we must force detection */ + io[0] = 0; + + printk("eepro_init_module: Auto-detecting boards (May God protect us...)\n"); + } - while (n_eepro < MAX_EEPRO && io[n_eepro] >= 0) { + for (i = 0; i < MAX_EEPRO; i++) { struct net_device *d = &dev_eepro[n_eepro]; d->mem_end = mem[n_eepro]; - d->base_addr = io[n_eepro]; + d->base_addr = io[0]; d->irq = irq[n_eepro]; d->init = eepro_probe; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c --- v2.4.0-test1/linux/drivers/net/eepro100.c Tue May 23 15:31:35 2000 +++ linux/drivers/net/eepro100.c Mon Jun 19 13:30:58 2000 @@ -4,27 +4,17 @@ May not compile for kernels 2.3.43-47. Written 1996-1999 by Donald Becker. + The driver also contains updates by different kernel developers + (see incomplete list below). + Current maintainer is Andrey V. Savochkin . + Please use this email address and linux-kernel mailing list for bug reports. + This software may be used and distributed according to the terms of the GNU Public License, incorporated herein by reference. This driver is for the Intel EtherExpress Pro100 (Speedo3) design. It should work with all i82557/558/559 boards. - The author may be reached as becker@CESDIS.usra.edu, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, NASA Goddard Space Flight Center, Greenbelt MD 20771 - For updates see - http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html - For installation instructions - http://cesdis.gsfc.nasa.gov/linux/misc/modules.html - There is a Majordomo mailing list based at - linux-eepro100@cesdis.gsfc.nasa.gov - - The driver also contains updates by different kernel developers - (see incomplete list below). - This driver clone is maintained by Andrey V. Savochkin . - Please use this email address and linux-kernel mailing list for bug reports. - Version history: 1998 Apr - 2000 Feb Andrey V. Savochkin Serious fixes for multicast filter list setting, TX timeout routine; @@ -33,12 +23,11 @@ Convert to new PCI driver interface 2000 Mar 24 Dragan Stancevic Disabled FC and ER, to avoid lockups when when we get FCP interrupts. - Dragan Stancevic March 24th, 2000. */ static const char *version = "eepro100.c:v1.09j-t 9/29/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n" -"eepro100.c: $Revision: 1.29 $ 2000/03/30 Modified by Andrey V. Savochkin and others\n"; +"eepro100.c: $Revision: 1.33 $ 2000/05/24 Modified by Andrey V. Savochkin and others\n"; /* A few user-configurable values that apply to all boards. First set is undocumented and spelled per Intel recommendations. */ @@ -218,9 +207,13 @@ } #endif -/* The total I/O port extent of the board. - The registers beyond 0x18 only exist on the i82558. */ -#define SPEEDO3_TOTAL_SIZE 0x20 +#ifndef PCI_DEVICE_ID_INTEL_ID1029 +#define PCI_DEVICE_ID_INTEL_ID1029 0x1029 +#endif +#ifndef PCI_DEVICE_ID_INTEL_ID1030 +#define PCI_DEVICE_ID_INTEL_ID1030 0x1030 +#endif + int speedo_debug = 1; @@ -338,21 +331,22 @@ */ -static int speedo_found1(struct pci_dev *pdev, long ioaddr, int irq, int chip_idx, int fnd_cnt, int acpi_idle_state); - -#ifdef USE_IO -#define SPEEDO_IOTYPE PCI_USES_MASTER|PCI_USES_IO|PCI_ADDR1 -#define SPEEDO_SIZE 32 -#else -#define SPEEDO_IOTYPE PCI_USES_MASTER|PCI_USES_MEM|PCI_ADDR0 -#define SPEEDO_SIZE 0x1000 -#endif +static int speedo_found1(struct pci_dev *pdev, long ioaddr, int fnd_cnt, int acpi_idle_state); enum pci_flags_bit { PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3, }; +static inline unsigned int io_inw(unsigned long port) +{ + return inw(port); +} +static inline void io_outw(unsigned int val, unsigned long port) +{ + outw(val, port); +} + #ifndef USE_IO /* Currently alpha headers define in/out macros. Undefine them. 2000/03/30 SAW */ @@ -377,6 +371,10 @@ int wait = 1000; do ; while(inb(cmd_ioaddr) && --wait >= 0); +#ifndef final_version + if (wait < 0) + printk(KERN_ALERT "eepro100: wait_for_cmd_done timeout!\n"); +#endif } /* Offsets to the various registers. @@ -412,15 +410,15 @@ #endif enum SCBCmdBits { - SCBMaskCmdDone=0x8000, SCBMaskRxDone=0x4000, SCBMaskCmdIdle=0x2000, - SCBMaskRxSuspend=0x1000, SCBMaskEarlyRx=0x0800, SCBMaskFlowCtl=0x0400, - SCBTriggerIntr=0x0200, SCBMaskAll=0x0100, - /* The rest are Rx and Tx commands. */ - CUStart=0x0010, CUResume=0x0020, CUStatsAddr=0x0040, CUShowStats=0x0050, - CUCmdBase=0x0060, /* CU Base address (set to zero) . */ - CUDumpStats=0x0070, /* Dump then reset stats counters. */ - RxStart=0x0001, RxResume=0x0002, RxAbort=0x0004, RxAddrLoad=0x0006, - RxResumeNoResources=0x0007, + SCBMaskCmdDone=0x8000, SCBMaskRxDone=0x4000, SCBMaskCmdIdle=0x2000, + SCBMaskRxSuspend=0x1000, SCBMaskEarlyRx=0x0800, SCBMaskFlowCtl=0x0400, + SCBTriggerIntr=0x0200, SCBMaskAll=0x0100, + /* The rest are Rx and Tx commands. */ + CUStart=0x0010, CUResume=0x0020, CUStatsAddr=0x0040, CUShowStats=0x0050, + CUCmdBase=0x0060, /* CU Base address (set to zero) . */ + CUDumpStats=0x0070, /* Dump then reset stats counters. */ + RxStart=0x0001, RxResume=0x0002, RxAbort=0x0004, RxAddrLoad=0x0006, + RxResumeNoResources=0x0007, }; enum SCBPort_cmds { @@ -656,7 +654,7 @@ pci_set_master(pdev); - if (speedo_found1(pdev, ioaddr, irq, 0, cards_found, acpi_idle_state) == 0) + if (speedo_found1(pdev, ioaddr, cards_found, acpi_idle_state) == 0) cards_found++; else goto err_out_iounmap; @@ -676,7 +674,7 @@ } static int speedo_found1(struct pci_dev *pdev, - long ioaddr, int irq, int chip_idx, int card_idx, int acpi_idle_state) + long ioaddr, int card_idx, int acpi_idle_state) { struct net_device *dev; struct speedo_private *sp; @@ -712,11 +710,15 @@ The size test is for 6 bit vs. 8 bit address serial EEPROMs. */ { - u16 sum = 0; - int j; + unsigned long iobase; int read_cmd, ee_size; + u16 sum; + int j; - if ((do_eeprom_cmd(ioaddr, EE_READ_CMD << 24, 27) & 0xffe0000) + /* Use IO only to avoid postponed writes and satisfy EEPROM timing + requirements. */ + iobase = pci_resource_start(pdev, 1); + if ((do_eeprom_cmd(iobase, EE_READ_CMD << 24, 27) & 0xffe0000) == 0xffe0000) { ee_size = 0x100; read_cmd = EE_READ_CMD << 24; @@ -725,8 +727,8 @@ read_cmd = EE_READ_CMD << 22; } - for (j = 0, i = 0; i < ee_size; i++) { - u16 value = do_eeprom_cmd(ioaddr, read_cmd | (i << 16), 27); + for (j = 0, i = 0, sum = 0; i < ee_size; i++) { + u16 value = do_eeprom_cmd(iobase, read_cmd | (i << 16), 27); eeprom[i] = value; sum += value; if (i < 3) { @@ -739,7 +741,8 @@ "check settings before activating this device!\n", dev->name, sum); /* Don't unregister_netdev(dev); as the EEPro may actually be - usable, especially if the MAC address is set later. */ + usable, especially if the MAC address is set later. + On the other hand, it may be unusable if MDI data is corrupted. */ } /* Reset the chip: stop Tx and Rx processes and clear counters. @@ -760,7 +763,7 @@ #ifdef USE_IO printk("I/O at %#3lx, ", ioaddr); #endif - printk("IRQ %d.\n", irq); + printk("IRQ %d.\n", pdev->irq); #if 1 || defined(kernel_bloat) /* OK, this is pure kernel bloat. I don't like it when other drivers @@ -839,7 +842,7 @@ pdev->driver_data = dev; dev->base_addr = ioaddr; - dev->irq = irq; + dev->irq = pdev->irq; sp = dev->priv; sp->pdev = pdev; @@ -887,30 +890,32 @@ #define EE_WRITE_1 0x4806 #define EE_OFFSET SCBeeprom -/* Delay between EEPROM clock transitions. - The code works with no delay on 33Mhz PCI. */ -#define eeprom_delay() inw(ee_addr) - +/* The fixes for the code were kindly provided by Dragan Stancevic + to strictly follow Intel specifications of EEPROM + access timing. + The publicly available sheet 64486302 (sec. 3.1) specifies 1us access + interval for serial EEPROM. However, it looks like that there is an + additional requirement dictating larger udelay's in the code below. + 2000/05/24 SAW */ static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len) { unsigned retval = 0; long ee_addr = ioaddr + SCBeeprom; - outw(EE_ENB | EE_SHIFT_CLK, ee_addr); + io_outw(EE_ENB, ee_addr); udelay(2); + io_outw(EE_ENB | EE_SHIFT_CLK, ee_addr); udelay(2); /* Shift the command bits out. */ do { short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0; - outw(dataval, ee_addr); - eeprom_delay(); - outw(dataval | EE_SHIFT_CLK, ee_addr); - eeprom_delay(); - retval = (retval << 1) | ((inw(ee_addr) & EE_DATA_READ) ? 1 : 0); + io_outw(dataval, ee_addr); udelay(2); + io_outw(dataval | EE_SHIFT_CLK, ee_addr); udelay(2); + retval = (retval << 1) | ((io_inw(ee_addr) & EE_DATA_READ) ? 1 : 0); } while (--cmd_len >= 0); - outw(EE_ENB, ee_addr); + io_outw(EE_ENB, ee_addr); udelay(2); /* Terminate the EEPROM access. */ - outw(EE_ENB & ~EE_CS, ee_addr); + io_outw(EE_ENB & ~EE_CS, ee_addr); udelay(4); return retval; } @@ -1104,8 +1109,11 @@ int partner = mdio_read(ioaddr, phy_num, 5); if (partner != sp->partner) { int flow_ctrl = sp->advertising & partner & 0x0400 ? 1 : 0; - if (speedo_debug > 2) + if (speedo_debug > 2) { printk(KERN_DEBUG "%s: Link status change.\n", dev->name); + printk(KERN_DEBUG "%s: Old partner %x, new %x, adv %x.\n", + dev->name, sp->partner, partner, sp->advertising); + } sp->partner = partner; if (flow_ctrl != sp->flow_ctrl) { sp->flow_ctrl = flow_ctrl; @@ -1137,6 +1145,9 @@ /* We must continue to monitor the media. */ sp->timer.expires = RUN_AT(2*HZ); /* 2.0 sec. */ add_timer(&sp->timer); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,43) + timer_exit(&sp->timer); +#endif /* LINUX_VERSION_CODE */ } static void speedo_show_state(struct net_device *dev) @@ -1169,12 +1180,14 @@ i, (sp->rx_ringp[i] != NULL) ? (unsigned)sp->rx_ringp[i]->status : 0); +#if 0 for (i = 0; i < 16; i++) { /* FIXME: what does it mean? --SAW */ if (i == 6) i = 21; printk(KERN_DEBUG "%s: PHY index %d register %d is %4.4x.\n", dev->name, phy_num, i, mdio_read(ioaddr, phy_num, i)); } +#endif } @@ -1247,6 +1260,29 @@ netif_wake_queue(dev); } +static void reset_mii(struct net_device *dev) +{ + struct speedo_private *sp = (struct speedo_private *)dev->priv; + long ioaddr = dev->base_addr; + /* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */ + if ((sp->phy[0] & 0x8000) == 0) { + int phy_addr = sp->phy[0] & 0x1f; + int advertising = mdio_read(ioaddr, phy_addr, 4); + int mii_bmcr = mdio_read(ioaddr, phy_addr, 0); + mdio_write(ioaddr, phy_addr, 0, 0x0400); + mdio_write(ioaddr, phy_addr, 1, 0x0000); + mdio_write(ioaddr, phy_addr, 4, 0x0000); + mdio_write(ioaddr, phy_addr, 0, 0x8000); +#ifdef honor_default_port + mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]); +#else + mdio_read(ioaddr, phy_addr, 0); + mdio_write(ioaddr, phy_addr, 0, mii_bmcr); + mdio_write(ioaddr, phy_addr, 4, advertising); +#endif + } +} + static void speedo_tx_timeout(struct net_device *dev) { struct speedo_private *sp = (struct speedo_private *)dev->priv; @@ -1273,6 +1309,7 @@ outl(cpu_to_le32(TX_RING_ELEM_DMA(sp, dirty_tx % TX_RING_SIZE])), ioaddr + SCBPointer); outw(CUStart, ioaddr + SCBCmd); + reset_mii(dev); } else { #else { @@ -1283,11 +1320,7 @@ del_timer(&sp->timer); end_bh_atomic(); #else /* LINUX_VERSION_CODE */ -#ifdef CONFIG_SMP del_timer_sync(&sp->timer); -#else /* SMP */ - del_timer(&sp->timer); -#endif /* SMP */ #endif /* LINUX_VERSION_CODE */ /* Reset the Tx and Rx units. */ outl(PortReset, ioaddr + SCBPort); @@ -1310,26 +1343,12 @@ dev->trans_start = jiffies; spin_unlock_irqrestore(&sp->lock, flags); set_rx_mode(dev); /* it takes the spinlock itself --SAW */ + /* Reset MII transceiver. Do it before starting the timer to serialize + mdio_xxx operations. Yes, it's a paranoya :-) 2000/05/09 SAW */ + reset_mii(dev); sp->timer.expires = RUN_AT(2*HZ); add_timer(&sp->timer); } - /* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */ - if ((sp->phy[0] & 0x8000) == 0) { - int phy_addr = sp->phy[0] & 0x1f; - int advertising = mdio_read(ioaddr, phy_addr, 4); - int mii_bmcr = mdio_read(ioaddr, phy_addr, 0); - mdio_write(ioaddr, phy_addr, 0, 0x0400); - mdio_write(ioaddr, phy_addr, 1, 0x0000); - mdio_write(ioaddr, phy_addr, 4, 0x0000); - mdio_write(ioaddr, phy_addr, 0, 0x8000); -#ifdef honor_default_port - mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]); -#else - mdio_read(ioaddr, phy_addr, 0); - mdio_write(ioaddr, phy_addr, 0, mii_bmcr); - mdio_write(ioaddr, phy_addr, 4, advertising); -#endif - } return; } @@ -1384,8 +1403,7 @@ sp->tx_ring[entry].link = cpu_to_le32(TX_RING_ELEM_DMA(sp, sp->cur_tx % TX_RING_SIZE)); sp->tx_ring[entry].tx_desc_addr = - cpu_to_le32(TX_RING_ELEM_DMA(sp, sp->cur_tx % TX_RING_SIZE) + - TX_DESCR_BUF_OFFSET); + cpu_to_le32(TX_RING_ELEM_DMA(sp, entry) + TX_DESCR_BUF_OFFSET); /* The data region is always in one buffer descriptor. */ sp->tx_ring[entry].count = cpu_to_le32(sp->tx_threshold); sp->tx_ring[entry].tx_buf_addr0 = @@ -1913,7 +1931,7 @@ if (netif_running(dev)) { unsigned long flags; /* Take a spinlock to make wait_for_cmd_done and sending the - * command atomic. --SAW */ + command atomic. --SAW */ spin_lock_irqsave(&sp->lock, flags); wait_for_cmd_done(ioaddr + SCBCmd); outb(CUDumpStats, ioaddr + SCBCmd); @@ -1935,17 +1953,35 @@ case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ data[0] = phy; case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - /* FIXME: these operations probably need to be serialized with MDIO - access from the timer routine and timeout handler. 2000/03/08 SAW */ + /* FIXME: these operations need to be serialized with MDIO + access from the timeout handler. + They are currently serialized only with MDIO access from the + timer routine. 2000/05/09 SAW */ saved_acpi = pci_set_power_state(sp->pdev, 0); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43) + start_bh_atomic(); + data[3] = mdio_read(ioaddr, data[0], data[1]); + end_bh_atomic(); +#else /* LINUX_VERSION_CODE */ + del_timer_sync(&sp->timer); data[3] = mdio_read(ioaddr, data[0], data[1]); + add_timer(&sp->timer); /* may be set to the past --SAW */ +#endif /* LINUX_VERSION_CODE */ pci_set_power_state(sp->pdev, saved_acpi); return 0; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ if (!capable(CAP_NET_ADMIN)) return -EPERM; saved_acpi = pci_set_power_state(sp->pdev, 0); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43) + start_bh_atomic(); + mdio_write(ioaddr, data[0], data[1], data[2]); + end_bh_atomic(); +#else /* LINUX_VERSION_CODE */ + del_timer_sync(&sp->timer); mdio_write(ioaddr, data[0], data[1], data[2]); + add_timer(&sp->timer); /* may be set to the past --SAW */ +#endif /* LINUX_VERSION_CODE */ pci_set_power_state(sp->pdev, saved_acpi); return 0; default: @@ -2205,6 +2241,10 @@ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82559ER, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1029, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1030, PCI_ANY_ID, PCI_ANY_ID, }, { 0,} }; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c --- v2.4.0-test1/linux/drivers/net/eexpress.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/eexpress.c Mon Jun 19 13:30:58 2000 @@ -396,7 +396,7 @@ if (ioaddr&0xfe00) return eexp_hw_probe(dev,ioaddr); else if (ioaddr) - return ENXIO; + return -ENXIO; for (port=&ports[0] ; *port ; port++ ) { @@ -1081,7 +1081,7 @@ dev->priv = lp = kmalloc(sizeof(struct net_local), GFP_KERNEL); if (!dev->priv) - return ENOMEM; + return -ENOMEM; memset(dev->priv, 0, sizeof(struct net_local)); @@ -1127,7 +1127,7 @@ default: printk(") bad memory size (%dk).\n", memory_size); kfree(dev->priv); - return ENODEV; + return -ENODEV; break; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/epic100.c linux/drivers/net/epic100.c --- v2.4.0-test1/linux/drivers/net/epic100.c Tue May 23 15:31:35 2000 +++ linux/drivers/net/epic100.c Mon Jun 19 13:30:58 2000 @@ -384,6 +384,8 @@ duplex = full_duplex[card_idx]; } + pdev->driver_data = dev; + dev->base_addr = ioaddr; dev->irq = pdev->irq; printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", @@ -1054,7 +1056,7 @@ printk(KERN_DEBUG " In epic_rx(), entry %d %8.8x.\n", entry, ep->rx_ring[entry].rxstatus); /* If we own the next entry, it's a new packet. Send it up. */ - while ( ! le32_to_cpu(ep->rx_ring[entry].rxstatus) & DescOwn) { + while (!(le32_to_cpu(ep->rx_ring[entry].rxstatus) & DescOwn)) { int status = le32_to_cpu(ep->rx_ring[entry].rxstatus); if (debug > 4) @@ -1295,9 +1297,6 @@ { struct net_device *dev = pdev->driver_data; - if (!dev) - BUG(); - unregister_netdev(dev); #ifndef USE_IO_OPS iounmap ((void*) dev->base_addr); @@ -1315,9 +1314,6 @@ struct net_device *dev = pdev->driver_data; long ioaddr = dev->base_addr; - if (!dev) - BUG(); - epic_pause(dev); /* Put the chip into low-power mode. */ outl(0x0008, ioaddr + GENCTL); @@ -1327,9 +1323,6 @@ static void epic_resume (struct pci_dev *pdev) { struct net_device *dev = pdev->driver_data; - - if (!dev) - BUG(); epic_restart (dev); } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/es3210.c linux/drivers/net/es3210.c --- v2.4.0-test1/linux/drivers/net/es3210.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/es3210.c Mon Jun 19 13:30:58 2000 @@ -181,9 +181,6 @@ return ENODEV; } - if (load_8390_module("es3210.c")) - return -ENOSYS; - /* We should have a "dev" from Space.c or the static module table. */ if (dev == NULL) { printk("es3210.c: Passed a NULL device.\n"); @@ -404,6 +401,9 @@ { int this_dev, found = 0; + if (load_8390_module("es3210.c")) + return -ENOSYS; + for (this_dev = 0; this_dev < MAX_ES_CARDS; this_dev++) { struct net_device *dev = &dev_es3210[this_dev]; dev->irq = irq[this_dev]; @@ -415,14 +415,13 @@ if (register_netdev(dev) != 0) { printk(KERN_WARNING "es3210.c: No es3210 card found (i/o = 0x%x).\n", io[this_dev]); if (found != 0) { /* Got at least one. */ - lock_8390_module(); return 0; } + unload_8390_module(); return -ENXIO; } found++; } - lock_8390_module(); return 0; } @@ -441,6 +440,6 @@ kfree(priv); } } - unlock_8390_module(); + unload_8390_module(); } #endif /* MODULE */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c --- v2.4.0-test1/linux/drivers/net/eth16i.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/eth16i.c Mon Jun 19 13:30:58 2000 @@ -448,7 +448,7 @@ if(base_addr > 0x1ff) /* Check only single location */ return eth16i_probe1(dev, base_addr); else if(base_addr != 0) /* Don't probe at all */ - return ENXIO; + return -ENXIO; /* Seek card from the ISA io address space */ for(i = 0; (ioaddr = eth16i_portlist[i]) ; i++) { @@ -466,7 +466,7 @@ return 0; } - return ENODEV; + return -ENODEV; } static int __init eth16i_probe1(struct net_device *dev, int ioaddr) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/fc/iph5526.c linux/drivers/net/fc/iph5526.c --- v2.4.0-test1/linux/drivers/net/fc/iph5526.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/net/fc/iph5526.c Mon Jun 19 13:30:58 2000 @@ -3771,7 +3771,9 @@ for (i = 0; i < clone_list[i].vendor_id != 0; i++) while ((pdev = pci_find_device(clone_list[i].vendor_id, clone_list[i].device_id, pdev))) { - unsigned short pci_command; + unsigned short pci_command; + if (pci_enable_device(pdev)) + continue; if (count < MAX_FC_CARDS) { fc[count] = kmalloc(sizeof(struct fc_info), GFP_ATOMIC); if (fc[count] == NULL) { @@ -3800,8 +3802,8 @@ host->hostt->use_new_eh_code = 1; host->this_id = tmpt->this_id; - pci_maddr = pdev->resource[0].start; - if ( (pdev->resource[0].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) { + pci_maddr = pci_resource_start(pdev, 0); + if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) { printk("iph5526.c : Cannot find proper PCI device base address.\n"); scsi_unregister(host); kfree(fc[count]); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/fmv18x.c linux/drivers/net/fmv18x.c --- v2.4.0-test1/linux/drivers/net/fmv18x.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/net/fmv18x.c Mon Jun 19 13:30:58 2000 @@ -137,7 +137,7 @@ if (base_addr > 0x1ff) /* Check a single specified location. */ return fmv18x_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ - return ENXIO; + return -ENXIO; for (i = 0; fmv18x_probe_list[i]; i++) { int ioaddr = fmv18x_probe_list[i]; @@ -147,7 +147,7 @@ return 0; } - return ENODEV; + return -ENODEV; } /* The Fujitsu datasheet suggests that the NIC be probed for by checking its @@ -194,7 +194,7 @@ if (request_irq(irq, &net_interrupt, 0, "fmv18x", dev)) { printk ("FMV-18x found at %#3x, but it's unusable due to a conflict on" "IRQ %d.\n", ioaddr, irq); - return EAGAIN; + return -EAGAIN; } /* Allocate a new 'dev' if needed. */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/hamradio/pi2.c linux/drivers/net/hamradio/pi2.c --- v2.4.0-test1/linux/drivers/net/hamradio/pi2.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/net/hamradio/pi2.c Mon Jun 19 13:30:58 2000 @@ -1378,7 +1378,7 @@ if (irqval) { printk(KERN_ERR "PI: unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval); - return EAGAIN; + return -EAGAIN; } } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/hamradio/pt.c linux/drivers/net/hamradio/pt.c --- v2.4.0-test1/linux/drivers/net/hamradio/pt.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/net/hamradio/pt.c Mon Jun 19 13:30:58 2000 @@ -833,7 +833,7 @@ if (irqval) { printk(KERN_ERR "PT: ERROR: Unable to get IRQ %d (irqval = %d).\n", dev->irq, irqval); - return EAGAIN; + return -EAGAIN; } } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/hp-plus.c linux/drivers/net/hp-plus.c --- v2.4.0-test1/linux/drivers/net/hp-plus.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/hp-plus.c Mon Jun 19 13:30:58 2000 @@ -131,7 +131,7 @@ if (base_addr > 0x1ff) /* Check a single specified location. */ return hpp_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ - return ENXIO; + return -ENXIO; for (i = 0; hpplus_portlist[i]; i++) { int ioaddr = hpplus_portlist[i]; @@ -141,7 +141,7 @@ return 0; } - return ENODEV; + return -ENODEV; } #endif @@ -157,10 +157,7 @@ /* Check for the HP+ signature, 50 48 0x 53. */ if (inw(ioaddr + HP_ID) != 0x4850 || (inw(ioaddr + HP_PAGING) & 0xfff0) != 0x5300) - return ENODEV; - - if (load_8390_module("hp-plus.c")) - return -ENOSYS; + return -ENODEV; /* We should have a "dev" from Space.c or the static module table. */ if (dev == NULL) { @@ -186,7 +183,7 @@ if (checksum != 0xff) { printk(" bad checksum %2.2x.\n", checksum); - return ENODEV; + return -ENODEV; } else { /* Point at the Software Configuration Flags. */ outw(ID_Page, ioaddr + HP_PAGING); @@ -436,6 +433,9 @@ { int this_dev, found = 0; + if (load_8390_module("hp-plus.c")) + return -ENOSYS; + for (this_dev = 0; this_dev < MAX_HPP_CARDS; this_dev++) { struct net_device *dev = &dev_hpp[this_dev]; dev->irq = irq[this_dev]; @@ -448,14 +448,13 @@ if (register_netdev(dev) != 0) { printk(KERN_WARNING "hp-plus.c: No HP-Plus card found (i/o = 0x%x).\n", io[this_dev]); if (found != 0) { /* Got at least one. */ - lock_8390_module(); return 0; } + unload_8390_module(); return -ENXIO; } found++; } - lock_8390_module(); return 0; } @@ -475,7 +474,7 @@ kfree(priv); } } - unlock_8390_module(); + unload_8390_module(); } #endif /* MODULE */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/hp.c linux/drivers/net/hp.c --- v2.4.0-test1/linux/drivers/net/hp.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/hp.c Mon Jun 19 13:30:58 2000 @@ -92,7 +92,7 @@ if (base_addr > 0x1ff) /* Check a single specified location. */ return hp_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ - return ENXIO; + return -ENXIO; for (i = 0; hppclan_portlist[i]; i++) { int ioaddr = hppclan_portlist[i]; @@ -102,7 +102,7 @@ return 0; } - return ENODEV; + return -ENODEV; } #endif @@ -119,7 +119,7 @@ || inb(ioaddr+1) != 0x00 || inb(ioaddr+2) != 0x09 || inb(ioaddr+14) == 0x57) - return ENODEV; + return -ENODEV; /* Set up the parameters based on the board ID. If you have additional mappings, please mail them to me -djb. */ @@ -131,9 +131,6 @@ wordmode = 0; } - if (load_8390_module("hp.c")) - return -ENOSYS; - /* We should have a "dev" from Space.c or the static module table. */ if (dev == NULL) { printk("hp.c: Passed a NULL device.\n"); @@ -178,7 +175,7 @@ printk(" no free IRQ lines.\n"); kfree(dev->priv); dev->priv = NULL; - return EBUSY; + return -EBUSY; } } else { if (dev->irq == 2) @@ -187,7 +184,7 @@ printk (" unable to get IRQ %d.\n", dev->irq); kfree(dev->priv); dev->priv = NULL; - return EBUSY; + return -EBUSY; } } @@ -407,6 +404,9 @@ { int this_dev, found = 0; + if (load_8390_module("hp.c")) + return -ENOSYS; + for (this_dev = 0; this_dev < MAX_HP_CARDS; this_dev++) { struct net_device *dev = &dev_hp[this_dev]; dev->irq = irq[this_dev]; @@ -419,14 +419,13 @@ if (register_netdev(dev) != 0) { printk(KERN_WARNING "hp.c: No HP card found (i/o = 0x%x).\n", io[this_dev]); if (found != 0) { /* Got at least one. */ - lock_8390_module(); return 0; } + unload_8390_module(); return -ENXIO; } found++; } - lock_8390_module(); return 0; } @@ -446,7 +445,7 @@ kfree(priv); } } - unlock_8390_module(); + unload_8390_module(); } #endif /* MODULE */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/hp100.c linux/drivers/net/hp100.c --- v2.4.0-test1/linux/drivers/net/hp100.c Tue May 23 15:31:35 2000 +++ linux/drivers/net/hp100.c Mon Jun 19 13:30:58 2000 @@ -8,7 +8,7 @@ ** Extended for new busmaster capable chipsets by ** Siegfried "Frieder" Loeffler (dg1sek) ** -** Maintained by: Jaroslav Kysela +** Maintained by: Jaroslav Kysela ** ** This driver has only been tested with ** -- HP J2585B 10/100 Mbit/s PCI Busmaster @@ -109,16 +109,9 @@ #include #include -#if LINUX_VERSION_CODE >= 0x020100 #define LINUX_2_1 typedef struct net_device_stats hp100_stats_t; EXPORT_NO_SYMBOLS; -#else -#include -#define ioremap vremap -#define iounmap vfree -typedef struct enet_statistics hp100_stats_t; -#endif #include "hp100.h" @@ -187,12 +180,7 @@ u_short priority_tx; /* != 0 - priority tx */ u_short mode; /* PIO, Shared Mem or Busmaster */ u_char bus; -#ifndef LINUX_2_1 - u_char pci_bus; - u_char pci_device_fn; -#else struct pci_dev *pci_dev; -#endif short mem_mapped; /* memory mapped access */ void *mem_ptr_virt; /* virtual memory mapped area, maybe NULL */ unsigned long mem_ptr_phys; /* physical memory mapped area */ @@ -287,21 +275,15 @@ static int hp100_priority_tx = HP100_DEFAULT_PRIORITY_TX; static int hp100_mode = 1; -#ifdef LINUX_2_1 MODULE_PARM( hp100_rx_ratio, "1i" ); MODULE_PARM( hp100_priority_tx, "1i" ); MODULE_PARM( hp100_mode, "1i" ); -#endif /* * prototypes */ -#ifdef LINUX_2_1 static int hp100_probe1( struct net_device *dev, int ioaddr, u_char bus, struct pci_dev *pci_dev ); -#else -static int hp100_probe1( struct net_device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn ); -#endif static int hp100_open( struct net_device *dev ); static int hp100_close( struct net_device *dev ); static int hp100_start_xmit( struct sk_buff *skb, struct net_device *dev ); @@ -361,25 +343,12 @@ { if ( check_region( base_addr, HP100_REGION_SIZE ) ) return -EINVAL; if ( base_addr < 0x400 ) -#ifdef LINUX_2_1 return hp100_probe1( dev, base_addr, HP100_BUS_ISA, NULL ); -#else - return hp100_probe1( dev, base_addr, HP100_BUS_ISA, 0, 0 ); -#endif if ( EISA_bus && base_addr >= 0x1c38 && ( (base_addr - 0x1c38) & 0x3ff ) == 0 ) -#ifdef LINUX_2_1 return hp100_probe1( dev, base_addr, HP100_BUS_EISA, NULL ); -#else - return hp100_probe1( dev, base_addr, HP100_BUS_EISA, 0, 0 ); -#endif #ifdef CONFIG_PCI -#ifdef LINUX_2_1 printk( "hp100: %s: You must specify card # in i/o address parameter for PCI bus...", dev->name ); #else - printk( "hp100: %s: You may specify card # in i/o address parameter for PCI bus...", dev->name ); - return hp100_probe1( dev, base_addr, HP100_BUS_PCI, 0, 0 ); -#endif -#else return -ENODEV; #endif } @@ -397,16 +366,13 @@ if ( pcibios_present() ) { int pci_index; -#ifdef LINUX_2_1 struct pci_dev *pci_dev = NULL; int pci_id_index; u_short pci_command; -#endif #ifdef HP100_DEBUG_PCI printk( "hp100: %s: PCI BIOS is present, checking for devices..\n", dev->name ); #endif -#ifdef LINUX_2_1 pci_index = 0; for ( pci_id_index = 0; pci_id_index < HP100_PCI_IDS_SIZE; pci_id_index++ ) { while ( (pci_dev = pci_find_device( hp100_pci_ids[ pci_id_index ].vendor, @@ -416,8 +382,10 @@ pci_index++; continue; } + if (pci_enable_device(pci_dev)) + continue; /* found... */ - ioaddr = pci_dev ->resource[ 0 ].start; + ioaddr = pci_resource_start (pci_dev, 0); if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue; pci_read_config_word( pci_dev, PCI_COMMAND, &pci_command ); if ( !( pci_command & PCI_COMMAND_IO ) ) { @@ -441,55 +409,6 @@ return 0; } } -#else /* old PCI interface */ - for ( pci_index = pci_start_index & 7; pci_index < 8; pci_index++ ) - { - u_char pci_bus, pci_device_fn; - u_short pci_command; - int pci_id_index; - - for ( pci_id_index = 0; pci_id_index < HP100_PCI_IDS_SIZE; pci_id_index++ ) - if ( pcibios_find_device( hp100_pci_ids[ pci_id_index ].vendor, - hp100_pci_ids[ pci_id_index ].device, - pci_index, &pci_bus, - &pci_device_fn ) == 0 ) goto __pci_found; - break; - - __pci_found: - pcibios_read_config_dword( pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_0, &ioaddr ); - - ioaddr &= ~3; /* remove I/O space marker in bit 0. */ - - if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue; - - pcibios_read_config_word( pci_bus, pci_device_fn, - PCI_COMMAND, &pci_command ); - if ( !( pci_command & PCI_COMMAND_IO ) ) - { -#ifdef HP100_DEBUG - printk( "hp100: %s: PCI I/O Bit has not been set. Setting...\n", dev->name ); -#endif - pci_command |= PCI_COMMAND_IO; - pcibios_write_config_word( pci_bus, pci_device_fn, - PCI_COMMAND, pci_command ); - } - if ( !( pci_command & PCI_COMMAND_MASTER ) ) - { -#ifdef HP100_DEBUG - printk( "hp100: %s: PCI Master Bit has not been set. Setting...\n", dev->name ); -#endif - pci_command |= PCI_COMMAND_MASTER; - pcibios_write_config_word( pci_bus, pci_device_fn, - PCI_COMMAND, pci_command ); - } -#ifdef HP100_DEBUG - printk( "hp100: %s: PCI adapter found at 0x%x\n", dev->name, ioaddr ); -#endif - if ( hp100_probe1( dev, ioaddr, HP100_BUS_PCI, pci_bus, pci_device_fn ) == 0 ) - return 0; - } -#endif } if ( pci_start_index > 0 ) return -ENODEV; #endif /* CONFIG_PCI */ @@ -498,33 +417,21 @@ for ( ioaddr = 0x1c38; EISA_bus && ioaddr < 0x10000; ioaddr += 0x400 ) { if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue; -#ifdef LINUX_2_1 if ( hp100_probe1( dev, ioaddr, HP100_BUS_EISA, NULL ) == 0 ) return 0; -#else - if ( hp100_probe1( dev, ioaddr, HP100_BUS_EISA, 0, 0 ) == 0 ) return 0; -#endif } /* Third Probe all ISA possible port regions */ for ( ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20 ) { if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue; -#ifdef LINUX_2_1 if ( hp100_probe1( dev, ioaddr, HP100_BUS_ISA, NULL ) == 0 ) return 0; -#else - if ( hp100_probe1( dev, ioaddr, HP100_BUS_ISA, 0, 0 ) == 0 ) return 0; -#endif } return -ENODEV; } -#ifdef LINUX_2_1 static int __init hp100_probe1( struct net_device *dev, int ioaddr, u_char bus, struct pci_dev *pci_dev ) -#else -static int __init hp100_probe1( struct net_device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn ) -#endif { int i; @@ -549,7 +456,7 @@ #ifdef HP100_DEBUG printk( "hp100_probe1: %s: dev == NULL ?\n", dev->name ); #endif - return EIO; + return -EIO; } if ( hp100_inw( HW_ID ) != HP100_HW_ID_CASCADE ) @@ -799,12 +706,7 @@ lp->chip = chip; lp->mode = local_mode; lp->bus = bus; -#ifdef LINUX_2_1 lp->pci_dev = pci_dev; -#else - lp->pci_bus = pci_bus; - lp->pci_device_fn = pci_device_fn; -#endif lp->priority_tx = hp100_priority_tx; lp->rx_ratio = hp100_rx_ratio; lp->mem_ptr_phys = mem_ptr_phys; @@ -836,18 +738,14 @@ dev->set_multicast_list = &hp100_set_multicast_list; /* Ask the card for which IRQ line it is configured */ -#ifdef LINUX_2_1 if ( bus == HP100_BUS_PCI ) { dev->irq = pci_dev->irq; } else { -#endif hp100_page( HW_MAP ); dev->irq = hp100_inb( IRQ_CHANNEL ) & HP100_IRQMASK; if ( dev->irq == 2 ) dev->irq = 9; -#ifdef LINUX_2_1 } -#endif if(lp->mode==1) /* busmaster */ dev->dma=4; @@ -1648,9 +1546,6 @@ if ( skb==NULL ) { -#ifndef LINUX_2_1 - dev_tint( dev ); -#endif return 0; } @@ -1754,9 +1649,7 @@ /* Update statistics */ lp->stats.tx_packets++; -#ifdef LINUX_2_1 lp->stats.tx_bytes += skb->len; -#endif dev->trans_start = jiffies; return 0; @@ -1799,11 +1692,7 @@ hp100_inb(TX_PDL), donecount); #endif -#ifdef LINUX_2_1 dev_kfree_skb_any( lp->txrhead->skb ); -#else - dev_kfree_skb_any( lp->txrhead->skb, FREE_WRITE ); -#endif lp->txrhead->skb=(void *)NULL; lp->txrhead=lp->txrhead->next; lp->txrcommit--; @@ -1826,9 +1715,6 @@ if ( skb==NULL ) { -#ifndef LINUX_2_1 - dev_tint( dev ); -#endif return 0; } @@ -1953,17 +1839,11 @@ hp100_outb( HP100_TX_CMD | HP100_SET_LB, OPTION_MSW ); /* send packet */ lp->stats.tx_packets++; -#ifdef LINUX_2_1 lp->stats.tx_bytes += skb->len; -#endif dev->trans_start=jiffies; hp100_ints_on(); -#ifdef LINUX_2_1 dev_kfree_skb_any( skb ); -#else - dev_kfree_skb_any( skb, FREE_WRITE ); -#endif #ifdef HP100_DEBUG_TX printk( "hp100: %s: start_xmit: end\n", dev->name ); @@ -2071,9 +1951,7 @@ netif_rx( skb ); lp->stats.rx_packets++; -#ifdef LINUX_2_1 lp->stats.rx_bytes += skb->len; -#endif #ifdef HP100_DEBUG_RX printk( "hp100: %s: rx: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", @@ -2180,9 +2058,7 @@ netif_rx( ptr->skb ); /* Up and away... */ lp->stats.rx_packets++; -#ifdef LINUX_2_1 lp->stats.rx_bytes += ptr->skb->len; -#endif } switch ( header & 0x00070000 ) { @@ -2197,11 +2073,7 @@ printk("hp100: %s: rx_bm: Received bad packet (length=%d)\n",dev->name,pkt_len); #endif if(ptr->skb!=NULL) -#ifdef LINUX_2_1 dev_kfree_skb_any( ptr->skb ); -#else - dev_kfree_skb_any( ptr->skb, FREE_READ ); -#endif lp->stats.rx_errors++; } @@ -3119,16 +2991,12 @@ /* Parameters set by insmod */ int hp100_port[5] = { 0, -1, -1, -1, -1 }; -#ifdef LINUX_2_1 MODULE_PARM(hp100_port, "1-5i"); -#endif /* Allocate 5 string of length IFNAMSIZ, one string for each device */ char hp100_name[5][IFNAMSIZ] = { "", "", "", "", "" }; -#ifdef LINUX_2_1 /* Allow insmod to write those 5 strings individually */ MODULE_PARM(hp100_name, "1-5c" __MODULE_STRING(IFNAMSIZ)); -#endif /* List of devices */ static struct net_device *hp100_devlist[5] = { NULL, NULL, NULL, NULL, NULL }; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/hplance.c linux/drivers/net/hplance.c --- v2.4.0-test1/linux/drivers/net/hplance.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/hplance.c Mon Jun 19 13:30:58 2000 @@ -93,7 +93,7 @@ } /* OK, return success, or ENODEV if we didn't find any cards */ if (!cards) - return ENODEV; + return -ENODEV; return 0; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/ibmlana.c linux/drivers/net/ibmlana.c --- v2.4.0-test1/linux/drivers/net/ibmlana.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/ibmlana.c Mon Jun 19 13:30:58 2000 @@ -0,0 +1,1260 @@ +/* +net-3-driver for the IBM LAN Adapter/A + +This is an extension to the Linux operating system, and is covered by the +same Gnu Public License that covers that work. + +Copyright 1999 by Alfred Arnold (alfred@ccac.rwth-aachen.de, aarnold@elsa.de) + +This driver is based both on the SK_MCA driver, which is itself based on the +SK_G16 and 3C523 driver. + +paper sources: + 'PC Hardware: Aufbau, Funktionsweise, Programmierung' by + Hans-Peter Messmer for the basic Microchannel stuff + + 'Linux Geraetetreiber' by Allesandro Rubini, Kalle Dalheimer + for help on Ethernet driver programming + + 'DP83934CVUL-20/25 MHz SONIC-T Ethernet Controller Datasheet' by National + Semiconductor for info on the MAC chip + + 'LAN Technical Reference Ethernet Adapter Interface Version 1 Release 1.0 + Document Number SC30-3661-00' by IBM for info on the adapter itself + + Also see http://www.natsemi.com/ + +special acknowledgements to: + - Bob Eager for helping me out with documentation from IBM + - Jim Shorney for his endless patience with me while I was using + him as a beta tester to trace down the address filter bug ;-) + + Missing things: + + -> set debug level via ioctl instead of compile-time switches + -> I didn't follow the development of the 2.1.x kernels, so my + assumptions about which things changed with which kernel version + are probably nonsense + +History: + Nov 6th, 1999 + startup from SK_MCA driver + Dec 6th, 1999 + finally got docs about the card. A big thank you to Bob Eager! + Dec 12th, 1999 + first packet received + Dec 13th, 1999 + recv queue done, tcpdump works + Dec 15th, 1999 + transmission part works + Dec 28th, 1999 + added usage of the isa_functions for Linux 2.3 . Things should + still work with 2.0.x.... + Jan 28th, 2000 + in Linux 2.2.13, the version.h file mysteriously didn't get + included. Added a workaround for this. Futhermore, it now + not only compiles as a modules ;-) + Jan 30th, 2000 + newer kernels automatically probe more than one board, so the + 'startslot' as a variable is also needed here + Apr 12th, 2000 + the interrupt mask register is not set 'hard' instead of individually + setting registers, since this seems to set bits that shouldn't be + set + May 21st, 2000 + reset interrupt status immediately after CAM load + add a recovery delay after releasing the chip's reset line + May 24th, 2000 + finally found the bug in the address filter setup - damned signed + chars! + June 1st, 2000 + corrected version codes, added support for the latest 2.3 changes + + *************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef MODULE +#include +#endif + +#include +#include +#include + +#define _IBM_LANA_DRIVER_ +#include "ibmlana.h" + +#undef DEBUG + +/* ------------------------------------------------------------------------ + * global static data - not more since we can handle multiple boards and + * have to pack all state info into the device struct! + * ------------------------------------------------------------------------ */ + +static char *MediaNames[Media_Count] = + { "10BaseT", "10Base5", "Unknown", "10Base2" }; + +/* ------------------------------------------------------------------------ + * private subfunctions + * ------------------------------------------------------------------------ */ + +#ifdef DEBUG + /* dump all registers */ + +static void dumpregs(struct IBMLANA_NETDEV *dev) +{ + int z; + + for (z = 0; z < 160; z += 2) { + if (!(z & 15)) + printk("REGS: %04x:", z); + printk(" %04x", inw(dev->base_addr + z)); + if ((z & 15) == 14) + printk("\n"); + } +} + +/* dump parts of shared memory - only needed during debugging */ + +static void dumpmem(struct IBMLANA_NETDEV *dev, u32 start, u32 len) +{ + int z; + + printk("Address %04x:\n", start); + for (z = 0; z < len; z++) { + if ((z & 15) == 0) + printk("%04x:", z); + printk(" %02x", IBMLANA_READB(dev->mem_start + start + z)); + if ((z & 15) == 15) + printk("\n"); + } + if ((z & 15) != 0) + printk("\n"); +} + +/* print exact time - ditto */ + +static void PrTime(void) +{ + struct timeval tv; + + do_gettimeofday(&tv); + printk("%9d:%06d: ", (int) tv.tv_sec, (int) tv.tv_usec); +} +#endif /* DEBUG */ + +/* deduce resources out of POS registers */ + +static void getaddrs(int slot, int *base, int *memlen, int *iobase, + int *irq, ibmlana_medium * medium) +{ + u_char pos0, pos1; + + pos0 = mca_read_stored_pos(slot, 2); + pos1 = mca_read_stored_pos(slot, 3); + + *base = 0xc0000 + ((pos1 & 0xf0) << 9); + *memlen = (pos1 & 0x01) ? 0x8000 : 0x4000; + *iobase = (pos0 & 0xe0) << 7; + switch (pos0 & 0x06) { + case 0: + *irq = 5; + break; + case 2: + *irq = 15; + break; + case 4: + *irq = 10; + break; + case 6: + *irq = 11; + break; + } + *medium = (pos0 & 0x18) >> 3; +} + +/* wait on register value with mask and timeout */ + +static int wait_timeout(struct IBMLANA_NETDEV *dev, int regoffs, u16 mask, + u16 value, int timeout) +{ + unsigned long fin = jiffies + timeout; + + while (jiffies != fin) + if ((inw(dev->base_addr + regoffs) & mask) == value) + return 1; + + return 0; +} + + +/* reset the whole board */ + +static void ResetBoard(struct IBMLANA_NETDEV *dev) +{ + unsigned char bcmval; + + /* read original board control value */ + + bcmval = inb(dev->base_addr + BCMREG); + + /* set reset bit for a while */ + + bcmval |= BCMREG_RESET; + outb(bcmval, dev->base_addr + BCMREG); + udelay(10); + bcmval &= ~BCMREG_RESET; + outb(bcmval, dev->base_addr + BCMREG); + + /* switch over to RAM again */ + + bcmval |= BCMREG_RAMEN | BCMREG_RAMWIN; + outb(bcmval, dev->base_addr + BCMREG); +} + +/* calculate RAM layout & set up descriptors in RAM */ + +static void InitDscrs(struct IBMLANA_NETDEV *dev) +{ + ibmlana_priv *priv = (ibmlana_priv *) dev->priv; + u32 addr, baddr, raddr; + int z; + tda_t tda; + rda_t rda; + rra_t rra; + + /* initialize RAM */ + + IBMLANA_SETIO(dev->mem_start, 0xaa, + dev->mem_start - dev->mem_start); + + /* setup n TX descriptors - independent of RAM size */ + + priv->tdastart = addr = 0; + priv->txbufstart = baddr = sizeof(tda_t) * TXBUFCNT; + for (z = 0; z < TXBUFCNT; z++) { + tda.status = 0; + tda.config = 0; + tda.length = 0; + tda.fragcount = 1; + tda.startlo = baddr; + tda.starthi = 0; + tda.fraglength = 0; + if (z == TXBUFCNT - 1) + tda.link = priv->tdastart; + else + tda.link = addr + sizeof(tda_t); + tda.link |= 1; + IBMLANA_TOIO(dev->mem_start + addr, &tda, sizeof(tda_t)); + addr += sizeof(tda_t); + baddr += PKTSIZE; + } + + /* calculate how many receive buffers fit into remaining memory */ + + priv->rxbufcnt = (dev->mem_end - dev->mem_start - baddr) / + (sizeof(rra_t) + sizeof(rda_t) + PKTSIZE); + + /* calculate receive addresses */ + + priv->rrastart = raddr = priv->txbufstart + (TXBUFCNT * PKTSIZE); + priv->rdastart = addr = + priv->rrastart + (priv->rxbufcnt * sizeof(rra_t)); + priv->rxbufstart = baddr = + priv->rdastart + (priv->rxbufcnt * sizeof(rda_t)); + for (z = 0; z < priv->rxbufcnt; z++) { + rra.startlo = baddr; + rra.starthi = 0; + rra.cntlo = PKTSIZE >> 1; + rra.cnthi = 0; + IBMLANA_TOIO(dev->mem_start + raddr, &rra, sizeof(rra_t)); + + rda.status = 0; + rda.length = 0; + rda.startlo = 0; + rda.starthi = 0; + rda.seqno = 0; + if (z < priv->rxbufcnt - 1) + rda.link = addr + sizeof(rda_t); + else + rda.link = 1; + rda.inuse = 1; + IBMLANA_TOIO(dev->mem_start + addr, &rda, sizeof(rda_t)); + + baddr += PKTSIZE; + raddr += sizeof(rra_t); + addr += sizeof(rda_t); + } + + /* initialize current pointers */ + + priv->nextrxdescr = 0; + priv->lastrxdescr = priv->rxbufcnt - 1; + priv->nexttxdescr = 0; + priv->currtxdescr = 0; + priv->txusedcnt = 0; + memset(priv->txused, 0, sizeof(priv->txused)); +} + +/* set up Rx + Tx descriptors in SONIC */ + +static int InitSONIC(struct IBMLANA_NETDEV *dev) +{ + ibmlana_priv *priv = (ibmlana_priv *) dev->priv; + + /* set up start & end of resource area */ + + outw(0, SONIC_URRA); + outw(priv->rrastart, dev->base_addr + SONIC_RSA); + outw(priv->rrastart + (priv->rxbufcnt * sizeof(rra_t)), + dev->base_addr + SONIC_REA); + outw(priv->rrastart, dev->base_addr + SONIC_RRP); + outw(priv->rrastart, dev->base_addr + SONIC_RWP); + + /* set EOBC so that only one packet goes into one buffer */ + + outw((PKTSIZE - 4) >> 1, dev->base_addr + SONIC_EOBC); + + /* let SONIC read the first RRA descriptor */ + + outw(CMDREG_RRRA, dev->base_addr + SONIC_CMDREG); + if (!wait_timeout(dev, SONIC_CMDREG, CMDREG_RRRA, 0, 2)) { + printk + ("%s: SONIC did not respond on RRRA command - giving up.", + dev->name); + return 0; + } + + /* point SONIC to the first RDA */ + + outw(0, dev->base_addr + SONIC_URDA); + outw(priv->rdastart, dev->base_addr + SONIC_CRDA); + + /* set upper half of TDA address */ + + outw(0, dev->base_addr + SONIC_UTDA); + + return 1; +} + +/* stop SONIC so we can reinitialize it */ + +static void StopSONIC(struct IBMLANA_NETDEV *dev) +{ + /* disable interrupts */ + + outb(inb(dev->base_addr + BCMREG) & (~BCMREG_IEN), + dev->base_addr + BCMREG); + outb(0, dev->base_addr + SONIC_IMREG); + + /* reset the SONIC */ + + outw(CMDREG_RST, dev->base_addr + SONIC_CMDREG); + udelay(10); + outw(CMDREG_RST, dev->base_addr + SONIC_CMDREG); +} + +/* initialize card and SONIC for proper operation */ + +static void putcam(camentry_t * cams, int *camcnt, char *addr) +{ + camentry_t *pcam = cams + (*camcnt); + u8 *uaddr = (u8 *) addr; + + pcam->index = *camcnt; + pcam->addr0 = (((u16) uaddr[1]) << 8) | uaddr[0]; + pcam->addr1 = (((u16) uaddr[3]) << 8) | uaddr[2]; + pcam->addr2 = (((u16) uaddr[5]) << 8) | uaddr[4]; + (*camcnt)++; +} + +static void InitBoard(struct IBMLANA_NETDEV *dev) +{ + int camcnt; + camentry_t cams[16]; + u32 cammask; + struct dev_mc_list *mcptr; + u16 rcrval; + + /* reset the SONIC */ + + outw(CMDREG_RST, dev->base_addr + SONIC_CMDREG); + udelay(10); + + /* clear all spurious interrupts */ + + outw(inw(dev->base_addr + SONIC_ISREG), + dev->base_addr + SONIC_ISREG); + + /* set up the SONIC's bus interface - constant for this adapter - + must be done while the SONIC is in reset */ + + outw(DCREG_USR1 | DCREG_USR0 | DCREG_WC1 | DCREG_DW32, + dev->base_addr + SONIC_DCREG); + outw(0, dev->base_addr + SONIC_DCREG2); + + /* remove reset form the SONIC */ + + outw(0, dev->base_addr + SONIC_CMDREG); + udelay(10); + + /* data sheet requires URRA to be programmed before setting up the CAM contents */ + + outw(0, dev->base_addr + SONIC_URRA); + + /* program the CAM entry 0 to the device address */ + + camcnt = 0; + putcam(cams, &camcnt, dev->dev_addr); + + /* start putting the multicast addresses into the CAM list. Stop if + it is full. */ + + for (mcptr = dev->mc_list; mcptr != NULL; mcptr = mcptr->next) { + putcam(cams, &camcnt, mcptr->dmi_addr); + if (camcnt == 16) + break; + } + + /* calculate CAM mask */ + + cammask = (1 << camcnt) - 1; + + /* feed CDA into SONIC, initialize RCR value (always get broadcasts) */ + + IBMLANA_TOIO(dev->mem_start, cams, sizeof(camentry_t) * camcnt); + IBMLANA_TOIO(dev->mem_start + (sizeof(camentry_t) * camcnt), + &cammask, sizeof(cammask)); + +#ifdef DEBUG + printk("CAM setup:\n"); + dumpmem(dev, 0, sizeof(camentry_t) * camcnt + sizeof(cammask)); +#endif + + outw(0, dev->base_addr + SONIC_CAMPTR); + outw(camcnt, dev->base_addr + SONIC_CAMCNT); + outw(CMDREG_LCAM, dev->base_addr + SONIC_CMDREG); + if (!wait_timeout(dev, SONIC_CMDREG, CMDREG_LCAM, 0, 2)) { + printk + ("%s:SONIC did not respond on LCAM command - giving up.", + dev->name); + return; + } else { + /* clear interrupt condition */ + + outw(ISREG_LCD, dev->base_addr + SONIC_ISREG); + +#ifdef DEBUG + printk("Loading CAM done, address pointers %04x:%04x\n", + inw(dev->base_addr + SONIC_URRA), + inw(dev->base_addr + SONIC_CAMPTR)); + { + int z; + + printk("\n-->CAM: PTR %04x CNT %04x\n", + inw(dev->base_addr + SONIC_CAMPTR), + inw(dev->base_addr + SONIC_CAMCNT)); + outw(CMDREG_RST, dev->base_addr + SONIC_CMDREG); + for (z = 0; z < camcnt; z++) { + outw(z, dev->base_addr + SONIC_CAMEPTR); + printk("Entry %d: %04x %04x %04x\n", z, + inw(dev->base_addr + + SONIC_CAMADDR0), + inw(dev->base_addr + + SONIC_CAMADDR1), + inw(dev->base_addr + + SONIC_CAMADDR2)); + } + outw(0, dev->base_addr + SONIC_CMDREG); + } +#endif + } + + rcrval = RCREG_BRD | RCREG_LB_NONE; + + /* if still multicast addresses left or ALLMULTI is set, set the multicast + enable bit */ + + if ((dev->flags & IFF_ALLMULTI) || (mcptr != NULL)) + rcrval |= RCREG_AMC; + + /* promiscous mode ? */ + + if (dev->flags & IFF_PROMISC) + rcrval |= RCREG_PRO; + + /* program receive mode */ + + outw(rcrval, dev->base_addr + SONIC_RCREG); +#ifdef DEBUG + printk("\nRCRVAL: %04x\n", rcrval); +#endif + + /* set up descriptors in shared memory + feed them into SONIC registers */ + + InitDscrs(dev); + if (!InitSONIC(dev)) + return; + + /* reset all pending interrupts */ + + outw(0xffff, dev->base_addr + SONIC_ISREG); + + /* enable transmitter + receiver interrupts */ + + outw(CMDREG_RXEN, dev->base_addr + SONIC_CMDREG); + outw(IMREG_PRXEN | IMREG_RBEEN | IMREG_PTXEN | IMREG_TXEREN, + dev->base_addr + SONIC_IMREG); + + /* turn on card interrupts */ + + outb(inb(dev->base_addr + BCMREG) | BCMREG_IEN, + dev->base_addr + BCMREG); + +#ifdef DEBUG + printk("Register dump after initialization:\n"); + dumpregs(dev); +#endif +} + +/* start transmission of a descriptor */ + +static void StartTx(struct IBMLANA_NETDEV *dev, int descr) +{ + ibmlana_priv *priv = (ibmlana_priv *) dev->priv; + int addr; + + addr = priv->tdastart + (descr * sizeof(tda_t)); + + /* put descriptor address into SONIC */ + + outw(addr, dev->base_addr + SONIC_CTDA); + + /* trigger transmitter */ + + priv->currtxdescr = descr; + outw(CMDREG_TXP, dev->base_addr + SONIC_CMDREG); +} + +/* ------------------------------------------------------------------------ + * interrupt handler(s) + * ------------------------------------------------------------------------ */ + +/* receive buffer area exhausted */ + +static void irqrbe_handler(struct IBMLANA_NETDEV *dev) +{ + ibmlana_priv *priv = (ibmlana_priv *) dev->priv; + + /* point the SONIC back to the RRA start */ + + outw(priv->rrastart, dev->base_addr + SONIC_RRP); + outw(priv->rrastart, dev->base_addr + SONIC_RWP); +} + +/* receive interrupt */ + +static void irqrx_handler(struct IBMLANA_NETDEV *dev) +{ + ibmlana_priv *priv = (ibmlana_priv *) dev->priv; + rda_t rda; + u32 rdaaddr, lrdaaddr; + + /* loop until ... */ + + while (1) { + /* read descriptor that was next to be filled by SONIC */ + + rdaaddr = + priv->rdastart + (priv->nextrxdescr * sizeof(rda_t)); + lrdaaddr = + priv->rdastart + (priv->lastrxdescr * sizeof(rda_t)); + IBMLANA_FROMIO(&rda, dev->mem_start + rdaaddr, + sizeof(rda_t)); + + /* iron out upper word halves of fields we use - SONIC will duplicate + bits 0..15 to 16..31 */ + + rda.status &= 0xffff; + rda.length &= 0xffff; + rda.startlo &= 0xffff; + + /* stop if the SONIC still owns it, i.e. there is no data for us */ + + if (rda.inuse) + break; + + /* good packet? */ + + else if (rda.status & RCREG_PRX) { + struct sk_buff *skb; + + /* fetch buffer */ + + skb = dev_alloc_skb(rda.length + 2); + if (skb == NULL) + priv->stat.rx_dropped++; + else { + /* copy out data */ + + IBMLANA_FROMIO(skb_put(skb, rda.length), + dev->mem_start + + rda.startlo, rda.length); + + /* set up skb fields */ + + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + skb->ip_summed = CHECKSUM_NONE; + + /* bookkeeping */ + + priv->stat.rx_packets++; +#if (LINUX_VERSION_CODE >= 0x20119) /* byte counters for kernel >= 2.1.25 */ + priv->stat.rx_bytes += rda.length; +#endif + + /* pass to the upper layers */ + + netif_rx(skb); + } + } + + /* otherwise check error status bits and increase statistics */ + + else { + priv->stat.rx_errors++; + + if (rda.status & RCREG_FAER) + priv->stat.rx_frame_errors++; + + if (rda.status & RCREG_CRCR) + priv->stat.rx_crc_errors++; + } + + /* descriptor processed, will become new last descriptor in queue */ + + rda.link = 1; + rda.inuse = 1; + IBMLANA_TOIO(dev->mem_start + rdaaddr, &rda, + sizeof(rda_t)); + + /* set up link and EOL = 0 in currently last descriptor. Only write + the link field since the SONIC may currently already access the + other fields. */ + + IBMLANA_TOIO(dev->mem_start + lrdaaddr + 20, &rdaaddr, 4); + + /* advance indices */ + + priv->lastrxdescr = priv->nextrxdescr; + if ((++priv->nextrxdescr) >= priv->rxbufcnt) + priv->nextrxdescr = 0; + } +} + +/* transmit interrupt */ + +static void irqtx_handler(struct IBMLANA_NETDEV *dev) +{ + ibmlana_priv *priv = (ibmlana_priv *) dev->priv; + tda_t tda; + + /* fetch descriptor (we forgot the size ;-) */ + + IBMLANA_FROMIO(&tda, + dev->mem_start + priv->tdastart + + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t)); + + /* update statistics */ + + priv->stat.tx_packets++; +#if (LINUX_VERSION_CODE >= 0x020119) + priv->stat.tx_bytes += tda.length; +#endif + + /* update our pointers */ + + priv->txused[priv->currtxdescr] = 0; + priv->txusedcnt--; + + /* if there are more descriptors present in RAM, start them */ + + if (priv->txusedcnt > 0) + StartTx(dev, (priv->currtxdescr + 1) % TXBUFCNT); + + /* tell the upper layer we can go on transmitting */ + +#if LINUX_VERSION_CODE >= 0x02032a + netif_wake_queue(dev); +#else + dev->tbusy = 0; + mark_bh(NET_BH); +#endif +} + +static void irqtxerr_handler(struct IBMLANA_NETDEV *dev) +{ + ibmlana_priv *priv = (ibmlana_priv *) dev->priv; + tda_t tda; + + /* fetch descriptor to check status */ + + IBMLANA_FROMIO(&tda, + dev->mem_start + priv->tdastart + + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t)); + + /* update statistics */ + + priv->stat.tx_errors++; + if (tda.status & (TCREG_NCRS | TCREG_CRSL)) + priv->stat.tx_carrier_errors++; + if (tda.status & TCREG_EXC) + priv->stat.tx_aborted_errors++; + if (tda.status & TCREG_OWC) + priv->stat.tx_window_errors++; + if (tda.status & TCREG_FU) + priv->stat.tx_fifo_errors++; + + /* update our pointers */ + + priv->txused[priv->currtxdescr] = 0; + priv->txusedcnt--; + + /* if there are more descriptors present in RAM, start them */ + + if (priv->txusedcnt > 0) + StartTx(dev, (priv->currtxdescr + 1) % TXBUFCNT); + + /* tell the upper layer we can go on transmitting */ + +#if LINUX_VERSION_CODE >= 0x02032a + netif_wake_queue(dev); +#else + dev->tbusy = 0; + mark_bh(NET_BH); +#endif +} + +/* general interrupt entry */ + +static void irq_handler(int irq, void *device, struct pt_regs *regs) +{ + struct IBMLANA_NETDEV *dev = (struct IBMLANA_NETDEV *) device; + u16 ival; + + /* in case we're not meant... */ + + if (!(inb(dev->base_addr + BCMREG) & BCMREG_IPEND)) + return; + +#if (LINUX_VERSION_CODE >= 0x02032a) +#if 0 + set_bit(LINK_STATE_RXSEM, &dev->state); +#endif +#else + dev->interrupt = 1; +#endif + + /* loop through the interrupt bits until everything is clear */ + + while (1) { + ival = inw(dev->base_addr + SONIC_ISREG); + + if (ival & ISREG_RBE) { + irqrbe_handler(dev); + outw(ISREG_RBE, dev->base_addr + SONIC_ISREG); + } + + if (ival & ISREG_PKTRX) { + irqrx_handler(dev); + outw(ISREG_PKTRX, dev->base_addr + SONIC_ISREG); + } + + if (ival & ISREG_TXDN) { + irqtx_handler(dev); + outw(ISREG_TXDN, dev->base_addr + SONIC_ISREG); + } + + if (ival & ISREG_TXER) { + irqtxerr_handler(dev); + outw(ISREG_TXER, dev->base_addr + SONIC_ISREG); + } + + break; + } + +#if (LINUX_VERSION_CODE >= 0x02032a) +#if 0 + clear_bit(LINK_STATE_RXSEM, &dev->state); +#endif +#else + dev->interrupt = 0; +#endif +} + +/* ------------------------------------------------------------------------ + * driver methods + * ------------------------------------------------------------------------ */ + +/* MCA info */ + +static int ibmlana_getinfo(char *buf, int slot, void *d) +{ + int len = 0, i; + struct IBMLANA_NETDEV *dev = (struct IBMLANA_NETDEV *) d; + ibmlana_priv *priv; + + /* can't say anything about an uninitialized device... */ + + if (dev == NULL) + return len; + if (dev->priv == NULL) + return len; + priv = (ibmlana_priv *) dev->priv; + + /* print info */ + + len += sprintf(buf + len, "IRQ: %d\n", priv->realirq); + len += sprintf(buf + len, "I/O: %#lx\n", dev->base_addr); + len += sprintf(buf + len, "Memory: %#lx-%#lx\n", dev->mem_start, + dev->mem_end - 1); + len += + sprintf(buf + len, "Transceiver: %s\n", + MediaNames[priv->medium]); + len += sprintf(buf + len, "Device: %s\n", dev->name); + len += sprintf(buf + len, "MAC address:"); + for (i = 0; i < 6; i++) + len += sprintf(buf + len, " %02x", dev->dev_addr[i]); + buf[len++] = '\n'; + buf[len] = 0; + + return len; +} + +/* open driver. Means also initialization and start of LANCE */ + +static int ibmlana_open(struct IBMLANA_NETDEV *dev) +{ + int result; + ibmlana_priv *priv = (ibmlana_priv *) dev->priv; + + /* register resources - only necessary for IRQ */ + + result = + request_irq(priv->realirq, irq_handler, + SA_SHIRQ | SA_SAMPLE_RANDOM, "ibm_lana", dev); + if (result != 0) { + printk("%s: failed to register irq %d\n", dev->name, + dev->irq); + return result; + } + dev->irq = priv->realirq; + + /* set up the card and SONIC */ + + InitBoard(dev); + + /* initialize operational flags */ + +#if (LINUX_VERSION_CODE >= 0x02032a) + netif_start_queue(dev); +#else + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; +#endif + +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + + return 0; +} + +/* close driver. Shut down board and free allocated resources */ + +static int ibmlana_close(struct IBMLANA_NETDEV *dev) +{ + /* turn off board */ + + /* release resources */ + if (dev->irq != 0) + free_irq(dev->irq, dev); + dev->irq = 0; + +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + + return 0; +} + +/* transmit a block. */ + +static int ibmlana_tx(struct sk_buff *skb, struct IBMLANA_NETDEV *dev) +{ + ibmlana_priv *priv = (ibmlana_priv *) dev->priv; + int retval = 0, tmplen, addr; + unsigned long flags; + tda_t tda; + int baddr; + + /* if we get called with a NULL descriptor, the Ethernet layer thinks + our card is stuck an we should reset it. We'll do this completely: */ + + if (skb == NULL) { + printk("%s: Resetting SONIC\n", dev->name); + StopSONIC(dev); + InitBoard(dev); + return 0; /* don't try to free the block here ;-) */ + } + + /* find out if there are free slots for a frame to transmit. If not, + the upper layer is in deep desperation and we simply ignore the frame. */ + + if (priv->txusedcnt >= TXBUFCNT) { + retval = -EIO; + priv->stat.tx_dropped++; + goto tx_done; + } + + /* copy the frame data into the next free transmit buffer - fillup missing */ + + tmplen = skb->len; + if (tmplen < 60) + tmplen = 60; + baddr = priv->txbufstart + (priv->nexttxdescr * PKTSIZE); + IBMLANA_TOIO(dev->mem_start + baddr, skb->data, skb->len); + + /* copy filler into RAM - in case we're filling up... + we're filling a bit more than necessary, but that doesn't harm + since the buffer is far larger... + Sorry Linus for the filler string but I couldn't resist ;-) */ + + if (tmplen > skb->len) { + char *fill = "NetBSD is a nice OS too! "; + unsigned int destoffs = skb->len, l = strlen(fill); + + while (destoffs < tmplen) { + IBMLANA_TOIO(dev->mem_start + baddr + destoffs, + fill, l); + destoffs += l; + } + } + + /* set up the new frame descriptor */ + + addr = priv->tdastart + (priv->nexttxdescr * sizeof(tda_t)); + IBMLANA_FROMIO(&tda, dev->mem_start + addr, sizeof(tda_t)); + tda.length = tda.fraglength = tmplen; + IBMLANA_TOIO(dev->mem_start + addr, &tda, sizeof(tda_t)); + + /* if there were no active descriptors, trigger the SONIC */ + + save_flags(flags); + cli(); + + priv->txusedcnt++; + priv->txused[priv->nexttxdescr] = 1; + + /* are all transmission slots used up ? */ + + if (priv->txusedcnt >= TXBUFCNT) +#if (LINUX_VERSION_CODE >= 0x02032a) + netif_stop_queue(dev); +#else + dev->tbusy = 1; +#endif + + if (priv->txusedcnt == 1) + StartTx(dev, priv->nexttxdescr); + priv->nexttxdescr = (priv->nexttxdescr + 1) % TXBUFCNT; + + restore_flags(flags); + + tx_done: + + /* When did that change exactly ? */ + +#if (LINUX_VERSION_CODE >= 0x20200) + dev_kfree_skb(skb); +#else + dev_kfree_skb(skb, FREE_WRITE); +#endif + return retval; +} + +/* return pointer to Ethernet statistics */ + +static struct enet_statistics *ibmlana_stats(struct IBMLANA_NETDEV *dev) +{ + ibmlana_priv *priv = (ibmlana_priv *) dev->priv; + + return &(priv->stat); +} + +/* we don't support runtime reconfiguration, since am MCA card can + be unambigously identified by its POS registers. */ + +static int ibmlana_config(struct IBMLANA_NETDEV *dev, struct ifmap *map) +{ + return 0; +} + +/* switch receiver mode. */ + +static void ibmlana_set_multicast_list(struct IBMLANA_NETDEV *dev) +{ + /* first stop the SONIC... */ + + StopSONIC(dev); + + /* ...then reinit it with the new flags */ + + InitBoard(dev); +} + +/* ------------------------------------------------------------------------ + * hardware check + * ------------------------------------------------------------------------ */ + +static int startslot; /* counts through slots when probing multiple devices */ + +int ibmlana_probe(struct IBMLANA_NETDEV *dev) +{ + int force_detect = 0; + int slot, z; + int base = 0, irq = 0, iobase = 0, memlen = 0; + ibmlana_priv *priv; + ibmlana_medium medium; + + /* can't work without an MCA bus ;-) */ + + if (MCA_bus == 0) + return ENODEV; + + /* start address of 1 --> forced detection */ + + if (dev->mem_start == 1) + force_detect = 1; + + /* search through slots */ + + if (dev != NULL) { + base = dev->mem_start; + irq = dev->irq; + } + slot = mca_find_adapter(IBM_LANA_ID, startslot); + + while (slot != -1) { + /* deduce card addresses */ + + getaddrs(slot, &base, &memlen, &iobase, &irq, &medium); + +#if (LINUX_VERSION_CODE >= 0x20300) + /* slot already in use ? */ + + if (mca_is_adapter_used(slot)) { + slot = mca_find_adapter(IBM_LANA_ID, slot + 1); + continue; + } +#endif + + /* were we looking for something different ? */ + + if ((dev->irq != 0) || (dev->mem_start != 0)) { + if ((dev->irq != 0) && (dev->irq != irq)) { + slot = + mca_find_adapter(IBM_LANA_ID, + slot + 1); + continue; + } + if ((dev->mem_start != 0) + && (dev->mem_start != base)) { + slot = + mca_find_adapter(IBM_LANA_ID, + slot + 1); + continue; + } + } + + /* found something that matches */ + + break; + } + + /* nothing found ? */ + + if (slot == -1) + return ((base != 0) || (irq != 0)) ? ENXIO : ENODEV; + + /* announce success */ + printk("%s: IBM LAN Adapter/A found in slot %d\n", dev->name, + slot + 1); + + /* try to obtain I/O range */ + if (check_region(iobase, IBM_LANA_IORANGE) < 0) { + printk("cannot allocate I/O range at %#x!\n", iobase); + startslot = slot + 1; + return 0; + } + request_region(iobase, IBM_LANA_IORANGE, "ibm_lana"); + + /* make procfs entries */ + + mca_set_adapter_name(slot, "IBM LAN Adapter/A"); + mca_set_adapter_procfn(slot, (MCA_ProcFn) ibmlana_getinfo, dev); + +#if (LINUX_VERSION_CODE >= 0x20200) + mca_mark_as_used(slot); +#endif + + /* allocate structure */ + + priv = dev->priv = + (ibmlana_priv *) kmalloc(sizeof(ibmlana_priv), GFP_KERNEL); + priv->slot = slot; + priv->realirq = irq; + priv->medium = medium; + memset(&(priv->stat), 0, sizeof(struct enet_statistics)); + + /* set base + irq for this device (irq not allocated so far) */ + + dev->irq = 0; + dev->mem_start = base; + dev->mem_end = base + memlen; + dev->base_addr = iobase; + + /* set methods */ + + dev->open = ibmlana_open; + dev->stop = ibmlana_close; + dev->set_config = ibmlana_config; + dev->hard_start_xmit = ibmlana_tx; + dev->do_ioctl = NULL; + dev->get_stats = ibmlana_stats; + dev->set_multicast_list = ibmlana_set_multicast_list; + dev->flags |= IFF_MULTICAST; + + /* generic setup */ + + ether_setup(dev); + + /* copy out MAC address */ + + for (z = 0; z < sizeof(dev->dev_addr); z++) + dev->dev_addr[z] = inb(dev->base_addr + MACADDRPROM + z); + + /* print config */ + + printk("%s: IRQ %d, I/O %#lx, memory %#lx-%#lx, " + "MAC address %02x:%02x:%02x:%02x:%02x:%02x.\n", + dev->name, priv->realirq, dev->base_addr, + dev->mem_start, dev->mem_end - 1, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + printk("%s: %s medium\n", dev->name, MediaNames[priv->medium]); + + /* reset board */ + + ResetBoard(dev); + + /* next probe will start at next slot */ + + startslot = slot + 1; + + return 0; +} + +/* ------------------------------------------------------------------------ + * modularization support + * ------------------------------------------------------------------------ */ + +#ifdef MODULE + +#define DEVMAX 5 + +#if (LINUX_VERSION_CODE >= 0x020363) +static struct IBMLANA_NETDEV moddevs[DEVMAX] = + { {" ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, ibmlana_probe}, +{" ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, ibmlana_probe}, +{" ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, ibmlana_probe}, +{" ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, ibmlana_probe}, +{" ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, ibmlana_probe} +}; +#else +static char NameSpace[8 * DEVMAX]; +static struct IBMLANA_NETDEV moddevs[DEVMAX] = + { {NameSpace + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, ibmlana_probe}, +{NameSpace + 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, ibmlana_probe}, +{NameSpace + 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, ibmlana_probe}, +{NameSpace + 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, ibmlana_probe}, +{NameSpace + 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, ibmlana_probe} +}; +#endif + +int irq = 0; +int io = 0; + +int init_module(void) +{ + int z, res; + + startslot = 0; + for (z = 0; z < DEVMAX; z++) { + strcpy(moddevs[z].name, " "); + res = register_netdev(moddevs + z); + if (res != 0) + return (z > 0) ? 0 : -EIO; + } + + return 0; +} + +void cleanup_module(void) +{ + struct IBMLANA_NETDEV *dev; + ibmlana_priv *priv; + int z; + + if (MOD_IN_USE) { + printk("cannot unload, module in use\n"); + return; + } + + for (z = 0; z < DEVMAX; z++) { + dev = moddevs + z; + if (dev->priv != NULL) { + priv = (ibmlana_priv *) dev->priv; + /*DeinitBoard(dev); */ + if (dev->irq != 0) + free_irq(dev->irq, dev); + dev->irq = 0; + release_region(dev->base_addr, IBM_LANA_IORANGE); + unregister_netdev(dev); +#if (LINUX_VERSION_CODE >= 0x20200) + mca_mark_as_unused(priv->slot); +#endif + mca_set_adapter_name(priv->slot, ""); + mca_set_adapter_procfn(priv->slot, NULL, NULL); + kfree_s(dev->priv, sizeof(ibmlana_priv)); + dev->priv = NULL; + } + } +} +#endif /* MODULE */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/ibmlana.h linux/drivers/net/ibmlana.h --- v2.4.0-test1/linux/drivers/net/ibmlana.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/ibmlana.h Mon Jun 19 13:30:58 2000 @@ -0,0 +1,295 @@ +#ifndef _IBM_LANA_INCLUDE_ +#define _IBM_LANA_INCLUDE_ + +#ifdef _IBM_LANA_DRIVER_ + +/* version-dependent functions/structures */ + +#if LINUX_VERSION_CODE >= 0x020318 +#define IBMLANA_READB(addr) isa_readb(addr) +#define IBMLANA_TOIO(dest, src, len) isa_memcpy_toio(dest, src, len) +#define IBMLANA_FROMIO(dest, src, len) isa_memcpy_fromio(dest, src, len) +#define IBMLANA_SETIO(dest, val, len) isa_memset_io(dest, val, len) +#define IBMLANA_NETDEV net_device +#else +#define IBMLANA_READB(addr) readb(addr) +#define IBMLANA_TOIO(dest, src, len) memcpy_toio(dest, src, len) +#define IBMLANA_FROMIO(dest, src, len) memcpy_fromio(dest, src, len) +#define IBMLANA_SETIO(dest, val, len) memset_io(dest, val, len) +#define IBMLANA_NETDEV device +#endif + +/* maximum packet size */ + +#define PKTSIZE 1524 + +/* number of transmit buffers */ + +#define TXBUFCNT 4 + +/* Adapter ID's */ +#define IBM_LANA_ID 0xffe0 + +/* media enumeration - defined in a way that it fits onto the LAN/A's + POS registers... */ + +typedef enum { Media_10BaseT, Media_10Base5, + Media_Unknown, Media_10Base2, Media_Count +} ibmlana_medium; + +/* private structure */ + +typedef struct { + unsigned int slot; /* MCA-Slot-# */ + struct enet_statistics stat; /* packet statistics */ + int realirq; /* memorizes actual IRQ, even when + currently not allocated */ + ibmlana_medium medium; /* physical cannector */ + u32 tdastart, txbufstart, /* addresses */ + rrastart, rxbufstart, rdastart, rxbufcnt, txusedcnt; + int nextrxdescr, /* next rx descriptor to be used */ + lastrxdescr, /* last free rx descriptor */ + nexttxdescr, /* last tx descriptor to be used */ + currtxdescr, /* tx descriptor currently tx'ed */ + txused[TXBUFCNT]; /* busy flags */ +} ibmlana_priv; + +/* this card uses quite a lot of I/O ports...luckily the MCA bus decodes + a full 64K I/O range... */ + +#define IBM_LANA_IORANGE 0xa0 + +/* Command Register: */ + +#define SONIC_CMDREG 0x00 +#define CMDREG_HTX 0x0001 /* halt transmission */ +#define CMDREG_TXP 0x0002 /* start transmission */ +#define CMDREG_RXDIS 0x0004 /* disable receiver */ +#define CMDREG_RXEN 0x0008 /* enable receiver */ +#define CMDREG_STP 0x0010 /* stop timer */ +#define CMDREG_ST 0x0020 /* start timer */ +#define CMDREG_RST 0x0080 /* software reset */ +#define CMDREG_RRRA 0x0100 /* force SONIC to read first RRA */ +#define CMDREG_LCAM 0x0200 /* force SONIC to read CAM descrs */ + +/* Data Configuration Register */ + +#define SONIC_DCREG 0x02 +#define DCREG_EXBUS 0x8000 /* Extended Bus Mode */ +#define DCREG_LBR 0x2000 /* Latched Bus Retry */ +#define DCREG_PO1 0x1000 /* Programmable Outputs */ +#define DCREG_PO0 0x0800 +#define DCREG_SBUS 0x0400 /* Synchronous Bus Mode */ +#define DCREG_USR1 0x0200 /* User Definable Pins */ +#define DCREG_USR0 0x0100 +#define DCREG_WC0 0x0000 /* 0..3 Wait States */ +#define DCREG_WC1 0x0040 +#define DCREG_WC2 0x0080 +#define DCREG_WC3 0x00c0 +#define DCREG_DW16 0x0000 /* 16 bit Bus Mode */ +#define DCREG_DW32 0x0020 /* 32 bit Bus Mode */ +#define DCREG_BMS 0x0010 /* Block Mode Select */ +#define DCREG_RFT4 0x0000 /* 4/8/16/24 bytes RX Threshold */ +#define DCREG_RFT8 0x0004 +#define DCREG_RFT16 0x0008 +#define DCREG_RFT24 0x000c +#define DCREG_TFT8 0x0000 /* 8/16/24/28 bytes TX Threshold */ +#define DCREG_TFT16 0x0001 +#define DCREG_TFT24 0x0002 +#define DCREG_TFT28 0x0003 + +/* Receive Control Register */ + +#define SONIC_RCREG 0x04 +#define RCREG_ERR 0x8000 /* accept damaged and collided pkts */ +#define RCREG_RNT 0x4000 /* accept packets that are < 64 */ +#define RCREG_BRD 0x2000 /* accept broadcasts */ +#define RCREG_PRO 0x1000 /* promiscous mode */ +#define RCREG_AMC 0x0800 /* accept all multicasts */ +#define RCREG_LB_NONE 0x0000 /* no loopback */ +#define RCREG_LB_MAC 0x0200 /* MAC loopback */ +#define RCREG_LB_ENDEC 0x0400 /* ENDEC loopback */ +#define RCREG_LB_XVR 0x0600 /* Transceiver loopback */ +#define RCREG_MC 0x0100 /* Multicast received */ +#define RCREG_BC 0x0080 /* Broadcast received */ +#define RCREG_LPKT 0x0040 /* last packet in RBA */ +#define RCREG_CRS 0x0020 /* carrier sense present */ +#define RCREG_COL 0x0010 /* recv'd packet with collision */ +#define RCREG_CRCR 0x0008 /* recv'd packet with CRC error */ +#define RCREG_FAER 0x0004 /* recv'd packet with inv. framing */ +#define RCREG_LBK 0x0002 /* recv'd loopback packet */ +#define RCREG_PRX 0x0001 /* recv'd packet is OK */ + +/* Transmit Control Register */ + +#define SONIC_TCREG 0x06 +#define TCREG_PINT 0x8000 /* generate interrupt after TDA read */ +#define TCREG_POWC 0x4000 /* timer start out of window detect */ +#define TCREG_CRCI 0x2000 /* inhibit CRC generation */ +#define TCREG_EXDIS 0x1000 /* disable excessive deferral timer */ +#define TCREG_EXD 0x0400 /* excessive deferral occured */ +#define TCREG_DEF 0x0200 /* single deferral occured */ +#define TCREG_NCRS 0x0100 /* no carrier detected */ +#define TCREG_CRSL 0x0080 /* carrier lost */ +#define TCREG_EXC 0x0040 /* excessive collisions occured */ +#define TCREG_OWC 0x0020 /* out of window collision occured */ +#define TCREG_PMB 0x0008 /* packet monitored bad */ +#define TCREG_FU 0x0004 /* FIFO underrun */ +#define TCREG_BCM 0x0002 /* byte count mismatch of fragments */ +#define TCREG_PTX 0x0001 /* packet transmitted OK */ + +/* Interrupt Mask Register */ + +#define SONIC_IMREG 0x08 +#define IMREG_BREN 0x4000 /* interrupt when bus retry occured */ +#define IMREG_HBLEN 0x2000 /* interrupt when heartbeat lost */ +#define IMREG_LCDEN 0x1000 /* interrupt when CAM loaded */ +#define IMREG_PINTEN 0x0800 /* interrupt when PINT in TDA set */ +#define IMREG_PRXEN 0x0400 /* interrupt when packet received */ +#define IMREG_PTXEN 0x0200 /* interrupt when packet was sent */ +#define IMREG_TXEREN 0x0100 /* interrupt when send failed */ +#define IMREG_TCEN 0x0080 /* interrupt when timer completed */ +#define IMREG_RDEEN 0x0040 /* interrupt when RDA exhausted */ +#define IMREG_RBEEN 0x0020 /* interrupt when RBA exhausted */ +#define IMREG_RBAEEN 0x0010 /* interrupt when RBA too short */ +#define IMREG_CRCEN 0x0008 /* interrupt when CRC counter rolls */ +#define IMREG_FAEEN 0x0004 /* interrupt when FAE counter rolls */ +#define IMREG_MPEN 0x0002 /* interrupt when MP counter rolls */ +#define IMREG_RFOEN 0x0001 /* interrupt when Rx FIFO overflows */ + +/* Interrupt Status Register */ + +#define SONIC_ISREG 0x0a +#define ISREG_BR 0x4000 /* bus retry occured */ +#define ISREG_HBL 0x2000 /* heartbeat lost */ +#define ISREG_LCD 0x1000 /* CAM loaded */ +#define ISREG_PINT 0x0800 /* PINT in TDA set */ +#define ISREG_PKTRX 0x0400 /* packet received */ +#define ISREG_TXDN 0x0200 /* packet was sent */ +#define ISREG_TXER 0x0100 /* send failed */ +#define ISREG_TC 0x0080 /* timer completed */ +#define ISREG_RDE 0x0040 /* RDA exhausted */ +#define ISREG_RBE 0x0020 /* RBA exhausted */ +#define ISREG_RBAE 0x0010 /* RBA too short for received frame */ +#define ISREG_CRC 0x0008 /* CRC counter rolls over */ +#define ISREG_FAE 0x0004 /* FAE counter rolls over */ +#define ISREG_MP 0x0002 /* MP counter rolls over */ +#define ISREG_RFO 0x0001 /* Rx FIFO overflows */ + +#define SONIC_UTDA 0x0c /* current transmit descr address */ +#define SONIC_CTDA 0x0e + +#define SONIC_URDA 0x1a /* current receive descr address */ +#define SONIC_CRDA 0x1c + +#define SONIC_CRBA0 0x1e /* current receive buffer address */ +#define SONIC_CRBA1 0x20 + +#define SONIC_RBWC0 0x22 /* word count in receive buffer */ +#define SONIC_RBWC1 0x24 + +#define SONIC_EOBC 0x26 /* minimum space to be free in RBA */ + +#define SONIC_URRA 0x28 /* upper address of CDA & Recv Area */ + +#define SONIC_RSA 0x2a /* start of receive resource area */ + +#define SONIC_REA 0x2c /* end of receive resource area */ + +#define SONIC_RRP 0x2e /* resource read pointer */ + +#define SONIC_RWP 0x30 /* resource write pointer */ + +#define SONIC_CAMEPTR 0x42 /* CAM entry pointer */ + +#define SONIC_CAMADDR2 0x44 /* CAM address ports */ +#define SONIC_CAMADDR1 0x46 +#define SONIC_CAMADDR0 0x48 + +#define SONIC_CAMPTR 0x4c /* lower address of CDA */ + +#define SONIC_CAMCNT 0x4e /* # of CAM descriptors to load */ + +/* Data Configuration Register 2 */ + +#define SONIC_DCREG2 0x7e +#define DCREG2_EXPO3 0x8000 /* extended programmable outputs */ +#define DCREG2_EXPO2 0x4000 +#define DCREG2_EXPO1 0x2000 +#define DCREG2_EXPO0 0x1000 +#define DCREG2_HD 0x0800 /* heartbeat disable */ +#define DCREG2_JD 0x0200 /* jabber timer disable */ +#define DCREG2_AUTO 0x0100 /* enable AUI/TP auto selection */ +#define DCREG2_XWRAP 0x0040 /* TP transceiver loopback */ +#define DCREG2_PH 0x0010 /* HOLD request timing */ +#define DCREG2_PCM 0x0004 /* packet compress when matched */ +#define DCREG2_PCNM 0x0002 /* packet compress when not matched */ +#define DCREG2_RJCM 0x0001 /* inverse packet match via CAM */ + +/* Board Control Register: Enable RAM, Interrupts... */ + +#define BCMREG 0x80 +#define BCMREG_RAMEN 0x80 /* switch over to RAM */ +#define BCMREG_IPEND 0x40 /* interrupt pending ? */ +#define BCMREG_RESET 0x08 /* reset board */ +#define BCMREG_16BIT 0x04 /* adapter in 16-bit slot */ +#define BCMREG_RAMWIN 0x02 /* enable RAM window */ +#define BCMREG_IEN 0x01 /* interrupt enable */ + +/* MAC Address PROM */ + +#define MACADDRPROM 0x92 + +/* structure of a CAM entry */ + +typedef struct { + u32 index; /* pointer into CAM area */ + u32 addr0; /* address part (bits 0..15 used) */ + u32 addr1; + u32 addr2; +} camentry_t; + +/* structure of a receive resource */ + +typedef struct { + u32 startlo; /* start address (bits 0..15 used) */ + u32 starthi; + u32 cntlo; /* size in 16-bit quantities */ + u32 cnthi; +} rra_t; + +/* structure of a receive descriptor */ + +typedef struct { + u32 status; /* packet status */ + u32 length; /* length in bytes */ + u32 startlo; /* start address */ + u32 starthi; + u32 seqno; /* frame sequence */ + u32 link; /* pointer to next descriptor */ + /* bit 0 = EOL */ + u32 inuse; /* !=0 --> free for SONIC to write */ +} rda_t; + +/* structure of a transmit descriptor */ + +typedef struct { + u32 status; /* transmit status */ + u32 config; /* value for TCR */ + u32 length; /* total length */ + u32 fragcount; /* number of fragments */ + u32 startlo; /* start address of fragment */ + u32 starthi; + u32 fraglength; /* length of this fragment */ + /* more address/length triplets may */ + /* follow here */ + u32 link; /* pointer to next descriptor */ + /* bit 0 = EOL */ +} tda_t; + +#endif /* _IBM_LANA_DRIVER_ */ + +extern int ibmlana_probe(struct IBMLANA_NETDEV *); + + +#endif /* _IBM_LANA_INCLUDE_ */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/ioc3-eth.c linux/drivers/net/ioc3-eth.c --- v2.4.0-test1/linux/drivers/net/ioc3-eth.c Tue May 23 15:31:35 2000 +++ linux/drivers/net/ioc3-eth.c Mon Jun 19 13:30:58 2000 @@ -1,5 +1,4 @@ -/* $Id$ - * +/* * 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. @@ -33,12 +32,8 @@ * * To do: * - * - ioc3_close() should attempt to shutdown the adapter somewhat more - * gracefully. - * - Free rings and buffers when closing or before re-initializing rings. * - Handle allocation failures in ioc3_alloc_skb() more gracefully. * - Handle allocation failures in ioc3_init_rings(). - * - Maybe implement private_ioctl(). * - Use prefetching for large packets. What is a good lower limit for * prefetching? * - We're probably allocating a bit too much memory. @@ -55,6 +50,7 @@ #include #include #include +#include #include #include @@ -75,20 +71,21 @@ /* 32 RX buffers. This is tunable in the range of 16 <= x < 512. */ #define RX_BUFFS 32 -static void ioc3_set_multicast_list(struct net_device *dev); -static int ioc3_open(struct net_device *dev); -static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev); -static void ioc3_timeout(struct net_device *dev); -static int ioc3_close(struct net_device *dev); -static inline unsigned int ioc3_hash(const unsigned char *addr); - -static const char ioc3_str[] = "IOC3 Ethernet"; +/* Private ioctls that de facto are well known and used for examply + by mii-tool. */ +#define SIOCGMIIPHY (SIOCDEVPRIVATE) /* Read from current PHY */ +#define SIOCGMIIREG (SIOCDEVPRIVATE+1) /* Read any PHY register */ +#define SIOCSMIIREG (SIOCDEVPRIVATE+2) /* Write any PHY register */ + +/* These exist in other drivers; we don't use them at this time. */ +#define SIOCGPARAMS (SIOCDEVPRIVATE+3) /* Read operational parameters */ +#define SIOCSPARAMS (SIOCDEVPRIVATE+4) /* Set operational parameters */ /* Private per NIC data of the driver. */ struct ioc3_private { struct ioc3 *regs; int phy; - unsigned long rxr; /* pointer to receiver ring */ + unsigned long *rxr; /* pointer to receiver ring */ struct ioc3_etxd *txr; struct sk_buff *rx_skbs[512]; struct sk_buff *tx_skbs[128]; @@ -97,9 +94,23 @@ int rx_pi; /* RX producer index */ int tx_ci; /* TX consumer index */ int tx_pi; /* TX producer index */ + int txqlen; + u32 emcr, ehar_h, ehar_l; spinlock_t ioc3_lock; }; +static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static void ioc3_set_multicast_list(struct net_device *dev); +static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev); +static void ioc3_timeout(struct net_device *dev); +static inline unsigned int ioc3_hash(const unsigned char *addr); +static void ioc3_stop(struct net_device *dev); +static void ioc3_clean_tx_ring(struct ioc3_private *ip); +static void ioc3_clean_rx_ring(struct ioc3_private *ip); +static void ioc3_init(struct net_device *dev); + +static const char ioc3_str[] = "IOC3 Ethernet"; + /* We use this to acquire receive skb's that we can DMA directly into. */ #define ALIGNED_RX_SKB_ADDR(addr) \ ((((unsigned long)(addr) + (128 - 1)) & ~(128 - 1)) - (unsigned long)(addr)) @@ -124,17 +135,6 @@ #define BARRIER() \ __asm__("sync" ::: "memory") -/* This El Cheapo implementatin of TX_BUFFS_AVAIL may leave on entry unused. - Since the TX ring has 128 entries which is fairly large we don't care and - use this, more efficient implementation. */ -#define TX_BUFFS_AVAIL(ip) \ -({ \ - struct ioc3_private *_ip = (ip); \ - ((512 + _ip->tx_ci + 1) - _ip->tx_pi) & 511; \ -}) -//#undef TX_BUFFS_AVAIL -//#define TX_BUFFS_AVAIL(ip) (1) - #define IOC3_SIZE 0x100000 @@ -182,6 +182,30 @@ return presence; } +static inline int +nic_read_bit(struct ioc3 *ioc3) +{ + int result; + + ioc3_w(mcr, mcr_pack(6, 13)); + result = nic_wait(ioc3); + ioc3_w(mcr, mcr_pack(0, 100)); + nic_wait(ioc3); + + return result; +} + +static inline void +nic_write_bit(struct ioc3 *ioc3, int bit) +{ + if (bit) + ioc3_w(mcr, mcr_pack(6, 110)); + else + ioc3_w(mcr, mcr_pack(80, 30)); + + nic_wait(ioc3); +} + /* * Read a byte from an iButton device */ @@ -191,13 +215,8 @@ u32 result = 0; int i; - for (i = 0; i < 8; i++) { - ioc3_w(mcr, mcr_pack(6, 13)); - result = (result >> 1) | (nic_wait(ioc3) << 7); - - ioc3_w(mcr, mcr_pack(0, 100)); - nic_wait(ioc3); - } + for (i = 0; i < 8; i++) + result = (result >> 1) | (nic_read_bit(ioc3) << 7); return result; } @@ -214,34 +233,106 @@ bit = byte & 1; byte >>= 1; - if (bit) - ioc3_w(mcr, mcr_pack(6, 110)); - else - ioc3_w(mcr, mcr_pack(80, 30)); - nic_wait(ioc3); + nic_write_bit(ioc3, bit); + } +} + +static u64 +nic_find(struct ioc3 *ioc3, int *last) +{ + int a, b, index, disc; + u64 address = 0; + + nic_reset(ioc3); + /* Search ROM. */ + nic_write_byte(ioc3, 0xf0); + + /* Algorithm from ``Book of iButton Standards''. */ + for (index = 0, disc = 0; index < 64; index++) { + a = nic_read_bit(ioc3); + b = nic_read_bit(ioc3); + + if (a && b) { + printk("NIC search failed (not fatal).\n"); + *last = 0; + return 0; + } + + if (!a && !b) { + if (index == *last) { + address |= 1UL << index; + } else if (index > *last) { + address &= ~(1UL << index); + disc = index; + } else if ((address & (1UL << index)) == 0) + disc = index; + nic_write_bit(ioc3, address & (1UL << index)); + continue; + } else { + if (a) + address |= 1UL << index; + else + address &= ~(1UL << index); + nic_write_bit(ioc3, a); + continue; + } } + + *last = disc; + + return address; } -static void nic_show_regnr(struct ioc3 *ioc3) +static int nic_init(struct ioc3 *ioc3) { const char *type; - u8 regnr[8]; - int i; + u8 crc; + u8 serial[6]; + int save = 0, i; + + type = "unknown"; + + while (1) { + u64 reg; + reg = nic_find(ioc3, &save); + + switch (reg & 0xff) { + case 0x91: + type = "DS1981U"; + break; + default: + if (save == 0) { + /* Let the caller try again. */ + return -1; + } + continue; + } - nic_write_byte(ioc3, 0x33); - for (i = 0; i < 8; i++) - regnr[i] = nic_read_byte(ioc3); + nic_reset(ioc3); + + /* Match ROM. */ + nic_write_byte(ioc3, 0x55); + for (i = 0; i < 8; i++) + nic_write_byte(ioc3, (reg >> (i << 3)) & 0xff); + + reg >>= 8; /* Shift out type. */ + for (i = 0; i < 6; i++) { + serial[i] = reg & 0xff; + reg >>= 8; + } + crc = reg & 0xff; + break; + } - switch(regnr[0]) { - case 0x01: type = "DS1990A"; break; - case 0x91: type = "DS1981U"; break; - default: type = "unknown"; break; + printk("Found %s NIC", type); + if (type != "unknown") { + printk (" registration number %02x:%02x:%02x:%02x:%02x:%02x," + " CRC %02x", serial[0], serial[1], serial[2], + serial[3], serial[4], serial[5], crc); } + printk(".\n"); - printk("Found %s NIC, registration number " - "%02x:%02x:%02x:%02x:%02x:%02x, CRC %02x.\n", type, - regnr[1], regnr[2], regnr[3], regnr[4], regnr[5], regnr[6], - regnr[7]); + return 0; } /* @@ -251,14 +342,22 @@ { u8 nic[14]; int i; + int tries = 2; /* There may be some problem with the battery? */ ioc3_w(gpcr_s, (1 << 21)); - nic_reset(ioc3); - nic_show_regnr(ioc3); + while (tries--) { + if (!nic_init(ioc3)) + break; + udelay(500); + } - nic_reset(ioc3); - nic_write_byte(ioc3, 0xcc); + if (tries < 0) { + printk("Failed to read MAC address\n"); + return; + } + + /* Read Memory. */ nic_write_byte(ioc3, 0xf0); nic_write_byte(ioc3, 0x00); nic_write_byte(ioc3, 0x00); @@ -276,6 +375,8 @@ printk(".\n"); } +/* Caller must hold the ioc3_lock ever for MII readers. This is also + used to protect the transmitter side but it's low contention. */ static u16 mii_read(struct ioc3 *ioc3, int phy, int reg) { while (ioc3->micr & MICR_BUSY); @@ -320,9 +421,6 @@ w0 = rxb->w0; while (w0 & ERXBUF_V) { - ioc3->eisr = EISR_RXTIMERINT; /* Ack */ - ioc3->eisr; /* Flush */ - err = rxb->err; /* It's valid ... */ if (err & ERXBUF_GOODPKT) { len = (w0 >> ERXBUF_BYTECNT_SHIFT) & 0x7ff; @@ -349,21 +447,17 @@ ip->stats.rx_packets++; /* Statistics */ ip->stats.rx_bytes += len; - goto next; - } - if (err & (ERXBUF_CRCERR | ERXBUF_FRAMERR | ERXBUF_CODERR | - ERXBUF_INVPREAMB | ERXBUF_BADPKT | ERXBUF_CARRIER)) { - /* We don't send the skbuf to the network layer, so - just recycle it. */ - new_skb = skb; - - if (err & ERXBUF_CRCERR) /* Statistics */ - ip->stats.rx_crc_errors++; - if (err & ERXBUF_FRAMERR) - ip->stats.rx_frame_errors++; - ip->stats.rx_errors++; + } else { + /* The frame is invalid and the skb never + reached the network layer so we can just + recycle it. */ + new_skb = skb; + ip->stats.rx_errors++; } - + if (err & ERXBUF_CRCERR) /* Statistics */ + ip->stats.rx_crc_errors++; + if (err & ERXBUF_FRAMERR) + ip->stats.rx_frame_errors++; next: ip->rx_skbs[n_entry] = new_skb; rxr[n_entry] = (0xa5UL << 56) | @@ -380,29 +474,28 @@ } ip->rx_pi = n_entry; ip->rx_ci = rx_entry; - - return; } static inline void -ioc3_tx(struct ioc3_private *ip, struct ioc3 *ioc3) +ioc3_tx(struct net_device *dev, struct ioc3_private *ip, struct ioc3 *ioc3) { + unsigned long packets, bytes; int tx_entry, o_entry; struct sk_buff *skb; u32 etcir; spin_lock(&ip->ioc3_lock); etcir = ioc3->etcir; + tx_entry = (etcir >> 7) & 127; o_entry = ip->tx_ci; + packets = 0; + bytes = 0; while (o_entry != tx_entry) { - ioc3->eisr = EISR_TXEXPLICIT; /* Ack */ - ioc3->eisr; /* Flush */ - + packets++; skb = ip->tx_skbs[o_entry]; - ip->stats.tx_packets++; - ip->stats.tx_bytes += skb->len; + bytes += skb->len; dev_kfree_skb_irq(skb); ip->tx_skbs[o_entry] = NULL; @@ -411,14 +504,24 @@ etcir = ioc3->etcir; /* More pkts sent? */ tx_entry = (etcir >> 7) & 127; } + + ip->stats.tx_packets += packets; + ip->stats.tx_bytes += bytes; + ip->txqlen -= packets; + + if (ip->txqlen < 128) + netif_wake_queue(dev); + ip->tx_ci = o_entry; spin_unlock(&ip->ioc3_lock); } /* - * Deal with fatal IOC3 errors. For now let's panic. This condition might - * be caused by a hard or software problems, so we should try to recover - * more gracefully if this ever happens. + * Deal with fatal IOC3 errors. This condition might be caused by a hard or + * software problems, so we should try to recover + * more gracefully if this ever happens. In theory we might be flooded + * with such error interrupts if something really goes wrong, so we might + * also consider to take the interface down. */ static void ioc3_error(struct net_device *dev, struct ioc3_private *ip, @@ -426,12 +529,19 @@ { if (eisr & (EISR_RXMEMERR | EISR_TXMEMERR)) { if (eisr & EISR_RXMEMERR) { - panic("%s: RX PCI error.\n", dev->name); + printk(KERN_ERR "%s: RX PCI error.\n", dev->name); } if (eisr & EISR_TXMEMERR) { - panic("%s: TX PCI error.\n", dev->name); + printk(KERN_ERR "%s: TX PCI error.\n", dev->name); } } + + ioc3_stop(dev); + ioc3_clean_tx_ring(dev->priv); + ioc3_init(dev); + + dev->trans_start = jiffies; + netif_wake_queue(dev); } /* The interrupt handler does all of the Rx thread work and cleans up @@ -441,47 +551,34 @@ struct net_device *dev = (struct net_device *)_dev; struct ioc3_private *ip = dev->priv; struct ioc3 *ioc3 = ip->regs; - u32 eisr, eier; - - ip = dev->priv; - - eier = ioc3->eier; /* Disable eth ints */ - ioc3->eier = 0; - eisr = ioc3->eisr; - __sti(); - - if (eisr & EISR_RXTIMERINT) { - ioc3_rx(dev, ip, ioc3); - } - if (eisr & EISR_TXEXPLICIT) { - ioc3_tx(ip, ioc3); - } - if (eisr & (EISR_RXMEMERR | EISR_TXMEMERR)) { - ioc3_error(dev, ip, ioc3, eisr); - } + const u32 enabled = EISR_RXTIMERINT | EISR_TXEXPLICIT | + EISR_RXMEMERR | EISR_TXMEMERR; + u32 eisr; + + eisr = ioc3->eisr & enabled; + while (eisr) { + ioc3->eisr = eisr; + ioc3->eisr; /* Flush */ - if ((TX_BUFFS_AVAIL(ip) >= 0) && netif_queue_stopped(dev)) { - netif_wake_queue(dev); + if (eisr & EISR_RXTIMERINT) + ioc3_rx(dev, ip, ioc3); + if (eisr & EISR_TXEXPLICIT) + ioc3_tx(dev, ip, ioc3); + if (eisr & (EISR_RXMEMERR | EISR_TXMEMERR)) + ioc3_error(dev, ip, ioc3, eisr); + eisr = ioc3->eisr & enabled; } - - __cli(); - ioc3->eier = eier; - - return; } -int -ioc3_eth_init(struct net_device *dev, struct ioc3_private *p, struct ioc3 *ioc3) +/* One day this will do the autonegotiation. */ +int ioc3_mii_init(struct net_device *dev, struct ioc3_private *ip, + struct ioc3 *ioc3) { u16 word, mii0, mii_status, mii2, mii3, mii4; u32 vendor, model, rev; int i, phy; - ioc3->emcr = EMCR_RST; /* Reset */ - ioc3->emcr; /* flush WB */ - udelay(4); /* Give it time ... */ - ioc3->emcr = 0; - + spin_lock_irq(&ip->ioc3_lock); phy = -1; for (i = 0; i < 32; i++) { word = mii_read(ioc3, i, 2); @@ -491,10 +588,11 @@ } } if (phy == -1) { + spin_unlock_irq(&ip->ioc3_lock); printk("Didn't find a PHY, goodbye.\n"); return -ENODEV; } - p->phy = phy; + ip->phy = phy; mii0 = mii_read(ioc3, phy, 0); mii_status = mii_read(ioc3, phy, 1); @@ -512,73 +610,150 @@ /* Autonegotiate 100mbit and fullduplex. */ mii_write(ioc3, phy, 0, mii0 | 0x3100); - mdelay(1000); + + spin_unlock_irq(&ip->ioc3_lock); + mdelay(1000); /* XXX Yikes XXX */ + spin_lock_irq(&ip->ioc3_lock); + mii_status = mii_read(ioc3, phy, 1); + spin_unlock_irq(&ip->ioc3_lock); - return 0; /* XXX */ + return 0; } -/* To do: For reinit of the ring we have to cleanup old skbs first ... */ static void -ioc3_init_rings(struct net_device *dev, struct ioc3_private *p, - struct ioc3 *ioc3) +ioc3_alloc_rings(struct net_device *dev, struct ioc3_private *ip, + struct ioc3 *ioc3) { struct ioc3_erxbuf *rxb; unsigned long *rxr; - unsigned long ring; int i; - /* Allocate and initialize rx ring. 4kb = 512 entries */ - p->rxr = get_free_page(GFP_KERNEL); - rxr = (unsigned long *) p->rxr; - - /* Now the rx buffers. The RX ring may be larger but we only - allocate 16 buffers for now. Need to tune this for performance - and memory later. */ - for (i = 0; i < RX_BUFFS; i++) { - struct sk_buff *skb; + if (ip->rxr == NULL) { + /* Allocate and initialize rx ring. 4kb = 512 entries */ + ip->rxr = (unsigned long *) get_free_page(GFP_KERNEL); + rxr = (unsigned long *) ip->rxr; + + /* Now the rx buffers. The RX ring may be larger but + we only allocate 16 buffers for now. Need to tune + this for performance and memory later. */ + for (i = 0; i < RX_BUFFS; i++) { + struct sk_buff *skb; + + skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, 0); + if (!skb) { + show_free_areas(); + continue; + } - skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, 0); - if (!skb) { - show_free_areas(); - continue; - } + ip->rx_skbs[i] = skb; + skb->dev = dev; - p->rx_skbs[i] = skb; - skb->dev = dev; + /* Because we reserve afterwards. */ + skb_put(skb, (1664 + RX_OFFSET)); + rxb = (struct ioc3_erxbuf *) skb->data; + rxr[i] = (0xa5UL << 56) + | ((unsigned long) rxb & TO_PHYS_MASK); + skb_reserve(skb, RX_OFFSET); + } + ip->rx_ci = 0; + ip->rx_pi = RX_BUFFS; + } - /* Because we reserve afterwards. */ - skb_put(skb, (1664 + RX_OFFSET)); - rxb = (struct ioc3_erxbuf *) skb->data; - rxb->w0 = 0; /* Clear valid bit */ - rxr[i] = (0xa5UL << 56) | ((unsigned long) rxb & TO_PHYS_MASK); - skb_reserve(skb, RX_OFFSET); + if (ip->txr == NULL) { + /* Allocate and initialize tx rings. 16kb = 128 bufs. */ + ip->txr = (struct ioc3_etxd *)__get_free_pages(GFP_KERNEL, 2); + ip->tx_pi = 0; + ip->tx_ci = 0; } +} + +static void +ioc3_init_rings(struct net_device *dev, struct ioc3_private *ip, + struct ioc3 *ioc3) +{ + unsigned long ring; + + ioc3_alloc_rings(dev, ip, ioc3); + + ioc3_clean_tx_ring(ip); + ioc3_clean_rx_ring(ip); /* Now the rx ring base, consume & produce registers. */ - ring = (0xa5UL << 56) | (p->rxr & TO_PHYS_MASK); + ring = (0xa5UL << 56) | ((unsigned long)ip->rxr & TO_PHYS_MASK); ioc3->erbr_h = ring >> 32; ioc3->erbr_l = ring & 0xffffffff; - p->rx_ci = 0; - ioc3->ercir = (p->rx_ci << 3); - p->rx_pi = RX_BUFFS; - ioc3->erpir = (p->rx_pi << 3) | ERPIR_ARM; - - /* Allocate and initialize tx rings. 16kb = 128 bufs. */ - p->txr = (struct ioc3_etxd *)__get_free_pages(GFP_KERNEL, 2); - ring = (0xa5UL << 56) | ((unsigned long)p->txr & TO_PHYS_MASK); + ioc3->ercir = (ip->rx_ci << 3); + ioc3->erpir = (ip->rx_pi << 3) | ERPIR_ARM; + + ring = (0xa5UL << 56) | ((unsigned long)ip->txr & TO_PHYS_MASK); + + ip->txqlen = 0; /* nothing queued */ /* Now the tx ring base, consume & produce registers. */ ioc3->etbr_h = ring >> 32; ioc3->etbr_l = ring & 0xffffffff; - p->tx_pi = 0; - ioc3->etpir = (p->tx_pi << 7); - p->tx_ci = 0; - ioc3->etcir = (p->tx_pi << 7); + ioc3->etpir = (ip->tx_pi << 7); + ioc3->etcir = (ip->tx_ci << 7); ioc3->etcir; /* Flush */ } -void +static void +ioc3_clean_tx_ring(struct ioc3_private *ip) +{ + struct sk_buff *skb; + int i; + + for (i=0; i < 128; i++) { + skb = ip->tx_skbs[i]; + if (skb) { + ip->tx_skbs[i] = NULL; + dev_kfree_skb_any(skb); + } + ip->txr[i].cmd = 0; + } +} + +static void +ioc3_clean_rx_ring(struct ioc3_private *ip) +{ + struct sk_buff *skb; + int i; + + for (i = 0; i < RX_BUFFS; i++) { + struct ioc3_erxbuf *rxb; + skb = ip->rx_skbs[i]; + rxb = (struct ioc3_erxbuf *) (skb->data - RX_OFFSET); + + rxb->w0 = 0; + } +} + +static void +ioc3_free_rings(struct ioc3_private *ip) +{ + struct sk_buff *skb; + int rx_entry, n_entry; + + ioc3_clean_tx_ring(ip); + free_pages((unsigned long)ip->txr, 2); + ip->txr = NULL; + + n_entry = ip->rx_ci; + rx_entry = ip->rx_pi; + + while (n_entry != rx_entry) { + skb = ip->rx_skbs[n_entry]; + if (skb) + dev_kfree_skb_any(skb); + + n_entry = (n_entry + 1) & 511; + } + free_page((unsigned long)ip->rxr); + ip->rxr = NULL; +} + +static inline void ioc3_ssram_disc(struct ioc3_private *ip) { struct ioc3 *ioc3 = ip->regs; @@ -595,40 +770,23 @@ if ((*ssram0 & IOC3_SSRAM_DM) != pattern || (*ssram1 & IOC3_SSRAM_DM) != (~pattern & IOC3_SSRAM_DM)) { /* set ssram size to 64 KB */ + ip->emcr = EMCR_RAMPAR; ioc3->emcr &= ~EMCR_BUFSIZ; - printk("IOC3 SSRAM has 64 kbyte.\n"); } else { - //ei->ei_ssram_bits = EMCR_BUFSIZ | EMCR_RAMPAR; - printk("IOC3 SSRAM has 64 kbyte.\n"); + ip->emcr = EMCR_BUFSIZ | EMCR_RAMPAR; } } -static void ioc3_probe1(struct net_device *dev, struct ioc3 *ioc3) +static void ioc3_init(struct net_device *dev) { - struct ioc3_private *ip; - - dev = init_etherdev(dev, 0); - - /* - * This probably needs to be register_netdevice, or call - * init_etherdev so that it calls register_netdevice. Quick - * hack for now. - */ - netif_device_attach(dev); - - ip = (struct ioc3_private *) kmalloc(sizeof(*ip), GFP_KERNEL); - memset(ip, 0, sizeof(*ip)); - dev->priv = ip; - dev->irq = IOC3_ETH_INT; - - ip->regs = ioc3; - - ioc3_eth_init(dev, ip, ioc3); - ioc3_ssram_disc(ip); - ioc3_get_eaddr(dev, ioc3); - ioc3_init_rings(dev, ip, ioc3); + struct ioc3_private *ip = dev->priv; + struct ioc3 *ioc3 = ip->regs; - spin_lock_init(&ip->ioc3_lock); + ioc3->emcr = EMCR_RST; /* Reset */ + ioc3->emcr; /* flush WB */ + udelay(4); /* Give it time ... */ + ioc3->emcr = 0; + ioc3->emcr; /* Misc registers */ ioc3->erbar = 0; @@ -640,65 +798,141 @@ ioc3->emar_l = (dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) | (dev->dev_addr[1] << 8) | dev->dev_addr[0]; ioc3->ehar_h = ioc3->ehar_l = 0; - ioc3->ersr = 42; /* XXX should be random */ + ioc3->ersr = 42; /* XXX should be random */ //ioc3->erpir = ERPIR_ARM; - /* The IOC3-specific entries in the device structure. */ - dev->open = &ioc3_open; - dev->hard_start_xmit = &ioc3_start_xmit; - dev->tx_timeout = ioc3_timeout; - dev->watchdog_timeo = (400 * HZ) / 1000; - dev->stop = &ioc3_close; - dev->get_stats = &ioc3_get_stats; - dev->set_multicast_list = &ioc3_set_multicast_list; + ioc3_init_rings(dev, ip, ioc3); + + ip->emcr |= ((RX_OFFSET / 2) << EMCR_RXOFF_SHIFT) | EMCR_TXDMAEN | + EMCR_TXEN | EMCR_RXDMAEN | EMCR_RXEN; + ioc3->emcr = ip->emcr; + ioc3->eier = EISR_RXTIMERINT | EISR_TXEXPLICIT | /* Interrupts ... */ + EISR_RXMEMERR | EISR_TXMEMERR; + ioc3->eier; } -int -ioc3_probe(struct net_device *dev) +static void ioc3_stop(struct net_device *dev) { - static int initialized; - struct ioc3 *ioc3; - nasid_t nid; + struct ioc3_private *ip = dev->priv; + struct ioc3 *ioc3 = ip->regs; - if (initialized) /* Only initialize once ... */ - return 0; - initialized++; + ioc3->emcr = 0; /* Shutup */ + ip->emcr = 0; + ioc3->eier = 0; /* Disable interrupts */ + ioc3->eier; /* Flush */ +} + +static int +ioc3_open(struct net_device *dev) +{ + if (request_irq(dev->irq, ioc3_interrupt, 0, ioc3_str, dev)) { + printk(KERN_ERR "%s: Can't get irq %d\n", dev->name, dev->irq); + + return -EAGAIN; + } - nid = get_nasid(); - ioc3 = (struct ioc3 *) KL_CONFIG_CH_CONS_INFO(nid)->memory_base; - ioc3_probe1(dev, ioc3); + ((struct ioc3_private *)dev->priv)->ehar_h = 0; + ((struct ioc3_private *)dev->priv)->ehar_l = 0; + ioc3_init(dev); + + netif_start_queue(dev); + + MOD_INC_USE_COUNT; return 0; } static int -ioc3_open(struct net_device *dev) +ioc3_close(struct net_device *dev) { struct ioc3_private *ip = dev->priv; - struct ioc3 *ioc3 = ip->regs; - unsigned long flags; - save_flags(flags); cli(); - if (request_irq(dev->irq, ioc3_interrupt, 0, ioc3_str, dev)) { - printk("%s: Can't get irq %d\n", dev->name, dev->irq); - restore_flags(flags); + netif_stop_queue(dev); - return -EAGAIN; - } + ioc3_stop(dev); /* Flush */ + free_irq(dev->irq, dev); - //ioc3_eth_init(dev, p, ioc3); + ioc3_free_rings(ip); - ioc3->emcr = ((RX_OFFSET / 2) << EMCR_RXOFF_SHIFT) | EMCR_TXDMAEN | - EMCR_TXEN | EMCR_RXDMAEN | EMCR_RXEN; - ioc3->eier = EISR_RXTIMERINT | EISR_TXEXPLICIT | /* Interrupts ... */ - EISR_RXMEMERR | EISR_TXMEMERR; + MOD_DEC_USE_COUNT; - netif_wake_queue(dev); - restore_flags(flags); + return 0; +} - MOD_INC_USE_COUNT; +static void ioc3_pci_init(struct pci_dev *pdev) +{ + struct net_device *dev = NULL; // XXX + struct ioc3_private *ip; + struct ioc3 *ioc3; + unsigned long ioc3_base, ioc3_size; + + dev = init_etherdev(dev, 0); + + /* + * This probably needs to be register_netdevice, or call + * init_etherdev so that it calls register_netdevice. Quick + * hack for now. + */ + netif_device_attach(dev); + + ip = (struct ioc3_private *) kmalloc(sizeof(*ip), GFP_KERNEL); + memset(ip, 0, sizeof(*ip)); + dev->priv = ip; + dev->irq = pdev->irq; + + ioc3_base = pdev->resource[0].start; + ioc3_size = pdev->resource[0].end - ioc3_base; + ioc3 = (struct ioc3 *) ioremap(ioc3_base, ioc3_size); + ip->regs = ioc3; + + spin_lock_init(&ip->ioc3_lock); + + ioc3_stop(dev); + ip->emcr = 0; + ioc3_init(dev); + ioc3_mii_init(dev, ip, ioc3); + + ioc3_ssram_disc(ip); + printk("IOC3 SSRAM has %d kbyte.\n", ip->emcr & EMCR_BUFSIZ ? 128 : 64); + + ioc3_get_eaddr(dev, ioc3); - return 0; + /* The IOC3-specific entries in the device structure. */ + dev->open = ioc3_open; + dev->hard_start_xmit = ioc3_start_xmit; + dev->tx_timeout = ioc3_timeout; + dev->watchdog_timeo = 5 * HZ; + dev->stop = ioc3_close; + dev->get_stats = ioc3_get_stats; + dev->do_ioctl = ioc3_ioctl; + dev->set_multicast_list = ioc3_set_multicast_list; +} + +static int __init ioc3_probe(void) +{ + static int called = 0; + int cards = 0; + + if (called) + return -ENODEV; + called = 1; + + if (pci_present()) { + struct pci_dev *pdev = NULL; + + while ((pdev = pci_find_device(PCI_VENDOR_ID_SGI, + PCI_DEVICE_ID_SGI_IOC3, pdev))) { + ioc3_pci_init(pdev); + cards++; + } + } + + return cards ? -ENODEV : 0; +} + +static void __exit ioc3_cleanup_module(void) +{ + /* Later, when we really support modules. */ } static int @@ -711,11 +945,8 @@ struct ioc3_etxd *desc; int produce; - if (!TX_BUFFS_AVAIL(ip)) { - return 1; - } - spin_lock_irq(&ip->ioc3_lock); + data = (unsigned long) skb->data; len = skb->len; @@ -759,8 +990,11 @@ ip->tx_pi = produce; ioc3->etpir = produce << 7; /* Fire ... */ - if (TX_BUFFS_AVAIL(ip)) - netif_wake_queue(dev); + ip->txqlen++; + + if (ip->txqlen > 127) + netif_stop_queue(dev); + spin_unlock_irq(&ip->ioc3_lock); return 0; @@ -768,55 +1002,16 @@ static void ioc3_timeout(struct net_device *dev) { - printk("%s: transmit timed out, resetting\n", dev->name); - /* XXX should reset device here. */ + printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name); + + ioc3_stop(dev); + ioc3_clean_tx_ring(dev->priv); + ioc3_init(dev); dev->trans_start = jiffies; netif_wake_queue(dev); } -static int -ioc3_close(struct net_device *dev) -{ - struct ioc3_private *ip = dev->priv; - struct ioc3 *ioc3 = ip->regs; - - netif_stop_queue(dev); - - ioc3->emcr = 0; /* Shutup */ - ioc3->eier = 0; /* Disable interrupts */ - ioc3->eier; /* Flush */ - free_irq(dev->irq, dev); - - MOD_DEC_USE_COUNT; - - return 0; -} - -#if 0 -/* Initialize the NIC */ -static int -ioc3_init(struct ioc3_private *p, struct pci_dev *dev) -{ -#if 0 - unsigned long base; - struct ioc3 *ioc3; - - pci_set_master(dev); - base = dev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK; - printk("Base address at %08lx\n", base); - - p->regs = ioc3 = ioremap (base, IOC3_SIZE); - printk("Remapped base address to %08lx\n", (unsigned long) regs); - - read_nic(ioc3); - - return 0; -#endif - panic(__FUNCTION__" has been called.\n"); -} -#endif - /* * Given a multicast ethernet address, this routine calculates the * address's bit index in the logical address filter mask @@ -853,33 +1048,68 @@ return temp; } +/* Provide ioctl() calls to examine the MII xcvr state. */ +static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct ioc3_private *ip = (struct ioc3_private *) dev->priv; + u16 *data = (u16 *)&rq->ifr_data; + struct ioc3 *ioc3 = ip->regs; + int phy = ip->phy; + + switch (cmd) { + case SIOCGMIIPHY: /* Get the address of the PHY in use. */ + if (phy == -1) + return -ENODEV; + data[0] = phy; + return 0; + + case SIOCGMIIREG: /* Read any PHY register. */ + spin_lock_irq(&ip->ioc3_lock); + data[3] = mii_read(ioc3, data[0], data[1]); + spin_unlock_irq(&ip->ioc3_lock); + return 0; + + case SIOCSMIIREG: /* Write any PHY register. */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + spin_lock_irq(&ip->ioc3_lock); + mii_write(ioc3, data[0], data[1], data[2]); + spin_unlock_irq(&ip->ioc3_lock); + return 0; + + default: + return -EOPNOTSUPP; + } + + return -EOPNOTSUPP; +} + static void ioc3_set_multicast_list(struct net_device *dev) { struct dev_mc_list *dmi = dev->mc_list; + struct ioc3_private *ip = dev->priv; + struct ioc3 *ioc3 = ip->regs; char *addr = dmi->dmi_addr; - struct ioc3_private *p; - struct ioc3 *ioc3; u64 ehar = 0; int i; - p = dev->priv; - ioc3 = p->regs; - if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ /* Unconditionally log net taps. */ printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); - ioc3->emcr |= EMCR_PROMISC; + ip->emcr |= EMCR_PROMISC; + ioc3->emcr = ip->emcr; ioc3->emcr; } else { - ioc3->emcr &= ~EMCR_PROMISC; /* Clear promiscuous. */ + ip->emcr &= ~EMCR_PROMISC; + ioc3->emcr = ip->emcr; /* Clear promiscuous. */ ioc3->emcr; if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { /* Too many for hashing to make sense or we want all multicast packets anyway, so skip computing all the hashes and just accept all packets. */ - ioc3->ehar_h = 0xffffffff; - ioc3->ehar_l = 0xffffffff; + ip->ehar_h = 0xffffffff; + ip->ehar_l = 0xffffffff; } else { for (i = 0; i < dev->mc_count; i++) { dmi = dmi->next; @@ -889,31 +1119,18 @@ ehar |= (1 << ioc3_hash(addr)); } - ioc3->ehar_h = ehar >> 32; - ioc3->ehar_l = ehar & 0xffffffff; + ip->ehar_h = ehar >> 32; + ip->ehar_l = ehar & 0xffffffff; } + ioc3->ehar_h = ip->ehar_h; + ioc3->ehar_l = ip->ehar_l; } } #ifdef MODULE MODULE_AUTHOR("Ralf Baechle "); MODULE_DESCRIPTION("SGI IOC3 Ethernet driver"); - -int -init_module(void) -{ - struct pci_dev *dev = NULL; - - while ((dev = pci_find_device(PCI_VENDOR_ID_SGI, 0x0003, dev))) { - ioc3_init(&p, dev); - } - - return -EBUSY; -} - -void -cleanup_module(void) -{ - printk("cleanup_module called\n"); -} #endif /* MODULE */ + +module_init(ioc3_probe); +module_exit(ioc3_cleanup_module); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/irda/Makefile linux/drivers/net/irda/Makefile --- v2.4.0-test1/linux/drivers/net/irda/Makefile Tue Feb 1 01:35:44 2000 +++ linux/drivers/net/irda/Makefile Tue Jun 20 14:14:50 2000 @@ -52,22 +52,6 @@ endif endif -ifeq ($(CONFIG_TOSHIBA_FIR),y) -L_OBJS += toshoboe.o -else - ifeq ($(CONFIG_TOSHIBA_FIR),m) - M_OBJS += toshoboe.o - endif -endif - -ifeq ($(CONFIG_TOSHIBA_FIR),y) -L_OBJS += toshoboe.o -else - ifeq ($(CONFIG_TOSHIBA_FIR),m) - M_OBJS += toshoboe.o - endif -endif - ifeq ($(CONFIG_SMC_IRCC_FIR),y) L_OBJS += smc-ircc.o LX_OBJS += irport.o diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/irda/girbil.c linux/drivers/net/irda/girbil.c --- v2.4.0-test1/linux/drivers/net/irda/girbil.c Fri Jan 7 19:13:22 2000 +++ linux/drivers/net/irda/girbil.c Wed Jun 21 10:10:02 2000 @@ -201,13 +201,13 @@ self->set_dtr_rts(self->dev, TRUE, FALSE); irda_task_next_state(task, IRDA_TASK_WAIT1); /* Sleep at least 5 ms */ - ret = MSECS_TO_JIFFIES(10); + ret = MSECS_TO_JIFFIES(20); break; case IRDA_TASK_WAIT1: /* Set DTR and clear RTS to enter command mode */ self->set_dtr_rts(self->dev, FALSE, TRUE); irda_task_next_state(task, IRDA_TASK_WAIT2); - ret = MSECS_TO_JIFFIES(10); + ret = MSECS_TO_JIFFIES(20); break; case IRDA_TASK_WAIT2: /* Write control byte */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/lance.c linux/drivers/net/lance.c --- v2.4.0-test1/linux/drivers/net/lance.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/lance.c Mon Jun 19 13:30:58 2000 @@ -361,7 +361,6 @@ lance_need_isa_bounce_buffers = 0; #if defined(CONFIG_PCI) - if (pci_present()) { struct pci_dev *pdev = NULL; if (lance_debug > 1) @@ -369,20 +368,12 @@ while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, pdev))) { unsigned int pci_ioaddr; - unsigned short pci_command; + if (pci_enable_device(pdev)) + continue; + pci_set_master(pdev); pci_irq_line = pdev->irq; - pci_ioaddr = pdev->resource[0].start; - /* PCI Spec 2.1 states that it is either the driver or PCI card's - * responsibility to set the PCI Master Enable Bit if needed. - * (From Mark Stockton ) - */ - pci_read_config_word(pdev, PCI_COMMAND, &pci_command); - if ( ! (pci_command & PCI_COMMAND_MASTER)) { - printk("PCI Master Bit has not been set. Setting...\n"); - pci_command |= PCI_COMMAND_MASTER; - pci_write_config_word(pdev, PCI_COMMAND, pci_command); - } + pci_ioaddr = pci_resource_start (pdev, 0); printk("Found PCnet/PCI at %#x, irq %d.\n", pci_ioaddr, pci_irq_line); result = lance_probe1(dev, pci_ioaddr, pci_irq_line, 0); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/lne390.c linux/drivers/net/lne390.c --- v2.4.0-test1/linux/drivers/net/lne390.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/lne390.c Mon Jun 19 13:30:58 2000 @@ -107,13 +107,13 @@ if (ioaddr > 0x1ff) /* Check a single specified location. */ return lne390_probe1(dev, ioaddr); else if (ioaddr > 0) /* Don't probe at all. */ - return ENXIO; + return -ENXIO; if (!EISA_bus) { #if LNE390_DEBUG & LNE390_D_PROBE printk("lne390-debug: Not an EISA bus. Not probing high ports.\n"); #endif - return ENXIO; + return -ENXIO; } /* EISA spec allows for up to 16 slots, but 8 is typical. */ @@ -124,7 +124,7 @@ return 0; } - return ENODEV; + return -ENODEV; } int __init lne390_probe1(struct net_device *dev, int ioaddr) @@ -144,7 +144,7 @@ /* Check the EISA ID of the card. */ eisa_id = inl(ioaddr + LNE390_ID_PORT); if ((eisa_id != LNE390_ID0) && (eisa_id != LNE390_ID1)) { - return ENODEV; + return -ENODEV; } revision = (eisa_id >> 24) & 0x01; /* 0 = rev A, 1 rev B */ @@ -158,13 +158,10 @@ for(i = 0; i < ETHER_ADDR_LEN; i++) printk(" %02x", inb(ioaddr + LNE390_SA_PROM + i)); printk(" (invalid prefix).\n"); - return ENODEV; + return -ENODEV; } #endif - if (load_8390_module("lne390.c")) - return -ENOSYS; - /* We should have a "dev" from Space.c or the static module table. */ if (dev == NULL) { printk("lne390.c: Passed a NULL device.\n"); @@ -198,7 +195,7 @@ printk (" unable to get IRQ %d.\n", dev->irq); kfree(dev->priv); dev->priv = NULL; - return EAGAIN; + return -EAGAIN; } if (dev->mem_start == 0) { @@ -231,7 +228,7 @@ free_irq(dev->irq, dev); kfree(dev->priv); dev->priv = NULL; - return EINVAL; + return -EINVAL; } dev->mem_start = (unsigned long)ioremap(dev->mem_start, LNE390_STOP_PG*0x100); if (dev->mem_start == 0) { @@ -241,7 +238,7 @@ free_irq(dev->irq, dev); kfree(dev->priv); dev->priv = NULL; - return EAGAIN; + return -EAGAIN; } ei_status.reg0 = 1; /* Use as remap flag */ printk("lne390.c: remapped %dkB card memory to virtual address %#lx\n", @@ -393,6 +390,9 @@ { int this_dev, found = 0; + if (load_8390_module("lne390.c")) + return -ENOSYS; + for (this_dev = 0; this_dev < MAX_LNE_CARDS; this_dev++) { struct net_device *dev = &dev_lne[this_dev]; dev->irq = irq[this_dev]; @@ -404,14 +404,13 @@ if (register_netdev(dev) != 0) { printk(KERN_WARNING "lne390.c: No LNE390 card found (i/o = 0x%x).\n", io[this_dev]); if (found != 0) { /* Got at least one. */ - lock_8390_module(); return 0; } + unload_8390_module(); return -ENXIO; } found++; } - lock_8390_module(); return 0; } @@ -431,7 +430,7 @@ kfree(priv); } } - unlock_8390_module(); + unload_8390_module(); } #endif /* MODULE */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/mac89x0.c linux/drivers/net/mac89x0.c --- v2.4.0-test1/linux/drivers/net/mac89x0.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/net/mac89x0.c Mon Jun 19 13:30:58 2000 @@ -180,14 +180,14 @@ unsigned short sig; if (once_is_enough) - return ENODEV; + return -ENODEV; once_is_enough = 1; /* We might have to parameterize this later */ slot = 0xE; /* Get out now if there's a real NuBus card in slot E */ if (nubus_find_slot(slot, NULL) != NULL) - return ENODEV; + return -ENODEV; /* The pseudo-ISA bits always live at offset 0x300 (gee, wonder why...) */ @@ -204,13 +204,13 @@ restore_flags(flags); if (!card_present) - return ENODEV; + return -ENODEV; } writew(0, ioaddr + ADD_PORT); sig = readw(ioaddr + DATA_PORT); if (sig != swab16(CHIP_EISA_ID_SIG)) - return ENODEV; + return -ENODEV; /* Initialize the net_device structure. */ if (dev->priv == NULL) { @@ -254,7 +254,7 @@ /* Try to read the MAC address */ if ((readreg(dev, PP_SelfST) & (EEPROM_PRESENT | EEPROM_OK)) == 0) { printk("\nmac89x0: No EEPROM, giving up now.\n"); - return ENODEV; + return -ENODEV; } else { for (i = 0; i < ETH_ALEN; i += 2) { /* Big-endian (why??!) */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/myri_sbus.c linux/drivers/net/myri_sbus.c --- v2.4.0-test1/linux/drivers/net/myri_sbus.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/myri_sbus.c Mon Jun 19 13:30:58 2000 @@ -982,7 +982,7 @@ mp->reg_size, "MyriCOM Regs"); if (!mp->regs) { printk("MyriCOM: Cannot map MyriCOM registers.\n"); - return ENODEV; + return -ENODEV; } mp->lanai = (unsigned short *) (mp->regs + (256 * 1024)); mp->lanai3 = (unsigned int *) mp->lanai; @@ -1059,7 +1059,7 @@ if (request_irq(dev->irq, &myri_interrupt, SA_SHIRQ, "MyriCOM Ethernet", (void *) dev)) { printk("MyriCOM: Cannot register interrupt handler.\n"); - return ENODEV; + return -ENODEV; } DET(("ether_setup()\n")); @@ -1109,7 +1109,7 @@ #endif if (called) - return ENODEV; + return -ENODEV; called++; for_each_sbus(bus) { @@ -1125,7 +1125,7 @@ } } if (!cards) - return ENODEV; + return -ENODEV; return 0; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/ne.c linux/drivers/net/ne.c --- v2.4.0-test1/linux/drivers/net/ne.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/ne.c Mon Jun 19 13:30:58 2000 @@ -195,7 +195,7 @@ if (base_addr > 0x1ff) /* Check a single specified location. */ return ne_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ - return ENXIO; + return -ENXIO; #ifdef CONFIG_PCI /* Then look for any installed PCI clones */ @@ -218,7 +218,7 @@ } #endif - return ENODEV; + return -ENODEV; } #endif @@ -232,7 +232,9 @@ unsigned int pci_ioaddr; while ((pdev = pci_find_device(pci_clone_list[i].vendor, pci_clone_list[i].dev_id, pdev))) { - pci_ioaddr = pdev->resource[0].start; + if (pci_enable_device(pdev)) + continue; + pci_ioaddr = pci_resource_start (pdev, 0); /* Avoid already found cards from previous calls */ if (check_region(pci_ioaddr, NE_IO_EXTENT)) continue; @@ -309,7 +311,7 @@ static unsigned version_printed = 0; if (reg0 == 0xFF) - return ENODEV; + return -ENODEV; /* Do a preliminary verification that we have a 8390. */ { @@ -322,13 +324,10 @@ if (inb_p(ioaddr + EN0_COUNTER0) != 0) { outb_p(reg0, ioaddr); outb_p(regd, ioaddr + 0x0d); /* Restore the old values. */ - return ENODEV; + return -ENODEV; } } - if (load_8390_module("ne.c")) - return -ENOSYS; - /* We should have a "dev" from Space.c or the static module table. */ if (dev == NULL) { @@ -364,7 +363,7 @@ break; } else { printk(" not found (no reset ack).\n"); - return ENODEV; + return -ENODEV; } } @@ -466,11 +465,11 @@ { printk(" not found (invalid signature %2.2x %2.2x).\n", SA_prom[14], SA_prom[15]); - return ENXIO; + return -ENXIO; } #else printk(" not found.\n"); - return ENXIO; + return -ENXIO; #endif } @@ -496,7 +495,7 @@ if (! dev->irq) { printk(" failed to detect IRQ line.\n"); - return EAGAIN; + return -EAGAIN; } /* Allocate dev->priv and fill in 8390 specific dev fields. */ @@ -516,7 +515,7 @@ printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval); kfree(dev->priv); dev->priv = NULL; - return EAGAIN; + return -EAGAIN; } } dev->base_addr = ioaddr; @@ -837,6 +836,9 @@ { int this_dev, found = 0; + if (load_8390_module("ne.c")) + return -ENOSYS; + for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { struct net_device *dev = &dev_ne[this_dev]; dev->irq = irq[this_dev]; @@ -848,16 +850,15 @@ continue; } if (found != 0) { /* Got at least one. */ - lock_8390_module(); return 0; } if (io[this_dev] != 0) printk(KERN_WARNING "ne.c: No NE*000 card found at i/o = %#x\n", io[this_dev]); else printk(KERN_NOTICE "ne.c: No PCI cards found. Use \"io=0xNNN\" value(s) for ISA cards.\n"); + unload_8390_module(); return -ENXIO; } - lock_8390_module(); return 0; } @@ -878,7 +879,7 @@ kfree(priv); } } - unlock_8390_module(); + unload_8390_module(); } #endif /* MODULE */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/ne2.c linux/drivers/net/ne2.c --- v2.4.0-test1/linux/drivers/net/ne2.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/ne2.c Mon Jun 19 13:30:58 2000 @@ -171,7 +171,7 @@ return ne2_probe1(dev, current_mca_slot); } } - return ENODEV; + return -ENODEV; } @@ -222,7 +222,7 @@ POS = mca_read_stored_pos(slot, 2); if(!(POS % 2)) { printk(" disabled.\n"); - return ENODEV; + return -ENODEV; } i = (POS & 0xE)>>1; @@ -245,7 +245,7 @@ outb(0x21, base_addr + NE_CMD); if (inb(base_addr + NE_CMD) != 0x21) { printk("NE/2 adapter not responding\n"); - return ENODEV; + return -ENODEV; } /* In the crynwr sources they do a RAM-test here. I skip it. I suppose @@ -266,7 +266,7 @@ while ((inb_p(base_addr + EN0_ISR) & ENISR_RESET) == 0) if (jiffies - reset_start_time > 2*HZ/100) { printk(" not found (no reset ack).\n"); - return ENODEV; + return -ENODEV; } outb_p(0xff, base_addr + EN0_ISR); /* Ack all intr. */ @@ -321,7 +321,7 @@ if (irqval) { printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, +irqval); - return EAGAIN; + return -EAGAIN; } } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/ne2k-pci.c linux/drivers/net/ne2k-pci.c --- v2.4.0-test1/linux/drivers/net/ne2k-pci.c Tue May 23 15:31:35 2000 +++ linux/drivers/net/ne2k-pci.c Mon Jun 19 13:30:58 2000 @@ -242,11 +242,6 @@ outb(0xff, ioaddr + EN0_ISR); /* Ack all intr. */ } - if (load_8390_module("ne2k-pci.c")) { - printk (KERN_ERR "ne2k-pci: cannot load 8390 module\n"); - goto err_out_free_netdev; - } - /* Read the 16 bytes of station address PROM. We must first initialize registers, similar to NS8390_init(eifdev, 0). We can't reliably read the SAPROM address without this. @@ -565,13 +560,18 @@ { int rc; - lock_8390_module(); + if (load_8390_module("ne2k-pci.c")) + return -ENOSYS; rc = pci_module_init (&ne2k_driver); /* XXX should this test CONFIG_HOTPLUG like pci_module_init? */ + + /* YYY No. If we're returning non-zero, we're being unloaded + * immediately. dwmw2 + */ if (rc <= 0) - unlock_8390_module(); + unload_8390_module(); return rc; } @@ -580,7 +580,7 @@ static void __exit ne2k_pci_cleanup(void) { pci_unregister_driver (&ne2k_driver); - unlock_8390_module(); + unload_8390_module(); } module_init(ne2k_pci_init); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/ne3210.c linux/drivers/net/ne3210.c --- v2.4.0-test1/linux/drivers/net/ne3210.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/ne3210.c Mon Jun 19 13:30:59 2000 @@ -102,13 +102,13 @@ if (ioaddr > 0x1ff) /* Check a single specified location. */ return ne3210_probe1(dev, ioaddr); else if (ioaddr > 0) /* Don't probe at all. */ - return ENXIO; + return -ENXIO; if (!EISA_bus) { #if NE3210_DEBUG & NE3210_D_PROBE printk("ne3210-debug: Not an EISA bus. Not probing high ports.\n"); #endif - return ENXIO; + return -ENXIO; } /* EISA spec allows for up to 16 slots, but 8 is typical. */ @@ -119,7 +119,7 @@ return 0; } - return ENODEV; + return -ENODEV; } int __init ne3210_probe1(struct net_device *dev, int ioaddr) @@ -140,7 +140,7 @@ /* Check the EISA ID of the card. */ eisa_id = inl(ioaddr + NE3210_ID_PORT); if (eisa_id != NE3210_ID) { - return ENODEV; + return -ENODEV; } @@ -153,13 +153,10 @@ for(i = 0; i < ETHER_ADDR_LEN; i++) printk(" %02x", inb(ioaddr + NE3210_SA_PROM + i)); printk(" (invalid prefix).\n"); - return ENODEV; + return -ENODEV; } #endif - if (load_8390_module("ne3210.c")) - return -ENOSYS; - /* We should have a "dev" from Space.c or the static module table. */ if (dev == NULL) { printk("ne3210.c: Passed a NULL device.\n"); @@ -194,7 +191,7 @@ printk (" unable to get IRQ %d.\n", dev->irq); kfree(dev->priv); dev->priv = NULL; - return EAGAIN; + return -EAGAIN; } if (dev->mem_start == 0) { @@ -223,7 +220,7 @@ free_irq(dev->irq, dev); kfree(dev->priv); dev->priv = NULL; - return EINVAL; + return -EINVAL; } dev->mem_start = (unsigned long)ioremap(dev->mem_start, NE3210_STOP_PG*0x100); if (dev->mem_start == 0) { @@ -233,7 +230,7 @@ free_irq(dev->irq, dev); kfree(dev->priv); dev->priv = NULL; - return EAGAIN; + return -EAGAIN; } ei_status.reg0 = 1; /* Use as remap flag */ printk("ne3210.c: remapped %dkB card memory to virtual address %#lx\n", @@ -384,6 +381,9 @@ { int this_dev, found = 0; + if (load_8390_module("ne3210.c")) + return -ENOSYS; + for (this_dev = 0; this_dev < MAX_NE3210_CARDS; this_dev++) { struct net_device *dev = &dev_ne3210[this_dev]; dev->irq = irq[this_dev]; @@ -395,14 +395,13 @@ if (register_netdev(dev) != 0) { printk(KERN_WARNING "ne3210.c: No NE3210 card found (i/o = 0x%x).\n", io[this_dev]); if (found != 0) { /* Got at least one. */ - lock_8390_module(); return 0; } + unload_8390_module(); return -ENXIO; } found++; } - lock_8390_module(); return 0; } @@ -422,7 +421,7 @@ kfree(priv); } } - unlock_8390_module(); + unload_8390_module(); } #endif /* MODULE */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/net_init.c linux/drivers/net/net_init.c --- v2.4.0-test1/linux/drivers/net/net_init.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/net_init.c Tue Jun 20 14:32:27 2000 @@ -115,14 +115,17 @@ * Allocate a name */ - if (dev->name[0] == '\0' || dev->name[0] == ' ') - { - if(dev_alloc_name(dev, mask)<0) - { - if(new_device) - kfree(dev); - return NULL; + if (dev->name[0] == '\0' || dev->name[0] == ' ') { + strcpy(dev->name, mask); + if (!netdev_boot_setup_check(dev)) { + if (dev_alloc_name(dev, mask)<0) { + if (new_device) + kfree(dev); + return NULL; + } } + } else { + netdev_boot_setup_check(dev); } /* diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/ni52.c linux/drivers/net/ni52.c --- v2.4.0-test1/linux/drivers/net/ni52.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/ni52.c Mon Jun 19 13:30:56 2000 @@ -367,7 +367,7 @@ (inb(base_addr+NI52_MAGIC2) == NI52_MAGICVAL2)) return ni52_probe1(dev, base_addr); } else if (base_addr > 0) /* Don't probe at all. */ - return ENXIO; + return -ENXIO; #ifdef MODULE printk("%s: no autoprobing allowed for modules.\n",dev->name); @@ -402,7 +402,7 @@ #endif dev->base_addr = base_addr; - return ENODEV; + return -ENODEV; } static int __init ni52_probe1(struct net_device *dev,int ioaddr) @@ -414,7 +414,7 @@ if(dev->dev_addr[0] != NI52_ADDR0 || dev->dev_addr[1] != NI52_ADDR1 || dev->dev_addr[2] != NI52_ADDR2) - return ENODEV; + return -ENODEV; printk("%s: NI5210 found at %#3lx, ",dev->name,dev->base_addr); @@ -428,12 +428,12 @@ if(size != 0x2000 && size != 0x4000) { printk("\n%s: Illegal memory size %d. Allowed is 0x2000 or 0x4000 bytes.\n",dev->name,size); - return ENODEV; + return -ENODEV; } if(!check586(dev,(char *) dev->mem_start,size)) { printk("?memcheck, Can't find memory at 0x%lx with size %d!\n",dev->mem_start,size); - return ENODEV; + return -ENODEV; } #else if(dev->mem_start != 0) /* no auto-mem-probe */ @@ -443,7 +443,7 @@ size = 0x2000; /* check for 8K mem */ if(!check586(dev,(char *) dev->mem_start,size)) { printk("?memprobe, Can't find memory at 0x%lx!\n",dev->mem_start); - return ENODEV; + return -ENODEV; } } } @@ -455,7 +455,7 @@ { if(!memaddrs[i]) { printk("?memprobe, Can't find io-memory!\n"); - return ENODEV; + return -ENODEV; } dev->mem_start = memaddrs[i]; size = 0x2000; /* check for 8K mem */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/oaknet.c linux/drivers/net/oaknet.c --- v2.4.0-test1/linux/drivers/net/oaknet.c Thu Feb 10 17:11:10 2000 +++ linux/drivers/net/oaknet.c Mon Jun 19 13:30:56 2000 @@ -144,16 +144,6 @@ } /* - * We're dependent on the 8390 generic driver module, make - * sure its symbols are loaded. - */ - - if (load_8390_module("oaknet.c")) { - release_region(dev->base_addr, OAKNET_IO_SIZE); - return (-ENOSYS); - } - - /* * We're not using the old-style probing API, so we have to allocate * our own device structure. */ @@ -676,13 +666,21 @@ { int status; + /* + * We're dependent on the 8390 generic driver module, make + * sure its symbols are loaded. + */ + + if (load_8390_module("oaknet.c")) + return (-ENOSYS); + if (oaknet_devs != NULL) return (-EBUSY); status = oaknet_init() - if (status == 0) - lock_8390_module(); + if (status != 0) + unload_8390_module(); return (status); } @@ -706,7 +704,7 @@ oaknet_devs = NULL; - unlock_8390_module(); + unload_8390_module(); } module_init(oaknet_init_module); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/pcmcia/Config.in linux/drivers/net/pcmcia/Config.in --- v2.4.0-test1/linux/drivers/net/pcmcia/Config.in Fri May 12 14:18:55 2000 +++ linux/drivers/net/pcmcia/Config.in Mon Jun 19 13:30:56 2000 @@ -21,12 +21,12 @@ tristate ' Xircom Tulip-like CardBus support' CONFIG_PCMCIA_XIRTULIP fi - bool 'Pcmcia Wireless LAN' CONFIG_NET_PCMCIA_RADIO + bool ' Pcmcia Wireless LAN' CONFIG_NET_PCMCIA_RADIO if [ "$CONFIG_NET_PCMCIA_RADIO" = "y" ]; then - dep_tristate ' Aviator/Raytheon 2.4MHz wireless support' CONFIG_PCMCIA_RAYCS $CONFIG_PCMCIA - dep_tristate ' Xircom Netwave AirSurfer wireless support' CONFIG_PCMCIA_NETWAVE $CONFIG_PCMCIA - dep_tristate ' AT&T/Lucent Wavelan wireless support' CONFIG_PCMCIA_WAVELAN $CONFIG_PCMCIA - dep_tristate ' Aironet 4500/4800 PCMCIA support' CONFIG_AIRONET4500_CS $CONFIG_AIRONET4500 $CONFIG_PCMCIA + dep_tristate ' Aviator/Raytheon 2.4MHz wireless support' CONFIG_PCMCIA_RAYCS $CONFIG_PCMCIA + dep_tristate ' Xircom Netwave AirSurfer wireless support' CONFIG_PCMCIA_NETWAVE $CONFIG_PCMCIA + dep_tristate ' AT&T/Lucent Wavelan wireless support' CONFIG_PCMCIA_WAVELAN $CONFIG_PCMCIA + dep_tristate ' Aironet 4500/4800 PCMCIA support' CONFIG_AIRONET4500_CS $CONFIG_AIRONET4500 $CONFIG_PCMCIA fi fi diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/pcnet32.c linux/drivers/net/pcnet32.c --- v2.4.0-test1/linux/drivers/net/pcnet32.c Tue May 23 15:31:35 2000 +++ linux/drivers/net/pcnet32.c Mon Jun 19 13:30:56 2000 @@ -311,21 +311,6 @@ int (*probe1) (unsigned long, unsigned char, int, int, struct pci_dev *); }; -static struct pcnet32_pci_id_info pcnet32_tbl[] = { - { "AMD PCnetPCI series", - PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0, 0, - PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE, - pcnet32_probe1}, - { "AMD PCnetPCI series (IBM)", - PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0x1014, 0x2000, - PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE, - pcnet32_probe1}, - { "AMD PCnetHome series", - PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_PCNETHOME, 0, 0, - PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE, - pcnet32_probe1}, - {0,} -}; /* * PCI device identifiers for "new style" Linux PCI Device Drivers @@ -751,7 +736,7 @@ } if (pcnet32_debug > 0) - printk(KERN_INFO, version); + printk(KERN_INFO "%s", version); /* The PCNET32-specific entries in the device structure. */ dev->open = &pcnet32_open; @@ -1257,8 +1242,7 @@ lp->stats.rx_errors++; } else { int rx_in_place = 0; - dma_addr_t rx_dma_addr = lp->rx_dma_addr[entry]; - + if (pkt_len > rx_copybreak) { struct sk_buff *newskb; @@ -1524,7 +1508,7 @@ /* find the PCI devices */ #define USE_PCI_REGISTER_DRIVER #ifdef USE_PCI_REGISTER_DRIVER - if (err = pci_module_init(&pcnet32_driver) < 0 ) + if ((err = pci_module_init(&pcnet32_driver)) < 0 ) return err; #else { diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/plip.c linux/drivers/net/plip.c --- v2.4.0-test1/linux/drivers/net/plip.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/plip.c Mon Jun 19 17:59:40 2000 @@ -1301,10 +1301,66 @@ static struct net_device *dev_plip[PLIP_MAX] = { NULL, }; +static int inline +plip_searchfor(int list[], int a) +{ + int i; + for (i = 0; i < PLIP_MAX && list[i] != -1; i++) { + if (list[i] == a) return 1; + } + return 0; +} + +/* plip_attach() is called (by the parport code) when a port is + * available to use. */ +static void plip_attach (struct parport *port) +{ + static int i = 0; + + if ((parport[0] == -1 && (!timid || !port->devices)) || + plip_searchfor(parport, port->number)) { + if (i == PLIP_MAX) { + printk(KERN_ERR "plip: too many devices\n"); + return; + } + dev_plip[i] = kmalloc(sizeof(struct net_device), + GFP_KERNEL); + if (!dev_plip[i]) { + printk(KERN_ERR "plip: memory squeeze\n"); + return; + } + memset(dev_plip[i], 0, sizeof(struct net_device)); + sprintf(dev_plip[i]->name, "plip%d", i); + dev_plip[i]->priv = port; + if (plip_init_dev(dev_plip[i],port) || + register_netdev(dev_plip[i])) { + kfree(dev_plip[i]); + dev_plip[i] = NULL; + } else { + i++; + } + } +} + +/* plip_detach() is called (by the parport code) when a port is + * no longer available to use. */ +static void plip_detach (struct parport *port) +{ + /* Nothing to do */ +} + +static struct parport_driver plip_driver = { + name: "plip", + attach: plip_attach, + detach: plip_detach +}; + static void __exit plip_cleanup_module (void) { int i; + parport_unregister_driver (&plip_driver); + for (i=0; i < PLIP_MAX; i++) { if (dev_plip[i]) { struct net_local *nl = @@ -1314,7 +1370,6 @@ parport_release(nl->pardev); parport_unregister_device(nl->pardev); kfree(dev_plip[i]->priv); - kfree(dev_plip[i]->name); kfree(dev_plip[i]); dev_plip[i] = NULL; } @@ -1357,21 +1412,8 @@ #endif /* !MODULE */ -static int inline -plip_searchfor(int list[], int a) -{ - int i; - for (i = 0; i < PLIP_MAX && list[i] != -1; i++) { - if (list[i] == a) return 1; - } - return 0; -} - static int __init plip_init (void) { - struct parport *pb = parport_enumerate(); - int i=0; - if (parport[0] == -2) return 0; @@ -1380,38 +1422,11 @@ timid = 0; } - /* If the user feeds parameters, use them */ - while (pb) { - if ((parport[0] == -1 && (!timid || !pb->devices)) || - plip_searchfor(parport, pb->number)) { - if (i == PLIP_MAX) { - printk(KERN_ERR "plip: too many devices\n"); - break; - } - dev_plip[i] = kmalloc(sizeof(struct net_device), - GFP_KERNEL); - if (!dev_plip[i]) { - printk(KERN_ERR "plip: memory squeeze\n"); - break; - } - memset(dev_plip[i], 0, sizeof(struct net_device)); - sprintf(dev_plip[i]->name, "plip%d", i); - dev_plip[i]->priv = pb; - if (plip_init_dev(dev_plip[i],pb) || register_netdev(dev_plip[i])) { - kfree(dev_plip[i]->name); - kfree(dev_plip[i]); - dev_plip[i] = NULL; - } else { - i++; - } - } - pb = pb->next; - } - - if (i == 0) { - printk(KERN_INFO "plip: no devices registered\n"); - return -EIO; + if (parport_register_driver (&plip_driver)) { + printk (KERN_WARNING "plip: couldn't register driver\n"); + return 1; } + return 0; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/ppp_generic.c linux/drivers/net/ppp_generic.c --- v2.4.0-test1/linux/drivers/net/ppp_generic.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/ppp_generic.c Wed Jun 21 22:31:01 2000 @@ -312,7 +312,6 @@ */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - MOD_INC_USE_COUNT; return 0; } @@ -333,7 +332,6 @@ } } } - MOD_DEC_USE_COUNT; return 0; } @@ -697,6 +695,7 @@ } static struct file_operations ppp_device_fops = { + owner: THIS_MODULE, read: ppp_read, write: ppp_write, poll: ppp_poll, @@ -719,9 +718,9 @@ err = devfs_register_chrdev(PPP_MAJOR, "ppp", &ppp_device_fops); if (err) printk(KERN_ERR "failed to register PPP device (%d)\n", err); - devfs_handle = devfs_register(NULL, "ppp", 0, DEVFS_FL_NONE, + devfs_handle = devfs_register(NULL, "ppp", DEVFS_FL_DEFAULT, PPP_MAJOR, 0, - S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR, &ppp_device_fops, NULL); return 0; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/ptifddi.c linux/drivers/net/ptifddi.c --- v2.4.0-test1/linux/drivers/net/ptifddi.c Wed Dec 29 13:13:16 1999 +++ linux/drivers/net/ptifddi.c Mon Jun 19 13:42:38 2000 @@ -1,4 +1,4 @@ -/* $Id: ptifddi.c,v 1.11 1999/10/25 01:50:16 zaitcev Exp $ +/* $Id: ptifddi.c,v 1.12 2000/06/19 06:24:46 davem Exp $ * ptifddi.c: Network driver for Performance Technologies single-attach * and dual-attach FDDI sbus cards. * @@ -165,7 +165,7 @@ &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; + return -ENODEV; } /* Next, register 1 contains reset byte. */ @@ -173,7 +173,7 @@ &sdep->resource[1], 0, 1, "PTI FDDI RESET Byte"); if(!pp->reset) { printk("ptiFDDI: Cannot map RESET byte.\n"); - return ENODEV; + return -ENODEV; } /* Register 2 contains unreset byte. */ @@ -181,7 +181,7 @@ &sdep->resource[2], 0, 1, "PTI FDDI UNRESET Byte"); if(!pp->unreset) { printk("ptiFDDI: Cannot map UNRESET byte.\n"); - return ENODEV; + return -ENODEV; } /* Reset the card. */ @@ -191,7 +191,7 @@ i = pti_card_test(pp); if(i) { printk("ptiFDDI: Bootup card test fails.\n"); - return ENODEV; + return -ENODEV; } /* Clear DPRAM, start afresh. */ @@ -212,7 +212,7 @@ int cards = 0, v; if(called) - return ENODEV; + return -ENODEV; called++; for_each_sbus(bus) { @@ -228,7 +228,7 @@ } } if(!cards) - return ENODEV; + return -ENODEV; return 0; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/rcpci45.c linux/drivers/net/rcpci45.c --- v2.4.0-test1/linux/drivers/net/rcpci45.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/rcpci45.c Mon Jun 19 13:42:38 2000 @@ -205,7 +205,7 @@ !((pdev = pci_find_slot(pci_bus, pci_device_fn)))) break; pci_irq_line = pdev->irq; - pci_ioaddr = pdev->resource[0].start; + pci_ioaddr = pci_resource_start (pdev, 0); #ifdef RCDEBUG printk("rc: Found RedCreek PCI adapter\n"); @@ -214,6 +214,8 @@ printk("rc: pci_ioaddr = 0x%x\n", pci_ioaddr); #endif + if (pci_enable_device(pdev)) + break; pci_set_master(pdev); if (!RCfound_device(pci_ioaddr, pci_irq_line, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/rrunner.c linux/drivers/net/rrunner.c --- v2.4.0-test1/linux/drivers/net/rrunner.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/net/rrunner.c Mon Jun 19 13:42:38 2000 @@ -146,6 +146,9 @@ PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER, pdev))) { + if (pci_enable_device(pdev)) + continue; + if (pdev == opdev) return 0; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/rtl8129.c linux/drivers/net/rtl8129.c --- v2.4.0-test1/linux/drivers/net/rtl8129.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/net/rtl8129.c Mon Jun 19 13:42:38 2000 @@ -353,8 +353,12 @@ continue; pdev = pci_find_slot(pci_bus, pci_device_fn); - ioaddr = pdev->resource[0].start; + + ioaddr = pci_resource_start(pdev, 0); irq = pdev->irq; + + if (pci_enable_device(pdev)) + continue; if ((pci_tbl[chip_idx].flags & PCI_USES_IO) && check_region(ioaddr, pci_tbl[chip_idx].io_size)) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/seeq8005.c linux/drivers/net/seeq8005.c --- v2.4.0-test1/linux/drivers/net/seeq8005.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/net/seeq8005.c Mon Jun 19 13:42:38 2000 @@ -119,7 +119,7 @@ if (base_addr > 0x1ff) /* Check a single specified location. */ return seeq8005_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ - return ENXIO; + return -ENXIO; for (i = 0; seeq8005_portlist[i]; i++) { int ioaddr = seeq8005_portlist[i]; @@ -129,7 +129,7 @@ return 0; } - return ENODEV; + return -ENODEV; } #endif @@ -153,27 +153,27 @@ old_stat = inw(SEEQ_STATUS); /* read status register */ if (old_stat == 0xffff) - return ENODEV; /* assume that 0xffff == no device */ + return -ENODEV; /* assume that 0xffff == no device */ if ( (old_stat & 0x1800) != 0x1800 ) { /* assume that unused bits are 1, as my manual says */ if (net_debug>1) { printk("seeq8005: reserved stat bits != 0x1800\n"); printk(" == 0x%04x\n",old_stat); } - return ENODEV; + return -ENODEV; } old_rear = inw(SEEQ_REA); if (old_rear == 0xffff) { outw(0,SEEQ_REA); if (inw(SEEQ_REA) == 0xffff) { /* assume that 0xffff == no device */ - return ENODEV; + return -ENODEV; } } else if ((old_rear & 0xff00) != 0xff00) { /* assume that unused bits are 1 */ if (net_debug>1) { printk("seeq8005: unused rear bits != 0xff00\n"); printk(" == 0x%04x\n",old_rear); } - return ENODEV; + return -ENODEV; } old_cfg2 = inw(SEEQ_CFG2); /* read CFG2 register */ @@ -207,7 +207,7 @@ outw( old_stat, SEEQ_STATUS); outw( old_dmaar, SEEQ_DMAAR); outw( old_cfg1, SEEQ_CFG1); - return ENODEV; + return -ENODEV; } #endif @@ -309,7 +309,7 @@ if (irqval) { printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name, dev->irq, irqval); - return EAGAIN; + return -EAGAIN; } } #endif @@ -356,7 +356,7 @@ if (irqval) { printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name, dev->irq, irqval); - return EAGAIN; + return -EAGAIN; } } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/sis900.c linux/drivers/net/sis900.c --- v2.4.0-test1/linux/drivers/net/sis900.c Tue May 23 15:31:35 2000 +++ linux/drivers/net/sis900.c Mon Jun 19 13:42:38 2000 @@ -1,6 +1,6 @@ /* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux. Copyright 1999 Silicon Integrated System Corporation - Revision: 1.06.04 Feb 11 2000 + Revision: 1.07 Mar. 07 2000 Modified from the driver which is originally written by Donald Becker. @@ -18,6 +18,7 @@ preliminary Rev. 1.0 Jan. 18, 1998 http://www.sis.com.tw/support/databook.htm + Rev 1.07 Mar. 07 2000 Ollie Lho bug fix in Rx buffer ring Rev 1.06.04 Feb. 11 2000 Jeff Garzik softnet and init for kernel 2.4 Rev 1.06.03 Dec. 23 1999 Ollie Lho Third release Rev 1.06.02 Nov. 23 1999 Ollie Lho bug in mac probing fixed @@ -69,17 +70,17 @@ char *card_name); enum { SIS_900 = 0, - SIS_7018 + SIS_7016 }; static char * card_names[] = { "SiS 900 PCI Fast Ethernet", "SiS 7016 PCI Fast Ethernet" }; -static struct pci_device_id sis900_pci_tbl [] __initdata = { +static struct pci_device_id sis900_pci_tbl [] __devinitdata = { {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_900}, {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7016, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_7018}, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_7016}, {0,} }; MODULE_DEVICE_TABLE (pci, sis900_pci_tbl); @@ -123,6 +124,7 @@ unsigned int cur_phy; struct timer_list timer; /* Link status detection timer. */ + unsigned int cur_rx, dirty_rx; unsigned int cur_tx, dirty_tx; @@ -131,8 +133,8 @@ struct sk_buff *rx_skbuff[NUM_RX_DESC]; BufferDesc tx_ring[NUM_TX_DESC]; BufferDesc rx_ring[NUM_RX_DESC]; - unsigned int tx_full; /* The Tx queue is full. */ + unsigned int tx_full; /* The Tx queue is full. */ int LinkOn; }; @@ -175,7 +177,7 @@ return -ENODEV; } - pci_io_base = pci_dev->resource[0].start; + pci_io_base = pci_resource_start(pci_dev, 0); if (check_region(pci_io_base, SIS900_TOTAL_SIZE)) { printk(KERN_ERR "sis900.c: can't allocate I/O space at 0x%08x\n", pci_io_base); @@ -189,7 +191,7 @@ /* do the real low level jobs */ if (sis900_mac_probe(pci_dev, card_names[pci_id->driver_data]) == NULL) - return -1; + return -ENODEV; return 0; } @@ -197,7 +199,7 @@ static struct net_device * __init sis900_mac_probe (struct pci_dev * pci_dev, char * card_name) { struct sis900_private *sis_priv; - long ioaddr = pci_dev->resource[0].start; + long ioaddr = pci_resource_start(pci_dev, 0); struct net_device *net_dev = NULL; int irq = pci_dev->irq; u16 signature; @@ -472,15 +474,16 @@ struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; long ioaddr = net_dev->base_addr; + MOD_INC_USE_COUNT; + /* Soft reset the chip. */ sis900_reset(net_dev); if (request_irq(net_dev->irq, &sis900_interrupt, SA_SHIRQ, net_dev->name, net_dev)) { + MOD_DEC_USE_COUNT; return -EAGAIN; } - MOD_INC_USE_COUNT; - sis900_init_rxfilter(net_dev); sis900_init_tx_ring(net_dev); @@ -1256,8 +1259,7 @@ struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; unregister_netdev(net_dev); - release_region(net_dev->base_addr, - SIS900_TOTAL_SIZE); + release_region(net_dev->base_addr, SIS900_TOTAL_SIZE); kfree(sis_priv); kfree(net_dev); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/sk98lin/skge.c linux/drivers/net/sk98lin/skge.c --- v2.4.0-test1/linux/drivers/net/sk98lin/skge.c Tue Apr 11 15:09:17 2000 +++ linux/drivers/net/sk98lin/skge.c Mon Jun 19 13:42:38 2000 @@ -369,24 +369,18 @@ if (!pci_present()) /* is PCI support present? */ return -ENODEV; - while((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev))) - { - dev = NULL; - - if (pdev->vendor != PCI_VENDOR_ID_SYSKONNECT || - pdev->device != PCI_DEVICE_ID_SYSKONNECT_GE) { + while((pdev = pci_find_device(PCI_VENDOR_ID_SYSKONNECT, + PCI_DEVICE_ID_SYSKONNECT_GE, pdev)) != NULL) { + if (pci_enable_device(pdev)) continue; - } dev = init_etherdev(dev, sizeof(SK_AC)); - if (dev == NULL || dev->priv == NULL){ + if (dev == NULL) { printk(KERN_ERR "Unable to allocate etherdev " "structure!\n"); break; } - memset(dev->priv, 0, sizeof(SK_AC)); - pAC = dev->priv; pAC->PciDev = *pdev; pAC->PciDevId = pdev->device; @@ -412,7 +406,7 @@ pci_set_master(pdev); - base_address = pdev->resource[0].start; + base_address = pci_resource_start (pdev, 0); #ifdef SK_BIG_ENDIAN /* diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c --- v2.4.0-test1/linux/drivers/net/sk_g16.c Sat Feb 26 22:31:47 2000 +++ linux/drivers/net/sk_g16.c Mon Jun 19 13:42:38 2000 @@ -556,11 +556,11 @@ return SK_probe(dev, base_addr); } - return ENODEV; /* Sorry, but on specified address NO SK_G16 */ + return -ENODEV; /* Sorry, but on specified address NO SK_G16 */ } else if (base_addr > 0) /* Don't probe at all */ { - return ENXIO; + return -ENXIO; } /* Autoprobe base_addr */ @@ -594,7 +594,7 @@ dev->base_addr = base_addr; /* Write back original base_addr */ - return ENODEV; /* Failed to find or init driver */ + return -ENODEV; /* Failed to find or init driver */ } /* End of SK_init */ @@ -752,7 +752,7 @@ { PRINTK(("## %s: We did not find SK_G16 at RAM location.\n", SK_NAME)); - return ENODEV; /* NO SK_G16 found */ + return -ENODEV; /* NO SK_G16 found */ } printk("%s: %s found at %#3x, HW addr: %#04x:%02x:%02x:%02x:%02x:%02x\n", diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/sk_mca.c linux/drivers/net/sk_mca.c --- v2.4.0-test1/linux/drivers/net/sk_mca.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/sk_mca.c Mon Jun 19 13:42:38 2000 @@ -62,14 +62,25 @@ implemented LANCE multicast filter Jun 6th, 1999 additions for Linux 2.2 - Aug 2nd, 1999 - small fixes (David Weinehall) + Dec 25th, 1999 + unfortunately there seem to be newer MC2+ boards that react + on IRQ 3/5/9/10 instead of 3/5/10/11, so we have to autoprobe + in questionable cases... + Dec 28th, 1999 + integrated patches from David Weinehall & Bill Wendling for 2.3 + kernels (isa_...functions). Things are defined in a way that + it still works with 2.0.x 8-) + Dec 30th, 1999 + added handling of the remaining interrupt conditions. That + should cure the spurious hangs. + Jan 30th, 2000 + newer kernels automatically probe more than one board, so the + 'startslot' as a variable is also needed here + June 1st, 2000 + added changes for recent 2.3 kernels *************************************************************************/ -#include -#include - #include #include #include @@ -84,6 +95,11 @@ #include #include +#ifdef MODULE +#include +#include +#endif + #include #include #include @@ -96,11 +112,11 @@ * have to pack all state info into the device struct! * ------------------------------------------------------------------------ */ -static char *MediaNames[Media_Count] = { - "10Base2", "10BaseT", "10Base5", "Unknown" }; +static char *MediaNames[Media_Count] = + { "10Base2", "10BaseT", "10Base5", "Unknown" }; -static unsigned char poly[] = { - 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, +static unsigned char poly[] = + { 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0 }; @@ -111,14 +127,14 @@ /* dump parts of shared memory - only needed during debugging */ #ifdef DEBUG -static void dumpmem(struct net_device *dev, u32 start, u32 len) +static void dumpmem(struct SKMCA_NETDEV *dev, u32 start, u32 len) { int z; for (z = 0; z < len; z++) { if ((z & 15) == 0) printk("%04x:", z); - printk(" %02x", readb(dev->mem_start + start + z)); + printk(" %02x", SKMCA_READB(dev->mem_start + start + z)); if ((z & 15) == 15) printk("\n"); } @@ -133,7 +149,6 @@ do_gettimeofday(&tv); printk("%9d:%06d: ", tv.tv_sec, tv.tv_usec); } - #endif /* deduce resources out of POS registers */ @@ -169,10 +184,10 @@ *irq = 5; break; case 8: - *irq = 10; + *irq = -10; break; case 12: - *irq = 11; + *irq = -11; break; } *medium = (pos2 >> 6) & 3; @@ -205,18 +220,37 @@ /* reset the whole board */ -static void ResetBoard(struct net_device *dev) +static void ResetBoard(struct SKMCA_NETDEV *dev) { skmca_priv *priv = (skmca_priv *) dev->priv; - writeb(CTRL_RESET_ON, priv->ctrladdr); + SKMCA_WRITEB(CTRL_RESET_ON, priv->ctrladdr); udelay(10); - writeb(CTRL_RESET_OFF, priv->ctrladdr); + SKMCA_WRITEB(CTRL_RESET_OFF, priv->ctrladdr); +} + +/* wait for LANCE interface to become not busy */ + +static int WaitLANCE(struct SKMCA_NETDEV *dev) +{ + skmca_priv *priv = (skmca_priv *) dev->priv; + int t = 0; + + while ((SKMCA_READB(priv->ctrladdr) & STAT_IO_BUSY) == + STAT_IO_BUSY) { + udelay(1); + if (++t > 1000) { + printk("%s: LANCE access timeout", dev->name); + return 0; + } + } + + return 1; } /* set LANCE register - must be atomic */ -static void SetLANCE(struct net_device *dev, u16 addr, u16 value) +static void SetLANCE(struct SKMCA_NETDEV *dev, u16 addr, u16 value) { skmca_priv *priv = (skmca_priv *) dev->priv; unsigned long flags; @@ -228,25 +262,25 @@ /* wait until no transfer is pending */ - while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY); + WaitLANCE(dev); /* transfer register address to RAP */ - writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, - priv->ctrladdr); - writew(addr, priv->ioregaddr); - writeb(IOCMD_GO, priv->cmdaddr); + SKMCA_WRITEB(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, + priv->ctrladdr); + SKMCA_WRITEW(addr, priv->ioregaddr); + SKMCA_WRITEB(IOCMD_GO, priv->cmdaddr); udelay(1); - while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY); + WaitLANCE(dev); /* transfer data to register */ - writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_DATA, - priv->ctrladdr); - writew(value, priv->ioregaddr); - writeb(IOCMD_GO, priv->cmdaddr); + SKMCA_WRITEB(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_DATA, + priv->ctrladdr); + SKMCA_WRITEW(value, priv->ioregaddr); + SKMCA_WRITEB(IOCMD_GO, priv->cmdaddr); udelay(1); - while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY); + WaitLANCE(dev); /* reenable interrupts */ @@ -255,7 +289,7 @@ /* get LANCE register */ -static u16 GetLANCE(struct net_device *dev, u16 addr) +static u16 GetLANCE(struct SKMCA_NETDEV *dev, u16 addr) { skmca_priv *priv = (skmca_priv *) dev->priv; unsigned long flags; @@ -268,25 +302,25 @@ /* wait until no transfer is pending */ - while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY); + WaitLANCE(dev); /* transfer register address to RAP */ - writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, - priv->ctrladdr); - writew(addr, priv->ioregaddr); - writeb(IOCMD_GO, priv->cmdaddr); + SKMCA_WRITEB(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, + priv->ctrladdr); + SKMCA_WRITEW(addr, priv->ioregaddr); + SKMCA_WRITEB(IOCMD_GO, priv->cmdaddr); udelay(1); - while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY); + WaitLANCE(dev); /* transfer data from register */ - writeb(CTRL_RESET_OFF | CTRL_RW_READ | CTRL_ADR_DATA, - priv->ctrladdr); - writeb(IOCMD_GO, priv->cmdaddr); + SKMCA_WRITEB(CTRL_RESET_OFF | CTRL_RW_READ | CTRL_ADR_DATA, + priv->ctrladdr); + SKMCA_WRITEB(IOCMD_GO, priv->cmdaddr); udelay(1); - while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY); - res = readw(priv->ioregaddr); + WaitLANCE(dev); + res = SKMCA_READW(priv->ioregaddr); /* reenable interrupts */ @@ -297,7 +331,7 @@ /* build up descriptors in shared RAM */ -static void InitDscrs(struct net_device *dev) +static void InitDscrs(struct SKMCA_NETDEV *dev) { u32 bufaddr; @@ -314,11 +348,11 @@ descr.Flags = 0; descr.Len = 0xf000; descr.Status = 0; - isa_memcpy_toio(dev->mem_start + RAM_TXBASE + - (z * sizeof(LANCE_TxDescr)), - &descr, sizeof(LANCE_TxDescr)); - memset_io(dev->mem_start + bufaddr, 0, - RAM_BUFSIZE); + SKMCA_TOIO(dev->mem_start + RAM_TXBASE + + (z * sizeof(LANCE_TxDescr)), &descr, + sizeof(LANCE_TxDescr)); + SKMCA_SETIO(dev->mem_start + bufaddr, 0, + RAM_BUFSIZE); bufaddr += RAM_BUFSIZE; } } @@ -334,11 +368,11 @@ descr.Flags = RXDSCR_FLAGS_OWN; descr.MaxLen = -RAM_BUFSIZE; descr.Len = 0; - isa_memcpy_toio(dev->mem_start + RAM_RXBASE + - (z * sizeof(LANCE_RxDescr)), - &descr, sizeof(LANCE_RxDescr)); - isa_memset_io(dev->mem_start + bufaddr, 0, - RAM_BUFSIZE); + SKMCA_TOIO(dev->mem_start + RAM_RXBASE + + (z * sizeof(LANCE_RxDescr)), &descr, + sizeof(LANCE_RxDescr)); + SKMCA_SETIO(dev->mem_start + bufaddr, 0, + RAM_BUFSIZE); bufaddr += RAM_BUFSIZE; } } @@ -393,7 +427,7 @@ /* feed ready-built initialization block into LANCE */ -static void InitLANCE(struct net_device *dev) +static void InitLANCE(struct SKMCA_NETDEV *dev) { skmca_priv *priv = (skmca_priv *) dev->priv; @@ -423,8 +457,12 @@ /* we don't get ready until the LANCE has read the init block */ +#if (LINUX_VERSION_CODE >= 0x02032a) netif_stop_queue(dev); - +#else + dev->tbusy = 1; +#endif + /* let LANCE read the initialization block. LANCE is ready when we receive the corresponding interrupt. */ @@ -433,12 +471,16 @@ /* stop the LANCE so we can reinitialize it */ -static void StopLANCE(struct net_device *dev) +static void StopLANCE(struct SKMCA_NETDEV *dev) { /* can't take frames any more */ +#if (LINUX_VERSION_CODE >= 0x02032a) netif_stop_queue(dev); - +#else + dev->tbusy = 1; +#endif + /* disable interrupts, stop it */ SetLANCE(dev, LANCE_CSR0, CSR0_STOP); @@ -446,7 +488,7 @@ /* initialize card and LANCE for proper operation */ -static void InitBoard(struct net_device *dev) +static void InitBoard(struct SKMCA_NETDEV *dev) { LANCE_InitBlock block; @@ -462,8 +504,7 @@ block.RdrP = (RAM_RXBASE & 0xffffff) | (LRXCOUNT << 29); block.TdrP = (RAM_TXBASE & 0xffffff) | (LTXCOUNT << 29); - isa_memcpy_toio(dev->mem_start + RAM_INITBASE, &block, - sizeof(block)); + SKMCA_TOIO(dev->mem_start + RAM_INITBASE, &block, sizeof(block)); /* initialize LANCE. Implicitly sets up other structures in RAM. */ @@ -472,7 +513,7 @@ /* deinitialize card and LANCE */ -static void DeinitBoard(struct net_device *dev) +static void DeinitBoard(struct SKMCA_NETDEV *dev) { /* stop LANCE */ @@ -483,44 +524,97 @@ ResetBoard(dev); } +/* probe for device's irq */ + +static int ProbeIRQ(struct SKMCA_NETDEV *dev) +{ + unsigned long imaskval, njiffies, irq; + u16 csr0val; + + /* enable all interrupts */ + + imaskval = probe_irq_on(); + + /* initialize the board. Wait for interrupt 'Initialization done'. */ + + ResetBoard(dev); + InitBoard(dev); + + njiffies = jiffies + 100; + do { + csr0val = GetLANCE(dev, LANCE_CSR0); + } + while (((csr0val & CSR0_IDON) == 0) && (jiffies != njiffies)); + + /* turn of interrupts again */ + + irq = probe_irq_off(imaskval); + + /* if we found something, ack the interrupt */ + + if (irq) + SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_IDON); + + /* back to idle state */ + + DeinitBoard(dev); + + return irq; +} + /* ------------------------------------------------------------------------ * interrupt handler(s) * ------------------------------------------------------------------------ */ -/* LANCE has read initializazion block -> start it */ +/* LANCE has read initialization block -> start it */ -static u16 irqstart_handler(struct net_device *dev, u16 oldcsr0) +static u16 irqstart_handler(struct SKMCA_NETDEV *dev, u16 oldcsr0) { /* now we're ready to transmit */ +#if (LINUX_VERSION_CODE >= 0x02032a) netif_wake_queue(dev); - +#else + dev->tbusy = 0; +#endif + /* reset IDON bit, start LANCE */ SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_IDON | CSR0_STRT); return GetLANCE(dev, LANCE_CSR0); } +/* did we loose blocks due to a FIFO overrun ? */ + +static u16 irqmiss_handler(struct SKMCA_NETDEV *dev, u16 oldcsr0) +{ + skmca_priv *priv = (skmca_priv *) dev->priv; + + /* update statistics */ + + priv->stat.rx_fifo_errors++; + + /* reset MISS bit */ + + SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_MISS); + return GetLANCE(dev, LANCE_CSR0); +} + /* receive interrupt */ -static u16 irqrx_handler(struct net_device *dev, u16 oldcsr0) +static u16 irqrx_handler(struct SKMCA_NETDEV *dev, u16 oldcsr0) { skmca_priv *priv = (skmca_priv *) dev->priv; LANCE_RxDescr descr; unsigned int descraddr; - /* did we loose blocks due to a FIFO overrun ? */ - - if (oldcsr0 & CSR0_MISS) - priv->stat.rx_fifo_errors++; - /* run through queue until we reach a descriptor we do not own */ descraddr = RAM_RXBASE + (priv->nextrx * sizeof(LANCE_RxDescr)); while (1) { /* read descriptor */ - isa_memcpy_fromio(&descr, dev->mem_start + descraddr, - sizeof(LANCE_RxDescr)); + SKMCA_FROMIO(&descr, dev->mem_start + descraddr, + sizeof(LANCE_RxDescr)); /* if we reach a descriptor we do not own, we're done */ if ((descr.Flags & RXDSCR_FLAGS_OWN) != 0) @@ -551,10 +645,9 @@ if (skb == NULL) priv->stat.rx_dropped++; else { - isa_memcpy_fromio(skb_put(skb, descr.Len), - dev->mem_start + - descr.LowAddr, - descr.Len); + SKMCA_FROMIO(skb_put(skb, descr.Len), + dev->mem_start + + descr.LowAddr, descr.Len); skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_NONE; @@ -571,8 +664,8 @@ descr.Flags |= RXDSCR_FLAGS_OWN; /* update descriptor in shared RAM */ - isa_memcpy_toio(dev->mem_start + descraddr, &descr, - sizeof(LANCE_RxDescr)); + SKMCA_TOIO(dev->mem_start + descraddr, &descr, + sizeof(LANCE_RxDescr)); /* go to next descriptor */ priv->nextrx++; @@ -591,7 +684,7 @@ /* transmit interrupt */ -static u16 irqtx_handler(struct net_device *dev, u16 oldcsr0) +static u16 irqtx_handler(struct SKMCA_NETDEV *dev, u16 oldcsr0) { skmca_priv *priv = (skmca_priv *) dev->priv; LANCE_TxDescr descr; @@ -603,8 +696,8 @@ RAM_TXBASE + (priv->nexttxdone * sizeof(LANCE_TxDescr)); while (priv->txbusy > 0) { /* read descriptor */ - isa_memcpy_fromio(&descr, dev->mem_start + descraddr, - sizeof(LANCE_TxDescr)); + SKMCA_FROMIO(&descr, dev->mem_start + descraddr, + sizeof(LANCE_TxDescr)); /* if the LANCE still owns this one, we've worked out all sent packets */ if ((descr.Flags & TXDSCR_FLAGS_OWN) != 0) @@ -653,9 +746,15 @@ /* at least one descriptor is freed. Therefore we can accept a new one */ + /* inform upper layers we're in business again */ +#if (LINUX_VERSION_CODE >= 0x02032a) netif_wake_queue(dev); - +#else + dev->tbusy = 0; + mark_bh(NET_BH); +#endif + return oldcsr0; } @@ -663,7 +762,7 @@ static void irq_handler(int irq, void *device, struct pt_regs *regs) { - struct net_device *dev = (struct net_device *) device; + struct SKMCA_NETDEV *dev = (struct SKMCA_NETDEV *) device; u16 csr0val; /* read CSR0 to get interrupt cause */ @@ -675,6 +774,14 @@ if ((csr0val & CSR0_INTR) == 0) return; +#if (LINUX_VERSION_CODE >= 0x02032a) +#if 0 + set_bit(LINK_STATE_RXSEM, &dev->state); +#endif +#else + dev->interrupt = 1; +#endif + /* loop through the interrupt bits until everything is clear */ do { @@ -682,10 +789,28 @@ csr0val = irqstart_handler(dev, csr0val); if ((csr0val & CSR0_RINT) != 0) csr0val = irqrx_handler(dev, csr0val); + if ((csr0val & CSR0_MISS) != 0) + csr0val = irqmiss_handler(dev, csr0val); if ((csr0val & CSR0_TINT) != 0) csr0val = irqtx_handler(dev, csr0val); + if ((csr0val & CSR0_MERR) != 0) { + SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_MERR); + csr0val = GetLANCE(dev, LANCE_CSR0); + } + if ((csr0val & CSR0_BABL) != 0) { + SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_BABL); + csr0val = GetLANCE(dev, LANCE_CSR0); + } } while ((csr0val & CSR0_INTR) != 0); + +#if (LINUX_VERSION_CODE >= 0x02032a) +#if 0 + clear_bit(LINK_STATE_RXSEM, &dev->state); +#endif +#else + dev->interrupt = 0; +#endif } /* ------------------------------------------------------------------------ @@ -697,7 +822,7 @@ static int skmca_getinfo(char *buf, int slot, void *d) { int len = 0, i; - struct net_device *dev = (struct net_device *) d; + struct SKMCA_NETDEV *dev = (struct SKMCA_NETDEV *) d; skmca_priv *priv; /* can't say anything about an uninitialized device... */ @@ -728,7 +853,7 @@ /* open driver. Means also initialization and start of LANCE */ -static int skmca_open(struct net_device *dev) +static int skmca_open(struct SKMCA_NETDEV *dev) { int result; skmca_priv *priv = (skmca_priv *) dev->priv; @@ -745,8 +870,19 @@ dev->irq = priv->realirq; /* set up the card and LANCE */ + InitBoard(dev); + /* set up flags */ + +#if (LINUX_VERSION_CODE >= 0x02032a) + netif_start_queue(dev); +#else + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 0; +#endif + #ifdef MODULE MOD_INC_USE_COUNT; #endif @@ -756,7 +892,7 @@ /* close driver. Shut down board and free allocated resources */ -static int skmca_close(struct net_device *dev) +static int skmca_close(struct SKMCA_NETDEV *dev) { /* turn off board */ DeinitBoard(dev); @@ -775,7 +911,7 @@ /* transmit a block. */ -static int skmca_tx(struct sk_buff *skb, struct net_device *dev) +static int skmca_tx(struct sk_buff *skb, struct SKMCA_NETDEV *dev) { skmca_priv *priv = (skmca_priv *) dev->priv; LANCE_TxDescr descr; @@ -783,8 +919,15 @@ int tmplen, retval = 0; unsigned long flags; - netif_stop_queue(dev); - + /* if we get called with a NULL descriptor, the Ethernet layer thinks + our card is stuck an we should reset it. We'll do this completely: */ + + if (skb == NULL) { + DeinitBoard(dev); + InitBoard(dev); + return 0; /* don't try to free the block here ;-) */ + } + /* is there space in the Tx queue ? If no, the upper layer gave us a packet in spite of us not being ready and is really in trouble. We'll do the dropping for him: */ @@ -796,8 +939,8 @@ /* get TX descriptor */ address = RAM_TXBASE + (priv->nexttxput * sizeof(LANCE_TxDescr)); - isa_memcpy_fromio(&descr, dev->mem_start + address, - sizeof(LANCE_TxDescr)); + SKMCA_FROMIO(&descr, dev->mem_start + address, + sizeof(LANCE_TxDescr)); /* enter packet length as 2s complement - assure minimum length */ tmplen = skb->len; @@ -813,15 +956,14 @@ unsigned int destoffs = 0, l = strlen(fill); while (destoffs < tmplen) { - isa_memcpy_toio(dev->mem_start + descr.LowAddr + - destoffs, fill, l); + SKMCA_TOIO(dev->mem_start + descr.LowAddr + + destoffs, fill, l); destoffs += l; } } /* do the real data copying */ - isa_memcpy_toio(dev->mem_start + descr.LowAddr, skb->data, - skb->len); + SKMCA_TOIO(dev->mem_start + descr.LowAddr, skb->data, skb->len); /* hand descriptor over to LANCE - this is the first and last chunk */ descr.Flags = @@ -840,12 +982,19 @@ if (priv->nexttxput >= TXCOUNT) priv->nexttxput = 0; priv->txbusy++; - if (priv->txbusy < TXCOUNT) - netif_wake_queue(dev); + + /* are we saturated ? */ + + if (priv->txbusy >= TXCOUNT) +#if (LINUX_VERSION_CODE >= 0x02032a) + netif_stop_queue(dev); +#else + dev->tbusy = 1; +#endif /* write descriptor back to RAM */ - isa_memcpy_toio(dev->mem_start + address, &descr, - sizeof(LANCE_TxDescr)); + SKMCA_TOIO(dev->mem_start + address, &descr, + sizeof(LANCE_TxDescr)); /* if no descriptors were active, give the LANCE a hint to read it immediately */ @@ -855,24 +1004,31 @@ restore_flags(flags); -tx_done: + tx_done: + /* When did that change exactly ? */ + +#if LINUX_VERSION_CODE >= 0x020200 dev_kfree_skb(skb); +#else + dev_kfree_skb(skb, FREE_WRITE); +#endif return retval; } /* return pointer to Ethernet statistics */ -static struct enet_statistics *skmca_stats(struct net_device *dev) +static struct enet_statistics *skmca_stats(struct SKMCA_NETDEV *dev) { skmca_priv *priv = (skmca_priv *) dev->priv; + return &(priv->stat); } /* we don't support runtime reconfiguration, since an MCA card can be unambigously identified by its POS registers. */ -static int skmca_config(struct net_device *dev, struct ifmap *map) +static int skmca_config(struct SKMCA_NETDEV *dev, struct ifmap *map) { return 0; } @@ -880,7 +1036,7 @@ /* switch receiver mode. We use the LANCE's multicast filter to prefilter multicast addresses. */ -static void skmca_set_multicast_list(struct net_device *dev) +static void skmca_set_multicast_list(struct SKMCA_NETDEV *dev) { LANCE_InitBlock block; @@ -888,8 +1044,7 @@ StopLANCE(dev); /* ...then modify the initialization block... */ - isa_memcpy_fromio(&block, dev->mem_start + RAM_INITBASE, - sizeof(block)); + SKMCA_FROMIO(&block, dev->mem_start + RAM_INITBASE, sizeof(block)); if (dev->flags & IFF_PROMISC) block.Mode |= LANCE_INIT_PROM; else @@ -909,8 +1064,7 @@ } } - isa_memcpy_toio(dev->mem_start + RAM_INITBASE, &block, - sizeof(block)); + SKMCA_TOIO(dev->mem_start + RAM_INITBASE, &block, sizeof(block)); /* ...then reinit LANCE with the correct flags */ InitLANCE(dev); @@ -920,13 +1074,9 @@ * hardware check * ------------------------------------------------------------------------ */ -#ifdef MODULE static int startslot; /* counts through slots when probing multiple devices */ -#else -#define startslot 0 /* otherwise a dummy, since there is only eth0 in-kern */ -#endif -int skmca_probe(struct net_device *dev) +int skmca_probe(struct SKMCA_NETDEV *dev) { int force_detect = 0; int junior, slot, i; @@ -937,7 +1087,7 @@ /* can't work without an MCA bus ;-) */ if (MCA_bus == 0) - return ENODEV; + return -ENODEV; /* start address of 1 --> forced detection */ @@ -957,7 +1107,7 @@ getaddrs(slot, junior, &base, &irq, &medium); -#if LINUX_VERSION_CODE >= 0x020200 +#if LINUX_VERSION_CODE >= 0x020300 /* slot already in use ? */ if (mca_is_adapter_used(slot)) { @@ -1015,7 +1165,6 @@ priv->ioregaddr = base + 0x3ff0; priv->ctrladdr = base + 0x3ff2; priv->cmdaddr = base + 0x3ff3; - priv->realirq = irq; priv->medium = medium; memset(&(priv->stat), 0, sizeof(struct enet_statistics)); @@ -1024,6 +1173,22 @@ dev->mem_start = base; dev->mem_end = base + 0x4000; + /* autoprobe ? */ + if (irq < 0) { + int nirq; + + printk + ("%s: ambigous POS bit combination, must probe for IRQ...\n", + dev->name); + nirq = ProbeIRQ(dev); + if (nirq <= 0) + printk("%s: IRQ probe failed, assuming IRQ %d", + dev->name, priv->realirq = -irq); + else + priv->realirq = nirq; + } else + priv->realirq = irq; + /* set methods */ dev->open = skmca_open; dev->stop = skmca_close; @@ -1039,7 +1204,7 @@ /* copy out MAC address */ for (i = 0; i < 6; i++) - dev->dev_addr[i] = readb(priv->macbase + (i << 1)); + dev->dev_addr[i] = SKMCA_READB(priv->macbase + (i << 1)); /* print config */ printk("%s: IRQ %d, memory %#lx-%#lx, " @@ -1053,9 +1218,7 @@ ResetBoard(dev); -#ifdef MODULE startslot = slot + 1; -#endif return 0; } @@ -1068,13 +1231,24 @@ #define DEVMAX 5 -static struct net_device moddevs[DEVMAX] = - { {"", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe}, -{"", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe}, -{"", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe}, -{"", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe}, -{"", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe} +#if (LINUX_VERSION_CODE >= 0x020369) +static struct SKMCA_NETDEV moddevs[DEVMAX] = + { {" ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe}, +{" ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe}, +{" ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe}, +{" ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe}, +{" ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe} }; +#else +static char NameSpace[8 * DEVMAX]; +static struct SKMCA_NETDEV moddevs[DEVMAX] = + { {NameSpace + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe}, +{NameSpace + 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe}, +{NameSpace + 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe}, +{NameSpace + 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe}, +{NameSpace + 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe} +}; +#endif int irq = 0; int io = 0; @@ -1096,7 +1270,7 @@ void cleanup_module(void) { - struct net_device *dev; + struct SKMCA_NETDEV *dev; skmca_priv *priv; int z; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/sk_mca.h linux/drivers/net/sk_mca.h --- v2.4.0-test1/linux/drivers/net/sk_mca.h Wed Aug 18 11:36:45 1999 +++ linux/drivers/net/sk_mca.h Mon Jun 19 13:42:38 2000 @@ -3,172 +3,191 @@ #ifdef _SK_MCA_DRIVER_ +/* version-dependent functions/structures */ + +#if LINUX_VERSION_CODE >= 0x020318 +#define SKMCA_READB(addr) isa_readb(addr) +#define SKMCA_READW(addr) isa_readw(addr) +#define SKMCA_WRITEB(data, addr) isa_writeb(data, addr) +#define SKMCA_WRITEW(data, addr) isa_writew(data, addr) +#define SKMCA_TOIO(dest, src, len) isa_memcpy_toio(dest, src, len) +#define SKMCA_FROMIO(dest, src, len) isa_memcpy_fromio(dest, src, len) +#define SKMCA_SETIO(dest, val, len) isa_memset_io(dest, val, len) +#define SKMCA_NETDEV net_device +#else +#define SKMCA_READB(addr) readb(addr) +#define SKMCA_READW(addr) readw(addr) +#define SKMCA_WRITEB(data, addr) writeb(data, addr) +#define SKMCA_WRITEW(data, addr) writew(data, addr) +#define SKMCA_TOIO(dest, src, len) memcpy_toio(dest, src, len) +#define SKMCA_FROMIO(dest, src, len) memcpy_fromio(dest, src, len) +#define SKMCA_SETIO(dest, val, len) memset_io(dest, val, len) +#define SKMCA_NETDEV device +#endif + /* Adapter ID's */ #define SKNET_MCA_ID 0x6afd #define SKNET_JUNIOR_MCA_ID 0x6be9 /* media enumeration - defined in a way that it fits onto the MC2+'s POS registers... */ - -typedef enum {Media_10Base2, Media_10BaseT, - Media_10Base5, Media_Unknown, Media_Count} skmca_medium; + +typedef enum { Media_10Base2, Media_10BaseT, + Media_10Base5, Media_Unknown, Media_Count +} skmca_medium; /* private structure */ -typedef struct - { - unsigned int slot; /* MCA-Slot-# */ - unsigned int macbase; /* base address of MAC address PROM */ - unsigned int ioregaddr; /* address of I/O-register (Lo) */ - unsigned int ctrladdr; /* address of control/stat register */ - unsigned int cmdaddr; /* address of I/O-command register */ - int nextrx; /* index of next RX descriptor to - be read */ - int nexttxput; /* index of next free TX descriptor */ - int nexttxdone; /* index of next TX descriptor to - be finished */ - int txbusy; /* # of busy TX descriptors */ - struct enet_statistics stat; /* packet statistics */ - int realirq; /* memorizes actual IRQ, even when - currently not allocated */ - skmca_medium medium; /* physical cannector */ - } skmca_priv; +typedef struct { + unsigned int slot; /* MCA-Slot-# */ + unsigned int macbase; /* base address of MAC address PROM */ + unsigned int ioregaddr; /* address of I/O-register (Lo) */ + unsigned int ctrladdr; /* address of control/stat register */ + unsigned int cmdaddr; /* address of I/O-command register */ + int nextrx; /* index of next RX descriptor to + be read */ + int nexttxput; /* index of next free TX descriptor */ + int nexttxdone; /* index of next TX descriptor to + be finished */ + int txbusy; /* # of busy TX descriptors */ + struct enet_statistics stat; /* packet statistics */ + int realirq; /* memorizes actual IRQ, even when + currently not allocated */ + skmca_medium medium; /* physical cannector */ +} skmca_priv; /* card registers: control/status register bits */ -#define CTRL_ADR_DATA 0 /* Bit 0 = 0 ->access data register */ -#define CTRL_ADR_RAP 1 /* Bit 0 = 1 ->access RAP register */ -#define CTRL_RW_WRITE 0 /* Bit 1 = 0 ->write register */ -#define CTRL_RW_READ 2 /* Bit 1 = 1 ->read register */ -#define CTRL_RESET_ON 0 /* Bit 3 = 0 ->reset board */ -#define CTRL_RESET_OFF 8 /* Bit 3 = 1 ->no reset of board */ +#define CTRL_ADR_DATA 0 /* Bit 0 = 0 ->access data register */ +#define CTRL_ADR_RAP 1 /* Bit 0 = 1 ->access RAP register */ +#define CTRL_RW_WRITE 0 /* Bit 1 = 0 ->write register */ +#define CTRL_RW_READ 2 /* Bit 1 = 1 ->read register */ +#define CTRL_RESET_ON 0 /* Bit 3 = 0 ->reset board */ +#define CTRL_RESET_OFF 8 /* Bit 3 = 1 ->no reset of board */ -#define STAT_ADR_DATA 0 /* Bit 0 of ctrl register read back */ +#define STAT_ADR_DATA 0 /* Bit 0 of ctrl register read back */ #define STAT_ADR_RAP 1 -#define STAT_RW_WRITE 0 /* Bit 1 of ctrl register read back */ +#define STAT_RW_WRITE 0 /* Bit 1 of ctrl register read back */ #define STAT_RW_READ 2 -#define STAT_RESET_ON 0 /* Bit 3 of ctrl register read back */ +#define STAT_RESET_ON 0 /* Bit 3 of ctrl register read back */ #define STAT_RESET_OFF 8 -#define STAT_IRQ_ACT 0 /* interrupt pending */ -#define STAT_IRQ_NOACT 16 /* no interrupt pending */ -#define STAT_IO_NOBUSY 0 /* no transfer busy */ -#define STAT_IO_BUSY 32 /* transfer busy */ +#define STAT_IRQ_ACT 0 /* interrupt pending */ +#define STAT_IRQ_NOACT 16 /* no interrupt pending */ +#define STAT_IO_NOBUSY 0 /* no transfer busy */ +#define STAT_IO_BUSY 32 /* transfer busy */ /* I/O command register bits */ -#define IOCMD_GO 128 /* Bit 7 = 1 -> start register xfer */ +#define IOCMD_GO 128 /* Bit 7 = 1 -> start register xfer */ /* LANCE registers */ -#define LANCE_CSR0 0 /* Status/Control */ +#define LANCE_CSR0 0 /* Status/Control */ -#define CSR0_ERR 0x8000 /* general error flag */ -#define CSR0_BABL 0x4000 /* transmitter timeout */ -#define CSR0_CERR 0x2000 /* collision error */ -#define CSR0_MISS 0x1000 /* lost Rx block */ -#define CSR0_MERR 0x0800 /* memory access error */ -#define CSR0_RINT 0x0400 /* receiver interrupt */ -#define CSR0_TINT 0x0200 /* transmitter interrupt */ -#define CSR0_IDON 0x0100 /* initialization done */ -#define CSR0_INTR 0x0080 /* general interrupt flag */ -#define CSR0_INEA 0x0040 /* interrupt enable */ -#define CSR0_RXON 0x0020 /* receiver enabled */ -#define CSR0_TXON 0x0010 /* transmitter enabled */ -#define CSR0_TDMD 0x0008 /* force transmission now */ -#define CSR0_STOP 0x0004 /* stop LANCE */ -#define CSR0_STRT 0x0002 /* start LANCE */ -#define CSR0_INIT 0x0001 /* read initialization block */ - -#define LANCE_CSR1 1 /* addr bit 0..15 of initialization */ -#define LANCE_CSR2 2 /* 16..23 block */ - -#define LANCE_CSR3 3 /* Bus control */ -#define CSR3_BCON_HOLD 0 /* Bit 0 = 0 -> BM1,BM0,HOLD */ -#define CSR3_BCON_BUSRQ 1 /* Bit 0 = 1 -> BUSAK0,BYTE,BUSRQ */ -#define CSR3_ALE_HIGH 0 /* Bit 1 = 0 -> ALE asserted high */ -#define CSR3_ALE_LOW 2 /* Bit 1 = 1 -> ALE asserted low */ -#define CSR3_BSWAP_OFF 0 /* Bit 2 = 0 -> no byte swap */ -#define CSR3_BSWAP_ON 0 /* Bit 2 = 1 -> byte swap */ +#define CSR0_ERR 0x8000 /* general error flag */ +#define CSR0_BABL 0x4000 /* transmitter timeout */ +#define CSR0_CERR 0x2000 /* collision error */ +#define CSR0_MISS 0x1000 /* lost Rx block */ +#define CSR0_MERR 0x0800 /* memory access error */ +#define CSR0_RINT 0x0400 /* receiver interrupt */ +#define CSR0_TINT 0x0200 /* transmitter interrupt */ +#define CSR0_IDON 0x0100 /* initialization done */ +#define CSR0_INTR 0x0080 /* general interrupt flag */ +#define CSR0_INEA 0x0040 /* interrupt enable */ +#define CSR0_RXON 0x0020 /* receiver enabled */ +#define CSR0_TXON 0x0010 /* transmitter enabled */ +#define CSR0_TDMD 0x0008 /* force transmission now */ +#define CSR0_STOP 0x0004 /* stop LANCE */ +#define CSR0_STRT 0x0002 /* start LANCE */ +#define CSR0_INIT 0x0001 /* read initialization block */ + +#define LANCE_CSR1 1 /* addr bit 0..15 of initialization */ +#define LANCE_CSR2 2 /* 16..23 block */ + +#define LANCE_CSR3 3 /* Bus control */ +#define CSR3_BCON_HOLD 0 /* Bit 0 = 0 -> BM1,BM0,HOLD */ +#define CSR3_BCON_BUSRQ 1 /* Bit 0 = 1 -> BUSAK0,BYTE,BUSRQ */ +#define CSR3_ALE_HIGH 0 /* Bit 1 = 0 -> ALE asserted high */ +#define CSR3_ALE_LOW 2 /* Bit 1 = 1 -> ALE asserted low */ +#define CSR3_BSWAP_OFF 0 /* Bit 2 = 0 -> no byte swap */ +#define CSR3_BSWAP_ON 0 /* Bit 2 = 1 -> byte swap */ /* LANCE structures */ -typedef struct /* LANCE initialization block */ - { - u16 Mode; /* mode flags */ - u8 PAdr[6]; /* MAC address */ - u8 LAdrF[8]; /* Multicast filter */ - u32 RdrP; /* Receive descriptor */ - u32 TdrP; /* Transmit descriptor */ - } LANCE_InitBlock; - +typedef struct { /* LANCE initialization block */ + u16 Mode; /* mode flags */ + u8 PAdr[6]; /* MAC address */ + u8 LAdrF[8]; /* Multicast filter */ + u32 RdrP; /* Receive descriptor */ + u32 TdrP; /* Transmit descriptor */ +} LANCE_InitBlock; + /* Mode flags init block */ -#define LANCE_INIT_PROM 0x8000 /* enable promiscous mode */ -#define LANCE_INIT_INTL 0x0040 /* internal loopback */ -#define LANCE_INIT_DRTY 0x0020 /* disable retry */ -#define LANCE_INIT_COLL 0x0010 /* force collision */ -#define LANCE_INIT_DTCR 0x0008 /* disable transmit CRC */ -#define LANCE_INIT_LOOP 0x0004 /* loopback */ -#define LANCE_INIT_DTX 0x0002 /* disable transmitter */ -#define LANCE_INIT_DRX 0x0001 /* disable receiver */ - -typedef struct /* LANCE Tx descriptor */ - { - u16 LowAddr; /* bit 0..15 of address */ - u16 Flags; /* bit 16..23 of address + Flags */ - u16 Len; /* 2s complement of packet length */ - u16 Status; /* Result of transmission */ - } LANCE_TxDescr; - -#define TXDSCR_FLAGS_OWN 0x8000 /* LANCE owns descriptor */ -#define TXDSCR_FLAGS_ERR 0x4000 /* summary error flag */ -#define TXDSCR_FLAGS_MORE 0x1000 /* more than one retry needed? */ -#define TXDSCR_FLAGS_ONE 0x0800 /* one retry? */ -#define TXDSCR_FLAGS_DEF 0x0400 /* transmission deferred? */ -#define TXDSCR_FLAGS_STP 0x0200 /* first packet in chain? */ -#define TXDSCR_FLAGS_ENP 0x0100 /* last packet in chain? */ - -#define TXDSCR_STATUS_BUFF 0x8000 /* buffer error? */ -#define TXDSCR_STATUS_UFLO 0x4000 /* silo underflow during transmit? */ -#define TXDSCR_STATUS_LCOL 0x1000 /* late collision? */ -#define TXDSCR_STATUS_LCAR 0x0800 /* loss of carrier? */ -#define TXDSCR_STATUS_RTRY 0x0400 /* retry error? */ - -typedef struct /* LANCE Rx descriptor */ - { - u16 LowAddr; /* bit 0..15 of address */ - u16 Flags; /* bit 16..23 of address + Flags */ - u16 MaxLen; /* 2s complement of buffer length */ - u16 Len; /* packet length */ - } LANCE_RxDescr; - -#define RXDSCR_FLAGS_OWN 0x8000 /* LANCE owns descriptor */ -#define RXDSCR_FLAGS_ERR 0x4000 /* summary error flag */ -#define RXDSCR_FLAGS_FRAM 0x2000 /* framing error flag */ -#define RXDSCR_FLAGS_OFLO 0x1000 /* FIFO overflow? */ -#define RXDSCR_FLAGS_CRC 0x0800 /* CRC error? */ -#define RXDSCR_FLAGS_BUFF 0x0400 /* buffer error? */ -#define RXDSCR_FLAGS_STP 0x0200 /* first packet in chain? */ -#define RXDCSR_FLAGS_ENP 0x0100 /* last packet in chain? */ +#define LANCE_INIT_PROM 0x8000 /* enable promiscous mode */ +#define LANCE_INIT_INTL 0x0040 /* internal loopback */ +#define LANCE_INIT_DRTY 0x0020 /* disable retry */ +#define LANCE_INIT_COLL 0x0010 /* force collision */ +#define LANCE_INIT_DTCR 0x0008 /* disable transmit CRC */ +#define LANCE_INIT_LOOP 0x0004 /* loopback */ +#define LANCE_INIT_DTX 0x0002 /* disable transmitter */ +#define LANCE_INIT_DRX 0x0001 /* disable receiver */ + +typedef struct { /* LANCE Tx descriptor */ + u16 LowAddr; /* bit 0..15 of address */ + u16 Flags; /* bit 16..23 of address + Flags */ + u16 Len; /* 2s complement of packet length */ + u16 Status; /* Result of transmission */ +} LANCE_TxDescr; + +#define TXDSCR_FLAGS_OWN 0x8000 /* LANCE owns descriptor */ +#define TXDSCR_FLAGS_ERR 0x4000 /* summary error flag */ +#define TXDSCR_FLAGS_MORE 0x1000 /* more than one retry needed? */ +#define TXDSCR_FLAGS_ONE 0x0800 /* one retry? */ +#define TXDSCR_FLAGS_DEF 0x0400 /* transmission deferred? */ +#define TXDSCR_FLAGS_STP 0x0200 /* first packet in chain? */ +#define TXDSCR_FLAGS_ENP 0x0100 /* last packet in chain? */ + +#define TXDSCR_STATUS_BUFF 0x8000 /* buffer error? */ +#define TXDSCR_STATUS_UFLO 0x4000 /* silo underflow during transmit? */ +#define TXDSCR_STATUS_LCOL 0x1000 /* late collision? */ +#define TXDSCR_STATUS_LCAR 0x0800 /* loss of carrier? */ +#define TXDSCR_STATUS_RTRY 0x0400 /* retry error? */ + +typedef struct { /* LANCE Rx descriptor */ + u16 LowAddr; /* bit 0..15 of address */ + u16 Flags; /* bit 16..23 of address + Flags */ + u16 MaxLen; /* 2s complement of buffer length */ + u16 Len; /* packet length */ +} LANCE_RxDescr; + +#define RXDSCR_FLAGS_OWN 0x8000 /* LANCE owns descriptor */ +#define RXDSCR_FLAGS_ERR 0x4000 /* summary error flag */ +#define RXDSCR_FLAGS_FRAM 0x2000 /* framing error flag */ +#define RXDSCR_FLAGS_OFLO 0x1000 /* FIFO overflow? */ +#define RXDSCR_FLAGS_CRC 0x0800 /* CRC error? */ +#define RXDSCR_FLAGS_BUFF 0x0400 /* buffer error? */ +#define RXDSCR_FLAGS_STP 0x0200 /* first packet in chain? */ +#define RXDCSR_FLAGS_ENP 0x0100 /* last packet in chain? */ /* RAM layout */ -#define TXCOUNT 4 /* length of TX descriptor queue */ -#define LTXCOUNT 2 /* log2 of it */ -#define RXCOUNT 4 /* length of RX descriptor queue */ -#define LRXCOUNT 2 /* log2 of it */ +#define TXCOUNT 4 /* length of TX descriptor queue */ +#define LTXCOUNT 2 /* log2 of it */ +#define RXCOUNT 4 /* length of RX descriptor queue */ +#define LRXCOUNT 2 /* log2 of it */ -#define RAM_INITBASE 0 /* LANCE init block */ -#define RAM_TXBASE 24 /* Start of TX descriptor queue */ +#define RAM_INITBASE 0 /* LANCE init block */ +#define RAM_TXBASE 24 /* Start of TX descriptor queue */ #define RAM_RXBASE \ -(RAM_TXBASE + (TXCOUNT * 8)) /* Start of RX descriptor queue */ +(RAM_TXBASE + (TXCOUNT * 8)) /* Start of RX descriptor queue */ #define RAM_DATABASE \ -(RAM_RXBASE + (RXCOUNT * 8)) /* Start of data area for frames */ -#define RAM_BUFSIZE 1580 /* max. frame size - should never be - reached */ +(RAM_RXBASE + (RXCOUNT * 8)) /* Start of data area for frames */ +#define RAM_BUFSIZE 1580 /* max. frame size - should never be + reached */ -#endif /* _SK_MCA_DRIVER_ */ +#endif /* _SK_MCA_DRIVER_ */ -extern int skmca_probe(struct net_device *); +extern int skmca_probe(struct SKMCA_NETDEV *); -#endif /* _SK_MCA_INCLUDE_ */ \ No newline at end of file +#endif /* _SK_MCA_INCLUDE_ */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/skfp/skfddi.c linux/drivers/net/skfp/skfddi.c --- v2.4.0-test1/linux/drivers/net/skfp/skfddi.c Fri May 12 14:18:55 2000 +++ linux/drivers/net/skfp/skfddi.c Mon Jun 19 13:42:38 2000 @@ -305,6 +305,8 @@ pdev)) == 0) { break; } + if (pci_enable_device(pdev)) + continue; #ifndef MEM_MAPPED_IO /* Verify that I/O enable bit is set (PCI slot is enabled) */ @@ -352,7 +354,7 @@ command &= ~PCI_COMMAND_IO; pci_write_config_word(pdev, PCI_COMMAND, command); - port = pdev->resource[0].start; + port = pci_resource_start(pdev, 0); port = (unsigned long)ioremap(port, 0x4000); if (!port){ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/smc-mca.c linux/drivers/net/smc-mca.c --- v2.4.0-test1/linux/drivers/net/smc-mca.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/smc-mca.c Mon Jun 19 13:42:39 2000 @@ -118,7 +118,7 @@ int irq = dev ? dev->irq : 0; if (!MCA_bus) { - return ENODEV; + return -ENODEV; } if (base_addr || irq) { @@ -252,9 +252,6 @@ reg4 = inb(ioaddr + 4) & 0x7f; outb(reg4, ioaddr + 4); - if (load_8390_module("wd.c")) - return -ENOSYS; - printk(KERN_INFO "%s: Parameters: %#3x,", dev->name, ioaddr); for (i = 0; i < 6; i++) @@ -458,6 +455,9 @@ { int this_dev, found = 0; + if (load_8390_module("wd.c")) + return -ENOSYS; + for (this_dev = 0; this_dev < MAX_ULTRAMCA_CARDS; this_dev++) { struct net_device *dev = &dev_ultra[this_dev]; dev->irq = irq[this_dev]; @@ -466,15 +466,14 @@ if (register_netdev(dev) != 0) { if (found != 0) { /* Got at least one. */ - lock_8390_module(); return 0; } + unload_8390_module(); printk(KERN_NOTICE "smc-mca.c: No SMC Ultra card found (i/o = 0x%x).\n", io[this_dev]); return -ENXIO; } found++; } - lock_8390_module(); return 0; } @@ -494,7 +493,7 @@ kfree(priv); } } - unlock_8390_module(); + unload_8390_module(); } #endif /* MODULE */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/smc-ultra.c linux/drivers/net/smc-ultra.c --- v2.4.0-test1/linux/drivers/net/smc-ultra.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/smc-ultra.c Mon Jun 19 13:42:39 2000 @@ -114,7 +114,7 @@ if (base_addr > 0x1ff) /* Check a single specified location. */ return ultra_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ - return ENXIO; + return -ENXIO; for (i = 0; ultra_portlist[i]; i++) { int ioaddr = ultra_portlist[i]; @@ -124,7 +124,7 @@ return 0; } - return ENODEV; + return -ENODEV; } #endif @@ -143,7 +143,7 @@ /* Check the ID nibble. */ if ((idreg & 0xF0) != 0x20 /* SMC Ultra */ && (idreg & 0xF0) != 0x40) /* SMC EtherEZ */ - return ENODEV; + return -ENODEV; /* Select the station address register set. */ outb(reg4, ioaddr + 4); @@ -151,10 +151,7 @@ for (i = 0; i < 8; i++) checksum += inb(ioaddr + 8 + i); if ((checksum & 0xff) != 0xFF) - return ENODEV; - - if (load_8390_module("smc-ultra.c")) - return -ENOSYS; + return -ENODEV; if (dev == NULL) dev = init_etherdev(0, 0); @@ -448,6 +445,9 @@ { int this_dev, found = 0; + if (load_8390_module("smc-ultra.c")) + return -ENOSYS; + for (this_dev = 0; this_dev < MAX_ULTRA_CARDS; this_dev++) { struct net_device *dev = &dev_ultra[this_dev]; dev->irq = irq[this_dev]; @@ -460,6 +460,7 @@ if (register_netdev(dev) != 0) { printk(KERN_WARNING "smc-ultra.c: No SMC Ultra card found (i/o = 0x%x).\n", io[this_dev]); if (found != 0) return 0; /* Got at least one. */ + unload_8390_module(); return -ENXIO; } found++; @@ -483,7 +484,7 @@ kfree(dev->priv); } } - unlock_8390_module(); + unload_8390_module(); } #endif /* MODULE */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/smc-ultra32.c linux/drivers/net/smc-ultra32.c --- v2.4.0-test1/linux/drivers/net/smc-ultra32.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/smc-ultra32.c Mon Jun 19 13:42:39 2000 @@ -108,7 +108,7 @@ const char *ifmap[] = {"UTP No Link", "", "UTP/AUI", "UTP/BNC"}; int ioaddr, edge, media; - if (!EISA_bus) return ENODEV; + if (!EISA_bus) return -ENODEV; /* EISA spec allows for up to 16 slots, but 8 is typical. */ for (ioaddr = 0x1000 + ULTRA32_BASE; ioaddr < 0x9000; ioaddr += 0x1000) @@ -123,7 +123,7 @@ if (ultra32_probe1(dev, ioaddr) == 0) return 0; } - return ENODEV; + return -ENODEV; } int __init ultra32_probe1(struct net_device *dev, int ioaddr) @@ -138,7 +138,7 @@ /* Check the ID nibble. */ if ((idreg & 0xf0) != 0x20) /* SMC Ultra */ - return ENODEV; + return -ENODEV; /* Select the station address register set. */ outb(reg4, ioaddr + 4); @@ -146,10 +146,7 @@ for (i = 0; i < 8; i++) checksum += inb(ioaddr + 8 + i); if ((checksum & 0xff) != 0xff) - return ENODEV; - - if (load_8390_module("smc-ultra32.c")) - return -ENOSYS; + return -ENODEV; /* We should have a "dev" from Space.c or the static module table. */ if (dev == NULL) { @@ -184,7 +181,7 @@ if ((inb(ioaddr + ULTRA32_CFG5) & 0x40) == 0) { printk("\nsmc-ultra32: Card RAM is disabled! " "Run EISA config utility.\n"); - return ENODEV; + return -ENODEV; } if ((inb(ioaddr + ULTRA32_CFG2) & 0x04) == 0) printk("\nsmc-ultra32: Ignoring Bus-Master enable bit. " @@ -381,20 +378,22 @@ { int this_dev, found = 0; + if (load_8390_module("smc-ultra32.c")) + return -ENOSYS; + for (this_dev = 0; this_dev < MAX_ULTRA32_CARDS; this_dev++) { struct net_device *dev = &dev_ultra[this_dev]; dev->init = ultra32_probe; if (register_netdev(dev) != 0) { if (found > 0) { /* Got at least one. */ - lock_8390_module(); return 0; } + unload_8390_module(); printk(KERN_WARNING "smc-ultra32.c: No SMC Ultra32 found.\n"); return -ENXIO; } found++; } - lock_8390_module(); return 0; } @@ -413,6 +412,6 @@ kfree(priv); } } - unlock_8390_module(); + unload_8390_module(); } #endif /* MODULE */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/smc9194.c linux/drivers/net/smc9194.c --- v2.4.0-test1/linux/drivers/net/smc9194.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/net/smc9194.c Mon Jun 19 13:42:39 2000 @@ -45,10 +45,12 @@ . Fixed bug reported by Gardner Buchanan in . smc_enable, with outw instead of outb . 03/06/96 Erik Stahlman Added hardware multicast from Peter Cammaert + . 04/14/00 Heiko Pruessing (SMA Regelsysteme) Fixed bug in chip memory + . allocation ----------------------------------------------------------------------------*/ static const char *version = - "smc9194.c:v0.12 03/06/96 by Erik Stahlman (erik@vt.edu)\n"; + "smc9194.c:v0.13 04/14/00 by Erik Stahlman (erik@vt.edu)\n"; #include #include @@ -517,11 +519,15 @@ length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + /* - . the MMU wants the number of pages to be the number of 256 bytes - . 'pages', minus 1 ( since a packet can't ever have 0 pages :) ) + ** The MMU wants the number of pages to be the number of 256 bytes + ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) ) + ** + ** Pkt size for allocating is data length +6 (for additional status words, + ** length and ctl!) If odd size last byte is included in this header. */ - numPages = length / 256; + numPages = ((length & 0xfffe) + 6) / 256; if (numPages > 7 ) { printk(CARDNAME": Far too big packet error. \n"); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/sonic.c linux/drivers/net/sonic.c --- v2.4.0-test1/linux/drivers/net/sonic.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/sonic.c Mon Jun 19 13:42:39 2000 @@ -44,7 +44,7 @@ // if (sonic_request_irq(dev->irq, &sonic_interrupt, 0, "sonic", dev)) { if (sonic_request_irq(dev->irq, &sonic_interrupt, SA_INTERRUPT, "sonic", dev)) { printk ("\n%s: unable to get IRQ %d .\n", dev->name, dev->irq); - return EAGAIN; + return -EAGAIN; } /* diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/stnic.c linux/drivers/net/stnic.c --- v2.4.0-test1/linux/drivers/net/stnic.c Tue May 23 15:31:35 2000 +++ linux/drivers/net/stnic.c Mon Jun 19 13:42:39 2000 @@ -175,7 +175,7 @@ *(vhalf *) PA_83902_RST = 0; udelay (5); if (ei_debug > 1) - printk("8390 reset done (%ld).", jiffies); + printk("8390 reset done (%ld).\n", jiffies); *(vhalf *) PA_83902_RST = ~0; udelay (5); } @@ -253,9 +253,17 @@ stnic_block_output (struct net_device *dev, int length, const unsigned char *buf, int output_page) { - +#if 0 STNIC_WRITE (PG0_RBCR0, 1); STNIC_WRITE (STNIC_CR, CR_RRD | CR_PG0 | CR_STA); +#else /* XXX: I don't know why but this works. -- gniibe */ + STNIC_WRITE (PG0_RBCR0, 0x42); + STNIC_WRITE (PG0_RBCR1, 0x00); + STNIC_WRITE (PG0_RBCR0, 0x42); + STNIC_WRITE (PG0_RBCR1, 0x00); + STNIC_WRITE (STNIC_CR, CR_RRD | CR_PG0 | CR_STA); + STNIC_DELAY (); +#endif STNIC_WRITE (PG0_RSAR0, 0); STNIC_WRITE (PG0_RSAR1, output_page); @@ -300,3 +308,6 @@ } module_init(stnic_probe); +/* No cleanup routine - if there were one, it should do a: + unload_8390_module() +*/ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/strip.c linux/drivers/net/strip.c --- v2.4.0-test1/linux/drivers/net/strip.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/strip.c Mon Jun 19 13:42:39 2000 @@ -2870,7 +2870,7 @@ /* Return "not found", so that dev_init() will unlink * the placeholder device entry for us. */ - return ENODEV; + return -ENODEV; #endif } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/sunbmac.c linux/drivers/net/sunbmac.c --- v2.4.0-test1/linux/drivers/net/sunbmac.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/sunbmac.c Mon Jun 19 13:42:39 2000 @@ -1,4 +1,4 @@ -/* $Id: sunbmac.c,v 1.18 2000/02/18 13:49:21 davem Exp $ +/* $Id: sunbmac.c,v 1.19 2000/06/19 06:24:46 davem Exp $ * sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) @@ -1262,7 +1262,7 @@ #endif if (called) - return ENODEV; + return -ENODEV; called++; for_each_sbus(sbus) { @@ -1278,7 +1278,7 @@ } } if (!cards) - return ENODEV; + return -ENODEV; return 0; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c --- v2.4.0-test1/linux/drivers/net/sunhme.c Tue Apr 11 15:09:18 2000 +++ linux/drivers/net/sunhme.c Mon Jun 19 13:42:39 2000 @@ -1,4 +1,4 @@ -/* $Id: sunhme.c,v 1.95 2000/03/25 05:18:15 davem Exp $ +/* $Id: sunhme.c,v 1.96 2000/06/09 07:35:27 davem Exp $ * sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching, * auto carrier detecting ethernet driver. Also known as the * "Happy Meal Ethernet" found on SunSwift SBUS cards. @@ -2519,12 +2519,12 @@ if (is_qfe) { qp = quattro_sbus_find(sdev); if (qp == NULL) - return ENODEV; + return -ENODEV; for (qfe_slot = 0; qfe_slot < 4; qfe_slot++) if (qp->happy_meals[qfe_slot] == NULL) break; if (qfe_slot == 4) - return ENODEV; + return -ENODEV; } if (dev == NULL) { dev = init_etherdev(0, sizeof(struct happy_meal)); @@ -2564,7 +2564,7 @@ printk(KERN_ERR "happymeal: Device does not have 5 regs, it has %d.\n", sdev->num_registers); printk(KERN_ERR "happymeal: Would you like that for here or to go?\n"); - return ENODEV; + return -ENODEV; } if (qp != NULL) { @@ -2578,35 +2578,35 @@ GREG_REG_SIZE, "HME Global Regs"); if (!hp->gregs) { printk(KERN_ERR "happymeal: Cannot map Happy Meal global registers.\n"); - return ENODEV; + return -ENODEV; } hp->etxregs = sbus_ioremap(&sdev->resource[1], 0, ETX_REG_SIZE, "HME TX Regs"); if (!hp->etxregs) { printk(KERN_ERR "happymeal: Cannot map Happy Meal MAC Transmit registers.\n"); - return ENODEV; + return -ENODEV; } hp->erxregs = sbus_ioremap(&sdev->resource[2], 0, ERX_REG_SIZE, "HME RX Regs"); if (!hp->erxregs) { printk(KERN_ERR "happymeal: Cannot map Happy Meal MAC Receive registers.\n"); - return ENODEV; + return -ENODEV; } hp->bigmacregs = sbus_ioremap(&sdev->resource[3], 0, BMAC_REG_SIZE, "HME BIGMAC Regs"); if (!hp->bigmacregs) { printk(KERN_ERR "happymeal: Cannot map Happy Meal BIGMAC registers.\n"); - return ENODEV; + return -ENODEV; } hp->tcvregs = sbus_ioremap(&sdev->resource[4], 0, TCVR_REG_SIZE, "HME Tranceiver Regs"); if (!hp->tcvregs) { printk(KERN_ERR "happymeal: Cannot map Happy Meal Tranceiver registers.\n"); - return ENODEV; + return -ENODEV; } hp->hm_revision = prom_getintdefault(sdev->prom_node, "hm-rev", 0xff); @@ -2695,7 +2695,7 @@ pcp = pdev->sysdata; if (pcp == NULL || pcp->prom_node == -1) { printk(KERN_ERR "happymeal(PCI): Some PCI device info missing\n"); - return ENODEV; + return -ENODEV; } node = pcp->prom_node; @@ -2703,12 +2703,12 @@ if (!strcmp(prom_name, "SUNW,qfe") || !strcmp(prom_name, "qfe")) { qp = quattro_pci_find(pdev); if (qp == NULL) - return ENODEV; + return -ENODEV; for (qfe_slot = 0; qfe_slot < 4; qfe_slot++) if (qp->happy_meals[qfe_slot] == NULL) break; if (qfe_slot == 4) - return ENODEV; + return -ENODEV; } if (dev == NULL) { dev = init_etherdev(0, sizeof(struct happy_meal)); @@ -2758,12 +2758,11 @@ qp->happy_meals[qfe_slot] = dev; } - hpreg_base = pdev->resource[0].start; + hpreg_base = pci_resource_start(pdev, 0); if ((pdev->resource[0].flags & IORESOURCE_IO) != 0) { printk(KERN_ERR "happymeal(PCI): Cannot find proper PCI device base address.\n"); - return ENODEV; + return -ENODEV; } - hpreg_base &= PCI_BASE_ADDRESS_MEM_MASK; hpreg_base = (unsigned long) ioremap(hpreg_base, 0x8000); if (qfe_slot != -1 && prom_getproplen(node, "local-mac-address") == 6) @@ -2806,7 +2805,7 @@ if (!hp->happy_block) { printk(KERN_ERR "happymeal(PCI): Cannot get hme init block.\n"); - return ENODEV; + return -ENODEV; } hp->linkcheck = 0; @@ -2920,7 +2919,7 @@ #endif if (called) - return ENODEV; + return -ENODEV; called++; cards = 0; @@ -2933,7 +2932,7 @@ cards += happy_meal_pci_probe(dev); #endif if (!cards) - return ENODEV; + return -ENODEV; return 0; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c --- v2.4.0-test1/linux/drivers/net/sunlance.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/net/sunlance.c Mon Jun 19 13:42:39 2000 @@ -1,4 +1,4 @@ -/* $Id: sunlance.c,v 1.100 2000/02/27 09:38:12 anton Exp $ +/* $Id: sunlance.c,v 1.101 2000/06/19 06:24:46 davem Exp $ * lance.c: Linux/Sparc/Lance driver * * Written 1995, 1996 by Miguel de Icaza @@ -1502,7 +1502,7 @@ fail: if (lp != NULL) lance_free_hwresources(lp); - return ENODEV; + return -ENODEV; } /* On 4m, find the associated dma for the lance chip */ @@ -1532,7 +1532,7 @@ #endif if (called) - return ENODEV; + return -ENODEV; called++; if ((idprom->id_machtype == (SM_SUN4|SM_4_330)) || @@ -1542,7 +1542,7 @@ sdev.irqs[0] = 6; return sparc_lance_init(NULL, &sdev, 0, 0); } - return ENODEV; + return -ENODEV; } #else /* !CONFIG_SUN4 */ @@ -1562,7 +1562,7 @@ #endif if (called) - return ENODEV; + return -ENODEV; called++; for_each_sbus (bus) { @@ -1593,7 +1593,7 @@ } /* for each sbusdev */ } /* for each sbus */ if (!cards) - return ENODEV; + return -ENODEV; return 0; } #endif /* !CONFIG_SUN4 */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/sunqe.c linux/drivers/net/sunqe.c --- v2.4.0-test1/linux/drivers/net/sunqe.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/sunqe.c Mon Jun 19 13:42:39 2000 @@ -1,4 +1,4 @@ -/* $Id: sunqe.c,v 1.45 2000/02/16 10:36:20 davem Exp $ +/* $Id: sunqe.c,v 1.46 2000/06/19 06:24:46 davem Exp $ * sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver. * Once again I am out to prove that every ethernet * controller out there can be most efficiently programmed @@ -999,7 +999,7 @@ #endif if (called) - return ENODEV; + return -ENODEV; called++; for_each_sbus(bus) { @@ -1015,7 +1015,7 @@ } } if (!cards) - return ENODEV; + return -ENODEV; return 0; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/tlan.c linux/drivers/net/tlan.c --- v2.4.0-test1/linux/drivers/net/tlan.c Mon Mar 27 08:08:26 2000 +++ linux/drivers/net/tlan.c Mon Jun 19 13:42:39 2000 @@ -72,6 +72,31 @@ * - TODO: Port completely to new PCI/DMA API * Auto-Neg fallback. * + * v1.6 April 04, 2000 - Fixed driver support for kernel-parameters. Haven't + * tested it though, as the kernel support is currently + * broken (2.3.99p4p3). + * - Updated tlan.txt accordingly. + * - Adjusted minimum/maximum frame length. + * - There is now a TLAN website up at + * http://tlan.kernel.dk + * + * v1.7 April 07, 2000 - Started to implement custom ioctls. Driver now + * reports PHY information when used with Donald + * Beckers userspace MII diagnostics utility. + * + * v1.8 April 23, 2000 - Fixed support for forced speed/duplex settings. + * - Added link information to Auto-Neg and forced + * modes. When NIC operates with auto-neg the driver + * will report Link speed & duplex modes as well as + * link partner abilities. When forced link is used, + * the driver will report status of the established + * link. + * Please read tlan.txt for additional information. + * - Removed call to check_region(), and used + * return value of request_region() instead. + * + * v1.8a May 28, 2000 - Minor updates. + * *******************************************************************************/ @@ -99,6 +124,8 @@ static int duplex = 0; static int speed = 0; +MODULE_AUTHOR("Maintainer: Torben Mathiasen "); +MODULE_DESCRIPTION("Driver for TI ThunderLAN based ethernet PCI adapters"); MODULE_PARM(aui, "i"); MODULE_PARM(duplex, "i"); MODULE_PARM(speed, "i"); @@ -111,9 +138,14 @@ static int bbuf = 0; static u8 *TLanPadBuffer; static char TLanSignature[] = "TLAN"; -static int TLanVersionMajor = 1; -static int TLanVersionMinor = 5; +static const char *tlan_banner = "ThunderLAN driver v1.8a\n"; +const char *media[] = { + "10BaseT-HD ", "10BaseT-FD ","100baseTx-HD ", + "100baseTx-FD", "100baseT4", 0 +}; + +int media_map[] = { 0x0020, 0x0040, 0x0080, 0x0100, 0x0200,}; static TLanAdapterEntry TLanAdapterList[] __initdata = { { PCI_VENDOR_ID_COMPAQ, @@ -211,6 +243,7 @@ static int TLan_Close(struct net_device *); static struct net_device_stats *TLan_GetStats( struct net_device * ); static void TLan_SetMulticastList( struct net_device * ); +static int TLan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static u32 TLan_HandleInvalid( struct net_device *, u16 ); static u32 TLan_HandleTxEOF( struct net_device *, u16 ); @@ -371,9 +404,7 @@ u32 io_base, index; int found; - printk(KERN_INFO "ThunderLAN driver v%d.%d\n", - TLanVersionMajor, - TLanVersionMinor); + printk(KERN_INFO "%s", tlan_banner); TLanPadBuffer = (u8 *) kmalloc(TLAN_MIN_FRAME_SIZE, (GFP_KERNEL | GFP_DMA)); @@ -404,17 +435,36 @@ dev->irq = irq; priv->adapter = &TLanAdapterList[index]; priv->adapterRev = rev; - priv->aui = aui; - if ( ( duplex != 1 ) && ( duplex != 2 ) ) - duplex = 0; - priv->duplex = duplex; + + /* Kernel parameters */ + if (dev->mem_start) { + priv->aui = dev->mem_start & 0x01; + priv->duplex = ((dev->mem_start & 0x06) == 0x06) ? 0 : (dev->mem_start & 0x06) >> 1; + priv->speed = ((dev->mem_start & 0x18) == 0x18) ? 0 : (dev->mem_start & 0x18) >> 3; + + if (priv->speed == 0x1) { + priv->speed = TLAN_SPEED_10; + } else if (priv->speed == 0x2) { + priv->speed = TLAN_SPEED_100; + } + debug = priv->debug = dev->mem_end; + } else { - if ( ( speed != 10 ) && ( speed != 100 ) ) - speed = 0; + if ( ( duplex != 1 ) && ( duplex != 2 ) ) + duplex = 0; + + priv->duplex = duplex; - priv->speed = speed; - priv->debug = debug; + if ( ( speed != 10 ) && ( speed != 100 ) ) + speed = 0; + + priv->aui = aui; + priv->speed = speed; + priv->debug = debug; + + } + spin_lock_init(&priv->lock); if (TLan_Init(dev)) { @@ -495,8 +545,11 @@ TLanAdapterList[dl_index].deviceId ); + if (pci_enable_device(pdev)) + continue; + *pci_irq = pdev->irq; - *pci_io_base = pdev->resource[0].start; + *pci_io_base = pci_resource_start (pdev, 0); *pci_dfn = pdev->devfn; pci_read_config_byte ( pdev, PCI_REVISION_ID, pci_rev); pci_read_config_word ( pdev, PCI_COMMAND, &pci_command); @@ -554,13 +607,13 @@ static int TLan_Init( struct net_device *dev ) { int dma_size; - int err; + int err; int i; TLanPrivateInfo *priv; priv = (TLanPrivateInfo *) dev->priv; - err = check_region( dev->base_addr, 0x10 ); - if ( err ) { + + 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, @@ -568,7 +621,6 @@ return -EIO; } - request_region( dev->base_addr, 0x10, TLanSignature ); if ( bbuf ) { dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS ) @@ -611,7 +663,7 @@ dev->stop = &TLan_Close; dev->get_stats = &TLan_GetStats; dev->set_multicast_list = &TLan_SetMulticastList; - + dev->do_ioctl = &TLan_ioctl; return 0; @@ -669,6 +721,49 @@ + /************************************************************** + * TLan_ioctl + * + * Returns: + * 0 on success, error code otherwise + * Params: + * dev structure of device to receive ioctl. + * + * rq ifreq structure to hold userspace data. + * + * cmd ioctl command. + * + * + *************************************************************/ + +static int TLan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + u16 *data = (u16 *)&rq->ifr_data; + u32 phy = priv->phy[priv->phyNum]; + + if (!priv->phyOnline) + return -EAGAIN; + + switch(cmd) { + case SIOCDEVPRIVATE: + data[0] = phy; + + case SIOCDEVPRIVATE+1: /* Read MII register */ + TLan_MiiReadReg(dev, data[0], data[1], &data[3]); + return 0; + + case SIOCDEVPRIVATE+2: /* Write MII register */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + TLan_MiiWriteReg(dev, data[0], data[1], data[2]); + return 0; + default: + return -EOPNOTSUPP; + } +} /* tlan_ioctl */ + + /*************************************************************** * TLan_StartTx @@ -1898,7 +1993,10 @@ u32 phy; u8 sio; u16 status; + u16 partner; u16 tlphy_ctl; + u16 tlphy_par; + int i; phy = priv->phy[priv->phyNum]; @@ -1922,7 +2020,26 @@ udelay( 1000 ); TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); if ( status & MII_GS_LINK ) { - printk( "TLAN: %s: Link active.\n", dev->name ); + TLan_MiiReadReg( dev, phy, MII_AN_LPA, &partner ); + TLan_MiiReadReg( dev, phy, TLAN_TLPHY_PAR, &tlphy_par ); + + printk( "TLAN: %s: Link active with ", dev->name ); + if (!(tlphy_par & TLAN_PHY_AN_EN_STAT)) { + printk( "forced 10%sMbps %s-Duplex\n", + tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0", + tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half"); + } else { + printk( "AutoNegotiation enabled, at 10%sMbps %s-Duplex\n", + tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0", + tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half"); + + printk("TLAN: Partner capability: "); + for (i = 5; i <= 10; i++) + if (partner & (1<base_addr, TLAN_LED_REG, TLAN_LED_LINK ); } } @@ -1946,7 +2063,7 @@ outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM ); outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD ); } else { - printk( "TLAN: %s: Link inactive, will retry in 10 secs...\n", dev->name ); + printk( "TLAN: %s: Link inactive, will retry in 10 secs...\n", dev->name ); TLan_SetTimer( dev, (10*HZ), TLAN_TIMER_FINISH_RESET ); return; } @@ -2149,10 +2266,10 @@ TLan_MiiSync( dev->base_addr ); value = MII_GC_LOOPBK; TLan_MiiWriteReg( dev, priv->phy[priv->phyNum], MII_GEN_CTL, value ); - + TLan_MiiSync(dev->base_addr); /* Wait for 500 ms and reset the * tranceiver. The TLAN docs say both 50 ms and - * 500 ms, so do the longer, just in case + * 500 ms, so do the longer, just in case. */ TLan_SetTimer( dev, (HZ/2), TLAN_TIMER_PHY_RESET ); @@ -2177,12 +2294,12 @@ while ( value & MII_GC_RESET ) { TLan_MiiReadReg( dev, phy, MII_GEN_CTL, &value ); } - TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0 ); /* Wait for 500 ms and initialize. * I don't remember why I wait this long. + * I've changed this to 50ms, as it seems long enough. */ - TLan_SetTimer( dev, (HZ/2), TLAN_TIMER_PHY_START_LINK ); + TLan_SetTimer( dev, (HZ/20), TLAN_TIMER_PHY_START_LINK ); } /* TLan_PhyReset */ @@ -2200,52 +2317,56 @@ u16 tctl; phy = priv->phy[priv->phyNum]; - TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Trying to activate link.\n", dev->name ); TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); + TLan_MiiReadReg( dev, phy, MII_GEN_STS, &ability ); if ( ( status & MII_GS_AUTONEG ) && - ( priv->duplex == TLAN_DUPLEX_DEFAULT ) && - ( priv->speed == TLAN_SPEED_DEFAULT ) && ( ! priv->aui ) ) { - ability = status >> 11; - - if ( priv->speed == TLAN_SPEED_10 ) { - ability &= 0x0003; - } else if ( priv->speed == TLAN_SPEED_100 ) { - ability &= 0x001C; - } - - if ( priv->duplex == TLAN_DUPLEX_FULL ) { - ability &= 0x000A; - } else if ( priv->duplex == TLAN_DUPLEX_HALF ) { - ability &= 0x0005; - } - - TLan_MiiWriteReg( dev, phy, MII_AN_ADV, ( ability << 5 ) | 1 ); - TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x1000 ); - TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x1200 ); - - /* Wait for 4 sec for autonegotiation - * to complete. The max spec time is less than this - * but the card need additional time to start AN. - * .5 sec should be plenty extra. - */ - printk( "TLAN: %s: Starting autonegotiation.\n", dev->name ); - TLan_SetTimer( dev, (4*HZ), TLAN_TIMER_PHY_FINISH_AN ); - return; - } + ability = status >> 11; + if ( priv->speed == TLAN_SPEED_10 && + priv->duplex == TLAN_DUPLEX_HALF) { + TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x0000); + } else if ( priv->speed == TLAN_SPEED_10 && + priv->duplex == TLAN_DUPLEX_FULL) { + TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x0100); + } else if ( priv->speed == TLAN_SPEED_100 && + priv->duplex == TLAN_DUPLEX_HALF) { + TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2000); + } else if ( priv->speed == TLAN_SPEED_100 && + priv->duplex == TLAN_DUPLEX_FULL) { + TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2100); + } else { + + /* Set Auto-Neg advertisement */ + TLan_MiiWriteReg( dev, phy, MII_AN_ADV, (ability << 5) | 1); + /* Enablee Auto-Neg */ + TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x1000 ); + /* Restart Auto-Neg */ + TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x1200 ); + /* Wait for 4 sec for autonegotiation + * to complete. The max spec time is less than this + * but the card need additional time to start AN. + * .5 sec should be plenty extra. + */ + printk( "TLAN: %s: Starting autonegotiation.\n", dev->name ); + TLan_SetTimer( dev, (4*HZ), TLAN_TIMER_PHY_FINISH_AN ); + return; + } + + } + if ( ( priv->aui ) && ( priv->phyNum != 0 ) ) { priv->phyNum = 0; data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN; TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, data ); - TLan_SetTimer( dev, (4*(HZ/1000)), TLAN_TIMER_PHY_PDOWN ); + TLan_SetTimer( dev, (40*HZ/1000), TLAN_TIMER_PHY_PDOWN ); return; - } else if ( priv->phyNum == 0 ) { + } else if ( priv->phyNum == 0 ) { TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tctl ); if ( priv->aui ) { tctl |= TLAN_TC_AUISEL; - } else { + } else { tctl &= ~TLAN_TC_AUISEL; control = 0; if ( priv->duplex == TLAN_DUPLEX_FULL ) { @@ -2260,10 +2381,10 @@ TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tctl ); } - /* Wait for 1 sec to give the tranceiver time + /* Wait for 2 sec to give the tranceiver time * to establish link. */ - TLan_SetTimer( dev, HZ, TLAN_TIMER_FINISH_RESET ); + TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_FINISH_RESET ); } /* TLan_PhyStartLink */ @@ -2306,14 +2427,14 @@ priv->phyNum = 0; data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN; TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, data ); - TLan_SetTimer( dev, (400*(HZ/1000)), TLAN_TIMER_PHY_PDOWN ); + TLan_SetTimer( dev, (400*HZ/1000), TLAN_TIMER_PHY_PDOWN ); return; } if ( priv->phyNum == 0 ) { if ( ( priv->duplex == TLAN_DUPLEX_FULL ) || ( an_adv & an_lpa & 0x0040 ) ) { TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, MII_GC_AUTOENB | MII_GC_DUPLEX ); - printk( "TLAN: Starting internal PHY with DUPLEX\n" ); + printk( "TLAN: Starting internal PHY with FULL-DUPLEX\n" ); } else { TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, MII_GC_AUTOENB ); printk( "TLAN: Starting internal PHY with HALF-DUPLEX\n" ); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/tlan.h linux/drivers/net/tlan.h --- v2.4.0-test1/linux/drivers/net/tlan.h Thu Feb 10 17:11:11 2000 +++ linux/drivers/net/tlan.h Mon Jun 19 13:42:39 2000 @@ -36,8 +36,8 @@ #define FALSE 0 #define TRUE 1 -#define TLAN_MIN_FRAME_SIZE 64 -#define TLAN_MAX_FRAME_SIZE 1600 +#define TLAN_MIN_FRAME_SIZE 60 +#define TLAN_MAX_FRAME_SIZE 1536 #define TLAN_NUM_RX_LISTS 4 #define TLAN_NUM_TX_LISTS 8 @@ -404,7 +404,11 @@ #define TLAN_TS_POLOK 0x2000 #define TLAN_TS_TPENERGY 0x1000 #define TLAN_TS_RESERVED 0x0FFF - +#define TLAN_TLPHY_PAR 0x19 +#define TLAN_PHY_CIM_STAT 0x0020 +#define TLAN_PHY_SPEED_100 0x0040 +#define TLAN_PHY_DUPLEX_FULL 0x0080 +#define TLAN_PHY_AN_EN_STAT 0x0400 #define CIRC_INC( a, b ) if ( ++a >= b ) a = 0 diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/tokenring/ibmtr.c linux/drivers/net/tokenring/ibmtr.c --- v2.4.0-test1/linux/drivers/net/tokenring/ibmtr.c Fri May 12 14:18:55 2000 +++ linux/drivers/net/tokenring/ibmtr.c Mon Jun 19 13:42:39 2000 @@ -781,6 +781,9 @@ { struct tok_info *ti=(struct tok_info *)dev->priv; + /* init the spinlock */ + spin_lock_init(&ti->lock); + SET_PAGE(ti->srb_page); ti->open_status = CLOSED; @@ -846,9 +849,6 @@ { struct tok_info *ti=(struct tok_info *)dev->priv; - /* init the spinlock */ - spin_lock_init(&ti->lock); - if (ti->open_status==CLOSED) tok_init_card(dev); if (ti->open_status==IN_PROGRESS) sleep_on(&ti->wait_for_reset); @@ -1750,9 +1750,9 @@ /* Copy the payload... */ for (;;) { if (IPv4_p) - chksum = csum_partial_copy_generic(bus_to_virt(rbufdata), data, + chksum = csum_partial_copy_nocheck(bus_to_virt(rbufdata), data, length < rbuffer_len ? length : rbuffer_len, - chksum, NULL, NULL); + chksum); else isa_memcpy_fromio(data, rbufdata, rbuffer_len); rbuffer = ntohs(isa_readw(rbuffer)); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/tokenring/lanstreamer.c linux/drivers/net/tokenring/lanstreamer.c --- v2.4.0-test1/linux/drivers/net/tokenring/lanstreamer.c Mon Mar 27 08:08:26 2000 +++ linux/drivers/net/tokenring/lanstreamer.c Mon Jun 19 13:42:39 2000 @@ -207,12 +207,14 @@ { while ((pci_device = pci_find_device(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR, pci_device))) { + if (pci_enable_device(pci_device)) + continue; pci_set_master(pci_device); /* Check to see if io has been allocated, if so, we've already done this card, so continue on the card discovery loop */ - if (check_region(pci_device->resource[0].start & (~3), STREAMER_IO_SPACE)) + if (check_region(pci_resource_start(pci_device,0), STREAMER_IO_SPACE)) { card_no++; continue; @@ -242,10 +244,11 @@ pci_device, dev, dev->priv); #endif dev->irq = pci_device->irq; - dev->base_addr = pci_device->resource[0].start & (~3); + dev->base_addr = pci_resource_start(pci_device, 0); dev->init = &streamer_init; streamer_priv->streamer_card_name = (char *)pci_device->resource[0].name; - streamer_priv->streamer_mmio = ioremap(pci_device->resource[1].start, 256); + streamer_priv->streamer_mmio = + ioremap(pci_resource_start(pci_device, 1), 256); if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000)) streamer_priv->pkt_buf_sz = PKT_BUF_SZ; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/tokenring/olympic.c linux/drivers/net/tokenring/olympic.c --- v2.4.0-test1/linux/drivers/net/tokenring/olympic.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/net/tokenring/olympic.c Mon Jun 19 13:42:39 2000 @@ -29,6 +29,16 @@ * 2/23/00 - Updated to dev_kfree_irq * 3/10/00 - Fixed FDX enable which triggered other bugs also * squashed. + * 5/20/00 - Changes to handle Olympic on LinuxPPC. Endian changes. + * The odd thing about the changes is that the fix for + * endian issues with the big-endian data in the arb, asb... + * was to always swab() the bytes, no matter what CPU. + * That's because the read[wl]() functions always swap the + * bytes on the way in on PPC. + * Fixing the hardware descriptors was another matter, + * because they weren't going through read[wl](), there all + * the results had to be in memory in le32 values. kdaaker + * * * To Do: * @@ -169,13 +179,25 @@ if (pci_present()) { while((pci_device=pci_find_device(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR_WAKE, pci_device))) { + __u16 pci_command ; + + if (pci_enable_device(pci_device)) + continue; + /* These lines are needed by the PowerPC, it appears +that these flags + * are not being set properly for the PPC, this may +well be fixed with + * the new PCI code */ + pci_read_config_word(pci_device, PCI_COMMAND, &pci_command); + pci_command |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY; + pci_write_config_word(pci_device, PCI_COMMAND,pci_command); pci_set_master(pci_device); /* Check to see if io has been allocated, if so, we've already done this card, so continue on the card discovery loop */ - if (check_region(pci_device->resource[0].start, OLYMPIC_IO_SPACE)) { + if (check_region(pci_resource_start(pci_device, 0), OLYMPIC_IO_SPACE)) { card_no++ ; continue ; } @@ -192,11 +214,13 @@ printk("pci_device: %p, dev:%p, dev->priv: %p\n", pci_device, dev, dev->priv); #endif dev->irq=pci_device->irq; - dev->base_addr=pci_device->resource[0].start; + dev->base_addr=pci_resource_start(pci_device, 0); dev->init=&olympic_init; olympic_priv->olympic_card_name = (char *)pci_device->resource[0].name ; - olympic_priv->olympic_mmio=ioremap(pci_device->resource[1].start,256); - olympic_priv->olympic_lap=ioremap(pci_device->resource[2].start,2048); + olympic_priv->olympic_mmio = + ioremap(pci_resource_start(pci_device,1),256); + olympic_priv->olympic_lap = + ioremap(pci_resource_start(pci_device,2),2048); if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000) ) olympic_priv->pkt_buf_sz = PKT_BUF_SZ ; @@ -329,7 +353,7 @@ } } - uaa_addr=ntohs(readw(init_srb+8)); + uaa_addr=swab16(readw(init_srb+8)); #if OLYMPIC_DEBUG printk("UAA resides at %x\n",uaa_addr); @@ -346,8 +370,8 @@ memcpy_fromio(&dev->dev_addr[0], adapter_addr,6); - olympic_priv->olympic_addr_table_addr = ntohs(readw(init_srb + 12)) ; - olympic_priv->olympic_parms_addr = ntohs(readw(init_srb + 14)) ; + olympic_priv->olympic_addr_table_addr = swab16(readw(init_srb + 12)); + olympic_priv->olympic_parms_addr = swab16(readw(init_srb + 14)); return 0; @@ -409,9 +433,9 @@ /* If Network Monitor, instruct card to copy MAC frames through the ARB */ #if OLYMPIC_NETWORK_MONITOR - writew(ntohs(OPEN_ADAPTER_ENABLE_FDX | OPEN_ADAPTER_PASS_ADC_MAC | OPEN_ADAPTER_PASS_ATT_MAC | OPEN_ADAPTER_PASS_BEACON),init_srb+8); + writew(swab16(OPEN_ADAPTER_ENABLE_FDX | OPEN_ADAPTER_PASS_ADC_MAC | OPEN_ADAPTER_PASS_ATT_MAC | OPEN_ADAPTER_PASS_BEACON), init_srb+8); #else - writew(ntohs(OPEN_ADAPTER_ENABLE_FDX),init_srb+8); + writew(swab16(OPEN_ADAPTER_ENABLE_FDX), init_srb+8); #endif if (olympic_priv->olympic_laa[0]) { @@ -445,7 +469,7 @@ #if OLYMPIC_DEBUG printk("init_srb(%p): ",init_srb); for(i=0;i<20;i++) - printk("%x ",readb(init_srb+i)); + printk("%02x ",readb(init_srb+i)); printk("\n"); #endif @@ -504,10 +528,10 @@ if (olympic_priv->olympic_message_level) printk(KERN_INFO "%s: Opened in %d Mbps mode\n",dev->name, olympic_priv->olympic_ring_speed); - olympic_priv->asb=ntohs(readw(init_srb+8)); - olympic_priv->srb=ntohs(readw(init_srb+10)); - olympic_priv->arb=ntohs(readw(init_srb+12)); - olympic_priv->trb=ntohs(readw(init_srb+16)); + olympic_priv->asb = swab16(readw(init_srb+8)); + olympic_priv->srb = swab16(readw(init_srb+10)); + olympic_priv->arb = swab16(readw(init_srb+12)); + olympic_priv->trb = swab16(readw(init_srb+16)); olympic_priv->olympic_receive_options = 0x01 ; olympic_priv->olympic_copy_all_options = 0 ; @@ -528,8 +552,8 @@ skb->dev = dev; - olympic_priv->olympic_rx_ring[i].buffer=virt_to_bus(skb->data); - olympic_priv->olympic_rx_ring[i].res_length = olympic_priv->pkt_buf_sz ; + olympic_priv->olympic_rx_ring[i].buffer = cpu_to_le32(virt_to_bus(skb->data)); + olympic_priv->olympic_rx_ring[i].res_length = cpu_to_le32(olympic_priv->pkt_buf_sz); olympic_priv->rx_ring_skb[i]=skb; } @@ -539,17 +563,17 @@ return -EIO; } - writel(virt_to_bus(&olympic_priv->olympic_rx_ring[0]),olympic_mmio+RXDESCQ); - writel(virt_to_bus(&olympic_priv->olympic_rx_ring[0]),olympic_mmio+RXCDA); - writew(i,olympic_mmio+RXDESCQCNT); + writel(virt_to_bus(&olympic_priv->olympic_rx_ring[0]), olympic_mmio+RXDESCQ); + writel(virt_to_bus(&olympic_priv->olympic_rx_ring[0]), olympic_mmio+RXCDA); + writew(i, olympic_mmio+RXDESCQCNT); - writel(virt_to_bus(&olympic_priv->olympic_rx_status_ring[0]),olympic_mmio+RXSTATQ); - writel(virt_to_bus(&olympic_priv->olympic_rx_status_ring[0]),olympic_mmio+RXCSA); + writel(virt_to_bus(&olympic_priv->olympic_rx_status_ring[0]), olympic_mmio+RXSTATQ); + writel(virt_to_bus(&olympic_priv->olympic_rx_status_ring[0]), olympic_mmio+RXCSA); - olympic_priv->rx_ring_last_received=OLYMPIC_RX_RING_SIZE-1; /* last processed rx status */ - olympic_priv->rx_status_last_received = OLYMPIC_RX_RING_SIZE-1; + olympic_priv->rx_ring_last_received = OLYMPIC_RX_RING_SIZE - 1; /* last processed rx status */ + olympic_priv->rx_status_last_received = OLYMPIC_RX_RING_SIZE - 1; - writew(i,olympic_mmio+RXSTATQCNT); + writew(i, olympic_mmio+RXSTATQCNT); #if OLYMPIC_DEBUG printk("# of rx buffers: %d, RXENQ: %x\n",i, readw(olympic_mmio+RXENQ)); @@ -578,9 +602,9 @@ olympic_priv->olympic_tx_ring[i].buffer=0xdeadbeef; olympic_priv->free_tx_ring_entries=OLYMPIC_TX_RING_SIZE; - writel(virt_to_bus(&olympic_priv->olympic_tx_ring[0]),olympic_mmio+TXDESCQ_1); - writel(virt_to_bus(&olympic_priv->olympic_tx_ring[0]),olympic_mmio+TXCDA_1); - writew(OLYMPIC_TX_RING_SIZE,olympic_mmio+TXDESCQCNT_1); + writel(virt_to_bus(&olympic_priv->olympic_tx_ring[0]), olympic_mmio+TXDESCQ_1); + writel(virt_to_bus(&olympic_priv->olympic_tx_ring[0]), olympic_mmio+TXCDA_1); + writew(OLYMPIC_TX_RING_SIZE, olympic_mmio+TXDESCQCNT_1); writel(virt_to_bus(&olympic_priv->olympic_tx_status_ring[0]),olympic_mmio+TXSTATQ_1); writel(virt_to_bus(&olympic_priv->olympic_tx_status_ring[0]),olympic_mmio+TXCSA_1); @@ -654,34 +678,35 @@ rx_status=&(olympic_priv->olympic_rx_status_ring[(olympic_priv->rx_status_last_received + 1) & (OLYMPIC_RX_RING_SIZE - 1)]) ; while (rx_status->status_buffercnt) { + __u32 l_status_buffercnt; olympic_priv->rx_status_last_received++ ; olympic_priv->rx_status_last_received &= (OLYMPIC_RX_RING_SIZE -1); #if OLYMPIC_DEBUG printk(" stat_ring addr: %x \n", &(olympic_priv->olympic_rx_status_ring[olympic_priv->rx_status_last_received]) ); - printk("rx status: %x rx len: %x \n",rx_status->status_buffercnt,rx_status->fragmentcnt_framelen); + printk("rx status: %x rx len: %x \n", le32_to_cpu(rx_status->status_buffercnt), le32_to_cpu(rx_status->fragmentcnt_framelen)); #endif - length=rx_status->fragmentcnt_framelen & 0xffff; - buffer_cnt = rx_status->status_buffercnt & 0xffff ; + length = le32_to_cpu(rx_status->fragmentcnt_framelen) & 0xffff; + buffer_cnt = le32_to_cpu(rx_status->status_buffercnt) & 0xffff; i = buffer_cnt ; /* Need buffer_cnt later for rxenq update */ - frag_len = rx_status->fragmentcnt_framelen >> 16 ; + frag_len = le32_to_cpu(rx_status->fragmentcnt_framelen) >> 16; #if OLYMPIC_DEBUG - printk("length: %x, frag_len: %x, buffer_cnt: %x\n",length,frag_len,buffer_cnt); + printk("length: %x, frag_len: %x, buffer_cnt: %x\n", length, frag_len, buffer_cnt); #endif - - if(rx_status->status_buffercnt & 0xC0000000) { - if (rx_status->status_buffercnt & 0x3B000000) { + l_status_buffercnt = le32_to_cpu(rx_status->status_buffercnt); + if(l_status_buffercnt & 0xC0000000) { + if (l_status_buffercnt & 0x3B000000) { if (olympic_priv->olympic_message_level) { - if (rx_status->status_buffercnt & (1<<29)) /* Rx Frame Truncated */ + if (l_status_buffercnt & (1<<29)) /* Rx Frame Truncated */ printk(KERN_WARNING "%s: Rx Frame Truncated \n",dev->name); - if (rx_status->status_buffercnt & (1<<28)) /*Rx receive overrun */ + if (l_status_buffercnt & (1<<28)) /*Rx receive overrun */ printk(KERN_WARNING "%s: Rx Frame Receive overrun \n",dev->name); - if (rx_status->status_buffercnt & (1<<27)) /* No receive buffers */ + if (l_status_buffercnt & (1<<27)) /* No receive buffers */ printk(KERN_WARNING "%s: No receive buffers \n",dev->name); - if (rx_status->status_buffercnt & (1<<25)) /* Receive frame error detect */ + if (l_status_buffercnt & (1<<25)) /* Receive frame error detect */ printk(KERN_WARNING "%s: Receive frame error detect \n",dev->name); - if (rx_status->status_buffercnt & (1<<24)) /* Received Error Detect */ + if (l_status_buffercnt & (1<<24)) /* Received Error Detect */ printk(KERN_WARNING "%s: Received Error Detect \n",dev->name); } olympic_priv->rx_ring_last_received += i ; @@ -717,8 +742,8 @@ skb2=olympic_priv->rx_ring_skb[rx_ring_last_received] ; skb_put(skb2,length); skb2->protocol = tr_type_trans(skb2,dev); - olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer=virt_to_bus(skb->data); - olympic_priv->olympic_rx_ring[rx_ring_last_received].res_length = olympic_priv->pkt_buf_sz ; + olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer = cpu_to_le32(virt_to_bus(skb->data)); + olympic_priv->olympic_rx_ring[rx_ring_last_received].res_length = cpu_to_le32(olympic_priv->pkt_buf_sz); olympic_priv->rx_ring_skb[rx_ring_last_received] = skb ; netif_rx(skb2) ; } else { @@ -727,8 +752,8 @@ olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1); rx_ring_last_received = olympic_priv->rx_ring_last_received ; rx_desc = &(olympic_priv->olympic_rx_ring[rx_ring_last_received]); - cpy_length = (i == 1 ? frag_len : rx_desc->res_length); - memcpy(skb_put(skb, cpy_length), bus_to_virt(rx_desc->buffer), cpy_length) ; + cpy_length = (i == 1 ? frag_len : le32_to_cpu(rx_desc->res_length)); + memcpy(skb_put(skb, cpy_length), bus_to_virt(le32_to_cpu(rx_desc->buffer)), cpy_length) ; } while (--i) ; skb->protocol = tr_type_trans(skb,dev); @@ -849,8 +874,8 @@ netif_stop_queue(dev); if(olympic_priv->free_tx_ring_entries) { - olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_free].buffer=virt_to_bus(skb->data); - olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_free].status_length=skb->len | (0x80000000); + olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_free].buffer = cpu_to_le32(virt_to_bus(skb->data)); + olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_free].status_length = cpu_to_le32(skb->len | (0x80000000)); olympic_priv->tx_ring_skb[olympic_priv->tx_ring_free]=skb; olympic_priv->free_tx_ring_entries--; @@ -1205,9 +1230,9 @@ if (readb(arb_block+0) == ARB_RECEIVE_DATA) { /* Receive.data, MAC frames */ header_len = readb(arb_block+8) ; /* 802.5 Token-Ring Header Length */ - frame_len = ntohs(readw(arb_block + 10)) ; + frame_len = swab16(readw(arb_block + 10)) ; - buff_off = ntohs(readw(arb_block + 6)) ; + buff_off = swab16(readw(arb_block + 6)) ; buf_ptr = olympic_priv->olympic_lap + buff_off ; @@ -1229,7 +1254,7 @@ do { frame_data = buf_ptr+offsetof(struct mac_receive_buffer,frame_data) ; - buffer_len = ntohs(readw(buf_ptr+offsetof(struct mac_receive_buffer,buffer_length))); + buffer_len = swab16(readw(buf_ptr+offsetof(struct mac_receive_buffer,buffer_length))); memcpy_fromio(skb_put(mac_frame, buffer_len), frame_data , buffer_len ) ; next_ptr=readw(buf_ptr+offsetof(struct mac_receive_buffer,next)); @@ -1271,7 +1296,7 @@ return ; } else if (readb(arb_block) == ARB_LAN_CHANGE_STATUS) { /* Lan.change.status */ - lan_status = ntohs(readw(arb_block+6)); + lan_status = swab16(readw(arb_block+6)); fdx_prot_error = readb(arb_block+8) ; /* Issue ARB Free */ @@ -1535,9 +1560,9 @@ readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+3), readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+4), readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+5), - ntohs(readw(opt+offsetof(struct olympic_parameters_table, acc_priority))), - ntohs(readw(opt+offsetof(struct olympic_parameters_table, auth_source_class))), - ntohs(readw(opt+offsetof(struct olympic_parameters_table, att_code)))); + swab16(readw(opt+offsetof(struct olympic_parameters_table, acc_priority))), + swab16(readw(opt+offsetof(struct olympic_parameters_table, auth_source_class))), + swab16(readw(opt+offsetof(struct olympic_parameters_table, att_code)))); size += sprintf(buffer+size, "%6s: Source Address : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n", dev->name) ; @@ -1550,20 +1575,20 @@ readb(opt+offsetof(struct olympic_parameters_table, source_addr)+3), readb(opt+offsetof(struct olympic_parameters_table, source_addr)+4), readb(opt+offsetof(struct olympic_parameters_table, source_addr)+5), - ntohs(readw(opt+offsetof(struct olympic_parameters_table, beacon_type))), - ntohs(readw(opt+offsetof(struct olympic_parameters_table, major_vector))), - ntohs(readw(opt+offsetof(struct olympic_parameters_table, lan_status))), - ntohs(readw(opt+offsetof(struct olympic_parameters_table, local_ring))), - ntohs(readw(opt+offsetof(struct olympic_parameters_table, mon_error))), - ntohs(readw(opt+offsetof(struct olympic_parameters_table, frame_correl)))); + swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_type))), + swab16(readw(opt+offsetof(struct olympic_parameters_table, major_vector))), + swab16(readw(opt+offsetof(struct olympic_parameters_table, lan_status))), + swab16(readw(opt+offsetof(struct olympic_parameters_table, local_ring))), + swab16(readw(opt+offsetof(struct olympic_parameters_table, mon_error))), + swab16(readw(opt+offsetof(struct olympic_parameters_table, frame_correl)))); size += sprintf(buffer+size, "%6s: Beacon Details : Tx : Rx : NAUN Node Address : NAUN Node Phys : \n", dev->name) ; size += sprintf(buffer+size, "%6s: : %02x : %02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x : \n", dev->name, - ntohs(readw(opt+offsetof(struct olympic_parameters_table, beacon_transmit))), - ntohs(readw(opt+offsetof(struct olympic_parameters_table, beacon_receive))), + swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_transmit))), + swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_receive))), readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)), readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+1), readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+2), diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/tokenring/olympic.h linux/drivers/net/tokenring/olympic.h --- v2.4.0-test1/linux/drivers/net/tokenring/olympic.h Sun Mar 19 18:35:30 2000 +++ linux/drivers/net/tokenring/olympic.h Mon Jun 19 13:42:39 2000 @@ -207,6 +207,8 @@ /* Olympic data structures */ +/* xxxx These structures are all little endian in hardware. */ + struct olympic_tx_desc { __u32 buffer; __u32 status_length; @@ -218,13 +220,15 @@ struct olympic_rx_desc { __u32 buffer; - __u32 res_length ; + __u32 res_length; }; struct olympic_rx_status { __u32 fragmentcnt_framelen; __u32 status_buffercnt; }; +/* xxxx END These structures are all little endian in hardware. */ +/* xxxx There may be more, but I'm pretty sure about these */ struct mac_receive_buffer { __u16 next ; @@ -236,10 +240,10 @@ struct olympic_private { - __u16 srb; - __u16 trb; - __u16 arb; - __u16 asb; + __u16 srb; /* be16 */ + __u16 trb; /* be16 */ + __u16 arb; /* be16 */ + __u16 asb; /* be16 */ __u8 *olympic_mmio; __u8 *olympic_lap; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/tulip/21142.c linux/drivers/net/tulip/21142.c --- v2.4.0-test1/linux/drivers/net/tulip/21142.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/net/tulip/21142.c Mon Jun 19 13:42:39 2000 @@ -14,14 +14,15 @@ */ #include "tulip.h" +#include +#include static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, }; -u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, }; +u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, }; static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; - /* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list of available transceivers. */ void t21142_timer(unsigned long data) @@ -82,8 +83,7 @@ tp->csr6 &= 0x00D5; tp->csr6 |= new_csr6; outl(0x0301, ioaddr + CSR12); - tulip_outl_CSR6(tp, tp->csr6 | 0x0002); - tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + tulip_restart_rxtx(tp, tp->csr6); } next_tick = 3*HZ; } @@ -102,19 +102,22 @@ int csr14 = ((tp->to_advertise & 0x0780) << 9) | ((tp->to_advertise&0x0020)<<1) | 0xffbf; + DPRINTK("ENTER\n"); + dev->if_port = 0; tp->nway = tp->mediasense = 1; tp->nwayset = tp->lpar = 0; if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, %8.8x.\n", + printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, csr14=%8.8x.\n", dev->name, csr14); outl(0x0001, ioaddr + CSR13); + udelay(100); outl(csr14, ioaddr + CSR14); if (tp->chip_id == PNIC2) tp->csr6 = 0x01a80000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0); else tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0); - tulip_outl_CSR6(tp, tp->csr6); + tulip_outl_csr(tp, tp->csr6, CSR6); if (tp->mtable && tp->mtable->csr15dir) { outl(tp->mtable->csr15dir, ioaddr + CSR15); outl(tp->mtable->csr15val, ioaddr + CSR15); @@ -180,12 +183,12 @@ outl(1, ioaddr + CSR13); } #if 0 /* Restart shouldn't be needed. */ - tulip_outl_CSR6(tp, tp->csr6 | 0x0000); + tulip_outl_csr(tp, tp->csr6 | csr6_sr, CSR6); if (tulip_debug > 2) printk(KERN_DEBUG "%s: Restarting Tx and Rx, CSR5 is %8.8x.\n", dev->name, inl(ioaddr + CSR5)); #endif - tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + tulip_outl_csr(tp, tp->csr6 | csr6_st | csr6_sr, CSR6); if (tulip_debug > 2) printk(KERN_DEBUG "%s: Setting CSR6 %8.8x/%x CSR12 %8.8x.\n", dev->name, tp->csr6, inl(ioaddr + CSR6), @@ -231,8 +234,7 @@ tp->csr6 = 0x83860000; outl(0x0003FF7F, ioaddr + CSR14); outl(0x0301, ioaddr + CSR12); - tulip_outl_CSR6(tp, tp->csr6 | 0x0002); - tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + tulip_restart_rxtx(tp, tp->csr6); } } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/tulip/eeprom.c linux/drivers/net/tulip/eeprom.c --- v2.4.0-test1/linux/drivers/net/tulip/eeprom.c Mon Mar 27 08:08:26 2000 +++ linux/drivers/net/tulip/eeprom.c Mon Jun 19 13:42:39 2000 @@ -162,6 +162,13 @@ if (tp->flags & CSR12_IN_SROM) csr12dir = *p++; count = *p++; + + /* there is no phy information, don't even try to build mtable */ + if (count == 0) { + DPRINTK("no phy info, aborting mtable build\n"); + return; + } + mtable = (struct mediatable *) kmalloc(sizeof(struct mediatable) + count*sizeof(struct medialeaf), GFP_KERNEL); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/tulip/interrupt.c linux/drivers/net/tulip/interrupt.c --- v2.4.0-test1/linux/drivers/net/tulip/interrupt.c Mon Mar 27 08:08:26 2000 +++ linux/drivers/net/tulip/interrupt.c Mon Jun 19 13:42:39 2000 @@ -178,7 +178,7 @@ int maxtx = TX_RING_SIZE; int maxoi = TX_RING_SIZE; int work_count = tulip_max_interrupt_work; - + tp->nir++; do { @@ -236,13 +236,7 @@ if (status & 0x0002) tp->stats.tx_fifo_errors++; if ((status & 0x0080) && tp->full_duplex == 0) tp->stats.tx_heartbeat_errors++; -#ifdef ETHER_STATS - if (status & 0x0100) tp->stats.collisions16++; -#endif } else { -#ifdef ETHER_STATS - if (status & 0x0001) tp->stats.tx_deferred++; -#endif tp->stats.tx_bytes += tp->tx_buffers[entry].skb->len; tp->stats.collisions += (status >> 3) & 15; @@ -280,8 +274,7 @@ printk(KERN_WARNING "%s: The transmitter stopped." " CSR5 is %x, CSR6 %x, new CSR6 %x.\n", dev->name, csr5, inl(ioaddr + CSR6), tp->csr6); - tulip_outl_CSR6(tp, tp->csr6 | 0x0002); - tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + tulip_restart_rxtx(tp, tp->csr6); } spin_unlock(&tp->lock); } @@ -297,14 +290,13 @@ else tp->csr6 |= 0x00200000; /* Store-n-forward. */ /* Restart the transmit process. */ - tulip_outl_CSR6(tp, tp->csr6 | 0x0002); - tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + tulip_restart_rxtx(tp, tp->csr6); outl(0, ioaddr + CSR1); } if (csr5 & RxDied) { /* Missed a Rx frame. */ tp->stats.rx_errors++; tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; - tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + tulip_outl_csr(tp, tp->csr6 | csr6_st | csr6_sr, CSR6); } if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) { if (tp->link_change) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/tulip/media.c linux/drivers/net/tulip/media.c --- v2.4.0-test1/linux/drivers/net/tulip/media.c Mon Mar 27 08:08:27 2000 +++ linux/drivers/net/tulip/media.c Mon Jun 19 13:42:39 2000 @@ -388,8 +388,7 @@ tp->csr6 &= ~0x00400000; if (tp->full_duplex) tp->csr6 |= 0x0200; else tp->csr6 &= ~0x0200; - tulip_outl_CSR6(tp, tp->csr6 | 0x0002); - tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + tulip_restart_rxtx(tp, tp->csr6); if (tulip_debug > 0) printk(KERN_INFO "%s: Setting %s-duplex based on MII" "#%d link partner capability of %4.4x.\n", diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/tulip/pnic.c linux/drivers/net/tulip/pnic.c --- v2.4.0-test1/linux/drivers/net/tulip/pnic.c Mon Mar 27 08:08:27 2000 +++ linux/drivers/net/tulip/pnic.c Mon Jun 19 13:42:39 2000 @@ -44,8 +44,7 @@ if (tp->csr6 != new_csr6) { tp->csr6 = new_csr6; /* Restart Tx */ - tulip_outl_CSR6(tp, tp->csr6 | 0x0002); - tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + tulip_restart_rxtx(tp, tp->csr6); dev->trans_start = jiffies; } } @@ -65,7 +64,7 @@ outl((inl(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7); if (! tp->nwayset || jiffies - dev->trans_start > 1*HZ) { tp->csr6 = 0x00420000 | (tp->csr6 & 0x0000fdff); - tulip_outl_CSR6(tp, tp->csr6); + tulip_outl_csr(tp, tp->csr6, CSR6); outl(0x30, ioaddr + CSR12); outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */ dev->trans_start = jiffies; @@ -128,8 +127,7 @@ if (tp->csr6 != new_csr6) { tp->csr6 = new_csr6; /* Restart Tx */ - tulip_outl_CSR6(tp, tp->csr6 | 0x0002); - tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + tulip_restart_rxtx(tp, tp->csr6); dev->trans_start = jiffies; if (tulip_debug > 1) printk(KERN_INFO "%s: Changing PNIC configuration to %s " diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/tulip/timer.c linux/drivers/net/tulip/timer.c --- v2.4.0-test1/linux/drivers/net/tulip/timer.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/net/tulip/timer.c Mon Jun 19 13:42:39 2000 @@ -154,8 +154,7 @@ medianame[tp->mtable->mleaf[tp->cur_index].media]); tulip_select_media(dev, 0); /* Restart the transmit process. */ - tulip_outl_CSR6(tp, tp->csr6 | 0x0002); - tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + tulip_restart_rxtx(tp, tp->csr6); next_tick = (24*HZ)/10; break; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/tulip/tulip.h linux/drivers/net/tulip/tulip.h --- v2.4.0-test1/linux/drivers/net/tulip/tulip.h Wed Apr 26 16:34:08 2000 +++ linux/drivers/net/tulip/tulip.h Mon Jun 19 13:42:39 2000 @@ -169,31 +169,54 @@ csr6_ra = (1<<30), csr6_ign_dest_msb = (1<<26), csr6_mbo = (1<<25), - csr6_scr = (1<<24), - csr6_pcs = (1<<23), - csr6_ttm = (1<<22), - csr6_sf = (1<<21), - csr6_hbd = (1<<19), - csr6_ps = (1<<18), - csr6_ca = (1<<17), - csr6_st = (1<<13), - csr6_fc = (1<<12), - csr6_om_int_loop = (1<<10), - csr6_om_ext_loop = (1<<11), - csr6_fd = (1<<9), - csr6_pm = (1<<7), - csr6_pr = (1<<6), - csr6_sb = (1<<5), - csr6_if = (1<<4), - csr6_pb = (1<<3), - csr6_ho = (1<<2), - csr6_sr = (1<<1), - csr6_hp = (1<<0), + csr6_scr = (1<<24), /* scramble mode flag: can't be set */ + csr6_pcs = (1<<23), /* Enables PCS functions (symbol mode requires csr6_ps be set) default is set */ + csr6_ttm = (1<<22), /* Transmit Threshold Mode, set for 10baseT, 0 for 100BaseTX */ + csr6_sf = (1<<21), /* Store and forward. If set ignores TR bits */ + csr6_hbd = (1<<19), /* Heart beat disable. Disables SQE function in 10baseT */ + csr6_ps = (1<<18), /* Port Select. 0 (defualt) = 10baseT, 1 = 100baseTX: can't be set */ + csr6_ca = (1<<17), /* Collision Offset Enable. If set uses special algorithm in low collision situations */ + csr6_trh = (1<<15), /* Transmit Threshold high bit */ + csr6_trl = (1<<14), /* Transmit Threshold low bit */ + + /*************************************************************** + * This table shows transmit threshold values based on media * + * and these two registers (from PNIC1 & 2 docs) Note: this is * + * all meaningless if sf is set. * + ***************************************************************/ + + /*********************************** + * (trh,trl) * 100BaseTX * 10BaseT * + *********************************** + * (0,0) * 128 * 72 * + * (0,1) * 256 * 96 * + * (1,0) * 512 * 128 * + * (1,1) * 1024 * 160 * + ***********************************/ + + csr6_st = (1<<13), /* Transmit conrol: 1 = transmit, 0 = stop */ + csr6_fc = (1<<12), /* Forces a collision in next transmission (for testing in loopback mode) */ + csr6_om_int_loop = (1<<10), /* internal (FIFO) loopback flag */ + csr6_om_ext_loop = (1<<11), /* external (PMD) loopback flag */ + /* set both and you get (PHY) loopback */ + csr6_fd = (1<<9), /* Full duplex mode, disables hearbeat, no loopback */ + csr6_pm = (1<<7), /* Pass All Multicast */ + csr6_pr = (1<<6), /* Promiscuous mode */ + csr6_sb = (1<<5), /* Start(1)/Stop(0) backoff counter */ + csr6_if = (1<<4), /* Inverse Filtering, rejects only addresses in address table: can't be set */ + csr6_pb = (1<<3), /* Pass Bad Frames, (1) causes even bad frames to be passed on */ + csr6_ho = (1<<2), /* Hash-only filtering mode: can't be set */ + csr6_sr = (1<<1), /* Start(1)/Stop(0) Receive */ + csr6_hp = (1<<0), /* Hash/Perfect Receive Filtering Mode: can't be set */ csr6_mask_capture = (csr6_sc | csr6_ca), csr6_mask_defstate = (csr6_mask_capture | csr6_mbo), - csr6_mask_fullcap = (csr6_mask_defstate | csr6_hbd | - csr6_ps | (3<<14) | csr6_fd), + csr6_mask_hdcap = (csr6_mask_defstate | csr6_hbd | csr6_ps), + csr6_mask_hdcaptt = (csr6_mask_hdcap | csr6_trh | csr6_trl), + csr6_mask_fullcap = (csr6_mask_hdcaptt | csr6_fd), + csr6_mask_fullpromisc = (csr6_pr | csr6_pm), + csr6_mask_filters = (csr6_hp | csr6_ho | csr6_if), + csr6_mask_100bt = (csr6_scr | csr6_pcs | csr6_hbd), }; @@ -397,11 +420,20 @@ extern u16 t21041_csr15[]; -extern inline void tulip_outl_CSR6 (struct tulip_private *tp, u32 newcsr6) +static inline void tulip_outl_csr (struct tulip_private *tp, u32 newValue, enum tulip_offsets offset) { - long ioaddr = tp->base_addr; + outl (newValue, tp->base_addr + offset); +} - outl (newcsr6, ioaddr + CSR6); +static inline void tulip_stop_rxtx(struct tulip_private *tp, u32 csr6mask) +{ + tulip_outl_csr(tp, csr6mask & ~(csr6_st | csr6_sr), CSR6); +} + +static inline void tulip_restart_rxtx(struct tulip_private *tp, u32 csr6mask) +{ + tulip_outl_csr(tp, csr6mask | csr6_sr, CSR6); + tulip_outl_csr(tp, csr6mask | csr6_st | csr6_sr, CSR6); } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/tulip/tulip_core.c linux/drivers/net/tulip/tulip_core.c --- v2.4.0-test1/linux/drivers/net/tulip/tulip_core.c Tue May 23 15:31:35 2000 +++ linux/drivers/net/tulip/tulip_core.c Mon Jun 19 13:42:39 2000 @@ -19,7 +19,7 @@ */ -static const char version[] = "Linux Tulip driver version 0.9.4.3 (Apr 14, 2000)\n"; +static const char version[] = "Linux Tulip driver version 0.9.6 (May 31, 2000)\n"; #include #include "tulip.h" @@ -50,7 +50,8 @@ }; /* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */ -#if defined(__alpha__) || defined(__arm__) || defined(__sparc__) +#if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \ + || defined(__sparc_) static int rx_copybreak = 1518; #else static int rx_copybreak = 100; @@ -71,7 +72,7 @@ #if defined(__alpha__) static int csr0 = 0x01A00000 | 0xE000; -#elif defined(__i386__) || defined(__powerpc__) +#elif defined(__i386__) || defined(__powerpc__) || defined(__hppa__) static int csr0 = 0x01A00000 | 0x8000; #elif defined(__sparc__) /* The UltraSparc PCI controllers will disconnect at every 64-byte @@ -210,13 +211,15 @@ int next_tick = 3*HZ; int i; + DPRINTK("ENTER\n"); + /* Wake the chip from sleep/snooze mode. */ if (tp->flags & HAS_ACPI) pci_write_config_dword(tp->pdev, 0x40, 0); /* On some chip revs we must set the MII/SYM port before the reset!? */ if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii)) - tulip_outl_CSR6 (tp, 0x00040000); + tulip_outl_csr (tp, 0x00040000, CSR6); /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */ outl(0x00000001, ioaddr + CSR0); @@ -311,9 +314,9 @@ tp->csr6 = 0; tp->cur_index = i; tp->nwayset = 0; - if (dev->if_port == 0 && tp->chip_id == DC21041) { + if (dev->if_port == 0 && tp->chip_id == DC21041) tp->nway = 1; - } + if (dev->if_port == 0 && tp->chip_id == DC21142) { if (tp->mii_cnt) { tulip_select_media(dev, 1); @@ -321,8 +324,8 @@ printk(KERN_INFO "%s: Using MII transceiver %d, status " "%4.4x.\n", dev->name, tp->phys[0], tulip_mdio_read(dev, tp->phys[0], 1)); - tulip_outl_CSR6(tp, 0x82020000); - tp->csr6 = 0x820E0000; + tulip_outl_csr(tp, csr6_mask_defstate, CSR6); + tp->csr6 = csr6_mask_hdcap; dev->if_port = 11; outl(0x0000, ioaddr + CSR13); outl(0x0000, ioaddr + CSR14); @@ -371,13 +374,13 @@ tulip_select_media(dev, 1); /* Start the chip's Tx to process setup frame. */ - tulip_outl_CSR6(tp, tp->csr6); - tulip_outl_CSR6(tp, tp->csr6 | 0x2000); + tulip_outl_csr(tp, tp->csr6, CSR6); + tulip_outl_csr(tp, tp->csr6 | csr6_st, CSR6); /* Enable interrupts by setting the interrupt mask. */ outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5); outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); - tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + tulip_outl_csr(tp, tp->csr6 | csr6_st | csr6_sr, CSR6); outl(0, ioaddr + CSR2); /* Rx poll demand */ if (tulip_debug > 2) { @@ -421,6 +424,8 @@ long ioaddr = dev->base_addr; unsigned long flags; + DPRINTK("ENTER\n"); + spin_lock_irqsave (&tp->lock, flags); if (tulip_media_cap[dev->if_port] & MediaIsMII) { @@ -510,8 +515,7 @@ #endif /* Stop and restart the chip's Tx processes . */ - tulip_outl_CSR6(tp, tp->csr6 | 0x0002); - tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + tulip_restart_rxtx(tp, tp->csr6); /* Trigger an immediate transmit demand. */ outl(0, ioaddr + CSR1); @@ -529,6 +533,8 @@ struct tulip_private *tp = (struct tulip_private *)dev->priv; int i; + DPRINTK("ENTER\n"); + tp->tx_full = 0; tp->cur_rx = tp->cur_tx = 0; tp->dirty_rx = tp->dirty_tx = 0; @@ -584,12 +590,11 @@ int entry; u32 flag; dma_addr_t mapping; - unsigned long cpuflags; /* Caution: the write order is important here, set the field with the ownership bits last. */ - spin_lock_irqsave(&tp->lock, cpuflags); + spin_lock_irq(&tp->lock); /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % TX_RING_SIZE; @@ -621,7 +626,7 @@ /* Trigger an immediate transmit demand. */ outl(0, dev->base_addr + CSR1); - spin_unlock_irqrestore(&tp->lock, cpuflags); + spin_unlock_irq(&tp->lock); dev->trans_start = jiffies; @@ -642,7 +647,7 @@ outl (0x00000000, ioaddr + CSR7); /* Stop the Tx and Rx processes. */ - tulip_outl_CSR6 (tp, inl (ioaddr + CSR6) & ~0x2002); + tulip_stop_rxtx(tp, inl(ioaddr + CSR6)); /* 21040 -- Leave the card in 10baseT state. */ if (tp->chip_id == DC21040) @@ -839,7 +844,14 @@ { struct tulip_private *tp = (struct tulip_private *)dev->priv; long ioaddr = dev->base_addr; - int csr6 = inl(ioaddr + CSR6) & ~0x00D5; + int csr6, need_lock = 0; + unsigned long flags; + + DPRINTK("ENTER\n"); + + spin_lock_irqsave(&tp->lock, flags); + csr6 = inl(ioaddr + CSR6) & ~0x00D5; + spin_unlock_irqrestore(&tp->lock, flags); tp->csr6 &= ~0x00D5; if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ @@ -847,10 +859,14 @@ csr6 |= 0x00C0; /* Unconditionally log net taps. */ printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); + + need_lock = 1; } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) { /* Too many to filter well -- accept all multicasts. */ tp->csr6 |= 0x0080; csr6 |= 0x0080; + + need_lock = 1; } else if (tp->flags & MC_HASH_ONLY) { /* Some work-alikes have only a 64-entry hash filter table. */ /* Should verify correctness on big-endian/__powerpc__ */ @@ -860,27 +876,35 @@ if (dev->mc_count > 64) { /* Arbitrary non-effective limit. */ tp->csr6 |= 0x0080; csr6 |= 0x0080; + need_lock = 1; } else { mc_filter[1] = mc_filter[0] = 0; for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, mc_filter); + if (tp->chip_id == AX88140) { + spin_lock_irqsave(&tp->lock, flags); outl(2, ioaddr + CSR13); outl(mc_filter[0], ioaddr + CSR14); outl(3, ioaddr + CSR13); outl(mc_filter[1], ioaddr + CSR14); + /* need_lock = 0; */ } else if (tp->chip_id == COMET) { /* Has a simple hash filter. */ + spin_lock_irqsave(&tp->lock, flags); outl(mc_filter[0], ioaddr + 0xAC); outl(mc_filter[1], ioaddr + 0xB0); + /* need_lock = 0; */ + } else { + need_lock = 1; } } + } else { u16 *eaddrs, *setup_frm = tp->setup_frame; struct dev_mc_list *mclist; u32 tx_flags = 0x08000000 | 192; int i; - unsigned long flags; /* Note that only the low-address shortword of setup_frame is valid! The values are doubled for big-endian architectures. */ @@ -923,7 +947,7 @@ if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) { /* Same setup recently queued, we need not add it. */ } else { - unsigned int entry; + unsigned int entry, dummy = -1; /* Now add this frame to the Tx list. */ @@ -936,7 +960,8 @@ tp->tx_ring[entry].length = (entry == TX_RING_SIZE-1) ? cpu_to_le32(DESC_RING_WRAP) : 0; tp->tx_ring[entry].buffer1 = 0; - tp->tx_ring[entry].status = cpu_to_le32(DescOwned); + /* Must set DescOwned later to avoid race with chip */ + dummy = entry; entry = tp->cur_tx++ % TX_RING_SIZE; } @@ -952,6 +977,8 @@ tp->tx_ring[entry].buffer1 = cpu_to_le32(tp->tx_buffers[entry].mapping); tp->tx_ring[entry].status = cpu_to_le32(DescOwned); + if (dummy >= 0) + tp->tx_ring[dummy].status = cpu_to_le32(DescOwned); if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) { netif_stop_queue(dev); tp->tx_full = 1; @@ -961,10 +988,15 @@ outl(0, ioaddr + CSR1); } - - spin_unlock_irqrestore(&tp->lock, flags); } - tulip_outl_CSR6(tp, csr6 | 0x0000); + + if (need_lock) + spin_lock_irqsave(&tp->lock, flags); + + /* Can someone explain to me what the OR here is supposed to accomplish???? */ + tulip_outl_csr(tp, csr6 | 0x0000, CSR6); + + spin_unlock_irqrestore(&tp->lock, flags); } @@ -999,29 +1031,33 @@ ioaddr = pci_resource_start (pdev, 0); irq = pdev->irq; - /* init_etherdev ensures qword aligned structures */ + /* init_etherdev ensures aligned and zeroed private structures */ dev = init_etherdev (NULL, sizeof (*tp)); if (!dev) { printk (KERN_ERR PFX "ether device alloc failed, aborting\n"); return -ENOMEM; } - /* We do a request_region() only to register /proc/ioports info. */ - /* Note that proper size is tulip_tbl[chip_idx].chip_name, but... */ - if (!request_region (ioaddr, tulip_tbl[chip_idx].io_size, dev->name)) { + /* grab all resources from both PIO and MMIO regions, as we + * don't want anyone else messing around with our hardware */ + if (!request_region (pci_resource_start (pdev, 0), + pci_resource_len (pdev, 0), + dev->name)) { printk (KERN_ERR PFX "I/O ports (0x%x@0x%lx) unavailable, " "aborting\n", tulip_tbl[chip_idx].io_size, ioaddr); goto err_out_free_netdev; } - - if (pci_enable_device(pdev)) { - printk (KERN_ERR PFX "cannot enable PCI device (id %04x:%04x, " - "bus %d, devfn %d), aborting\n", - pdev->vendor, pdev->device, - pdev->bus->number, pdev->devfn); - goto err_out_free_netdev; + if (!request_mem_region (pci_resource_start (pdev, 1), + pci_resource_len (pdev, 1), + dev->name)) { + printk (KERN_ERR PFX "MMIO resource (0x%x@0x%lx) unavailable, " + "aborting\n", tulip_tbl[chip_idx].io_size, ioaddr); + goto err_out_free_pio_res; } + if (pci_enable_device(pdev)) + goto err_out_free_mmio_res; + pci_set_master(pdev); pci_read_config_byte (pdev, PCI_REVISION_ID, &chip_rev); @@ -1044,8 +1080,13 @@ tp->pdev = pdev; tp->base_addr = ioaddr; tp->revision = chip_rev; + tp->csr0 = csr0; spin_lock_init(&tp->lock); + dev->base_addr = ioaddr; + dev->irq = irq; + pdev->driver_data = dev; + #ifdef TULIP_FULL_DUPLEX tp->full_duplex = 1; tp->full_duplex_lock = 1; @@ -1060,8 +1101,17 @@ printk(KERN_INFO "%s: %s rev %d at %#3lx,", dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr); + /* bugfix: the ASIX must have a burst limit or horrible things happen. */ + if (chip_idx == AX88140) { + if ((tp->csr0 & 0x3f00) == 0) + tp->csr0 |= 0x2000; + } + else if (chip_idx == DC21143 && chip_rev == 65) + tp->csr0 &= ~0x01000000; + /* Stop the chip's Tx and Rx processes. */ - tulip_outl_CSR6(tp, inl(ioaddr + CSR6) & ~0x2002); + tulip_stop_rxtx(tp, inl(ioaddr + CSR6)); + /* Clear the missed-packet counter. */ (volatile int)inl(ioaddr + CSR8); @@ -1158,20 +1208,6 @@ printk(", IRQ %d.\n", irq); last_irq = irq; - pdev->driver_data = dev; - dev->base_addr = ioaddr; - dev->irq = irq; - tp->csr0 = csr0; - - /* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles. - And the ASIX must have a burst limit or horrible things happen. */ - if (chip_idx == DC21143 && chip_rev == 65) - tp->csr0 &= ~0x01000000; - else if (chip_idx == AX88140) { - if ((tp->csr0 & 0x3f00) == 0) - tp->csr0 |= 0x2000; - } - /* The lower four bits are the media type. */ if (board_idx >= 0 && board_idx < MAX_UNITS) { tp->default_port = options[board_idx] & 15; @@ -1198,7 +1234,7 @@ else tp->to_advertise = 0x01e1; - /* This is logically part of probe1(), but too complex to write inline. */ + /* This is logically part of _init_one(), but too complex to write inline. */ if (tp->flags & HAS_MEDIA_TABLE) { memcpy(tp->eeprom, ee_data, sizeof(tp->eeprom)); tulip_parse_eeprom(dev); @@ -1280,7 +1316,7 @@ outl(0x00000000, ioaddr + CSR13); outl(0xFFFFFFFF, ioaddr + CSR14); outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */ - tulip_outl_CSR6(tp, inl(ioaddr + CSR6) | 0x0200); + tulip_outl_csr(tp, inl(ioaddr + CSR6) | csr6_fd, CSR6); outl(0x0000EF05, ioaddr + CSR13); break; case DC21040: @@ -1295,10 +1331,10 @@ case DC21142: case PNIC2: if (tp->mii_cnt || tulip_media_cap[dev->if_port] & MediaIsMII) { - tulip_outl_CSR6(tp, 0x82020000); + tulip_outl_csr(tp, csr6_mask_defstate, CSR6); outl(0x0000, ioaddr + CSR13); outl(0x0000, ioaddr + CSR14); - tulip_outl_CSR6(tp, 0x820E0000); + tulip_outl_csr(tp, csr6_mask_hdcap, CSR6); } else t21142_start_nway(dev); break; @@ -1306,19 +1342,21 @@ if ( ! tp->mii_cnt) { tp->nway = 1; tp->nwayset = 0; - tulip_outl_CSR6(tp, 0x00420000); + tulip_outl_csr(tp, csr6_ttm | csr6_ca, CSR6); outl(0x30, ioaddr + CSR12); - tulip_outl_CSR6(tp, 0x0001F078); - tulip_outl_CSR6(tp, 0x0201F078); /* Turn on autonegotiation. */ + tulip_outl_csr(tp, 0x0001F078, CSR6); + tulip_outl_csr(tp, 0x0201F078, CSR6); /* Turn on autonegotiation. */ } break; - case MX98713: case COMPEX9881: - tulip_outl_CSR6(tp, 0x00000000); + case MX98713: + case COMPEX9881: + tulip_outl_csr(tp, 0x00000000, CSR6); outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */ outl(0x00000001, ioaddr + CSR13); break; - case MX98715: case MX98725: - tulip_outl_CSR6(tp, 0x01a80000); + case MX98715: + case MX98725: + tulip_outl_csr(tp, 0x01a80000, CSR6); outl(0xFFFFFFFF, ioaddr + CSR14); outl(0x00001000, ioaddr + CSR12); break; @@ -1333,6 +1371,12 @@ return 0; +err_out_free_mmio_res: + release_mem_region (pci_resource_start (pdev, 1), + pci_resource_len (pdev, 1)); +err_out_free_pio_res: + release_region (pci_resource_start (pdev, 0), + pci_resource_len (pdev, 0)); err_out_free_netdev: unregister_netdev (dev); kfree (dev); @@ -1376,8 +1420,10 @@ tp->rx_ring, tp->rx_ring_dma); unregister_netdev(dev); - release_region(dev->base_addr, - tulip_tbl[tp->chip_id].io_size); + release_mem_region (pci_resource_start (pdev, 1), + pci_resource_len (pdev, 1)); + release_region (pci_resource_start (pdev, 0), + pci_resource_len (pdev, 0)); kfree(dev); } } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/wan/Config.in linux/drivers/net/wan/Config.in --- v2.4.0-test1/linux/drivers/net/wan/Config.in Wed Apr 26 16:34:08 2000 +++ linux/drivers/net/wan/Config.in Tue Jun 20 14:14:51 2000 @@ -81,7 +81,9 @@ dep_tristate 'LAPB over Ethernet driver' CONFIG_LAPBETHER $CONFIG_LAPB $CONFIG_X25 dep_tristate 'X.25 async driver' CONFIG_X25_ASY $CONFIG_LAPB $CONFIG_X25 - tristate 'SBNI12-xx support' CONFIG_SBNI + if [ "$CONFIG_X86" = "y" ]; then + tristate 'SBNI12-xx support' CONFIG_SBNI + fi fi endmenu diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/wan/comx.c linux/drivers/net/wan/comx.c --- v2.4.0-test1/linux/drivers/net/wan/comx.c Tue May 23 15:31:35 2000 +++ linux/drivers/net/wan/comx.c Wed Jun 21 10:10:02 2000 @@ -81,6 +81,10 @@ static struct comx_hardware *comx_channels = NULL; static struct comx_protocol *comx_lines = NULL; +static int comx_mkdir(struct inode *, struct dentry *, int); +static int comx_rmdir(struct inode *, struct dentry *); +static struct dentry *comx_lookup(struct inode *, struct dentry *); + static struct inode_operations comx_root_inode_ops = { lookup: comx_lookup, mkdir: comx_mkdir, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/wan/cosa.c linux/drivers/net/wan/cosa.c --- v2.4.0-test1/linux/drivers/net/wan/cosa.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/wan/cosa.c Wed Jun 21 22:31:02 2000 @@ -318,6 +318,7 @@ #endif static struct file_operations cosa_fops = { + owner: THIS_MODULE, llseek: cosa_lseek, read: cosa_read, write: cosa_write, @@ -397,7 +398,7 @@ devfs_handle = devfs_mk_dir (NULL, "cosa", 4, NULL); devfs_register_series (devfs_handle, "%u", nr_cards, DEVFS_FL_DEFAULT, cosa_major, 0, - S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR, &cosa_fops, NULL); if (!nr_cards) { printk(KERN_WARNING "cosa: no devices found.\n"); @@ -969,9 +970,6 @@ chan->tx_done = chrdev_tx_done; chan->setup_rx = chrdev_setup_rx; chan->rx_done = chrdev_rx_done; -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif spin_unlock_irqrestore(&cosa->lock, flags); return 0; } @@ -985,9 +983,6 @@ spin_lock_irqsave(&cosa->lock, flags); cosa->usage--; channel->usage--; -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif spin_unlock_irqrestore(&cosa->lock, flags); return 0; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/wan/cycx_main.c linux/drivers/net/wan/cycx_main.c --- v2.4.0-test1/linux/drivers/net/wan/cycx_main.c Tue Apr 11 15:09:18 2000 +++ linux/drivers/net/wan/cycx_main.c Tue Jun 20 14:14:51 2000 @@ -13,6 +13,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* 2000/07/06 acme __exit at cyclomx_cleanup * 2000/04/02 acme dprintk and cycx_debug * module_init/module_exit * 2000/01/21 acme rename cyclomx_open to cyclomx_mod_inc_use_count @@ -59,7 +60,7 @@ /* Defines & Macros */ #define DRV_VERSION 0 /* version number */ -#define DRV_RELEASE 7 /* release (minor version) number */ +#define DRV_RELEASE 8 /* release (minor version) number */ #define MAX_CARDS 1 /* max number of adapters */ #ifndef CONFIG_CYCLOMX_CARDS /* configurable option */ @@ -102,7 +103,7 @@ * < 0 error. * Context: process */ -int __init cyclomx_init (void) +static int __init cyclomx_init (void) { int cnt, err = 0; @@ -156,7 +157,7 @@ * o unregister all adapters from the WAN router * o release all remaining system resources */ -void cyclomx_cleanup (void) +static void __exit cyclomx_cleanup (void) { int i = 0; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/wan/lmc/lmc_main.c linux/drivers/net/wan/lmc/lmc_main.c --- v2.4.0-test1/linux/drivers/net/wan/lmc/lmc_main.c Tue May 23 15:31:35 2000 +++ linux/drivers/net/wan/lmc/lmc_main.c Tue Jun 20 14:14:51 2000 @@ -1042,14 +1042,9 @@ int lmc_probe (struct net_device *dev) /*fold00*/ { int pci_index = 0; -#if LINUX_VERSION_CODE >= 0x20155 unsigned long pci_ioaddr; unsigned short pci_command; unsigned int pci_irq_line; -#else - unsigned char pci_irq_line; - u32 pci_ioaddr; -#endif u16 vendor, subvendor, device, subdevice; u32 foundaddr = 0; unsigned char pci_bus, pci_device_fn; @@ -1065,6 +1060,7 @@ } /* Loop basically until we don't find anymore. */ while (pci_index < 0xff){ + struct pci_dev *pdev; /* The tulip is considered an ethernet class of card... */ if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index, &pci_bus, @@ -1075,46 +1071,20 @@ /* Read the info we need to determine if this is * our card or not */ -#if LINUX_VERSION_CODE >= 0x20155 - vendor = pci_find_slot (pci_bus, pci_device_fn)->vendor; - device = pci_find_slot (pci_bus, pci_device_fn)->device; - pci_irq_line = pci_find_slot (pci_bus, pci_device_fn)->irq; -#if LINUX_VERSION_CODE < 0x20363 - pci_ioaddr = pci_find_slot (pci_bus, pci_device_fn)->base_address[0]; -#else - pci_ioaddr = pci_resource_start (pci_find_slot (pci_bus, pci_device_fn), 0); -#endif - pci_read_config_word (pci_find_slot (pci_bus, pci_device_fn), - PCI_SUBSYSTEM_VENDOR_ID, &subvendor); - pci_read_config_word (pci_find_slot (pci_bus, pci_device_fn), - PCI_SUBSYSTEM_ID, &subdevice); - /* - * SPARC PCI Bios doesn't set the BUS Master bit, unlike intel - * Without it we won't do much packet work - * Do this to everyone - */ - pci_read_config_word(pci_find_slot (pci_bus, pci_device_fn), PCI_COMMAND, - &pci_command); - pci_command |= PCI_COMMAND_MASTER; - pci_write_config_word(pci_find_slot (pci_bus, pci_device_fn), PCI_COMMAND, - pci_command); -#else - pcibios_read_config_word (pci_bus, pci_device_fn, - PCI_VENDOR_ID, &vendor); - pcibios_read_config_word (pci_bus, pci_device_fn, - PCI_DEVICE_ID, &device); - pcibios_read_config_byte (pci_bus, pci_device_fn, - PCI_INTERRUPT_LINE, &pci_irq_line); - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_0, &pci_ioaddr); - pcibios_read_config_word (pci_bus, pci_device_fn, - PCI_SUBSYSTEM_VENDOR_ID, &subvendor); - pcibios_read_config_word (pci_bus, pci_device_fn, - PCI_SUBSYSTEM_ID, &subdevice); -#endif + pdev = pci_find_slot (pci_bus, pci_device_fn); + if (!pdev) break; + + if (pci_enable_device(pdev)) + break; + + vendor = pdev->vendor; + device = pdev->device; + pci_irq_line = pdev->irq; + pci_ioaddr = pci_resource_start (pdev, 0); + subvendor = pdev->subsystem_vendor; + subdevice = pdev->subsystem_device; - /* Align the io address on the 32 bit boundry just in case */ - pci_ioaddr &= ~3; + pci_set_master (pdev); /* * Make sure it's the correct card. CHECK SUBVENDOR ID! diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/wan/sbni.c linux/drivers/net/wan/sbni.c --- v2.4.0-test1/linux/drivers/net/wan/sbni.c Tue Mar 14 19:10:40 2000 +++ linux/drivers/net/wan/sbni.c Tue Jun 20 14:14:51 2000 @@ -334,7 +334,7 @@ if(base_addr > 0x1ff) /* Check a single specified location. */ return sbni_probe1(dev, base_addr); else if(base_addr != 0) /* Don't probe at all. */ - return ENXIO; + return -ENXIO; for(i = 0; (base_addr = netcard_portlist[i]); i++) { if(!check_region(base_addr, SBNI_IO_EXTENT) && base_addr != 1) @@ -345,7 +345,7 @@ return 0; } } - return ENODEV; + return -ENODEV; } #endif /* have devlist*/ @@ -408,7 +408,7 @@ } if(bad_card) - return ENODEV; + return -ENODEV; else outb(0, ioaddr + CSR0); if(dev->irq < 2) @@ -422,7 +422,7 @@ if(autoirq == 0) { printk("sbni probe at %#x failed to detect IRQ line\n", ioaddr); - return EAGAIN; + return -EAGAIN; } } /* clear FIFO buffer */ @@ -436,7 +436,7 @@ if (irqval) { printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval); - return EAGAIN; + return -EAGAIN; } } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/wan/sdladrv.c linux/drivers/net/wan/sdladrv.c --- v2.4.0-test1/linux/drivers/net/wan/sdladrv.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/net/wan/sdladrv.c Tue Jun 20 14:14:51 2000 @@ -1983,8 +1983,9 @@ while ((pci_dev = pci_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev)) != NULL) { - pci_read_config_word(pci_dev, PCI_SUBSYS_VENDOR_WORD, - &PCI_subsys_vendor); + if (pci_enable_device(pci_dev)) + continue; + PCI_subsys_vendor = pci_dev->subsystem_vendor; if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR) continue; hw->pci_dev = pci_dev; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c --- v2.4.0-test1/linux/drivers/net/wavelan.c Tue May 23 15:31:35 2000 +++ linux/drivers/net/wavelan.c Tue Jun 20 14:14:51 2000 @@ -3623,7 +3623,7 @@ /* Check if the base address if available. */ if (check_region(ioaddr, sizeof(ha_t))) - return EADDRINUSE; /* ioaddr already used */ + return -EADDRINUSE; /* ioaddr already used */ /* Reset host interface */ wv_hacr_reset(ioaddr); @@ -3649,7 +3649,7 @@ "WaveLAN (0x%3X): your MAC address might be %02X:%02X:%02X.\n", ioaddr, mac[0], mac[1], mac[2]); #endif - return ENODEV; + return -ENODEV; } /************************ INTERRUPT HANDLING ************************/ @@ -4002,7 +4002,7 @@ "%s: wavelan_config(): could not wavelan_map_irq(%d).\n", dev->name, irq_mask); #endif - return EAGAIN; + return -EAGAIN; } dev->irq = irq; @@ -4095,7 +4095,7 @@ printk(KERN_WARNING "%s: wavelan_probe(): structure/compiler botch: \"%s\"\n", dev->name, wv_struct_check()); - return ENODEV; + return -ENODEV; } #endif /* STRUCT_CHECK */ @@ -4109,7 +4109,7 @@ "%s: wavelan_probe(): invalid base address\n", dev->name); #endif - return ENXIO; + return -ENXIO; } /* Check a single specified location. */ @@ -4157,7 +4157,7 @@ dev->name); #endif - return ENODEV; + return -ENODEV; } /****************************** MODULE ******************************/ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/wd.c linux/drivers/net/wd.c --- v2.4.0-test1/linux/drivers/net/wd.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/wd.c Mon Jun 19 13:42:38 2000 @@ -94,7 +94,7 @@ if (base_addr > 0x1ff) /* Check a single specified location. */ return wd_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ - return ENXIO; + return -ENXIO; for (i = 0; wd_portlist[i]; i++) { int ioaddr = wd_portlist[i]; @@ -104,7 +104,7 @@ return 0; } - return ENODEV; + return -ENODEV; } #endif @@ -122,11 +122,7 @@ if (inb(ioaddr + 8) == 0xff /* Extra check to avoid soundcard. */ || inb(ioaddr + 9) == 0xff || (checksum & 0xff) != 0xFF) - return ENODEV; - - /* Looks like we have a card. Make sure 8390 support is available. */ - if (load_8390_module("wd.c")) - return -ENOSYS; + return -ENODEV; /* We should have a "dev" from Space.c or the static module table. */ if (dev == NULL) { @@ -268,7 +264,7 @@ printk (" unable to get IRQ %d.\n", dev->irq); kfree(dev->priv); dev->priv = NULL; - return EAGAIN; + return -EAGAIN; } /* OK, were are certain this is going to work. Setup the device. */ @@ -468,6 +464,9 @@ { int this_dev, found = 0; + if (load_8390_module("wd.c")) + return -ENOSYS; + for (this_dev = 0; this_dev < MAX_WD_CARDS; this_dev++) { struct net_device *dev = &dev_wd[this_dev]; dev->irq = irq[this_dev]; @@ -482,14 +481,13 @@ if (register_netdev(dev) != 0) { printk(KERN_WARNING "wd.c: No wd80x3 card found (i/o = 0x%x).\n", io[this_dev]); if (found != 0) { /* Got at least one. */ - lock_8390_module(); return 0; } + unload_8390_module(); return -ENXIO; } found++; } - lock_8390_module(); return 0; } @@ -507,9 +505,9 @@ release_region(ioaddr, WD_IO_EXTENT); unregister_netdev(dev); kfree(priv); - unlock_8390_module(); } } + unload_8390_module(); } #endif /* MODULE */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/znet.c linux/drivers/net/znet.c --- v2.4.0-test1/linux/drivers/net/znet.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/net/znet.c Mon Jun 19 13:42:38 2000 @@ -218,7 +218,7 @@ if (p >= (char *)phys_to_virt(0x100000)) { if (znet_debug > 1) printk(KERN_INFO "No Z-Note ethernet adaptor found.\n"); - return ENODEV; + return -ENODEV; } netinfo = (struct netidblk *)p; dev->base_addr = netinfo->iobase1; @@ -256,7 +256,7 @@ || request_dma(zn.rx_dma,"ZNet rx") || request_dma(zn.tx_dma,"ZNet tx")) { printk(KERN_WARNING "%s: Not opened -- resource busy?!?\n", dev->name); - return EBUSY; + return -EBUSY; } /* Allocate buffer memory. We can cross a 128K boundary, so we diff -u --recursive --new-file v2.4.0-test1/linux/drivers/parport/BUGS-parport linux/drivers/parport/BUGS-parport --- v2.4.0-test1/linux/drivers/parport/BUGS-parport Thu Jun 3 16:21:47 1999 +++ linux/drivers/parport/BUGS-parport Mon Jun 19 13:42:38 2000 @@ -1,5 +1,6 @@ Currently known (or at least suspected) bugs in parport: -o lp doesn't allow you to read status while printing is in progress. +o lp doesn't allow you to read status while printing is in progress (is + this still true?). -See . +See . diff -u --recursive --new-file v2.4.0-test1/linux/drivers/parport/ChangeLog linux/drivers/parport/ChangeLog --- v2.4.0-test1/linux/drivers/parport/ChangeLog Tue May 23 15:31:35 2000 +++ linux/drivers/parport/ChangeLog Mon Jun 19 13:42:38 2000 @@ -1,3 +1,27 @@ +2000-06-13 Tim Waugh + + * procfs.c: Break 'hardware' out into separate files. + +2000-05-28 Gunther Mayer + + * Fix PCI ID printk for non-superio PCI cards. + +2000-05-28 Tim Waugh + + * share.c (call_driver_chain): Get the driverlist_lock. + (parport_register_device): Make sure that port->devices always + looks consistent. + (parport_register_driver): Ensure that parport drivers are given + parameters that are valid for the duration of the callback by + locking the portlist against changes. + (parport_unregister_driver): Likewise. + (parport_claim): Don't overwrite flags. + +2000-05-28 Tim Waugh + + * daisy.c (assign_addrs): Avoid double-probing daisy-chain devices + if the first probe succeeds. + 2000-05-16 Tim Waugh * share.c (parport_claim): Fix SMP race. diff -u --recursive --new-file v2.4.0-test1/linux/drivers/parport/Config.in linux/drivers/parport/Config.in --- v2.4.0-test1/linux/drivers/parport/Config.in Tue Mar 14 19:10:40 2000 +++ linux/drivers/parport/Config.in Mon Jun 19 13:42:38 2000 @@ -1,6 +1,6 @@ # # For a description of the syntax of this configuration file, -# see the Configure script. +# see Documentation/kbuild/config-language.txt. # # Parport configuration. # diff -u --recursive --new-file v2.4.0-test1/linux/drivers/parport/TODO-parport linux/drivers/parport/TODO-parport --- v2.4.0-test1/linux/drivers/parport/TODO-parport Thu Jun 3 16:21:47 1999 +++ linux/drivers/parport/TODO-parport Mon Jun 19 13:42:38 2000 @@ -17,4 +17,4 @@ 4. A better PLIP (make use of bidirectional/ECP/EPP ports). -See . +See . diff -u --recursive --new-file v2.4.0-test1/linux/drivers/parport/daisy.c linux/drivers/parport/daisy.c --- v2.4.0-test1/linux/drivers/parport/daisy.c Tue May 23 15:31:35 2000 +++ linux/drivers/parport/daisy.c Mon Jun 19 13:42:38 2000 @@ -428,6 +428,7 @@ unsigned char s, last_dev; unsigned char daisy; int thisdev = numdevs; + int detected; char *deviceid; parport_data_forward (port); @@ -484,8 +485,9 @@ } parport_write_data (port, 0xff); udelay (2); + detected = numdevs - thisdev; DPRINTK (KERN_DEBUG "%s: Found %d daisy-chained devices\n", port->name, - numdevs - thisdev); + detected); /* Ask the new devices to introduce themselves. */ deviceid = kmalloc (1000, GFP_KERNEL); @@ -495,7 +497,7 @@ parport_device_id (thisdev, deviceid, 1000); kfree (deviceid); - return numdevs - thisdev; + return detected; } /* Find a device with a particular manufacturer and model string, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/parport/parport_amiga.c linux/drivers/parport/parport_amiga.c --- v2.4.0-test1/linux/drivers/parport/parport_amiga.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/parport/parport_amiga.c Mon Jun 19 13:42:38 2000 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -239,14 +240,19 @@ struct parport *p; if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_PARALLEL)) { + if (!request_mem_region(CIAA_PHYSADDR+0x100, 1, "parallel")) + return 0; ciaa.ddrb = 0xff; ciab.ddra &= 0xf8; if (!(p = parport_register_port((unsigned long)&ciaa.prb, IRQ_AMIGA_CIAA_FLG, PARPORT_DMA_NONE, - &pp_amiga_ops))) + &pp_amiga_ops))) { + release_mem_region(CIAA_PHYSADDR+0x100, 1); return 0; + } if (!request_irq(IRQ_AMIGA_CIAA_FLG, amiga_interrupt, 0, p->name, p)) { parport_unregister_port (p); + release_mem_region(CIAA_PHYSADDR+0x100, 1); return 0; } @@ -277,9 +283,10 @@ void cleanup_module(void) { if (this_port->irq != PARPORT_IRQ_NONE) - free_irq(IRQ_MFP_BUSY, this_port); + free_irq(IRQ_AMIGA_CIAA_FLG, this_port); parport_proc_unregister(this_port); parport_unregister_port(this_port); + release_mem_region(CIAA_PHYSADDR+0x100, 1); } #endif diff -u --recursive --new-file v2.4.0-test1/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c --- v2.4.0-test1/linux/drivers/parport/parport_pc.c Tue May 23 15:31:35 2000 +++ linux/drivers/parport/parport_pc.c Mon Jun 19 13:42:38 2000 @@ -2430,8 +2430,9 @@ def.) */ /* TODO: test if sharing interrupts works */ printk (KERN_DEBUG "PCI parallel port detected: %04x:%04x, " - "I/O at %#lx(%#lx)\n", parport_pc_pci_tbl[i].vendor, - parport_pc_pci_tbl[i].device, io_lo, io_hi); + "I/O at %#lx(%#lx)\n", + parport_pc_pci_tbl[i + last_sio].vendor, + parport_pc_pci_tbl[i + last_sio].device, io_lo, io_hi); if (parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, dev)) count++; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/parport/procfs.c linux/drivers/parport/procfs.c --- v2.4.0-test1/linux/drivers/parport/procfs.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/parport/procfs.c Mon Jun 19 13:42:38 2000 @@ -109,38 +109,106 @@ } #endif /* IEEE1284.3 support. */ -static int do_hardware(ctl_table *table, int write, struct file *filp, - void *result, size_t *lenp) +static int do_hardware_base_addr (ctl_table *table, int write, + struct file *filp, void *result, + size_t *lenp) { struct parport *port = (struct parport *)table->extra1; - char buffer[256]; + char buffer[20]; int len = 0; if (filp->f_pos) { *lenp = 0; return 0; } - - if (write) /* can't happen anyway */ + + if (write) /* permissions prevent this anyway */ return -EACCES; - - len += sprintf(buffer+len, "base:\t0x%lx", port->base); - if (port->base_hi) - len += sprintf(buffer+len, " (0x%lx)", port->base_hi); - buffer[len++] = '\n'; - if (port->irq == PARPORT_IRQ_NONE) { - len += sprintf(buffer+len, "irq:\tnone\n"); - } else { - len += sprintf(buffer+len, "irq:\t%d\n", port->irq); + len += sprintf (buffer, "%lu\t%lu\n", port->base, port->base_hi); + + if (len > *lenp) + len = *lenp; + else + *lenp = len; + + filp->f_pos += len; + + return copy_to_user(result, buffer, len) ? -EFAULT : 0; +} + +static int do_hardware_irq (ctl_table *table, int write, + struct file *filp, void *result, + size_t *lenp) +{ + struct parport *port = (struct parport *)table->extra1; + char buffer[20]; + int len = 0; + + if (filp->f_pos) { + *lenp = 0; + return 0; } - if (port->dma == PARPORT_DMA_NONE) - len += sprintf(buffer+len, "dma:\tnone\n"); + if (write) /* permissions prevent this anyway */ + return -EACCES; + + len += sprintf (buffer, "%d\n", port->irq); + + if (len > *lenp) + len = *lenp; else - len += sprintf(buffer+len, "dma:\t%d\n", port->dma); + *lenp = len; + + filp->f_pos += len; + + return copy_to_user(result, buffer, len) ? -EFAULT : 0; +} + +static int do_hardware_dma (ctl_table *table, int write, + struct file *filp, void *result, + size_t *lenp) +{ + struct parport *port = (struct parport *)table->extra1; + char buffer[20]; + int len = 0; + + if (filp->f_pos) { + *lenp = 0; + return 0; + } + + if (write) /* permissions prevent this anyway */ + return -EACCES; + + len += sprintf (buffer, "%d\n", port->dma); + + if (len > *lenp) + len = *lenp; + else + *lenp = len; + + filp->f_pos += len; + + return copy_to_user(result, buffer, len) ? -EFAULT : 0; +} + +static int do_hardware_modes (ctl_table *table, int write, + struct file *filp, void *result, + size_t *lenp) +{ + struct parport *port = (struct parport *)table->extra1; + char buffer[20]; + int len = 0; + + if (filp->f_pos) { + *lenp = 0; + return 0; + } + + if (write) /* permissions prevent this anyway */ + return -EACCES; - len += sprintf(buffer+len, "modes:\t"); { #define printmode(x) {if(port->modes&PARPORT_MODE_##x){len+=sprintf(buffer+len,"%s%s",f?",":"",#x);f++;}} int f = 0; @@ -186,7 +254,7 @@ struct parport_sysctl_table { struct ctl_table_header *sysctl_header; - ctl_table vars[9]; + ctl_table vars[12]; ctl_table device_dir[2]; ctl_table port_dir[2]; ctl_table parport_dir[2]; @@ -201,9 +269,18 @@ &proc_dointvec_minmax, NULL, NULL, (void*) &parport_min_spintime_value, (void*) &parport_max_spintime_value }, - { DEV_PARPORT_HARDWARE, "hardware", + { DEV_PARPORT_BASE_ADDR, "base-addr", + NULL, 0, 0444, NULL, + &do_hardware_base_addr }, + { DEV_PARPORT_IRQ, "irq", + NULL, 0, 0444, NULL, + &do_hardware_irq }, + { DEV_PARPORT_DMA, "dma", + NULL, 0, 0444, NULL, + &do_hardware_dma }, + { DEV_PARPORT_MODES, "modes", NULL, 0, 0444, NULL, - &do_hardware }, + &do_hardware_modes }, PARPORT_DEVICES_ROOT_DIR, #ifdef CONFIG_PARPORT_1284 { DEV_PARPORT_AUTOPROBE, "autoprobe", @@ -314,10 +391,10 @@ t->vars[i].extra1 = port; t->vars[0].data = &port->spintime; - t->vars[2].child = t->device_dir; + t->vars[5].child = t->device_dir; for (i = 0; i < 5; i++) - t->vars[3 + i].extra2 = &port->probe_info[i]; + t->vars[6 + i].extra2 = &port->probe_info[i]; t->port_dir[0].procname = port->name; t->port_dir[0].ctl_name = port->number + 1; /* nb 0 isn't legal here */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/parport/share.c linux/drivers/parport/share.c --- v2.4.0-test1/linux/drivers/parport/share.c Tue May 23 15:31:35 2000 +++ linux/drivers/parport/share.c Mon Jun 19 13:42:38 2000 @@ -87,12 +87,14 @@ { struct parport_driver *drv; + spin_lock (&driverlist_lock); for (drv = driver_chain; drv; drv = drv->next) { if (attach) drv->attach (port); else drv->detach (port); } + spin_unlock (&driverlist_lock); } /* Ask kmod for some lowlevel drivers. */ @@ -126,8 +128,12 @@ driver_chain = drv; spin_unlock (&driverlist_lock); + /* We have to take the portlist lock for this to be sure + * that port is valid for the duration of the callback. */ + spin_lock (&parportlist_lock); for (port = portlist; port; port = port->next) drv->attach (port); + spin_unlock (&parportlist_lock); if (!portlist) get_lowlevel_driver (); @@ -171,8 +177,10 @@ /* Call the driver's detach routine for each * port to clean up any resources that the * attach routine acquired. */ + spin_lock (&parportlist_lock); for (port = portlist; port; port = port->next) drv->detach (port); + spin_unlock (&parportlist_lock); return; } @@ -195,6 +203,8 @@ struct parport *parport_enumerate(void) { + /* Don't use this: use parport_register_driver instead. */ + if (!portlist) get_lowlevel_driver (); @@ -297,7 +307,18 @@ * This function must not run from an irq handler so we don' t need * to clear irq on the local CPU. -arca */ + spin_lock(&parportlist_lock); + + /* We are locked against anyone else performing alterations, but + * because of parport_enumerate people can still _read_ the list + * while we are changing it; so be careful.. + * + * It's okay to have portlist_tail a little bit out of sync + * since it's only used for changing the list, not for reading + * from it. + */ + if (portlist_tail) portlist_tail->next = tmp; portlist_tail = tmp; @@ -403,6 +424,10 @@ #endif spin_lock(&parportlist_lock); + + /* We are protected from other people changing the list, but + * they can see see it (using parport_enumerate). So be + * careful about the order of writes.. */ if (portlist == port) { if ((portlist = port->next) == NULL) portlist_tail = NULL; @@ -418,6 +443,7 @@ } spin_unlock(&parportlist_lock); + /* Yes, parport_enumerate _is_ unsafe. Don't use it. */ if (!port->devices) free_port (port); } @@ -565,6 +591,9 @@ } tmp->next = port->physport->devices; + wmb(); /* Make sure that tmp->next is written before it's + added to the list; see comments marked 'no locking + required' */ if (port->physport->devices) port->physport->devices->prev = tmp; port->physport->devices = tmp; @@ -647,6 +676,11 @@ * free up the resources. */ if (port->ops == &dead_ops && !port->devices) free_port (port); + + /* Yes, that's right, someone _could_ still have a pointer to + * port, if they used parport_enumerate. That's why they + * shouldn't use it (and use parport_register_driver instead).. + */ } /** @@ -702,7 +736,7 @@ dev->waiting = 0; /* Take ourselves out of the wait list again. */ - spin_lock_irqsave (&port->waitlist_lock, flags); + spin_lock_irq (&port->waitlist_lock); if (dev->waitprev) dev->waitprev->waitnext = dev->waitnext; else @@ -711,7 +745,7 @@ dev->waitnext->waitprev = dev->waitprev; else port->waittail = dev->waitprev; - spin_unlock_irqrestore (&port->waitlist_lock, flags); + spin_unlock_irq (&port->waitlist_lock); dev->waitprev = dev->waitnext = NULL; } @@ -878,7 +912,7 @@ } /* Nobody was waiting, so walk the list to see if anyone is - interested in being woken up. */ + interested in being woken up. (Note: no locking required) */ for (pd = port->devices; (port->cad == NULL) && pd; pd = pd->next) { if (pd->wakeup && pd != dev) pd->wakeup(pd->private); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/pci/pci.c linux/drivers/pci/pci.c --- v2.4.0-test1/linux/drivers/pci/pci.c Thu May 11 15:30:07 2000 +++ linux/drivers/pci/pci.c Mon Jun 19 13:42:38 2000 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include diff -u --recursive --new-file v2.4.0-test1/linux/drivers/pci/pci.ids linux/drivers/pci/pci.ids --- v2.4.0-test1/linux/drivers/pci/pci.ids Mon Jun 19 16:31:59 2000 +++ linux/drivers/pci/pci.ids Mon Jun 19 13:42:38 2000 @@ -238,11 +238,12 @@ 100a Phoenix Technologies 100b National Semiconductor Corporation 0001 DP83810 - 0002 87415 + 0002 87415/87560 IDE + 000e 87560 Legacy I/O 000f OHCI Compliant FireWire Controller 0011 National PCI System I/O 0012 USB Controller - d001 87410 + d001 87410 IDE 100c Tseng Labs Inc 3202 ET4000/W32p rev A 3205 ET4000/W32p rev B @@ -976,6 +977,7 @@ 1058 Electronics & Telecommunications RSH 1059 Teknor Industrial Computers Inc 105a Promise Technology, Inc. + 4d30 20267 4d33 20246 4d38 20262 5300 DC5300 @@ -1228,6 +1230,7 @@ 0646 PCI0646 0647 PCI0647 0648 PCI0648 + 0649 PCI0649 0650 PBC0650A 0670 USB0670 0673 USB0673 @@ -1458,6 +1461,8 @@ 5055 3c555 Laptop Hurricane 5057 3c575 [Megahertz] 10/100 LAN CardBus 10b7 5a57 3C575 Megahertz 10/100 LAN Cardbus PC Card + 5b57 3c575 [Megahertz] 10/100 LAN CardBus + 10b7 5a57 3C575 Megahertz 10/100 LAN Cardbus 5157 3c575 [Megahertz] 10/100 LAN CardBus 10b7 5b57 3C575 Megahertz 10/100 LAN Cardbus PC Card 5257 3CCFE575CT Cyclone CardBus @@ -1469,6 +1474,7 @@ 5970 3c597 EISA Fast Demon/Vortex 6560 3CCFE656 Cyclone CardBus 6562 3CCFEM656 Cyclone CardBus + 6564 3CCFEM656 Cyclone CardBus (0x6564) 7646 3cSOHO100-TX Hurricane 8811 Token ring 9000 3c900 10BaseT [Boomerang] @@ -1509,6 +1515,8 @@ 10b7 1000 3C905C-TX Fast Etherlink for PC Management NIC 9800 3c980-TX [Fast Etherlink XL Server Adapter] 10b7 9800 3c980-TX Fast Etherlink XL Server Adapter + 9805 3c980-TX [10/100 Base-TX NIC(Python-T)] + 10b7 9805 3c980 10/100 Base-TX NIC(Python-T) 10b8 Standard Microsystems Corp [SMC] 0005 83C170QF 1055 e000 LANEPIC @@ -4517,6 +4525,13 @@ 11d4 0048 SoundMAX Integrated Digital Audio 2426 82801AB 82810 AC'97 Modem 2428 82801AB 82810 PCI Bridge + 2440 82820 820 (Camino 2) Chipset ISA Bridge (ICH2) + 2442 82820 820 (Camino 2) Chipset USB (Hub A) + 2443 82820 820 (Camino 2) Chipset SMBus + 2444 82820 820 (Camino 2) Chipset USB (Hub B) + 2449 82820 820 (Camino 2) Chipset Ethernet + 244b 82820 820 (Camino 2) Chipset IDE U100 + 244e 82820 820 (Camino 2) Chipset PCI 2500 82820 820 (Camino) Chipset Host Bridge (MCH) 1043 801c P3C-2000 system chipset 2501 82820 820 (Camino) Chipset Host Bridge (MCH) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/pci/quirks.c linux/drivers/pci/quirks.c --- v2.4.0-test1/linux/drivers/pci/quirks.c Thu May 11 15:30:07 2000 +++ linux/drivers/pci/quirks.c Mon Jun 19 13:42:39 2000 @@ -138,7 +138,7 @@ * 0xE0 (64 bytes of ACPI registers) * 0xE2 (32 bytes of SMB registers) */ -static void __init quirk_ali7101(struct pci_dev *dev) +static void __init quirk_ali7101_acpi(struct pci_dev *dev) { u16 region; @@ -153,7 +153,7 @@ * 0x40 (64 bytes of ACPI registers) * 0x90 (32 bytes of SMB registers) */ -static void __init quirk_piix4acpi(struct pci_dev *dev) +static void __init quirk_piix4_acpi(struct pci_dev *dev) { u32 region; @@ -167,7 +167,7 @@ * VIA ACPI: One IO region pointed to by longword at * 0x48 or 0x20 (256 bytes of ACPI registers) */ -static void __init quirk_via_acpi(struct pci_dev *dev) +static void __init quirk_vt82c586_acpi(struct pci_dev *dev) { u8 rev; u32 region; @@ -181,6 +181,48 @@ } /* + * VIA VT82C686 ACPI: Three IO region pointed to by (long)words at + * 0x48 (256 bytes of ACPI registers) + * 0x70 (128 bytes of hardware monitoring register) + * 0x90 (16 bytes of SMB registers) + */ +static void __init quirk_vt82c686_acpi(struct pci_dev *dev) +{ + u16 hm; + u32 smb; + + quirk_vt82c586_acpi(dev); + + pci_read_config_word(dev, 0x70, &hm); + hm &= PCI_BASE_ADDRESS_IO_MASK; + quirk_io_region(dev, hm, 128, PCI_BRIDGE_RESOURCES + 1); + + pci_read_config_dword(dev, 0x90, &smb); + smb &= PCI_BASE_ADDRESS_IO_MASK; + quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 2); +} + +/* + * PIIX3 USB: We have to disable USB interrupts that are + * hardwired to PIRQD# and may be shared with an + * external device. + * + * Legacy Support Register (LEGSUP): + * bit13: USB PIRQ Enable (USBPIRQDEN), + * bit4: Trap/SMI ON IRQ Enable (USBSMIEN). + * + * We mask out all r/wc bits, too. + */ +static void __init quirk_piix3usb(struct pci_dev *dev) +{ + u16 legsup; + + pci_read_config_word(dev, 0xc0, &legsup); + legsup &= 0x50ef; + pci_write_config_word(dev, 0xc0, legsup); +} + +/* * The main table of quirks. */ @@ -209,10 +251,11 @@ { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2, quirk_natoma }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_acpi }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_acpi }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, quirk_piix4acpi }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, quirk_ali7101 }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_vt82c586_acpi }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vt82c686_acpi }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, quirk_piix4_acpi }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, quirk_ali7101_acpi }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_2, quirk_piix3usb }, { 0 } }; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/pci/setup-res.c linux/drivers/pci/setup-res.c --- v2.4.0-test1/linux/drivers/pci/setup-res.c Tue Apr 11 15:09:18 2000 +++ linux/drivers/pci/setup-res.c Tue Jun 20 14:14:51 2000 @@ -77,6 +77,10 @@ pcibios_align_resource, dev) < 0) { printk(KERN_ERR "PCI: Failed to allocate resource %d for %s\n", i, dev->name); + printk(KERN_ERR " failed root[%lx:%lx] min[%lx] size[%lx]\n", + root->start, root->end, min, size); + printk(KERN_ERR " failed res[%lx:%lx]\n", + res->start, res->end); return -EBUSY; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/pcmcia/yenta.c linux/drivers/pcmcia/yenta.c --- v2.4.0-test1/linux/drivers/pcmcia/yenta.c Tue May 23 15:31:35 2000 +++ linux/drivers/pcmcia/yenta.c Wed Jun 21 15:39:14 2000 @@ -127,6 +127,8 @@ val = (state & CB_3VCARD) ? SS_3VCARD : 0; val |= (state & CB_XVCARD) ? SS_XVCARD : 0; + val |= (state & (CB_CDETECT1 | CB_CDETECT2 | CB_5VCARD | CB_3VCARD + | CB_XVCARD | CB_YVCARD)) ? 0 : SS_PENDING; if (state & CB_CBCARD) { val |= SS_CARDBUS; @@ -556,30 +558,6 @@ } } -/* - * Many chipsets (all TI chips?) seem to have - * problems sensing the power state of the card - * that was inserted at chip init time, so force - * it if necessary.. - */ -static void yenta_power_sense(pci_socket_t *socket) -{ - u32 status = cb_readl(socket, CB_SOCKET_STATE); - - /* - * Nothing inserted, nothing to sense.. - * ..or sense status already available. - */ - if (status & (CB_CDETECT1 | CB_CDETECT2 | CB_5VCARD | CB_3VCARD | CB_XVCARD | CB_YVCARD)) - return; - - /* - * Ho humm. It reports a card, but it doesn't report - * any voltages. Need to redo the VS test.. - */ - cb_writel(socket, CB_SOCKET_FORCE, CB_CVSTEST); -} - /* Called at resume and initialization events */ static int yenta_init(pci_socket_t *socket) { @@ -620,7 +598,8 @@ exca_writeb(socket, I365_GBLCTL, 0x00); exca_writeb(socket, I365_GENCTL, 0x00); - yenta_power_sense(socket); + /* Redo card voltage interrogation */ + cb_writel(socket, CB_SOCKET_FORCE, CB_CVSTEST); yenta_clear_maps(socket); return 0; @@ -788,7 +767,7 @@ */ if (pci_enable_device(dev)) return -1; - if (!dev->resource[0].start) { + if (!pci_resource_start(dev, 0)) { printk("No cardbus resource!\n"); return -1; } @@ -797,7 +776,7 @@ * Ok, start setup.. Map the cardbus registers, * and request the IRQ. */ - socket->base = ioremap(dev->resource[0].start, 0x1000); + socket->base = ioremap(pci_resource_start(dev, 0), 0x1000); if (!socket->base) return -1; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/pnp/isapnp.c linux/drivers/pnp/isapnp.c --- v2.4.0-test1/linux/drivers/pnp/isapnp.c Mon Mar 27 08:08:27 2000 +++ linux/drivers/pnp/isapnp.c Thu Jun 22 07:17:16 2000 @@ -500,6 +500,7 @@ int dependent, int size) { unsigned char tmp[3]; + int i; struct isapnp_irq *irq, *ptr; isapnp_peek(tmp, size); @@ -526,6 +527,9 @@ ptr->next = irq; else (*res)->irq = irq; + for (i=0; i<16; i++) + if (irq->map & i) + pcibios_penalize_isa_irq(i); } /* @@ -1603,6 +1607,14 @@ return 1; } } +#ifdef CONFIG_PCI + if (!isapnp_skip_pci_scan) { + pci_for_each_dev(dev) { + if (dev->irq == irq) + return 1; + } + } +#endif if (request_irq(irq, isapnp_test_handler, SA_INTERRUPT, "isapnp", NULL)) return 1; free_irq(irq, NULL); @@ -2059,56 +2071,17 @@ if (isapnp_rdp >= 0x203 && isapnp_rdp <= 0x3ff) release_resource(isapnp_rdp_res); #ifdef MODULE +#ifdef CONFIG_PROC_FS + isapnp_proc_done(); +#endif while (!list_empty(&isapnp_cards)) { struct list_head *list = isapnp_cards.next; list_del(list); isapnp_free_card(pci_bus_b(list)); } -#ifdef CONFIG_PROC_FS - isapnp_proc_done(); -#endif -#endif -} - -static int __init isapnp_do_reserve_irq(int irq) -{ - int i; - - if (irq < 0 || irq > 15) - return -EINVAL; - for (i = 0; i < 16; i++) { - if (isapnp_reserve_irq[i] == irq) - return 0; - } - for (i = 0; i < 16; i++) { - if (isapnp_reserve_irq[i] < 0) { - isapnp_reserve_irq[i] = irq; -#ifdef ISAPNP_DEBUG - printk("isapnp: IRQ %i is reserved now.\n", irq); -#endif - return 0; - } - } - return -ENOMEM; -} - -#ifdef CONFIG_PCI - -static void __init isapnp_pci_init(void) -{ - struct pci_dev *dev; - - pci_for_each_dev(dev) { -#ifdef ISAPNP_DEBUG - printk("isapnp: PCI: reserved IRQ: %i\n", dev->irq); #endif - if (dev->irq > 0) - isapnp_do_reserve_irq(dev->irq); - } } -#endif /* CONFIG_PCI */ - EXPORT_SYMBOL(isapnp_cards); EXPORT_SYMBOL(isapnp_devices); EXPORT_SYMBOL(isapnp_present); @@ -2200,10 +2173,6 @@ } else { printk("isapnp: No Plug & Play card found\n"); } -#ifdef CONFIG_PCI - if (!isapnp_skip_pci_scan) - isapnp_pci_init(); -#endif #ifdef CONFIG_PROC_FS isapnp_proc_init(); #endif diff -u --recursive --new-file v2.4.0-test1/linux/drivers/s390/block/dasd.c linux/drivers/s390/block/dasd.c --- v2.4.0-test1/linux/drivers/s390/block/dasd.c Fri May 12 14:18:55 2000 +++ linux/drivers/s390/block/dasd.c Wed Jun 21 22:31:02 2000 @@ -792,11 +792,10 @@ dasd_info[di]->info.devno,'\0' ); dasd_info[di] -> devfs_entry = devfs_register ( NULL /* dir */, - name, strlen(name), - 0 /* flags */, + name, + DEVFS_FL_DEFAULT /* flags */, DASD_MAJOR, minor, 0755 /* mode */, - 0 /* uid */ , 0 /* gid */, &dasd_device_operations, (void *)dasd_info[di]); } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sbus/audio/audio.c linux/drivers/sbus/audio/audio.c --- v2.4.0-test1/linux/drivers/sbus/audio/audio.c Tue Mar 14 19:10:40 2000 +++ linux/drivers/sbus/audio/audio.c Thu Jun 22 07:21:12 2000 @@ -1,4 +1,4 @@ -/* $Id: audio.c,v 1.50 2000/03/13 03:54:07 davem Exp $ +/* $Id: audio.c,v 1.52 2000/06/22 11:42:27 davem Exp $ * drivers/sbus/audio/audio.c * * Copyright 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu) @@ -87,8 +87,6 @@ #include #define COPY_IN(arg, get) get_user(get, (int *)arg) #define COPY_OUT(arg, ret) put_user(ret, (int *)arg) -#define sparcaudio_release_ret sparcaudio_release -#define sparcaudioctl_release_ret sparcaudioctl_release #define sparcaudio_select sparcaudio_poll #endif @@ -1767,24 +1765,10 @@ return retval; } -static int sparcaudioctl_release_ret(struct inode * inode, struct file * file) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -/* For 2.0 kernels */ -#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100 -static void sparcaudioctl_release(struct inode * inode, struct file * file) -{ - sparcaudioctl_release_ret(inode, file); -} -#endif - static struct file_operations sparcaudioctl_fops = { + owner: THIS_MODULE, poll: sparcaudio_select, ioctl: sparcaudio_ioctl, - release: sparcaudioctl_release, }; static int sparcaudio_open(struct inode * inode, struct file * file) @@ -1917,13 +1901,11 @@ } } - MOD_INC_USE_COUNT; - /* Success! */ return 0; } -static int sparcaudio_release_ret(struct inode * inode, struct file * file) +static int sparcaudio_release(struct inode * inode, struct file * file) { struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >> SPARCAUDIO_DEVICE_SHIFT)]; @@ -1968,21 +1950,11 @@ /* Status changed. Signal control device */ kill_procs(drv->sd_siglist,SIGPOLL,S_MSG); - MOD_DEC_USE_COUNT; - wake_up_interruptible(&drv->open_wait); return 0; } -/* For 2.0 kernels */ -#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100 -static void sparcaudio_release(struct inode * inode, struct file * file) -{ - sparcaudio_release_ret(inode, file); -} -#endif - static struct file_operations sparcaudio_fops = { llseek: sparcaudio_lseek, read: sparcaudio_read, @@ -2038,9 +2010,9 @@ for (i=0; i < sizeof (dev_list) / sizeof (*dev_list); i++) { sparcaudio_mkname (name_buf, dev_list[i].name, dev); minor = (dev << SPARCAUDIO_DEVICE_SHIFT) | dev_list[i].minor; - devfs_register (devfs_handle, name_buf, 0, DEVFS_FL_NONE, + devfs_register (devfs_handle, name_buf, DEVFS_FL_NONE, SOUND_MAJOR, minor, S_IFCHR | dev_list[i].mode, - 0, 0, &sparcaudio_fops, NULL); + &sparcaudio_fops, NULL); } /* Setup the circular queues of output and input buffers diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sbus/char/bpp.c linux/drivers/sbus/char/bpp.c --- v2.4.0-test1/linux/drivers/sbus/char/bpp.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/sbus/char/bpp.c Wed Jun 21 22:31:02 2000 @@ -835,6 +835,7 @@ } static struct file_operations bpp_fops = { + owner: THIS_MODULE, read: bpp_read, write: bpp_write, ioctl: bpp_ioctl, @@ -1030,7 +1031,7 @@ } devfs_handle = devfs_mk_dir (NULL, "bpp", 3, NULL); devfs_register_series (devfs_handle, "%u", BPP_NO, DEVFS_FL_DEFAULT, - BPP_MAJOR, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + BPP_MAJOR, 0, S_IFCHR | S_IRUSR | S_IWUSR, &bpp_fops, NULL); return 0; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sbus/char/envctrl.c linux/drivers/sbus/char/envctrl.c --- v2.4.0-test1/linux/drivers/sbus/char/envctrl.c Mon Mar 27 08:08:27 2000 +++ linux/drivers/sbus/char/envctrl.c Mon Jun 19 17:59:41 2000 @@ -1,4 +1,4 @@ -/* $Id: envctrl.c,v 1.16 2000/03/22 21:29:23 ecd Exp $ +/* $Id: envctrl.c,v 1.17 2000/06/19 06:24:47 davem Exp $ * envctrl.c: Temperature and Fan monitoring on Machines providing it. * * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) @@ -1507,24 +1507,16 @@ envctrl_open(struct inode *inode, struct file *file) { file->private_data = 0; - MOD_INC_USE_COUNT; - return 0; -} - -static int -envctrl_release(struct inode *inode, struct file *file) -{ - MOD_DEC_USE_COUNT; return 0; } static struct file_operations envctrl_fops = { + owner: THIS_MODULE, llseek: envctrl_llseek, read: envctrl_read, write: envctrl_write, ioctl: envctrl_ioctl, open: envctrl_open, - release: envctrl_release, }; static struct miscdevice envctrl_dev = { diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sbus/char/flash.c linux/drivers/sbus/char/flash.c --- v2.4.0-test1/linux/drivers/sbus/char/flash.c Thu Feb 10 17:11:12 2000 +++ linux/drivers/sbus/char/flash.c Mon Jun 19 17:59:41 2000 @@ -1,4 +1,4 @@ -/* $Id: flash.c,v 1.17 2000/02/10 02:51:35 davem Exp $ +/* $Id: flash.c,v 1.18 2000/06/19 06:24:47 davem Exp $ * flash.c: Allow mmap access to the OBP Flash, for OBP updates. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -115,14 +115,12 @@ if (test_and_set_bit(0, (void *)&flash.busy) != 0) return -EBUSY; - MOD_INC_USE_COUNT; return 0; } static int flash_release(struct inode *inode, struct file *file) { - MOD_DEC_USE_COUNT; flash.busy = 0; return 0; } @@ -131,6 +129,7 @@ /* no write to the Flash, use mmap * and play flash dependent tricks. */ + owner: THIS_MODULE, llseek: flash_llseek, read: flash_read, mmap: flash_mmap, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sbus/char/jsflash.c linux/drivers/sbus/char/jsflash.c --- v2.4.0-test1/linux/drivers/sbus/char/jsflash.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/sbus/char/jsflash.c Thu Jun 22 07:21:12 2000 @@ -271,7 +271,7 @@ } /* - * P3: OS SIMM Cannot be read in other size but a 32bits word. + * OS SIMM Cannot be read in other size but a 32bits word. */ static ssize_t jsf_read(struct file * file, char * buf, size_t togo, loff_t *ppos) @@ -479,7 +479,6 @@ if (test_and_set_bit(0, (void *)&jsf0.busy) != 0) return -EBUSY; - MOD_INC_USE_COUNT; return 0; /* XXX What security? */ } @@ -505,9 +504,6 @@ static int jsf_release(struct inode *inode, struct file *file) { - - MOD_DEC_USE_COUNT; - jsf0.busy = 0; return 0; } @@ -537,6 +533,7 @@ } static struct file_operations jsf_fops = { + owner: THIS_MODULE, llseek: jsf_lseek, read: jsf_read, write: jsf_write, @@ -650,8 +647,7 @@ int i; if (jsf0.base == 0) { - printk("jsfd_init: no flash\n"); /* P3 */ - return -EIO; + return -ENXIO; } if (register_blkdev(JSFD_MAJOR, "jsfd", &jsfd_fops)) { @@ -659,8 +655,6 @@ JSFD_MAJOR); return -EIO; } - - printk("jsfd0: at major %d\n", MAJOR_NR); /* P3 */ blksize_size[JSFD_MAJOR] = jsfd_blksizes; blk_size[JSFD_MAJOR] = jsfd_sizes; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sbus/char/openprom.c linux/drivers/sbus/char/openprom.c --- v2.4.0-test1/linux/drivers/sbus/char/openprom.c Thu Feb 10 17:11:12 2000 +++ linux/drivers/sbus/char/openprom.c Mon Jun 19 17:59:41 2000 @@ -595,19 +595,17 @@ data->lastnode = prom_root_node; file->private_data = (void *)data; - MOD_INC_USE_COUNT; - return 0; } static int openprom_release(struct inode * inode, struct file * file) { kfree_s(file->private_data, sizeof(DATA)); - MOD_DEC_USE_COUNT; return 0; } static struct file_operations openprom_fops = { + owner: THIS_MODULE, llseek: openprom_lseek, ioctl: openprom_ioctl, open: openprom_open, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sbus/char/pcikbd.c linux/drivers/sbus/char/pcikbd.c --- v2.4.0-test1/linux/drivers/sbus/char/pcikbd.c Thu May 11 15:30:07 2000 +++ linux/drivers/sbus/char/pcikbd.c Mon Jun 19 17:59:41 2000 @@ -1,4 +1,4 @@ -/* $Id: pcikbd.c,v 1.46 2000/05/03 06:37:05 davem Exp $ +/* $Id: pcikbd.c,v 1.48 2000/06/19 06:24:47 davem Exp $ * pcikbd.c: Ultra/AX PC keyboard support. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -737,8 +737,7 @@ spin_unlock_irqrestore(&pcikbd_lock, flags); - if (queue->fasync) - kill_fasync(queue->fasync, SIGIO, POLL_IN); + kill_fasync(&queue->fasync, SIGIO, POLL_IN); wake_up_interruptible(&queue->proc_list); } @@ -762,7 +761,6 @@ spin_unlock_irqrestore(&pcikbd_lock, flags); - MOD_DEC_USE_COUNT; return 0; } @@ -790,8 +788,6 @@ } queue->head = queue->tail = 0; /* Flush input queue */ - MOD_INC_USE_COUNT; - poll_aux_status(); pcimouse_outb(KBD_CCMD_MOUSE_ENABLE, pcimouse_iobase+KBD_CNTL_REG); /* Enable Aux */ aux_write_dev(AUX_ENABLE_DEV); /* Enable aux device */ @@ -902,6 +898,7 @@ } struct file_operations psaux_fops = { + owner: THIS_MODULE, read: aux_read, write: aux_write, poll: aux_poll, @@ -916,6 +913,7 @@ } struct file_operations psaux_no_fops = { + owner: THIS_MODULE, open: aux_no_open, }; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sbus/char/rtc.c linux/drivers/sbus/char/rtc.c --- v2.4.0-test1/linux/drivers/sbus/char/rtc.c Thu Feb 10 17:11:12 2000 +++ linux/drivers/sbus/char/rtc.c Mon Jun 19 17:59:41 2000 @@ -1,4 +1,4 @@ -/* $Id: rtc.c,v 1.19 2000/02/09 22:33:26 davem Exp $ +/* $Id: rtc.c,v 1.20 2000/06/19 06:24:47 davem Exp $ * * Linux/SPARC Real Time Clock Driver * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) @@ -124,19 +124,17 @@ rtc_busy = 1; - MOD_INC_USE_COUNT; - return 0; } static int rtc_release(struct inode *inode, struct file *file) { - MOD_DEC_USE_COUNT; rtc_busy = 0; return 0; } static struct file_operations rtc_fops = { + owner: THIS_MODULE, llseek: rtc_lseek, ioctl: rtc_ioctl, open: rtc_open, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sbus/char/sunkbd.c linux/drivers/sbus/char/sunkbd.c --- v2.4.0-test1/linux/drivers/sbus/char/sunkbd.c Thu May 11 15:30:07 2000 +++ linux/drivers/sbus/char/sunkbd.c Wed Jun 21 22:31:02 2000 @@ -1310,8 +1310,7 @@ } spin_unlock_irqrestore(&kbd_queue_lock, flags); - if (kb_fasync) - kill_fasync (kb_fasync, SIGIO, POLL_IN); + kill_fasync (&kb_fasync, SIGIO, POLL_IN); wake_up_interruptible (&kbd_wait); } @@ -1606,9 +1605,9 @@ spin_unlock_irq(&sunkbd_lock); /* Register the /dev/kbd interface */ - devfs_register (NULL, "kbd", 0, DEVFS_FL_NONE, + devfs_register (NULL, "kbd", DEVFS_FL_DEFAULT, KBD_MAJOR, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, &kbd_fops, NULL); if (devfs_register_chrdev (KBD_MAJOR, "kbd", &kbd_fops)){ printk ("Could not register /dev/kbd device\n"); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sbus/char/sunmouse.c linux/drivers/sbus/char/sunmouse.c --- v2.4.0-test1/linux/drivers/sbus/char/sunmouse.c Thu May 11 15:30:07 2000 +++ linux/drivers/sbus/char/sunmouse.c Mon Jun 19 17:59:41 2000 @@ -147,8 +147,7 @@ spin_unlock_irqrestore(&sunmouse.lock, flags); - if (sunmouse.fasync) - kill_fasync (sunmouse.fasync, SIGIO, POLL_IN); + kill_fasync (&sunmouse.fasync, SIGIO, POLL_IN); wake_up_interruptible (&sunmouse.proc_list); } @@ -382,8 +381,7 @@ /* We just completed a transaction, wake up whoever is awaiting * this event. */ - if (sunmouse.fasync) - kill_fasync (sunmouse.fasync, SIGIO, POLL_IN); + kill_fasync (&sunmouse.fasync, SIGIO, POLL_IN); wake_up_interruptible(&sunmouse.proc_list); } return; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sbus/char/uctrl.c linux/drivers/sbus/char/uctrl.c --- v2.4.0-test1/linux/drivers/sbus/char/uctrl.c Thu Feb 10 17:11:12 2000 +++ linux/drivers/sbus/char/uctrl.c Mon Jun 19 17:59:41 2000 @@ -1,4 +1,4 @@ -/* $Id: uctrl.c,v 1.7 2000/02/09 22:33:28 davem Exp $ +/* $Id: uctrl.c,v 1.8 2000/06/19 06:24:47 davem Exp $ * uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3 * * Copyright 1999 Derrick J Brashear (shadow@dementia.org) @@ -218,19 +218,11 @@ static int uctrl_open(struct inode *inode, struct file *file) { - MOD_INC_USE_COUNT; uctrl_get_event_status(); uctrl_get_external_status(); return 0; } -static int -uctrl_release(struct inode *inode, struct file *file) -{ - MOD_DEC_USE_COUNT; - return 0; -} - void uctrl_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct uctrl_driver *driver = (struct uctrl_driver *)dev_id; @@ -238,10 +230,10 @@ } static struct file_operations uctrl_fops = { + owner: THIS_MODULE, llseek: uctrl_llseek, ioctl: uctrl_ioctl, open: uctrl_open, - release: uctrl_release, }; static struct miscdevice uctrl_dev = { diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sbus/char/vfc_dev.c linux/drivers/sbus/char/vfc_dev.c --- v2.4.0-test1/linux/drivers/sbus/char/vfc_dev.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/sbus/char/vfc_dev.c Wed Jun 21 22:31:02 2000 @@ -166,9 +166,9 @@ return -EIO; sprintf (devname, "%d", instance); - dev->de = devfs_register (devfs_handle, devname, 0, DEVFS_FL_DEFAULT, + dev->de = devfs_register (devfs_handle, devname, DEVFS_FL_DEFAULT, VFC_MAJOR, instance, - S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR, &vfc_fops, NULL); return 0; } @@ -190,7 +190,6 @@ return -EBUSY; dev->busy = 1; - MOD_INC_USE_COUNT; vfc_lock_device(dev); vfc_csr_init(dev); @@ -214,7 +213,6 @@ if (!dev->busy) return; dev->busy = 0; - MOD_DEC_USE_COUNT; } static int vfc_debug(struct vfc_dev *dev, int cmd, unsigned long arg) @@ -635,6 +633,7 @@ } static struct file_operations vfc_fops = { + owner: THIS_MODULE, llseek: vfc_lseek, ioctl: vfc_ioctl, mmap: vfc_mmap, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/3w-xxxx.c linux/drivers/scsi/3w-xxxx.c --- v2.4.0-test1/linux/drivers/scsi/3w-xxxx.c Fri Mar 10 16:40:43 2000 +++ linux/drivers/scsi/3w-xxxx.c Mon Jun 19 17:59:40 2000 @@ -565,6 +565,8 @@ dprintk(KERN_NOTICE "3w-xxxx: tw_findcards()\n"); while ((tw_pci_dev = pci_find_device(TW_VENDOR_ID, TW_DEVICE_ID, tw_pci_dev))) { + if (pci_enable_device(tw_pci_dev)) + continue; /* Prepare temporary device extension */ tw_dev=(TW_Device_Extension *)kmalloc(sizeof(TW_Device_Extension), GFP_ATOMIC); if (tw_dev == NULL) { @@ -582,11 +584,11 @@ } /* Calculate the cards register addresses */ - tw_dev->registers.base_addr = tw_pci_dev->resource[0].start; - tw_dev->registers.control_reg_addr = (tw_pci_dev->resource[0].start & ~15); - tw_dev->registers.status_reg_addr = ((tw_pci_dev->resource[0].start & ~15) + 0x4); - tw_dev->registers.command_que_addr = ((tw_pci_dev->resource[0].start & ~15) + 0x8); - tw_dev->registers.response_que_addr = ((tw_pci_dev->resource[0].start & ~15) + 0xC); + tw_dev->registers.base_addr = pci_resource_start(tw_pci_dev, 0); + tw_dev->registers.control_reg_addr = pci_resource_start(tw_pci_dev, 0); + tw_dev->registers.status_reg_addr = pci_resource_start(tw_pci_dev, 0) + 0x4; + tw_dev->registers.command_que_addr = pci_resource_start(tw_pci_dev, 0) + 0x8; + tw_dev->registers.response_que_addr = pci_resource_start(tw_pci_dev, 0) + 0xC; /* Save pci_dev struct to device extension */ tw_dev->tw_pci_dev = tw_pci_dev; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/53c7,8xx.c linux/drivers/scsi/53c7,8xx.c --- v2.4.0-test1/linux/drivers/scsi/53c7,8xx.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/scsi/53c7,8xx.c Mon Jun 19 17:59:41 2000 @@ -1412,8 +1412,10 @@ " perhaps you specified an incorrect PCI bus, device, or function.\n", error); return -1; } - io_port = pdev->resource[0].start; - base = pdev->resource[1].start; + if (pci_enable_device(pdev)) + return -1; + io_port = pci_resource_start(pdev, 0); + base = pci_resource_start(pdev, 1); irq = pdev->irq; /* If any one ever clones the NCR chips, this will have to change */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/AM53C974.c linux/drivers/scsi/AM53C974.c --- v2.4.0-test1/linux/drivers/scsi/AM53C974.c Tue Nov 23 22:42:21 1999 +++ linux/drivers/scsi/AM53C974.c Mon Jun 19 17:59:41 2000 @@ -616,27 +616,23 @@ * * Returns : number of host adapters detected **************************************************************************/ -static __inline__ int AM53C974_pci_detect(Scsi_Host_Template * tpnt) +static inline int AM53C974_pci_detect(Scsi_Host_Template * tpnt) { int count = 0; /* number of boards detected */ struct pci_dev *pdev = NULL; unsigned short command; while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_SCSI, pdev))) { + if (pci_enable_device(pdev)) + continue; pci_read_config_word(pdev, PCI_COMMAND, &command); /* check whether device is I/O mapped -- should be */ if (!(command & PCI_COMMAND_IO)) continue; - /* PCI Spec 2.1 states that it is either the driver's or the PCI card's responsibility - to set the PCI Master Enable Bit if needed. - (from Mark Stockton ) */ - if (!(command & PCI_COMMAND_MASTER)) { - command |= PCI_COMMAND_MASTER; - printk("PCI Master Bit has not been set. Setting...\n"); - pci_write_config_word(pdev, PCI_COMMAND, command); - } + pci_set_master (pdev); + /* everything seems OK now, so initialize */ if (AM53C974_init(tpnt, pdev)) count++; @@ -696,7 +692,7 @@ instance = scsi_register(tpnt, sizeof(struct AM53C974_hostdata)); hostdata = (struct AM53C974_hostdata *) instance->hostdata; instance->base = 0; - instance->io_port = pdev->resource[0].start; + instance->io_port = pci_resource_start(pdev, 0); instance->irq = pdev->irq; instance->dma_channel = -1; AM53C974_setio(instance); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/BusLogic.c linux/drivers/scsi/BusLogic.c --- v2.4.0-test1/linux/drivers/scsi/BusLogic.c Tue May 23 15:31:35 2000 +++ linux/drivers/scsi/BusLogic.c Mon Jun 19 17:59:41 2000 @@ -771,12 +771,15 @@ unsigned char Bus = PCI_Device->bus->number; unsigned char Device = PCI_Device->devfn >> 3; unsigned int IRQ_Channel = PCI_Device->irq; - unsigned long BaseAddress0 = PCI_Device->resource[0].start; - unsigned long BaseAddress1 = PCI_Device->resource[1].start; + unsigned long BaseAddress0 = pci_resource_start(PCI_Device, 0); + unsigned long BaseAddress1 = pci_resource_start(PCI_Device, 1); BusLogic_IO_Address_T IO_Address = BaseAddress0; BusLogic_PCI_Address_T PCI_Address = BaseAddress1; + + if (pci_enable_device(PCI_Device)) + continue; - if (!(PCI_Device->resource[0].flags & PCI_BASE_ADDRESS_SPACE_IO)) + if (pci_resource_flags(PCI_Device, 0) & IORESOURCE_MEM) { BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for " "MultiMaster Host Adapter\n", NULL, BaseAddress0); @@ -784,7 +787,7 @@ NULL, Bus, Device, IO_Address); continue; } - if (PCI_Device->resource[1].flags & PCI_BASE_ADDRESS_SPACE_IO) + if (pci_resource_flags(PCI_Device,1) & IORESOURCE_IO) { BusLogic_Error("BusLogic: Base Address1 0x%X not Memory for " "MultiMaster Host Adapter\n", NULL, BaseAddress1); @@ -973,7 +976,10 @@ unsigned char Bus = PCI_Device->bus->number; unsigned char Device = PCI_Device->devfn >> 3; unsigned int IRQ_Channel = PCI_Device->irq; - BusLogic_IO_Address_T IO_Address = PCI_Device->resource[0].start; + BusLogic_IO_Address_T IO_Address = pci_resource_start(PCI_Device, 0); + + if (pci_enable_device(PCI_Device)) + continue; if (IO_Address == 0 || IRQ_Channel == 0) continue; for (i = 0; i < BusLogic_ProbeInfoCount; i++) @@ -1017,12 +1023,16 @@ unsigned char Bus = PCI_Device->bus->number; unsigned char Device = PCI_Device->devfn >> 3; unsigned int IRQ_Channel = PCI_Device->irq; - unsigned long BaseAddress0 = PCI_Device->resource[0].start; - unsigned long BaseAddress1 = PCI_Device->resource[1].start; + unsigned long BaseAddress0 = pci_resource_start(PCI_Device, 0); + unsigned long BaseAddress1 = pci_resource_start(PCI_Device, 1); BusLogic_IO_Address_T IO_Address = BaseAddress0; BusLogic_PCI_Address_T PCI_Address = BaseAddress1; + + if (pci_enable_device(PCI_Device)) + continue; + #ifndef CONFIG_SCSI_OMIT_FLASHPOINT - if (!(PCI_Device->resource[0].flags & PCI_BASE_ADDRESS_SPACE_IO)) + if (pci_resource_flags(PCI_Device, 0) & IORESOURCE_MEM) { BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for " "FlashPoint Host Adapter\n", NULL, BaseAddress0); @@ -1030,7 +1040,7 @@ NULL, Bus, Device, IO_Address); continue; } - if (PCI_Device->resource[1].flags & PCI_BASE_ADDRESS_SPACE_IO) + if (pci_resource_flags(PCI_Device, 1) & IORESOURCE_IO) { BusLogic_Error("BusLogic: Base Address1 0x%X not Memory for " "FlashPoint Host Adapter\n", NULL, BaseAddress1); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/ChangeLog.ips linux/drivers/scsi/ChangeLog.ips --- v2.4.0-test1/linux/drivers/scsi/ChangeLog.ips Fri Oct 15 15:25:14 1999 +++ linux/drivers/scsi/ChangeLog.ips Tue Jun 20 14:14:51 2000 @@ -1,25 +1,53 @@ -Change Log -~~~~~~~~~~ +IBM ServeRAID driver Change Log +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 4.00.06 - Fix timeout with initial FFDC command + + 4.00.05 - Remove wish_block from init routine + - Use linux/spinlock.h instead of asm/spinlock.h for kernels + 2.3.18 and later + - Sync with other changes from the 2.3 kernels - 1.00.00 - Initial Public Release - - Functionally equivalent to 0.99.05 + 4.00.04 - Rename structures/constants to be prefixed with IPS_ + + 4.00.03 - Add alternative passthru interface + - Add ability to flash ServeRAID BIOS + + 4.00.02 - Fix problem with PT DCDB with no buffer + + 4.00.01 - Add support for First Failure Data Capture + + 4.00.00 - Add support for ServeRAID 4 + + 3.60.02 - Make DCDB direction based on lookup table. + - Only allow one DCDB command to a SCSI ID at a time. + + 3.60.01 - Remove bogus error check in passthru routine. + + 3.60.00 - Bump max commands to 128 for use with ServeRAID + firmware 3.60. + - Change version to 3.60 to coincide with ServeRAID release + numbering. + + 1.00.00 - Initial Public Release + - Functionally equivalent to 0.99.05 0.99.05 - Fix an oops on certain passthru commands - 0.99.04 - Fix race condition in the passthru mechanism + 0.99.04 - Fix race condition in the passthru mechanism -- this required the interface to the utilities to change - - Fix error recovery code + - Fix error recovery code - 0.99.03 - Make interrupt routine handle all completed request on the - adapter not just the first one - - Make sure passthru commands get woken up if we run out of - SCBs - - Send all of the commands on the queue at once rather than - one at a time since the card will support it. + 0.99.03 - Make interrupt routine handle all completed request on the + adapter not just the first one + - Make sure passthru commands get woken up if we run out of + SCBs + - Send all of the commands on the queue at once rather than + one at a time since the card will support it. - 0.99.02 - Added some additional debug statements to print out + 0.99.02 - Added some additional debug statements to print out errors if an error occurs while trying to read/write to a logical drive (IPS_DEBUG). - Fixed read/write errors when the adapter is using an + - Fixed read/write errors when the adapter is using an 8K stripe size. + diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/ChangeLog.ncr53c8xx linux/drivers/scsi/ChangeLog.ncr53c8xx --- v2.4.0-test1/linux/drivers/scsi/ChangeLog.ncr53c8xx Wed Apr 26 16:34:08 2000 +++ linux/drivers/scsi/ChangeLog.ncr53c8xx Mon Jun 19 17:59:41 2000 @@ -1,3 +1,6 @@ +Thu May 11 12:30 2000 Pam Delaney (pam.delaney@lsil.com) + * revision 3.3b + Mon Apr 24 12:00 2000 Gerard Roudier (groudier@club-internet.fr) * revision 3.2i - Return value 1 (instead of 0) from the driver setup routine. @@ -14,6 +17,11 @@ that supply SCSI_DATA_NONE direction (this avoids some BUG() statement in the PCI code when a data buffer is also supplied). +Thu Mar 16 9:30 2000 Pam Delaney (pam.delaney@lsil.com) + * revision 3.3b-3 + - Added exclusion for the 53C1010 and 53C1010_66 chips + to the driver (change to sym53c8xx_comm.h). + Mon March 6 23:15 2000 Gerard Roudier (groudier@club-internet.fr) * revision 3.2g - Add the file sym53c8xx_comm.h that collects code that should @@ -31,6 +39,40 @@ - Get data transfer direction from the scsi command structure (Scsi_Cmnd) when this information is available. +Mon March 6 23:15 2000 Gerard Roudier (groudier@club-internet.fr) + * revision 3.2g + - Add the file sym53c8xx_comm.h that collects code that should + be shared by sym53c8xx and ncr53c8xx drivers. For now, it is + a header file that is only included by the ncr53c8xx driver, + but things will be cleaned up later. This code addresses + notably: + * Chip detection and PCI related initialisations + * NVRAM detection and reading + * DMA mapping + * Boot setup command + * And some other ... + - Add support for the new dynamic dma mapping kernel interface. + Requires Linux-2.3.47 (tested with pre-2.3.47-6). + - Get data transfer direction from the scsi command structure + (Scsi_Cmnd) when this information is available. + +Fri Jan 14 14:00 2000 Pam Delaney (pam.delaney@lsil.com) + * revision pre-3.3b-1 + - Merge parallel driver series 3.31 and 3.2e + +Tue Jan 11 14:00 2000 Pam Delaney (pam.delaney@lsil.com) + * revision 3.31 + - Added support for mounting disks on wide-narrow-wide + scsi configurations. + - Built off of version 3.30 + +Mon Jan 10 13:30 2000 Pam Delaney (pam.delaney@lsil.com) + * revision 3.30 + - Added capability to use the integrity checking code + in the kernel (optional). + - Disabled support for the 53C1010. + - Built off of version 3.2c + Sat Jan 8 22:00 2000 Gerard Roudier (groudier@club-internet.fr) * revision 3.2e - Add year 2000 copyright. @@ -94,7 +136,7 @@ * revision 3.2 (8xx-896 driver bundle) - Only define the host template in ncr53c8xx.h and include the sym53c8xx_defs.h file. - - Declare static all symbols that donnot need to be visible from + - Declare static all symbols that do not need to be visible from outside the driver code. - Add 'excl' boot command option that allows to pass to the driver io address of devices not to attach. diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/ChangeLog.sym53c8xx linux/drivers/scsi/ChangeLog.sym53c8xx --- v2.4.0-test1/linux/drivers/scsi/ChangeLog.sym53c8xx Wed Apr 26 16:34:08 2000 +++ linux/drivers/scsi/ChangeLog.sym53c8xx Mon Jun 19 17:59:41 2000 @@ -1,9 +1,20 @@ +Thu May 11 12:40 2000 Pam Delaney (pam.delaney@lsil.com) + * version sym53c8xx-1.6b + - Merged version. + Mon Apr 24 12:00 2000 Gerard Roudier (groudier@club-internet.fr) * version sym53c8xx-1.5m - Return value 1 (instead of 0) from the driver setup routine. - - Donnot enable PCI DAC cycles. This just broke support for + - Do not enable PCI DAC cycles. This just broke support for SYM534C896 on sparc64. Problem fixed by David S. Miller. +Fri Apr 14 9:00 2000 Pam Delaney (pam.delaney@lsil.com) + * version sym53c8xx-1.6b-9 + - Added 53C1010_66 support. + - Small fix to integrity checking code. + - Removed requirement for integrity checking if want to run + at ultra 3. + Sat Apr 1 12:00 2000 Gerard Roudier (groudier@club-internet.fr) * version sym53c8xx-1.5l - Tiny change for __sparc__ appeared in 2.3.99-pre4.1 that @@ -12,6 +23,16 @@ that supply SCSI_DATA_NONE direction (this avoids some BUG() statement in the PCI code when a data buffer is also supplied). +Sat Mar 11 12:00 2000 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.6b-5 + - Test against expected data transfer direction from SCRIPTS. + - Add support for the new dynamic dma mapping kernel interface. + Requires Linux-2.3.47 (tested with pre-2.3.47-6). + Many thanks to David S. Miller for his preliminary changes + that have been useful guidelines. + - Get data transfer direction from the scsi command structure + (Scsi_Cmnd) with kernels that provide this information. + Mon Mar 6 23:30 2000 Gerard Roudier (groudier@club-internet.fr) * version sym53c8xx-1.5k - Test against expected data transfer direction from SCRIPTS. @@ -21,6 +42,16 @@ - Miscellaneous (minor) fixes in the code added in driver version 1.5j. +Mon Feb 14 4:00 2000 Pam Delaney (pam.delaney@lsil.com) + * version sym53c8xx-pre-1.6b-2. + - Updated the SCRIPTS error handling of the SWIDE + condition - to remove any reads of the sbdl + register. Changes needed because the 896 and 1010 + chips will check parity in some special circumstances. + This will cause a parity error interrupt if not in + data phase. Changes based on those made in the + FreeBSD driver version 1.3.2. + Sun Feb 20 11:00 2000 Gerard Roudier (groudier@club-internet.fr) * version sym53c8xx-1.5j - Add support for the new dynamic dma mapping kernel interface. @@ -35,6 +66,26 @@ - Fix an old bug that only affected 896 rev. 1 when driver profile support option was set in kernel configuration. +Fri Jan 14 14:00 2000 Pam Delaney (pam.delaney@lsil.com) + * version sym53c8xx-pre-1.6b-1. + - Merge parallel driver series 1.61 and 1.5e + +Tue Jan 11 14:00 2000 Pam Delaney (pam.delaney@lsil.com) + * version sym53c8xx-1.61 + - Added support for mounting disks on wide-narrow-wide + scsi configurations. + - Modified offset to be a maximum of 31 in ST mode, + 62 in DT mode. + - Based off of 1.60 + +Mon Jan 10 10:00 2000 Pam Delaney (pam.delaney@lsil.com) + * version sym53c8xx-1.60 + - Added capability to use the integrity checking code + in the kernel (optional). + - Added PPR negotiation. + - Added support for 53C1010 Ultra 3 part. + - Based off of 1.5f + Sat Jan 8 22:00 2000 Gerard Roudier (groudier@club-internet.fr) * version sym53c8xx-1.5h - Add year 2000 copyright. @@ -118,7 +169,7 @@ Sat Jun 5 11:00 1999 Gerard Roudier (groudier@club-internet.fr) * version sym53c8xx-1.5c - - Donnot negotiate on auto-sense if we are currently using 8 bit + - Do not negotiate on auto-sense if we are currently using 8 bit async transfer for the target. - Only check for SISL/RAID on i386 platforms. (A problem has been reported on PPC with that code). @@ -179,7 +230,7 @@ - Do some work in SCRIPTS after the SELECT instruction and prior to testing for a PHASE. SYMBIOS say this feature is working fine. (Btw, only problems with Toshiba 3401B had been reported). - - Measure the PCI clock speed and donnot attach controllers if + - Measure the PCI clock speed and do not attach controllers if result is greater than 37 MHz. Since the precision of the algorithm (from Stefan Esser) is better than 2%, this should be fine. @@ -353,7 +404,7 @@ transactions since those early chip revisions may use such on LOAD/STORE instructions (work-around). - Remove some useless and bloat code from the pci init stuff. - - Donnot use the readX()/writeX() kernel functions for __i386__, + - Do not use the readX()/writeX() kernel functions for __i386__, since they perform useless masking operations in order to deal with broken driver in 2.1.X kernel. @@ -379,7 +430,7 @@ * version pre-sym53c8xx-0.12 - Damned! I just broke the driver for Alpha by leaving a stale instruction in the source code. Hopefully fixed. - - Donnot set PFEN when it is useless. Doing so we are sure that BOF + - Do not set PFEN when it is useless. Doing so we are sure that BOF will be active, since the manual appears to be very unclear on what feature is actually used by the chip when both PFEN and BOF are set. diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile --- v2.4.0-test1/linux/drivers/scsi/Makefile Tue Apr 11 15:09:18 2000 +++ linux/drivers/scsi/Makefile Tue Jun 20 14:14:51 2000 @@ -1,19 +1,18 @@ +# # Makefile for linux/drivers/scsi # -# 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). +# 30 May 2000, Christoph Hellwig +# Rewritten to use lists instead of if-statements. # -L_TARGET := scsi.a -L_OBJS := -M_OBJS := -MX_OBJS := -MIX_OBJS := +O_TARGET := scsidrv.o MOD_LIST_NAME := SCSI_MODULES -SCSI_SRCS = $(wildcard $(L_OBJS:%.o=%.c)) -ALL_SUB_DIRS := pcmcia +SUB_DIRS := +MOD_SUB_DIRS := +MOD_IN_SUBDIRS := +ALL_SUB_DIRS := $(SUB_DIRS) pcmcia + ifeq ($(CONFIG_PCMCIA),y) SUB_DIRS += pcmcia MOD_IN_SUB_DIRS += pcmcia @@ -23,697 +22,146 @@ endif endif +export-objs := scsi_syms.o +list-multi := scsi_mod.o sr_mod.o initio.o a100u2w.o + CFLAGS_aha152x.o = -DAHA152X_STAT -DAUTOCONF CFLAGS_gdth.o = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS CFLAGS_seagate.o = -DARBITRATE -DPARITY -DSEAGATE_USE_ASM -.SUFFIXES: -.SUFFIXES: .c .o .h .a .S - -ifeq (${CFLAGS},) -CFLAGS = -D__KERNEL__=1 \ - -DMODULE -Wall -Wstrict-prototypes -I. -I../../include \ - -O2 -fomit-frame-pointer - -include ../../.config - -TOPDIR = ../.. - -endif - -ifeq ($(CONFIG_SCSI),y) - # We must attach scsi_syms.o to scsi.o, as otherwise there is nothing to - # pull the object file from the archive. - O_TARGET := scsi_n_syms.o - O_OBJS := scsi.o - ifeq ($(CONFIG_MODULES),y) - OX_OBJS := scsi_syms.o - endif - L_OBJS += scsi_n_syms.o hosts.o scsi_ioctl.o constants.o scsicam.o - L_OBJS += scsi_error.o scsi_obsolete.o scsi_queue.o scsi_lib.o - L_OBJS += scsi_merge.o scsi_proc.o scsi_dma.o scsi_scan.o -else - ifeq ($(CONFIG_SCSI),m) - MIX_OBJS += scsi_syms.o - M_OBJS += scsi_mod.o - endif -endif - -ifeq ($(CONFIG_CHR_DEV_ST),y) -L_OBJS += st.o -else - ifeq ($(CONFIG_CHR_DEV_ST),m) - M_OBJS += st.o - endif -endif - -ifeq ($(CONFIG_BLK_DEV_SD),y) -L_OBJS += sd.o -else - ifeq ($(CONFIG_BLK_DEV_SD),m) - M_OBJS += sd_mod.o - endif -endif - -ifeq ($(CONFIG_BLK_DEV_SR),y) -L_OBJS += sr.o sr_ioctl.o sr_vendor.o -else - ifeq ($(CONFIG_BLK_DEV_SR),m) - M_OBJS += sr_mod.o - endif -endif - -ifeq ($(CONFIG_CHR_DEV_SG),y) -L_OBJS += sg.o -else - ifeq ($(CONFIG_CHR_DEV_SG),m) - M_OBJS += sg.o - endif -endif - -ifeq ($(CONFIG_SCSI_ADVANSYS),y) -L_OBJS += advansys.o -else - ifeq ($(CONFIG_SCSI_ADVANSYS),m) - M_OBJS += advansys.o - endif -endif - -ifeq ($(CONFIG_SCSI_PCI2000),y) -L_OBJS += pci2000.o -else - ifeq ($(CONFIG_SCSI_PCI2000),m) - M_OBJS += pci2000.o - endif -endif - -ifeq ($(CONFIG_SCSI_PCI2220I),y) -L_OBJS += pci2220i.o -else - ifeq ($(CONFIG_SCSI_PCI2220I),m) - M_OBJS += pci2220i.o - endif -endif - -ifeq ($(CONFIG_SCSI_PSI240I),y) -L_OBJS += psi240i.o -else - ifeq ($(CONFIG_SCSI_PSI240I),m) - M_OBJS += psi240i.o - endif -endif - -ifeq ($(CONFIG_MVME16x_SCSI),y) -L_OBJS += mvme16x.o 53c7xx.o -else - ifeq ($(CONFIG_MVME16x_SCSI),m) - M_OBJS += mvme16x.o 53c7xx.o - endif -endif - -ifeq ($(CONFIG_BVME6000_SCSI),y) -L_OBJS += bvme6000.o 53c7xx.o -else - ifeq ($(CONFIG_BVME6000_SCSI),m) - M_OBJS += bvme6000.o 53c7xx.o - endif -endif - -ifeq ($(CONFIG_SCSI_SIM710),y) -L_OBJS += sim710.o -else - ifeq ($(CONFIG_SCSI_SIM710),m) - M_OBJS += sim710.o - endif -endif - -ifeq ($(CONFIG_A4000T_SCSI),y) -L_OBJS += amiga7xx.o 53c7xx.o -else - ifeq ($(CONFIG_A4000T_SCSI),m) - M_OBJS += amiga7xx.o 53c7xx.o - endif -endif - -ifeq ($(CONFIG_A4091_SCSI),y) -L_OBJS += amiga7xx.o 53c7xx.o -else - ifeq ($(CONFIG_A4091_SCSI),m) - M_OBJS += amiga7xx.o 53c7xx.o - endif -endif - -ifeq ($(CONFIG_BLZ603EPLUS_SCSI),y) -L_OBJS += amiga7xx.o 53c7xx.o -else - ifeq ($(CONFIG_BLZ603EPLUS_SCSI),m) - M_OBJS += amiga7xx.o 53c7xx.o - endif -endif - -ifeq ($(CONFIG_WARPENGINE_SCSI),y) -L_OBJS += amiga7xx.o 53c7xx.o -else - ifeq ($(CONFIG_WARPENGINE_SCSI),m) - M_OBJS += amiga7xx.o 53c7xx.o - endif -endif - -ifeq ($(CONFIG_A3000_SCSI),y) -L_OBJS += a3000.o wd33c93.o -else - ifeq ($(CONFIG_A3000_SCSI),m) - M_OBJS += a3000.o wd33c93.o - endif -endif - -ifeq ($(CONFIG_A2091_SCSI),y) -L_OBJS += a2091.o wd33c93.o -else - ifeq ($(CONFIG_A2091_SCSI),m) - M_OBJS += a2091.o wd33c93.o - endif -endif - -ifeq ($(CONFIG_GVP11_SCSI),y) -L_OBJS += gvp11.o wd33c93.o -else - ifeq ($(CONFIG_GVP11_SCSI),m) - M_OBJS += gvp11.o wd33c93.o - endif -endif - -ifeq ($(CONFIG_SCSI_SGIWD93),y) -L_OBJS += sgiwd93.o wd33c93.o -else - ifeq ($(CONFIG_SCSI_SGIWD93),m) - M_OBJS += sgiwd93.o wd33c93.o - endif -endif - -ifeq ($(CONFIG_SCSI_MCA_53C9X),y) -L_OBJS += NCR53C9x.o mca_53c9x.o -else - ifeq ($(CONFIG_SCSI_MCA_53C9X),m) - M_OBJS += NCR53C9x.o mca_53c9x.o - endif -endif - -ifeq ($(CONFIG_CYBERSTORM_SCSI),y) -L_OBJS += NCR53C9x.o cyberstorm.o -else - ifeq ($(CONFIG_CYBERSTORM_SCSI),m) - M_OBJS += NCR53C9x.o cyberstorm.o - endif -endif - -ifeq ($(CONFIG_CYBERSTORMII_SCSI),y) -L_OBJS += NCR53C9x.o cyberstormII.o -else - ifeq ($(CONFIG_CYBERSTORMII_SCSI),m) - M_OBJS += NCR53C9x.o cyberstormII.o - endif -endif - -ifeq ($(CONFIG_BLZ2060_SCSI),y) -L_OBJS += NCR53C9x.o blz2060.o -else - ifeq ($(CONFIG_BLZ2060_SCSI),m) - M_OBJS += NCR53C9x.o blz2060.o - endif -endif - -ifeq ($(CONFIG_BLZ1230_SCSI),y) -L_OBJS += NCR53C9x.o blz1230.o -else - ifeq ($(CONFIG_BLZ1230_SCSI),m) - M_OBJS += NCR53C9x.o blz1230.o - endif -endif - -ifeq ($(CONFIG_FASTLANE_SCSI),y) -L_OBJS += NCR53C9x.o fastlane.o -else - ifeq ($(CONFIG_FASTLANE_SCSI),m) - M_OBJS += NCR53C9x.o fastlane.o - endif -endif - -ifeq ($(CONFIG_OKTAGON_SCSI),y) -L_OBJS += NCR53C9x.o oktagon_esp.o oktagon_io.o -else - ifeq ($(CONFIG_OKTAGON_SCSI),m) - M_OBJS += NCR53C9x.o oktagon_esp.o oktagon_io.o - endif -endif - -ifeq ($(CONFIG_ATARI_SCSI),y) -L_OBJS += atari_scsi.o -else - ifeq ($(CONFIG_ATARI_SCSI),m) - M_OBJS += atari_scsi.o - endif -endif - -ifeq ($(CONFIG_MAC_SCSI),y) -L_OBJS += mac_scsi.o -else - ifeq ($(CONFIG_MAC_SCSI),m) - M_OBJS += mac_scsi.o - endif -endif - -ifeq ($(CONFIG_SUN3_SCSI),y) -L_OBJS += sun3_scsi.o -else - ifeq ($(CONFIG_SUN3_SCSI),m) - M_OBJS += sun3_scsi.o - endif -endif - -ifeq ($(CONFIG_SCSI_MAC_ESP),y) -L_OBJS += mac_esp.o NCR53C9x.o -else - ifeq ($(CONFIG_SCSI_MAC_ESP),m) - M_OBJS += mac_esp.o NCR53C9x.o - endif -endif - -ifeq ($(CONFIG_SCSI_PPA),y) -L_OBJS += ppa.o -else - ifeq ($(CONFIG_SCSI_PPA),m) - M_OBJS += ppa.o - endif -endif - -ifeq ($(CONFIG_SCSI_IMM),y) -L_OBJS += imm.o -else - ifeq ($(CONFIG_SCSI_IMM),m) - M_OBJS += imm.o - endif -endif - -ifeq ($(CONFIG_SCSI_QLOGIC_FAS),y) -L_OBJS += qlogicfas.o -else - ifeq ($(CONFIG_SCSI_QLOGIC_FAS),m) - M_OBJS += qlogicfas.o - endif -endif - - -ifeq ($(CONFIG_SCSI_QLOGIC_ISP),y) -L_OBJS += qlogicisp.o -else - ifeq ($(CONFIG_SCSI_QLOGIC_ISP),m) - M_OBJS += qlogicisp.o - endif -endif - -ifeq ($(CONFIG_SCSI_QLOGIC_1280),y) -L_OBJS += qla1280.o -else - ifeq ($(CONFIG_SCSI_QLOGIC_1280),m) - M_OBJS += qla1280.o - endif -endif - -ifeq ($(CONFIG_SCSI_ACARD),y) -L_OBJS += atp870u.o -else - ifeq ($(CONFIG_SCSI_ACARD),m) - M_OBJS += atp870u.o - endif -endif - -ifeq ($(CONFIG_SCSI_INITIO),y) -L_OBJS += initio.o -else - ifeq ($(CONFIG_SCSI_INITIO),m) - M_OBJS += initio.o - endif -endif - -ifeq ($(CONFIG_SCSI_INIA100),y) -L_OBJS += a100u2w.o -else - ifeq ($(CONFIG_SCSI_INIA100),m) - M_OBJS += a100u2w.o - endif -endif - -ifeq ($(CONFIG_SCSI_QLOGIC_FC),y) -L_OBJS += qlogicfc.o -else - ifeq ($(CONFIG_SCSI_QLOGIC_FC),m) - M_OBJS += qlogicfc.o - endif -endif - -ifeq ($(CONFIG_SCSI_AHA152X),y) -L_OBJS += aha152x.o -else - ifeq ($(CONFIG_SCSI_AHA152X),m) - M_OBJS += aha152x.o - endif -endif - -ifeq ($(CONFIG_SCSI_AHA1542),y) -L_OBJS += aha1542.o -else - ifeq ($(CONFIG_SCSI_AHA1542),m) - M_OBJS += aha1542.o - endif -endif - -ifeq ($(CONFIG_SCSI_AHA1740),y) -L_OBJS += aha1740.o -else - ifeq ($(CONFIG_SCSI_AHA1740),m) - M_OBJS += aha1740.o - endif -endif - -ifeq ($(CONFIG_SCSI_AIC7XXX),y) -L_OBJS += aic7xxx.o -else - ifeq ($(CONFIG_SCSI_AIC7XXX),m) - M_OBJS += aic7xxx.o - endif -endif - -ifeq ($(CONFIG_SCSI_IPS),y) -L_OBJS += ips.o -else - ifeq ($(CONFIG_SCSI_IPS),m) - M_OBJS += ips.o - endif -endif - -ifeq ($(CONFIG_SCSI_DC390T),y) -L_OBJS += tmscsim.o -else - ifeq ($(CONFIG_SCSI_DC390T),m) - M_OBJS += tmscsim.o - endif -endif - -ifeq ($(CONFIG_SCSI_AM53C974),y) -L_OBJS += AM53C974.o -else - ifeq ($(CONFIG_SCSI_AM53C974),m) - M_OBJS += AM53C974.o - endif -endif - -ifeq ($(CONFIG_SCSI_BUSLOGIC),y) -L_OBJS += BusLogic.o -else - ifeq ($(CONFIG_SCSI_BUSLOGIC),m) - M_OBJS += BusLogic.o - endif -endif - -ifeq ($(CONFIG_SCSI_EATA_DMA),y) -L_OBJS += eata_dma.o -else - ifeq ($(CONFIG_SCSI_EATA_DMA),m) - M_OBJS += eata_dma.o - endif -endif - -ifeq ($(CONFIG_SCSI_EATA_PIO),y) -L_OBJS += eata_pio.o -else - ifeq ($(CONFIG_SCSI_EATA_PIO),m) - M_OBJS += eata_pio.o - endif -endif - -ifeq ($(CONFIG_SCSI_U14_34F),y) -L_OBJS += u14-34f.o -else - ifeq ($(CONFIG_SCSI_U14_34F),m) - M_OBJS += u14-34f.o - endif -endif - -ifeq ($(CONFIG_SCSI_SUNESP),y) -L_OBJS += esp.o -else - ifeq ($(CONFIG_SCSI_SUNESP),m) - M_OBJS += esp.o - endif -endif - -ifeq ($(CONFIG_SCSI_QLOGICPTI),y) -L_OBJS += qlogicpti.o -else - ifeq ($(CONFIG_SCSI_QLOGICPTI),m) - M_OBJS += qlogicpti.o - endif -endif - -ifeq ($(CONFIG_SCSI_MESH),y) -L_OBJS += mesh.o -else - ifeq ($(CONFIG_SCSI_MESH),m) - M_OBJS += mesh.o - endif -endif - -ifeq ($(CONFIG_SCSI_MAC53C94),y) -L_OBJS += mac53c94.o -else - ifeq ($(CONFIG_SCSI_MAC53C94),m) - M_OBJS += mac53c94.o - endif -endif - -ifeq ($(CONFIG_SCSI_GDTH),y) -L_OBJS += gdth.o -else - ifeq ($(CONFIG_SCSI_GDTH),m) - M_OBJS += gdth.o - endif -endif - -ifeq ($(CONFIG_SCSI_DEBUG),y) -L_OBJS += scsi_debug.o -else - ifeq ($(CONFIG_SCSI_DEBUG),m) - M_OBJS += scsi_debug.o - endif -endif - -ifeq ($(CONFIG_SCSI_FUTURE_DOMAIN),y) -L_OBJS += fdomain.o -else - ifeq ($(CONFIG_SCSI_FUTURE_DOMAIN),m) - M_OBJS += fdomain.o - endif -endif - -ifeq ($(CONFIG_SCSI_IN2000),y) -L_OBJS += in2000.o -else - ifeq ($(CONFIG_SCSI_IN2000),m) - M_OBJS += in2000.o - endif -endif - -ifeq ($(CONFIG_SCSI_GENERIC_NCR5380),y) -L_OBJS += g_NCR5380.o -else - ifeq ($(CONFIG_SCSI_GENERIC_NCR5380),m) - M_OBJS += g_NCR5380.o - endif -endif - -ifeq ($(CONFIG_SCSI_NCR53C7xx),y) -L_OBJS += 53c7,8xx.o -else - ifeq ($(CONFIG_SCSI_NCR53C7xx),m) - M_OBJS += 53c7,8xx.o - endif -endif - -ifeq ($(CONFIG_SCSI_NCR53C8XX),y) -L_OBJS += ncr53c8xx.o -else - ifeq ($(CONFIG_SCSI_NCR53C8XX),m) - M_OBJS += ncr53c8xx.o - endif -endif - -ifeq ($(CONFIG_SCSI_SYM53C8XX),y) -L_OBJS += sym53c8xx.o -else - ifeq ($(CONFIG_SCSI_SYM53C8XX),m) - M_OBJS += sym53c8xx.o - endif -endif - -ifeq ($(CONFIG_SCSI_PAS16),y) -L_OBJS += pas16.o -else - ifeq ($(CONFIG_SCSI_PAS16),m) - M_OBJS += pas16.o - endif -endif - -ifeq ($(CONFIG_SCSI_SEAGATE),y) -L_OBJS += seagate.o -else - ifeq ($(CONFIG_SCSI_SEAGATE),m) - M_OBJS += seagate.o - endif -endif -ifndef CONFIG_SCSI_SEAGATE - ifeq ($(CONFIG_SCSI_FD_8xx),y) - L_OBJS += seagate.o - else - ifeq ($(CONFIG_SCSI_FD_8xx),m) - M_OBJS += seagate.o - endif - endif -endif - -ifeq ($(CONFIG_SCSI_7000FASST),y) -L_OBJS += wd7000.o -else - ifeq ($(CONFIG_SCSI_7000FASST),m) - M_OBJS += wd7000.o - endif -endif - -ifeq ($(CONFIG_SCSI_IBMMCA),y) -L_OBJS += ibmmca.o -else - ifeq ($(CONFIG_SCSI_IBMMCA),m) - M_OBJS += ibmmca.o - endif -endif +obj-$(CONFIG_SCSI) += scsi_mod.o +obj-$(CONFIG_CHR_DEV_ST) += st.o +obj-$(CONFIG_BLK_DEV_SD) += sd.o +obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o +obj-$(CONFIG_CHR_DEV_SG) += sg.o + +obj-$(CONFIG_SCSI_ADVANSYS) += advansys.o +obj-$(CONFIG_SCSI_PCI2000) += pci2000.o +obj-$(CONFIG_SCSI_PCI2220I) += pci2220i.o +obj-$(CONFIG_SCSI_PSI240I) += psi240i.o +obj-$(CONFIG_MVME16x_SCSI) += mvme16x.o 53c7xx.o +obj-$(CONFIG_BVME6000_SCSI) += bvme6000.o 53c7xx.o +obj-$(CONFIG_SCSI_SIM710) += sim710.o +obj-$(CONFIG_A4000T_SCSI) += amiga7xx.o 53c7xx.o +obj-$(CONFIG_A4091_SCSI) += amiga7xx.o 53c7xx.o +obj-$(CONFIG_BLZ603EPLUS_SCSI) += amiga7xx.o 53c7xx.o +obj-$(CONFIG_WARPENGINE_SCSI) += amiga7xx.o 53c7xx.o +obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o +obj-$(CONFIG_A2091_SCSI) += a2091.o wd33c93.o +obj-$(CONFIG_GVP11_SCSI) += gvp11.o wd33c93.o +obj-$(CONFIG_SCSI_SGIWD93) += sgiwd93.o wd33c93.o +obj-$(CONFIG_SCSI_MCA_53C9X) += NCR53C9x.o mca_53c9x.o +obj-$(CONFIG_CYBERSTORM_SCSI) += NCR53C9x.o cyberstorm.o +obj-$(CONFIG_CYBERSTORMII_SCSI) += NCR53C9x.o cyberstormII.o +obj-$(CONFIG_BLZ2060_SCSI) += NCR53C9x.o blz2060.o +obj-$(CONFIG_BLZ1230_SCSI) += NCR53C9x.o blz1230.o +obj-$(CONFIG_FASTLANE_SCSI) += NCR53C9x.o fastlane.o +obj-$(CONFIG_OKTAGON_SCSI) += NCR53C9x.o oktagon_esp.o oktagon_io.o +obj-$(CONFIG_ATARI_SCSI) += atari_scsi.o +obj-$(CONFIG_MAC_SCSI) += mac_scsi.o +obj-$(CONFIG_SUN3_SCSI) += sun3_scsi.o +obj-$(CONFIG_SCSI_MAC_ESP) += mac_esp.o NCR53C9x.o +obj-$(CONFIG_SCSI_PPA) += ppa.o +obj-$(CONFIG_SCSI_IMM) += imm.o +obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas.o +obj-$(CONFIG_SCSI_QLOGIC_ISP) += qlogicisp.o +obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o +obj-$(CONFIG_SCSI_ACARD) += atp870u.o +obj-$(CONFIG_SCSI_INITIO) += initio.o +obj-$(CONFIG_SCSI_INIA100) += a100u2w.o +obj-$(CONFIG_SCSI_QLOGIC_FC) += qlogicfc.o +obj-$(CONFIG_SCSI_AHA152X) += aha152x.o +obj-$(CONFIG_SCSI_AHA1542) += aha1542.o +obj-$(CONFIG_SCSI_AHA1740) += aha1740.o +obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx.o +obj-$(CONFIG_SCSI_IPS) += ips.o +obj-$(CONFIG_SCSI_DC390T) += tmscsim.o +obj-$(CONFIG_SCSI_AM53C974) += AM53C974.o +obj-$(CONFIG_SCSI_BUSLOGIC) += BusLogic.o +obj-$(CONFIG_SCSI_EATA_DMA) += eata_dma.o +obj-$(CONFIG_SCSI_EATA_PIO) += eata_pio.o +obj-$(CONFIG_SCSI_U14_34F) += u14-34f.o +obj-$(CONFIG_SCSI_SUNESP) += esp.o +obj-$(CONFIG_SCSI_QLOGICPTI) += qlogicpti.o +obj-$(CONFIG_SCSI_MESH) += mesh.o +obj-$(CONFIG_SCSI_MAC53C94) += mac53c94.o +obj-$(CONFIG_SCSI_GDTH) += gdth.o + +obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o + +obj-$(CONFIG_SCSI_FUTURE_DOMAIN)+= fdomain.o +obj-$(CONFIG_SCSI_IN2000) += in2000.o +obj-$(CONFIG_SCSI_GENERIC_NCR5380) += g_NCR5380.o +obj-$(CONFIG_SCSI_NCR53C7xx) += 53c7,8xx.o +obj-$(CONFIG_SCSI_NCR53C8XX) += ncr53c8xx.o +obj-$(CONFIG_SCSI_SYM53C8XX) += sym53c8xx.o +obj-$(CONFIG_SCSI_PAS16) += pas16.o +obj-$(CONFIG_SCSI_SEAGATE) += seagate.o +obj-$(CONFIG_SCSI_FD_8xx) += seagate.o +obj-$(CONFIG_SCSI_7000FASST) += wd7000.o +obj-$(CONFIG_SCSI_IBMMCA) += ibmmca.o +obj-$(CONFIG_SCSI_FD_MCS) += fd_mcs.o +obj-$(CONFIG_SCSI_T128) += t128.o +obj-$(CONFIG_SCSI_DMX3191D) += dmx3191d.o +obj-$(CONFIG_SCSI_DTC3280) += dtc.o +obj-$(CONFIG_SCSI_ULTRASTOR) += ultrastor.o +obj-$(CONFIG_SCSI_PLUTO) += pluto.o +obj-$(CONFIG_SCSI_FCAL) += fcal.o +obj-$(CONFIG_SCSI_EATA) += eata.o +obj-$(CONFIG_SCSI_NCR53C406A) += NCR53c406a.o +obj-$(CONFIG_SCSI_MEGARAID) += megaraid.o +obj-$(CONFIG_SCSI_SYM53C416) += sym53c416.o +obj-$(CONFIG_BLK_DEV_IDESCSI) += ide-scsi.o +obj-$(CONFIG_JAZZ_ESP) += NCR53C9x.o jazz_esp.o +obj-$(CONFIG_SCSI_DECNCR) += NCR53C9x.o dec_esp.o +obj-$(CONFIG_SUN3X_ESP) += NCR53C9x.o sun3x_esp.o +obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o + +scsi_mod-objs := hosts.o scsi.o scsi_ioctl.o constants.o \ + scsicam.o scsi_proc.o scsi_error.o \ + scsi_obsolete.o scsi_queue.o scsi_lib.o \ + scsi_merge.o scsi_dma.o scsi_scan.o \ + scsi_syms.o +sr_mod-objs := sr.o sr_ioctl.o sr_vendor.o +initio-objs := ini9100u.o i91uscsi.o +a100u2w-objs := inia100.o i60uscsi.o + +# Extract lists of the multi-part drivers. +# The 'int-*' lists are the intermediate files used to build the multi's. +multi-y := $(filter $(list-multi), $(obj-y)) +multi-m := $(filter $(list-multi), $(obj-m)) +int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs))) +int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs))) + +# Files that are both resident and modular: remove from modular. +obj-m := $(filter-out $(obj-y), $(obj-m)) +int-m := $(filter-out $(int-y), $(int-m)) + +# Take multi-part drivers out of obj-y and put components in. +obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y) + +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) +MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m))) +MIX_OBJS := $(sort $(filter $(export-objs), $(int-m))) -ifeq ($(CONFIG_SCSI_FD_MCS),y) -L_OBJS += fd_mcs.o -else - ifeq ($(CONFIG_SCSI_FD_MCS),m) - M_OBJS += fd_mcs.o - endif -endif - -ifeq ($(CONFIG_SCSI_T128),y) -L_OBJS += t128.o -else - ifeq ($(CONFIG_SCSI_T128),m) - M_OBJS += t128.o - endif -endif - -ifeq ($(CONFIG_SCSI_DMX3191D),y) -L_OBJS += dmx3191d.o -else - ifeq ($(CONFIG_SCSI_DMX3191D),m) - M_OBJS += dmx3191d.o - endif -endif - -ifeq ($(CONFIG_SCSI_DTC3280),y) -L_OBJS += dtc.o -else - ifeq ($(CONFIG_SCSI_DTC3280),m) - M_OBJS += dtc.o - endif -endif - -ifeq ($(CONFIG_SCSI_ULTRASTOR),y) -L_OBJS += ultrastor.o -else - ifeq ($(CONFIG_SCSI_ULTRASTOR),m) - M_OBJS += ultrastor.o - endif -endif - -ifeq ($(CONFIG_SCSI_PLUTO),y) -L_OBJS += pluto.o -else - ifeq ($(CONFIG_SCSI_PLUTO),m) - M_OBJS += pluto.o - endif -endif - -ifeq ($(CONFIG_SCSI_FCAL),y) -L_OBJS += fcal.o -else - ifeq ($(CONFIG_SCSI_FCAL),m) - M_OBJS += fcal.o - endif -endif - -ifeq ($(CONFIG_SCSI_EATA),y) -L_OBJS += eata.o -else - ifeq ($(CONFIG_SCSI_EATA),m) - M_OBJS += eata.o - endif -endif - -ifeq ($(CONFIG_SCSI_NCR53C406A),y) -L_OBJS += NCR53c406a.o -else - ifeq ($(CONFIG_SCSI_NCR53C406A),m) - M_OBJS += NCR53c406a.o - endif -endif - -ifeq ($(CONFIG_SCSI_MEGARAID),y) -L_OBJS += megaraid.o -else - ifeq ($(CONFIG_SCSI_MEGARAID),m) - M_OBJS += megaraid.o - endif -endif - -ifeq ($(CONFIG_SCSI_SYM53C416),y) -L_OBJS += sym53c416.o -else - ifeq ($(CONFIG_SCSI_SYM53C416),m) - M_OBJS += sym53c416.o - endif -endif +include $(TOPDIR)/Rules.make -ifeq ($(CONFIG_BLK_DEV_IDESCSI),y) -L_OBJS += ide-scsi.o -else - ifeq ($(CONFIG_BLK_DEV_IDESCSI),m) - M_OBJS += ide-scsi.o - endif -endif -ifeq ($(CONFIG_JAZZ_ESP),y) -L_OBJS += NCR53C9x.o jazz_esp.o -endif +scsi_mod.o: $(scsi_mod-objs) + $(LD) -r -o $@ $(scsi_mod-objs) -ifeq ($(CONFIG_SCSI_DECNCR),y) -L_OBJS += NCR53C9x.o dec_esp.o -endif +sr_mod.o: $(sr_mod-objs) + $(LD) -r -o $@ $(sr_mod-objs) -ifeq ($(CONFIG_SUN3X_ESP),y) -L_OBJS += NCR53C9x.o sun3x_esp.o -endif +initio.o: $(initio-objs) + $(LD) -r -o $@ $(initio-objs) -ifeq ($(CONFIG_BLK_DEV_3W_XXXX_RAID),y) -L_OBJS += 3w-xxxx.o -else - ifeq ($(CONFIG_BLK_DEV_3W_XXXX_RAID),m) - M_OBJS += 3w-xxxx.o - endif -endif +a100u2w.o: $(a100u2w-objs) + $(LD) -r -o $@ $(a100u2w-objs) -include $(TOPDIR)/Rules.make 53c8xx_d.h: 53c7,8xx.scr script_asm.pl ln -sf 53c7,8xx.scr fake8.c @@ -745,23 +193,3 @@ sim710_u.h: sim710_d.h sim710.o : sim710_d.h - -initio.o: ini9100u.o i91uscsi.o - $(LD) -r -o initio.o ini9100u.o i91uscsi.o - -a100u2w.o: inia100.o i60uscsi.o - $(LD) -r -o a100u2w.o inia100.o i60uscsi.o - -scsi_mod.o: $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o \ - scsicam.o scsi_proc.o scsi_error.o scsi_obsolete.o \ - scsi_queue.o scsi_lib.o scsi_merge.o scsi_dma.o scsi_scan.o - $(LD) $(LD_RFLAG) -r -o $@ $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o \ - constants.o scsicam.o scsi_proc.o scsi_merge.o \ - scsi_error.o scsi_obsolete.o scsi_queue.o scsi_lib.o \ - scsi_dma.o scsi_scan.o - -sr_mod.o: sr.o sr_ioctl.o sr_vendor.o - $(LD) $(LD_RFLAG) -r -o $@ sr.o sr_ioctl.o sr_vendor.o - -sd_mod.o: sd.o - $(LD) $(LD_RFLAG) -r -o $@ sd.o diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/NCR53C9x.c linux/drivers/scsi/NCR53C9x.c --- v2.4.0-test1/linux/drivers/scsi/NCR53C9x.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/scsi/NCR53C9x.c Mon Jun 19 17:59:41 2000 @@ -3578,7 +3578,7 @@ } #else /* For SMP we only service one ESP on the list list at our IRQ level! */ -static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs) +void esp_intr(int irq, void *dev_id, struct pt_regs *pregs) { struct NCR_ESP *esp; unsigned long flags; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/README.ncr53c8xx linux/drivers/scsi/README.ncr53c8xx --- v2.4.0-test1/linux/drivers/scsi/README.ncr53c8xx Sat Oct 9 11:47:50 1999 +++ linux/drivers/scsi/README.ncr53c8xx Mon Jun 19 17:59:41 2000 @@ -168,6 +168,12 @@ 895 Y Y FAST40 80 MB/s Y Y 895A Y Y FAST40 80 MB/s Y Y 896 Y Y FAST40 80 MB/s Y Y +897 Y Y FAST40 80 MB/s Y Y +1510D Y Y FAST40 80 MB/s Y Y +1010 Y Y FAST80 160 MB/s N Y +1010_66* Y Y FAST80 160 MB/s N Y + +* Chip supports 33MHz and 66MHz PCI buses. Summary of other supported features: @@ -686,11 +692,12 @@ Invalidate. 10.2.5 Ultra SCSI support - Only apply to 860, 875 and 895 controllers. + Only apply to 860, 875, 895, 895a, 896, 1010 and 1010_66 controllers. Have no effect with other ones. + ultra:n All ultra speeds enabled ultra:2 Ultra2 enabled ultra:1 Ultra enabled - ultra:n disabled + ultra:0 Ultra speeds disabled 10.2.6 Default number of tagged commands tags:0 (or tags:1 ) tagged command queuing disabled @@ -822,6 +829,7 @@ 0x0: No check. 0x1: Check and donnot attach the controller on error. 0x2: Check and just warn on error. + 0x4: Disable SCSI bus integrity checking. 10.2.20 Exclude a host from being attached excl= diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c --- v2.4.0-test1/linux/drivers/scsi/advansys.c Mon Mar 27 08:08:27 2000 +++ linux/drivers/scsi/advansys.c Mon Jun 19 13:42:40 2000 @@ -4699,7 +4699,8 @@ NULL) { pci_device_id_cnt++; } else { - pci_devicep[pci_card_cnt_max++] = pci_devp; + if (pci_enable_device(pci_devp) == 0) + pci_devicep[pci_card_cnt_max++] = pci_devp; } } @@ -4739,7 +4740,7 @@ #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,13) iop = pci_devp->base_address[0] & PCI_IOADDRESS_MASK; #else /* version >= v2.3.13 */ - iop = pci_devp->resource[0].start & PCI_IOADDRESS_MASK; + iop = pci_resource_start(pci_devp, 0); #endif /* version >= v2.3.13 */ ASC_DBG2(1, "advansys_detect: vendorID %X, deviceID %X\n", @@ -4900,7 +4901,7 @@ #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,13) pci_memory_address = pci_devp->base_address[1]; #else /* version >= v2.3.13 */ - pci_memory_address = pci_devp->resource[1].start; + pci_memory_address = pci_resource_start(pci_devp, 1); #endif /* version >= v2.3.13 */ ASC_DBG1(1, "advansys_detect: pci_memory_address: %x\n", pci_memory_address); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c --- v2.4.0-test1/linux/drivers/scsi/aha152x.c Tue May 23 15:31:35 2000 +++ linux/drivers/scsi/aha152x.c Mon Jun 19 13:42:40 2000 @@ -1301,10 +1301,11 @@ printk(KERN_ERR "aha152x%d: IRQ %d possibly wrong. Please verify.\n", HOSTNO, shpnt->irq); - scsi_unregister(shpnt); registered_count--; release_region(shpnt->io_port, IO_RANGE); - shpnt = aha152x_host[shpnt->irq - IRQ_MIN] = 0; + aha152x_host[shpnt->irq - IRQ_MIN] = 0; + scsi_unregister(shpnt); + shpnt=NULL; continue; } printk("ok.\n"); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/aic7xxx/aic7xxx.seq linux/drivers/scsi/aic7xxx/aic7xxx.seq --- v2.4.0-test1/linux/drivers/scsi/aic7xxx/aic7xxx.seq Sat Feb 12 11:22:11 2000 +++ linux/drivers/scsi/aic7xxx/aic7xxx.seq Wed Jun 21 17:25:03 2000 @@ -60,11 +60,7 @@ clr SCSISIGO; /* De-assert BSY */ and SXFRCTL1, ~BITBUCKET; /* Always allow reselection */ - if ((p->flags & AHC_TARGETMODE) != 0) { - mvi SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP; - } else { - mvi SCSISEQ, ENRSELI|ENAUTOATNP; - } + mvi SCSISEQ, ENRSELI|ENAUTOATNP; if ((p->features & AHC_CMD_CHAN) != 0) { /* Ensure that no DMA operations are in progress */ @@ -182,6 +178,15 @@ and SCSIID, OID; /* Clear old target */ or SCSIID, A; } + mov SCSIDATL, ALLZEROS; /* clear out the latched */ + /* data register, this */ + /* fixes a bug on some */ + /* controllers where the */ + /* last byte written to */ + /* this register can leak */ + /* onto the data bus at */ + /* bad times, such as during */ + /* selection timeouts */ mvi SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret; /* @@ -227,118 +232,6 @@ selection: test SSTAT0,SELDO jnz select_out; -select_in: - if ((p->flags & AHC_TARGETMODE) != 0) { - test SSTAT0, TARGET jz initiator_reselect; - /* - * We've just been selected. Assert BSY and - * setup the phase for receiving the messages - * from the target. - */ - mvi SCSISIGO, P_MESGOUT|BSYO; - mvi CLRSINT0, CLRSELDO; - - /* - * If ATN isn't asserted, go directly to bus free. - */ - test SCSISIGI, ATNI jz target_busfree; - - /* - * Setup the DMA for sending the identify and - * command information. - */ - mov A, TMODE_CMDADDR_NEXT; - mvi DINDEX, HADDR; - mvi TMODE_CMDADDR call set_32byte_addr; - mvi DFCNTRL, FIFORESET; - - clr SINDEX; - /* Watch ATN closely now */ -message_loop: - or SXFRCTL0, SPIOEN; - test SSTAT0, SPIORDY jz .; - and SXFRCTL0, ~SPIOEN; - mov DINDEX, SCSIDATL; - mov DFDAT, DINDEX; - inc SINDEX; - - /* Message Testing... */ - test DINDEX, MSG_IDENTIFYFLAG jz . + 2; - mov ARG_1, DINDEX; - - test SCSISIGI, ATNI jnz message_loop; - add A, -4, SINDEX; - jc target_cmdphase; - mvi DFDAT, SCB_LIST_NULL; /* Terminate the message list */ - -target_cmdphase: - add HCNT[0], 1, A; - clr HCNT[1]; - clr HCNT[2]; - mvi SCSISIGO, P_COMMAND|BSYO; - or SXFRCTL0, SPIOEN; - test SSTAT0, SPIORDY jz .; - mov A, SCSIDATL; - mov DFDAT, A; /* Store for host */ - - /* - * Determine the number of bytes to read - * based on the command group code. Count is - * one less than the total since we've already - * fetched the first byte. - */ - clr SINDEX; - shr A, CMD_GROUP_CODE_SHIFT; - add SEQADDR0, A; - - add SINDEX, CMD_GROUP0_BYTE_DELTA; - nop; /* Group 1 and 2 are the same */ - add SINDEX, CMD_GROUP2_BYTE_DELTA; - nop; /* Group 3 is reserved */ - add SINDEX, CMD_GROUP4_BYTE_DELTA; - add SINDEX, CMD_GROUP5_BYTE_DELTA; - /* Group 6 and 7 are not handled yet */ - - mov A, SINDEX; - add HCNT[0], A; - -command_loop: - test SSTAT0, SPIORDY jz .; - cmp SINDEX, 1 jne . + 2; - and SXFRCTL0, ~SPIOEN; /* Last Byte */ - mov DFDAT, SCSIDATL; - dec SINDEX; - test SINDEX, 0xFF jnz command_loop; - - or DFCNTRL, HDMAEN|FIFOFLUSH; - - call dma_finish; - - test ARG_1, MSG_IDENTIFY_DISCFLAG jz selectin_post; - - mvi SCSISIGO, P_MESGIN|BSYO; - - or SXFRCTL0, SPIOEN; - - mvi MSG_DISCONNECT call target_outb; - -selectin_post: - inc TMODE_CMDADDR_NEXT; - cmp TMODE_CMDADDR_NEXT, TMODE_NUMCMDS jne . + 2; - clr TMODE_CMDADDR_NEXT; - mvi QOUTFIFO, SCB_LIST_NULL; - mvi INTSTAT,CMDCMPLT; - - test ARG_1, MSG_IDENTIFY_DISCFLAG jnz target_busfree; - - /* Busy loop on something then go to data or status phase */ - -target_busfree: - clr SCSISIGO; - jmp poll_for_work; - - } - /* * Reselection has been initiated by a target. Make a note that we've been * reselected, but haven't seen an IDENTIFY message from the target yet. @@ -444,13 +337,14 @@ * STCNT may have been cleared, so restore it from the residual field. */ data_phase_reinit: - if ((p->features & AHC_CMD_CHAN) != 0) { - if ((p->features & AHC_ULTRA2) != 0) { - bmov HADDR, SHADDR, 4; - bmov HCNT, SCB_RESID_DCNT, 3; - } + if ((p->features & AHC_ULTRA2) != 0) { + bmov HADDR, SHADDR, 4; + bmov HCNT, SCB_RESID_DCNT, 3; + } + if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { bmov STCNT, SCB_RESID_DCNT, 3; - } else { + } + if ((p->features & AHC_CMD_CHAN) == 0) { mvi DINDEX, STCNT; mvi SCB_RESID_DCNT call bcopy_3; } @@ -677,10 +571,13 @@ test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; test DFSTATUS, MREQPEND jnz .; ultra2_dmahalt: - and DFCNTRL, ~HDMAEN; - test DFCNTRL, HDMAEN jnz .; - and DFCNTRL, ~SCSIEN; - test DFCNTRL, SCSIEN jnz .; + test SCSIOFFSET, 0x7f jnz ultra2_shutdown; +ultra2_await_nreq: + test SCSISIGI, REQI jz ultra2_shutdown; + test SSTAT1, (PHASEMIS|REQINIT) jz ultra2_await_nreq; +ultra2_shutdown: + and DFCNTRL, ~(HDMAEN|SCSIEN); + test DFCNTRL, (HDMAEN|SCSIEN) jnz .; bmov SCB_RESID_DCNT, STCNT, 3; mov SCB_RESID_SGCNT, SG_COUNT; or SXFRCTL0, CLRSTCNT|CLRCHN; @@ -719,10 +616,11 @@ test SSTAT0, SDONE jnz p_command_ultra2_dma_done; test SSTAT1,PHASEMIS jz p_command_dma_loop; /* ie. underrun */ p_command_ultra2_dma_done: - and DFCNTRL, ~HDMAEN; - test DFCNTRL, HDMAEN jnz .; - and DFCNTRL, ~SCSIEN; - test DFCNTRL, SCSIEN jnz .; + test SCSISIGI, REQI jz p_command_ultra2_shutdown; + test SSTAT1, (PHASEMIS|REQINIT) jz p_command_ultra2_dma_done; +p_command_ultra2_shutdown: + and DFCNTRL, ~(HDMAEN|SCSIEN); + test DFCNTRL, (HDMAEN|SCSIEN) jnz .; or SXFRCTL0, CLRSTCNT|CLRCHN; } jmp ITloop; @@ -1069,25 +967,12 @@ mvi ARG_1 call inb_next; /* ACK the wide_residue and get */ /* the size byte */ /* - * See if we'll ignore this wide residue (because it's an overrun byte) - */ - if ((p->features & AHC_ULTRA2) != 0) { - test SSTAT2, WIDE_RES jnz mesgin_done; - } else { - test SCB_RESID_SGCNT,0xff jnz wide_residue_int; - test SCB_RESID_DCNT[0],0xff jnz wide_residue_int; - test SCB_RESID_DCNT[1],0xff jnz wide_residue_int; - test SCB_RESID_DCNT[2],0xff jnz wide_residue_int; - jmp mesgin_done; - } -wide_residue_int: -/* * In order for this to be reliable, we have to do all sorts of horrible * magic in terms of resetting the datafifo and reloading the shadow layer * with the correct new values (so that a subsequent save data pointers * message will do the right thing). We let the kernel do that work. */ - mvi INTSTAT,WIDE_RESIDUE; + mvi INTSTAT, WIDE_RESIDUE; jmp mesgin_done; /* @@ -1136,17 +1021,6 @@ inb_last: mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ -if ((p->flags & AHC_TARGETMODE) != 0) { - /* - * Send a byte to an initiator in Automatic PIO mode. - * SPIOEN must be on prior to calling this routine. - */ -target_outb: - mov SCSIDATL, SINDEX; - test SSTAT0, SPIORDY jz .; - ret; -} - mesgin_phasemis: /* * We expected to receive another byte, but the target changed phase @@ -1191,6 +1065,12 @@ * actually off first lest we get an ILLSADDR. */ dma_dmadone: + cmp LASTPHASE, P_COMMAND je dma_await_nreq; + test SCSIRATE, 0x0f jnz dma_shutdown; +dma_await_nreq: + test SCSISIGI, REQI jz dma_shutdown; + test SSTAT1, (PHASEMIS|REQINIT) jz dma_await_nreq; +dma_shutdown: and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); dma_halt: /* diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c --- v2.4.0-test1/linux/drivers/scsi/aic7xxx.c Thu May 11 15:30:07 2000 +++ linux/drivers/scsi/aic7xxx.c Wed Jun 21 17:25:57 2000 @@ -243,6 +243,8 @@ #include #include #include +#include +#include #include "sd.h" #include "scsi.h" #include "hosts.h" @@ -264,7 +266,7 @@ */ #define VIRT_TO_BUS(a) (unsigned int)virt_to_bus((void *)(a)) -#define AIC7XXX_C_VERSION "5.2.0" +#define AIC7XXX_C_VERSION "5.2.1" #define NUMBER(arr) (sizeof(arr) / sizeof(arr[0])) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) @@ -281,45 +283,12 @@ # define FALSE 0 #endif -/* - * We need the bios32.h file if we are kernel version 2.1.92 or less. The - * full set of pci_* changes wasn't in place until 2.1.93 - */ - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,1,92) -# if defined(__sparc_v9__) || defined(__powerpc__) -# error "PPC and Sparc platforms are only support under 2.1.92 and above" -# endif -# include -#endif - -#if defined(__powerpc__) -# define MMAPIO -# ifdef mb -# undef mb -# endif -# define mb() \ - __asm__ __volatile__("eieio" ::: "memory") -#elif defined(__i386__) +#if defined(__powerpc__) || defined(__i386) # define MMAPIO -# ifdef mb -# undef mb -# endif -# define mb() \ - __asm__ __volatile__("lock ; addl $0,0(%%esp)": : :"memory") -#elif defined(__alpha__) -# ifdef mb -# undef mb -# endif -# define mb() \ - __asm__ __volatile__("mb": : :"memory") #endif -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0) -# include -# include -# define cpuid smp_processor_id() # if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) +# define cpuid smp_processor_id() # define DRIVER_LOCK_INIT \ spin_lock_init(&p->spin_lock); # define DRIVER_LOCK \ @@ -337,17 +306,6 @@ # define DRIVER_LOCK # define DRIVER_UNLOCK # endif -#else -# define cpuid 0 -# define DRIVER_LOCK_INIT -# define DRIVER_LOCK \ - save_flags(cpu_flags); \ - cli(); -# define DRIVER_UNLOCK \ - restore_flags(cpu_flags); -# define le32_to_cpu(x) (x) -# define cpu_to_le32(x) (x) -#endif /* * You can try raising me if tagged queueing is enabled, or lowering @@ -359,13 +317,6 @@ #define AIC7XXX_CMDS_PER_DEVICE 8 #endif -/* Set this to the delay in seconds after SCSI bus reset. */ -#ifdef CONFIG_AIC7XXX_RESET_DELAY -#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY -#else -#define AIC7XXX_RESET_DELAY 5 -#endif - /* * Control collection of SCSI transfer statistics for the /proc filesystem. * @@ -377,28 +328,6 @@ #endif /* - * NOTE: Uncommenting the define below no longer has any effect, the - * tagged queue value array is always active now. I've added - * a setup option to set this particular array and I'm hoping - * insmod will be smart enough to set it properly as well. It's - * by use of this array that a person can enable tagged queueing. - * The DEFAULT_TAG_COMMANDS define has been changed to disable - * tagged queueing by default, so if your devices can handle tagged - * queueing you will need to add a line to their lilo.conf file like: - * append="aic7xxx=verbose,tag_info:{{32,32,32,32},{32,32,32,32}}" - * which will result in the first four devices on the first two - * controllers being set to a tagged queue depth of 32. - * - * Set this for defining the number of tagged commands on a device - * by device, and controller by controller basis. The first set - * of tagged commands will be used for the first detected aic7xxx - * controller, the second set will be used for the second detected - * aic7xxx controller, and so on. These values will *only* be used - * for targets that are tagged queueing capable; these values will - * be ignored in all other cases. The tag_commands is an array of - * 16 to allow for wide and twin adapters. Twin adapters will use - * indexes 0-7 for channel 0, and indexes 8-15 for channel 1. - * * *** Determining commands per LUN *** * * When AIC7XXX_CMDS_PER_DEVICE is not defined, the driver will use its @@ -408,7 +337,6 @@ * use an internal queue depth of 3, with no more than one of those * three commands active at one time. */ -/* #define AIC7XXX_TAGGED_QUEUEING_BY_DEVICE */ typedef struct { @@ -453,8 +381,8 @@ /* * NOTE: The below structure is for reference only, the actual structure - * to modify in order to change things is located around line - * number 1305 + * to modify in order to change things is found after this fake one. + * adapter_tag_info_t aic7xxx_tag_info[] = { {DEFAULT_TAG_COMMANDS}, @@ -509,6 +437,7 @@ "Adaptec AHA-394X Ultra SCSI host adapter", /* AIC_7882 */ "Adaptec AHA-398X Ultra SCSI host adapter", /* AIC_7883 */ "Adaptec AHA-2944 Ultra SCSI host adapter", /* AIC_7884 */ + "Adaptec AHA-2940UW Pro Ultra SCSI host adapter", /* AIC_7887 */ "Adaptec AIC-7895 Ultra SCSI host adapter", /* AIC_7895 */ "Adaptec AIC-7890/1 Ultra2 SCSI host adapter", /* AIC_7890 */ "Adaptec AHA-293X Ultra2 SCSI host adapter", /* AIC_7890 */ @@ -565,7 +494,7 @@ * AIC-7770 I/O range to reserve for a card */ #define MINREG 0xC00 -#define MAXREG 0xCBF +#define MAXREG 0xCFF #define INTDEF 0x5C /* Interrupt Definition Register */ @@ -828,7 +757,8 @@ * and what flags weren't. This way, I could clean up the flag usage on * a use by use basis. Doug Ledford */ - AHC_NO_STPWR = 0x00040000, + AHC_MOTHERBOARD = 0x00020000, + AHC_NO_STPWEN = 0x00040000, AHC_RESET_DELAY = 0x00080000, AHC_A_SCANNED = 0x00100000, AHC_B_SCANNED = 0x00200000, @@ -1056,11 +986,8 @@ struct timer_list dev_timer; unsigned long dev_expires[MAX_TARGETS]; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0) spinlock_t spin_lock; volatile unsigned char cpu_lock_count[NR_CPUS]; -#endif - Scsi_Cmnd *dev_dtr_cmnd[MAX_TARGETS]; @@ -1384,9 +1311,7 @@ */ #ifdef MODULE static char * aic7xxx = NULL; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,18) MODULE_PARM(aic7xxx, "s"); -#endif /* * Just in case someone uses commas to separate items on the insmod @@ -1444,32 +1369,6 @@ * ***************************************************************************/ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) -static inline void -mdelay(int milliseconds) -{ - int i; - - for(i=0; i= 0L); -} - -static inline int -timer_pending(struct timer_list *timer) -{ - return( timer->prev != NULL ); -} - -#define PCI_DEVICE_ID_ADAPTEC_1480A 0x6075 - -#endif - static inline unsigned char aic_inb(struct aic7xxx_host *p, long port) { @@ -1483,7 +1382,6 @@ { x = inb(p->base + port); } - mb(); return(x); #else return(inb(p->base + port)); @@ -1497,14 +1395,17 @@ if(p->maddr) { writeb(val, p->maddr + port); + mb(); /* locked operation in order to force CPU ordering */ + readb(p->maddr + HCNTRL); /* dummy read to flush the PCI write */ } else { outb(val, p->base + port); + mb(); /* locked operation in order to force CPU ordering */ } - mb(); #else outb(val, p->base + port); + mb(); /* locked operation in order to force CPU ordering */ #endif } @@ -1642,7 +1543,7 @@ } else if (!strncmp(p, "verbose", n)) { - *(options[i].flag) = 0xff09; + *(options[i].flag) = 0xff29; } else { @@ -1669,7 +1570,7 @@ * is important since the sequencer can disable pausing for critical * sections. *-F*************************************************************************/ -static inline void +static void pause_sequencer(struct aic7xxx_host *p) { aic_outb(p, p->pause, HCNTRL); @@ -1677,6 +1578,10 @@ { ; } + if(p->features & AHC_ULTRA2) + { + aic_inb(p, CCSCBCTL); + } } /*+F************************************************************************* @@ -1687,7 +1592,7 @@ * Unpause the sequencer. Unremarkable, yet done often enough to * warrant an easy way to do it. *-F*************************************************************************/ -static inline void +static void unpause_sequencer(struct aic7xxx_host *p, int unpause_always) { if (unpause_always || @@ -1706,7 +1611,7 @@ * Restart the sequencer program from address zero. This assumes * that the sequencer is already paused. *-F*************************************************************************/ -static inline void +static void restart_sequencer(struct aic7xxx_host *p) { aic_outb(p, 0, SEQADDR0); @@ -1787,7 +1692,6 @@ struct ins_format1 *fmt1_ins; struct ins_format3 *fmt3_ins; unsigned char opcode; - volatile unsigned char hcntrl; instr = *(union ins_formats*) &seqprog[instrptr * 4]; @@ -1889,14 +1793,10 @@ } } aic_outb(p, (instr.integer & 0xff), SEQRAM); - hcntrl = aic_inb(p, HCNTRL); aic_outb(p, ((instr.integer >> 8) & 0xff), SEQRAM); - hcntrl = aic_inb(p, HCNTRL); aic_outb(p, ((instr.integer >> 16) & 0xff), SEQRAM); - hcntrl = aic_inb(p, HCNTRL); aic_outb(p, ((instr.integer >> 24) & 0xff), SEQRAM); - hcntrl = aic_inb(p, HCNTRL); - udelay(50); + udelay(10); break; default: @@ -2151,7 +2051,7 @@ * Use async transfers for this target */ *options = 0; - *period = 0; + *period = 255; syncrate = NULL; } return (syncrate); @@ -2950,6 +2850,7 @@ #define WIDE_INQUIRY_BITS 0x60 #define SYNC_INQUIRY_BITS 0x10 #define SCSI_VERSION_BITS 0x07 +#define SCSI_DT_BIT 0x04 if ( (buffer[7] & WIDE_INQUIRY_BITS) && (p->features & AHC_WIDE) ) { @@ -2968,48 +2869,66 @@ AHC_TRANS_CUR) ); unpause_sequencer(p, FALSE); } - if (buffer[7] & SYNC_INQUIRY_BITS) + if ( (buffer[7] & SYNC_INQUIRY_BITS) && + p->transinfo[tindex].user_offset ) { - p->needsdtr |= (1<needsdtr_copy |= (1<transinfo[tindex].goal_period = p->transinfo[tindex].user_period; p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options; - if (p->transinfo[tindex].user_offset) + if (p->features & AHC_ULTRA2) + p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; + else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT) + p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT; + else + p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; + if ( (((buffer[2] & SCSI_VERSION_BITS) == 3) || + (buffer[56] & SCSI_DT_BIT) || + (p->dev_flags[tindex] & DEVICE_SCSI_3) ) && + (p->transinfo[tindex].user_period <= 9) && + (p->transinfo[tindex].user_options) ) { - if (p->features & AHC_ULTRA2) - p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; - else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT) - p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT; - else - p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; + p->needppr |= (1<needppr_copy |= (1<needsdtr &= ~(1<needsdtr_copy &= ~(1<needwdtr &= ~(1<needwdtr_copy &= ~(1<dev_flags[tindex] |= DEVICE_SCSI_3; + } + else + { + p->needsdtr |= (1<needsdtr_copy |= (1<transinfo[tindex].goal_period = + MAX(10, p->transinfo[tindex].goal_period); + p->transinfo[tindex].goal_options = 0; } } else { p->needsdtr &= ~(1<needsdtr_copy &= ~(1<transinfo[tindex].goal_period = 0; + p->transinfo[tindex].goal_period = 255; p->transinfo[tindex].goal_offset = 0; p->transinfo[tindex].goal_options = 0; } - if ( (buffer[2] & SCSI_VERSION_BITS) == 3 ) + /* + * This is needed to work around a sequencer bug for now. Regardless + * of the controller in use, if we have a Quantum drive, we need to + * limit the speed to 80MByte/sec. As soon as I get a fixed version + * of the sequencer, this code will get yanked. + */ + if(!strncmp(buffer + 8, "QUANTUM", 7) && + p->transinfo[tindex].goal_options ) { - p->dev_flags[tindex] |= DEVICE_SCSI_3; - /* - * OK, we are a SCSI 3 device and we are in need of negotiation. - * Use PPR messages instead of WDTR and SDTR messages. - */ - if ( (p->needsdtr & (1<needwdtr & (1<needppr |= (1<needppr_copy |= (1<needwdtr &= ~(1<needwdtr_copy &= ~(1<needsdtr &= ~(1<needsdtr_copy &= ~(1<transinfo[tindex].goal_period = + MAX(p->transinfo[tindex].goal_period, 10); + p->transinfo[tindex].goal_options = 0; + p->needppr &= ~(1<needppr_copy &= ~(1<needsdtr |= (1<needsdtr_copy |= (1<needwdtr |= (1<needwdtr_copy |= (1<flags & SCB_MSGOUT_BITS) != 0) @@ -4170,12 +4090,7 @@ { unsigned char status1; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) pci_read_config_byte(p->pdev, PCI_STATUS + 1, &status1); -#else - pcibios_read_config_byte(p->pci_bus, p->pci_device_fn, - PCI_STATUS + 1, &status1); -#endif if ( (status1 & DPE) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ) printk(WARN_LEAD "Data Parity Error during PCI address or PCI write" @@ -4196,12 +4111,7 @@ printk(WARN_LEAD "Data Parity Error has been reported via PCI pin " "PERR#\n", p->host_no, -1, -1, -1); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) pci_write_config_byte(p->pdev, PCI_STATUS + 1, status1); -#else - pcibios_write_config_byte(p->pci_bus, p->pci_device_fn, - PCI_STATUS + 1, status1); -#endif if (status1 & (DPR|RMA|RTA)) aic_outb(p, CLRPARERR, CLRINT); @@ -4226,11 +4136,7 @@ unsigned long cpu_flags = 0; struct aic7xxx_scb *scb; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) - DRIVER_LOCK -#else spin_lock_irqsave(&io_request_lock, cpu_flags); -#endif p->dev_timer_active &= ~(0x01 << MAX_TARGETS); if ( (p->dev_timer_active & (0x01 << p->scsi_id)) && time_after_eq(jiffies, p->dev_expires[p->scsi_id]) ) @@ -4287,11 +4193,7 @@ } aic7xxx_run_waiting_queues(p); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) - DRIVER_UNLOCK -#else spin_unlock_irqrestore(&io_request_lock, cpu_flags); -#endif } /*+F************************************************************************* @@ -4673,7 +4575,9 @@ * As per the draft specs, any device capable of supporting any of * the option values other than 0 are not allowed to reject the * PPR message. Instead, they must negotiate out what they do - * support instead of rejecting our offering. + * support instead of rejecting our offering or else they cause + * a parity error during msg_out phase to signal that they don't + * like our settings. */ p->needppr &= ~target_mask; p->needppr_copy &= ~target_mask; @@ -4813,39 +4717,36 @@ case CHECK_CONDITION: if ( !(scb->flags & SCB_SENSE) ) { - unsigned char *sense_buffer; - /* - * XXX - How do we save the residual (if there is one). - */ - if ( hscb->residual_SG_segment_count != 0 ) - aic7xxx_calculate_residual(p, scb); - /* - * Send a sense command to the requesting target. + * Send a sense command to the requesting target. * XXX - revisit this and get rid of the memcopys. - */ + */ memcpy(scb->sense_cmd, &generic_sense[0], sizeof(generic_sense)); scb->sense_cmd[1] = (cmd->lun << 5); scb->sense_cmd[4] = sizeof(cmd->sense_buffer); - sense_buffer = cmd->sense_buffer; scb->sg_list[0].length = cpu_to_le32(sizeof(cmd->sense_buffer)); + scb->sg_list[0].address = + cpu_to_le32(pci_map_single(p->pdev, cmd->sense_buffer, + sizeof(cmd->sense_buffer), + PCI_DMA_FROMDEVICE)); /* * XXX - We should allow disconnection, but can't as it * might allow overlapped tagged commands. */ - /* hscb->control &= DISCENB; */ + /* hscb->control &= DISCENB; */ hscb->control = 0; hscb->target_status = 0; hscb->SG_list_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, scb->sg_list)); - hscb->data_count = scb->sg_list[0].length; hscb->SCSI_cmd_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, scb->sense_cmd)); + hscb->data_count = scb->sg_list[0].length; + hscb->data_pointer = scb->sg_list[0].address; hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]); hscb->residual_SG_segment_count = 0; hscb->residual_data_count[0] = 0; @@ -4855,53 +4756,6 @@ scb->sg_count = hscb->SG_segment_count = 1; scb->sg_length = sizeof(cmd->sense_buffer); scb->tag_action = 0; - /* - * This problem could be caused if the target has lost power - * or found some other way to loose the negotiation settings, - * so if needed, we'll re-negotiate while doing the sense cmd. - * However, if this SCB already was attempting to negotiate, - * then we assume this isn't the problem and skip this part. - */ - if ( (scb->cmd->cmnd[0] != TEST_UNIT_READY) && - (p->dev_flags[tindex] & DEVICE_SCANNED) && - !(p->dtr_pending & target_mask) ) - { - p->needppr |= (p->needppr_copy & target_mask); - p->needwdtr |= (p->needwdtr_copy & target_mask); - p->needsdtr |= (p->needsdtr_copy & target_mask); - } - else if ( scb->cmd == p->dev_dtr_cmnd[tindex] ) - { - /* - * This is already a negotiation command, so we must have - * already done PPR, WDTR or SDTR. Since our negotiation - * could have gotten rejected, we don't really know the - * full state of things. Don't do anything here, and allow - * the negotiation_complete() handler to do the right - * thing. - */ - - /* - * This is the important part though. We are getting sense - * info back from this device. It's going into a fake - * command. We need to put that into the real command - * instead so that the mid level SCSI code can act upon it. - * So, when we set up these fake commands, the next pointer - * is used to point to the real command. Use that to change - * the address of our sense_buffer[] to the real command. - * However, don't do this if the real command is also a - * TEST_UNIT_READY as it will most likely pull down its own - * SENSE information anyway. - */ - if (cmd->next->cmnd[0] != TEST_UNIT_READY) - sense_buffer = cmd->next->sense_buffer; - } - scb->sg_list[0].address = - cpu_to_le32(pci_map_single(p->pdev, sense_buffer, - sizeof(cmd->sense_buffer), - PCI_DMA_FROMDEVICE)); - hscb->data_pointer = scb->sg_list[0].address; - scb->flags |= SCB_SENSE; /* * Ensure the target is busy since this will be an @@ -4924,7 +4778,7 @@ aic7xxx_error(cmd) = DID_OK; break; } /* first time sense, no errors */ - aic7xxx_error(cmd) = DID_OK; + aic7xxx_error(cmd) = DID_ERROR; scb->flags &= ~SCB_SENSE; break; @@ -5171,51 +5025,14 @@ } else if (scb->flags & SCB_MSGOUT_PPR) { - unsigned int max_sync, period; - unsigned char options = 0; - - if (p->features & AHC_ULTRA2) - { - if ( (aic_inb(p, SBLKCTL) & ENAB40) && - !(aic_inb(p, SSTAT2) & EXP_ACTIVE) ) - { - if( (p->features & AHC_ULTRA3) && - (p->dev_flags[tindex] & DEVICE_SCSI_3) && - (p->transinfo[tindex].goal_width == - MSG_EXT_WDTR_BUS_16_BIT) && - (p->transinfo[tindex].goal_options != 0) ) - { - max_sync = AHC_SYNCRATE_ULTRA3; - options = p->transinfo[tindex].goal_options; - } - else - { - max_sync = AHC_SYNCRATE_ULTRA2; - } - } - else - { - max_sync = AHC_SYNCRATE_ULTRA; - } - } - else if (p->features & AHC_ULTRA) - { - max_sync = AHC_SYNCRATE_ULTRA; - } - else - { - max_sync = AHC_SYNCRATE_FAST; - } - period = p->transinfo[tindex].goal_period; - aic7xxx_find_syncrate(p, &period, max_sync, &options); - p->transinfo[tindex].goal_period = period; - p->transinfo[tindex].goal_options = options; if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) { printk(INFO_LEAD "Sending PPR (%d/%d/%d/%d) message.\n", - p->host_no, CTL_OF_SCB(scb), period, + p->host_no, CTL_OF_SCB(scb), + p->transinfo[tindex].goal_period, p->transinfo[tindex].goal_offset, - p->transinfo[tindex].goal_width, options); + p->transinfo[tindex].goal_width, + p->transinfo[tindex].goal_options); } aic7xxx_construct_ppr(p, scb); } @@ -5261,8 +5078,7 @@ if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) { printk(INFO_LEAD "Sending SDTR %d/%d message.\n", p->host_no, - CTL_OF_SCB(scb), - p->transinfo[tindex].goal_period, + CTL_OF_SCB(scb), period, p->transinfo[tindex].goal_offset); } aic7xxx_construct_sdtr(p, period, @@ -5375,15 +5191,15 @@ resid_sgcnt = aic_inb(p, SCB_RESID_SGCNT); resid_dcnt = aic_inb(p, SCB_RESID_DCNT) | (aic_inb(p, SCB_RESID_DCNT + 1) << 8) | - (aic_inb(p, SCB_RESID_DCNT + 2) << 24); - index = scb->sg_count - resid_sgcnt; + (aic_inb(p, SCB_RESID_DCNT + 2) << 16); + index = scb->sg_count - (resid_sgcnt + 1); native_addr = le32_to_cpu(scb->sg_list[index].address); native_length = le32_to_cpu(scb->sg_list[index].length); /* * Make sure this is a valid sg_seg for the given pointer */ if(cur_addr < native_addr || - cur_addr > (native_addr + native_length)) + cur_addr > (native_addr + native_length + 1)) { printk(WARN_LEAD "invalid cur_addr:0x%x during WIDE_RESIDUE\n", p->host_no, CTL_OF_SCB(scb), cur_addr); @@ -5400,16 +5216,31 @@ p->host_no, CTL_OF_SCB(scb), le32_to_cpu(scb->sg_list[index + 1].address), le32_to_cpu(scb->sg_list[index + 1].length)); + printk(WARN_LEAD " cur_address:0x%x resid_dcnt:0x%06x\n", + p->host_no, CTL_OF_SCB(scb), + cur_addr, resid_dcnt); break; } - /* - * If our current address matches the sg_seg->address then we - * have to back up the sg array to the previous segment and set - * it up to have only one byte of transfer left to go. - */ - if(cur_addr == native_addr) + if( (resid_sgcnt == 0) && + ((resid_dcnt == 0) || (resid_dcnt == 0xffffff))) + { + /* + * We are at the end of the transfer and this is about a byte + * we ignored already (because the sequencer knew this was + * the last segment and set the adapter to ignore any wide + * residue bytes that might come through, which is only done + * on the last scatter gather segment of transfers). + */ + break; + } + else if(cur_addr == native_addr) { + /* + * If our current address matches the sg_seg->address then we + * have to back up the sg array to the previous segment and set + * it up to have only one byte of transfer left to go. + */ if(index == 0) { printk(WARN_LEAD "bogus WIDE_RESIDUE message, no data has been " @@ -5439,39 +5270,6 @@ aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1); aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2); aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3); - /* - * The sequencer actually wants to find the new address and byte - * count in the SHCNT and SHADDR register sets. These registers - * are a shadow of the regular HCNT and HADDR registers. On the - * Ultra2 controllers, these registers are read only and the way - * we have to set their values is to put the values we want into - * the HCNT and HADDR registers and then output PRELOADEN into - * the DFCNTRL register which causes the card to latch the current - * values in the HADDR and HCNT registers and drop it through to - * the shadow registers. On older cards we copy them directly - * across by hand. - */ - if(p->features & AHC_ULTRA2) - { - aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL); - i=0; - udelay(1); - while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000)) - { - aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL); - udelay(1); - } - } - else - { - aic_outb(p, 1, STCNT); - aic_outb(p, 0, STCNT + 1); - aic_outb(p, 0, STCNT + 2); - aic_outb(p, cur_addr & 0xff, SHADDR); - aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1); - aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2); - aic_outb(p, (cur_addr >> 24) & 0xff, SHADDR + 3); - } } else { @@ -5491,28 +5289,46 @@ aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1); aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2); aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3); - if(p->features & AHC_ULTRA2) + } + /* + * The sequencer actually wants to find the new address and byte + * count in the SHCNT and SHADDR register sets. These registers + * are a shadow of the regular HCNT and HADDR registers. On the + * Ultra2 controllers, these registers are read only and the way + * we have to set their values is to put the values we want into + * the HCNT and HADDR registers and then output PRELOADEN into + * the DFCNTRL register which causes the card to latch the current + * values in the HADDR and HCNT registers and drop it through to + * the shadow registers. On older cards we copy them directly + * across by hand. + */ + if(p->features & AHC_ULTRA2) + { + aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL); + i=0; + udelay(1); + while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000)) { - aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL); - i=0; udelay(1); - while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000)) - { - aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL); - udelay(1); - } } - else + aic_outb(p, aic_inb(p, DMAPARAMS) & ~(SCSIEN|HDMAEN), DFCNTRL); + i=0; + udelay(1); + while(((aic_inb(p, DFCNTRL) & (SCSIEN|HDMAEN)) != 0) && (i++ < 1000)) { - aic_outb(p, resid_dcnt & 0xff, STCNT); - aic_outb(p, (resid_dcnt >> 8) & 0xff, STCNT + 1); - aic_outb(p, (resid_dcnt >> 16) & 0xff, STCNT + 2); - aic_outb(p, cur_addr & 0xff, SHADDR); - aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1); - aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2); - aic_outb(p, (cur_addr >> 24) & 0xff, SHADDR + 3); + udelay(1); } } + else + { + aic_outb(p, resid_dcnt & 0xff, STCNT); + aic_outb(p, (resid_dcnt >> 8) & 0xff, STCNT + 1); + aic_outb(p, (resid_dcnt >> 16) & 0xff, STCNT + 2); + aic_outb(p, cur_addr & 0xff, SHADDR); + aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1); + aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2); + aic_outb(p, (cur_addr >> 24) & 0xff, SHADDR + 3); + } } break; @@ -5921,6 +5737,7 @@ reply = TRUE; scb->flags &= ~SCB_MSGOUT_BITS; scb->flags |= SCB_MSGOUT_PPR; + p->dev_flags[tindex] |= DEVICE_SCSI_3; if (!(p->dev_flags[tindex] & DEVICE_SCANNED)) { /* @@ -5954,7 +5771,6 @@ p->transinfo[tindex].user_width; p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options; - p->needppr_copy |= target_mask; } if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) { @@ -5988,6 +5804,25 @@ break; } } + if ( (p->transinfo[tindex].goal_period > 9) || + (p->transinfo[tindex].goal_options == 0) ) + { + scb->flags &= ~SCB_MSGOUT_BITS; + reject = TRUE; + reply = FALSE; + p->needppr &= ~(1 << tindex); + p->needppr_copy &= ~(1 << tindex); + if ( p->transinfo[tindex].goal_offset ) + { + p->needsdtr |= (1 << tindex); + p->needsdtr_copy |= (1 << tindex); + } + if ( p->transinfo[tindex].goal_width ) + { + p->needwdtr |= (1 << tindex); + p->needwdtr_copy |= (1 << tindex); + } + } } else { @@ -5995,7 +5830,7 @@ { default: { - reply = TRUE; + reject = TRUE; if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) || (aic7xxx_verbose > 0xffff)) ) @@ -6021,27 +5856,18 @@ } } - aic7xxx_set_width(p, target, channel, lun, bus_width, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR); - syncrate = aic7xxx_find_syncrate(p, &period, maxsync, - &new_trans_options); - aic7xxx_validate_offset(p, syncrate, &offset, bus_width); - aic7xxx_set_syncrate(p, syncrate, target, channel, period, - offset, new_trans_options, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR); - - if( (offset != saved_offset) || - (trans_options != new_trans_options) || - ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) != - (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) ) + if ( !reject ) { aic7xxx_set_width(p, target, channel, lun, bus_width, - AHC_TRANS_GOAL|AHC_TRANS_QUITE); + AHC_TRANS_ACTIVE|AHC_TRANS_CUR); + syncrate = aic7xxx_find_syncrate(p, &period, maxsync, + &new_trans_options); + aic7xxx_validate_offset(p, syncrate, &offset, bus_width); aic7xxx_set_syncrate(p, syncrate, target, channel, period, offset, new_trans_options, - AHC_TRANS_GOAL|AHC_TRANS_QUITE); - reply = TRUE; + AHC_TRANS_ACTIVE|AHC_TRANS_CUR); } + p->dtr_pending &= ~target_mask; p->needppr &= ~target_mask; if(reply) @@ -6445,15 +6271,33 @@ } } /* - * Restarting the sequencer will stop the selection and make sure devices - * are allowed to reselect in. + * Keep the sequencer from trying to restart any selections + */ + aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ); + /* + * Make sure the data bits on the bus are released + * Don't do this on 7770 chipsets, it makes them give us + * a BRKADDRINT and kills the card. */ - aic_outb(p, 0, SCSISEQ); + if( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI ) + aic_outb(p, 0, SCSIBUSL); + + /* + * Delay for the selection timeout delay period then stop the selection + */ + udelay(301); aic_outb(p, CLRSELINGO, CLRSINT0); + /* + * Clear out all the interrupt status bits + */ aic_outb(p, aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE), SIMODE1); p->flags &= ~AHC_HANDLING_REQINITS; aic_outb(p, CLRSELTIMEO | CLRBUSFREE, CLRSINT1); aic_outb(p, CLRSCSIINT, CLRINT); + /* + * Restarting the sequencer will stop the selection and make sure devices + * are allowed to reselect in. + */ restart_sequencer(p); unpause_sequencer(p, TRUE); } @@ -6519,7 +6363,9 @@ * A parity error has occurred during a data * transfer phase. Flag it and continue. */ - if( (aic_inb(p, SCSIRATE) & AHC_SYNCRATE_CRC) && (lastphase == P_DATAIN) ) + if( (p->features & AHC_ULTRA3) && + (aic_inb(p, SCSIRATE) & AHC_SYNCRATE_CRC) && + (lastphase == P_DATAIN) ) { printk(WARN_LEAD "CRC error during %s phase.\n", p->host_no, CTL_OF_SCB(scb), phase); @@ -6544,13 +6390,50 @@ p->host_no, CTL_OF_SCB(scb)); } } - else + else if( (lastphase == P_MESGOUT) && + (cmd == p->dev_dtr_cmnd[tindex]) && + (scb->flags & SCB_MSGOUT_PPR) ) { - printk(WARN_LEAD "Parity error during %s phase.\n", - p->host_no, CTL_OF_SCB(scb), phase); + /* + * As per the draft specs, any device capable of supporting any of + * the option values other than 0 are not allowed to reject the + * PPR message. Instead, they must negotiate out what they do + * support instead of rejecting our offering or else they cause + * a parity error during msg_out phase to signal that they don't + * like our settings. + */ + p->needppr &= ~(1 << tindex); + p->needppr_copy &= ~(1 << tindex); + aic7xxx_set_width(p, scb->cmd->target, scb->cmd->channel, scb->cmd->lun, + MSG_EXT_WDTR_BUS_8_BIT, + (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE)); + aic7xxx_set_syncrate(p, NULL, scb->cmd->target, scb->cmd->channel, 0, 0, + 0, AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE); + p->transinfo[tindex].goal_options = 0; + p->dtr_pending &= ~(1 << tindex); + scb->flags &= ~SCB_MSGOUT_BITS; + if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) + { + printk(INFO_LEAD "parity error during PPR message, reverting " + "to WDTR/SDTR\n", p->host_no, CTL_OF_SCB(scb)); + } + if ( p->transinfo[tindex].goal_width ) + { + p->needwdtr |= (1 << tindex); + p->needwdtr_copy |= (1 << tindex); + } + if ( p->transinfo[tindex].goal_offset ) + { + if( p->transinfo[tindex].goal_period <= 9 ) + { + p->transinfo[tindex].goal_period = 10; + } + p->needsdtr |= (1 << tindex); + p->needsdtr_copy |= (1 << tindex); + } + scb = NULL; } - - if(p->dev_flags[tindex] & DEVICE_PARITY_ERROR) + else if(p->dev_flags[tindex] & DEVICE_PARITY_ERROR) { struct aic7xxx_syncrate *syncrate; unsigned int period = p->transinfo[tindex].cur_period; @@ -6562,6 +6445,8 @@ * instead of slowing down if those exist. That's hard to do with simple * checksums though. */ + printk(WARN_LEAD "Parity error during %s phase.\n", + p->host_no, CTL_OF_SCB(scb), phase); if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL) { syncrate++; @@ -6569,20 +6454,59 @@ (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) ) { p->transinfo[tindex].goal_period = syncrate->period; - if( !(syncrate->sxfr_ultra2 & 0x40) ) + if( p->transinfo[tindex].goal_period > 9 ) { p->transinfo[tindex].goal_options = 0; + p->needppr &= ~(1<needsdtr |= (1<needppr_copy &= ~(1<needsdtr_copy |= (1<transinfo[tindex].goal_width) + { + p->needwdtr |= (1<needwdtr_copy |= (1<transinfo[tindex].goal_width) + { + p->transinfo[tindex].goal_width = 0; + p->needwdtr &= ~(1<needwdtr_copy &= ~(1<transinfo[tindex].goal_offset = + p->transinfo[tindex].user_offset; + p->transinfo[tindex].goal_period = + p->transinfo[tindex].user_period; + p->transinfo[tindex].goal_options = + p->transinfo[tindex].user_options; + if( p->transinfo[tindex].goal_period <= 9 ) + { + p->needppr |= (1<needsdtr &= ~(1<needppr_copy |= (1<needsdtr_copy &= ~(1<needppr &= ~(1<needsdtr |= (1<needppr_copy &= ~(1<needsdtr_copy |= (1<transinfo[tindex].goal_offset = 0; - p->transinfo[tindex].goal_period = 0; + p->transinfo[tindex].goal_period = 255; p->transinfo[tindex].goal_options = 0; + p->transinfo[tindex].goal_width = 0; + p->needppr &= ~(1<needsdtr &= ~(1<needwdtr &= ~(1<needppr_copy &= ~(1<needsdtr_copy &= ~(1<needwdtr_copy &= ~(1<needppr |= (p->needppr_copy & (1<needsdtr |= (p->needsdtr_copy & (1<needwdtr |= (p->needwdtr_copy & (1<dev_flags[tindex] &= ~DEVICE_PARITY_ERROR; } @@ -6600,6 +6524,7 @@ if (mesg_out != MSG_NOOP) { aic_outb(p, mesg_out, MSG_OUT); + aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO); scb = NULL; } aic_outb(p, CLRSCSIPERR, CLRSINT1); @@ -6791,7 +6716,7 @@ { struct aic7xxx_scb *scb = NULL; Scsi_Cmnd *cmd; - unsigned char scb_index; + unsigned char scb_index, tindex; #ifdef AIC7XXX_VERBOSE_DEBUGGING if( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) ) @@ -6817,23 +6742,21 @@ scb_index = p->qoutfifo[p->qoutfifonext]; p->qoutfifo[p->qoutfifonext++] = SCB_LIST_NULL; if ( scb_index >= p->scb_data->numscbs ) - scb = NULL; - else - scb = p->scb_data->scb_array[scb_index]; - if (scb == NULL) { printk(WARN_LEAD "CMDCMPLT with invalid SCB index %d\n", p->host_no, -1, -1, -1, scb_index); continue; } - else if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL)) + scb = p->scb_data->scb_array[scb_index]; + if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL)) { printk(WARN_LEAD "CMDCMPLT without command for SCB %d, SCB flags " "0x%x, cmd 0x%lx\n", p->host_no, -1, -1, -1, scb_index, scb->flags, (unsigned long) scb->cmd); continue; } - else if (scb->flags & SCB_QUEUED_ABORT) + tindex = TARGET_INDEX(scb->cmd); + if (scb->flags & SCB_QUEUED_ABORT) { pause_sequencer(p); if ( ((aic_inb(p, LASTPHASE) & PHASE_MASK) != P_BUSFREE) && @@ -6856,6 +6779,43 @@ */ scb->flags &= ~(SCB_ABORT|SCB_RESET); } + else if (scb->flags & SCB_SENSE) + { + char *buffer = &scb->cmd->sense_buffer[0]; + if (scb->cmd == p->dev_dtr_cmnd[tindex]) + { + struct aic7xxx_scb *old_scb; + /* + * We have valid sense data, send it back immediately. + */ + old_scb = p->scb_data->scb_array[scb->cmd->next->tag]; + *old_scb->cmd->sense_buffer = *scb->cmd->sense_buffer; + old_scb->hscb->target_status = scb->hscb->target_status; + old_scb->cmd->result = scb->hscb->target_status; + old_scb->cmd->result |= (DID_ERROR << 16); + aic7xxx_status(old_scb->cmd) = scb->hscb->target_status; + scbq_remove(&p->waiting_scbs, old_scb); + scbq_remove(&p->delayed_scbs[tindex], old_scb); + scb->cmd->next = NULL; + aic7xxx_done(p, scb); + aic7xxx_done(p, old_scb); + continue; + } + else if (buffer[12] == 0x47 || buffer[12] == 0x54) + { + /* + * SCSI errors, run domain validation and re-run negotiation + */ + p->needdv |= (1<needppr |= (p->needppr_copy & (1<needsdtr |= (p->needsdtr_copy & (1<needwdtr |= (p->needwdtr_copy & (1<hscb->target_status)) { case QUEUE_FULL: @@ -6985,6 +6945,13 @@ if (intstat & SEQINT) { + /* + * Read the CCSCBCTL register to work around a bug in the Ultra2 cards + */ + if(p->features & AHC_ULTRA2) + { + aic_inb(p, CCSCBCTL); + } aic7xxx_handle_seqint(p, intstat); } @@ -7019,10 +6986,10 @@ p = (struct aic7xxx_host *)dev_id; if(!p) return; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,95) spin_lock_irqsave(&io_request_lock, cpu_flags); if(test_and_set_bit(AHC_IN_ISR_BIT, (void *)&p->flags)) { + spin_unlock_irqrestore(&io_request_lock, cpu_flags); return; } do @@ -7033,21 +7000,6 @@ aic7xxx_run_waiting_queues(p); clear_bit(AHC_IN_ISR_BIT, (void *)&p->flags); spin_unlock_irqrestore(&io_request_lock, cpu_flags); -#else - if(set_bit(AHC_IN_ISR_BIT, (int *)&p->flags)) - { - return; - } - DRIVER_LOCK - do - { - aic7xxx_isr(irq, dev_id, regs); - } while ( (aic_inb(p, INTSTAT) & INT_PEND) ); - DRIVER_UNLOCK - aic7xxx_done_cmds_complete(p); - aic7xxx_run_waiting_queues(p); - clear_bit(AHC_IN_ISR_BIT, (int *)&p->flags); -#endif } /*+F************************************************************************* @@ -7067,7 +7019,7 @@ * with queue depths for individual devices. It also allows tagged * queueing to be [en|dis]abled for a specific adapter. *-F*************************************************************************/ -static void +static int aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device) { int default_depth = 3; @@ -7077,6 +7029,14 @@ tindex = device->id | (device->channel << 3); target_mask = (1 << tindex); + if (p->dev_max_queue_depth[tindex] > 1) + { + /* + * We've already scanned this device, leave it alone + */ + return(p->dev_max_queue_depth[tindex]); + } + device->queue_depth = default_depth; p->dev_temp_queue_depth[tindex] = 1; p->dev_max_queue_depth[tindex] = 1; @@ -7145,6 +7105,7 @@ } } } + return(p->dev_max_queue_depth[tindex]); } /*+F************************************************************************* @@ -7172,8 +7133,7 @@ { if (device->host == host) { - aic7xxx_device_queue_depth(p, device); - scbnum += device->queue_depth; + scbnum += aic7xxx_device_queue_depth(p, device); } } while (scbnum > p->scb_data->numscbs) @@ -7481,7 +7441,6 @@ */ CLOCK_PULSE(p); aic_outb(p, 0, SEECTL); - CLOCK_PULSE(p); } /*+F************************************************************************* @@ -7757,8 +7716,6 @@ } } -#undef CLOCK_PULSE - /*+F************************************************************************* * Function: * aic785x_cable_detect @@ -7773,16 +7730,64 @@ unsigned char brdctl; aic_outb(p, BRDRW | BRDCS, BRDCTL); - udelay(1); + CLOCK_PULSE(p); aic_outb(p, 0, BRDCTL); - udelay(1); + CLOCK_PULSE(p); brdctl = aic_inb(p, BRDCTL); - udelay(1); + CLOCK_PULSE(p); *int_50 = !(brdctl & BRDDAT5); *ext_present = !(brdctl & BRDDAT6); *eeprom = (aic_inb(p, SPIOCAP) & EEPROM); } +#undef CLOCK_PULSE + +/*+F************************************************************************* + * Function: + * aic2940_uwpro_cable_detect + * + * Description: + * Detect the cables that are present on the 2940-UWPro cards + * + * NOTE: This functions assumes the SEEPROM will have already been aquired + * prior to invocation of this function. + *-F*************************************************************************/ +static void +aic2940_uwpro_wide_cable_detect(struct aic7xxx_host *p, int *int_68, + int *ext_68, int *eeprom) +{ + unsigned char brdctl; + + /* + * First read the status of our cables. Set the rom bank to + * 0 since the bank setting serves as a multiplexor for the + * cable detection logic. BRDDAT5 controls the bank switch. + */ + write_brdctl(p, 0); + + /* + * Now we read the state of the internal 68 connector. BRDDAT6 + * is don't care, BRDDAT7 is internal 68. The cable is + * present if the bit is 0 + */ + brdctl = read_brdctl(p); + *int_68 = !(brdctl & BRDDAT7); + + /* + * Set the bank bit in brdctl and then read the external cable state + * and the EEPROM status + */ + write_brdctl(p, BRDDAT5); + brdctl = read_brdctl(p); + + *ext_68 = !(brdctl & BRDDAT6); + *eeprom = !(brdctl & BRDDAT7); + + /* + * We're done, the calling function will release the SEEPROM for us + */ +} + /*+F************************************************************************* * Function: * aic787x_cable_detect @@ -7887,59 +7892,182 @@ max_target = 8; aic_outb(p, SEEMS | SEECS, SEECTL); sxfrctl1 &= ~STPWEN; - if ( (p->adapter_control & CFAUTOTERM) || - (p->features & AHC_NEW_AUTOTERM) ) + /* + * The termination/cable detection logic is split into three distinct + * groups. Ultra2 and later controllers, 2940UW-Pro controllers, and + * older 7850, 7860, 7870, 7880, and 7895 controllers. Each has its + * own unique way of detecting their cables and writing the results + * back to the card. + */ + if (p->features & AHC_ULTRA2) { - if ( (p->adapter_control & CFAUTOTERM) && - !(p->features & AHC_NEW_AUTOTERM) ) + /* + * As long as user hasn't overridden term settings, always check the + * cable detection logic + */ + if (aic7xxx_override_term == -1) { - printk(KERN_INFO "(scsi%d) Warning - detected auto-termination\n", - p->host_no); - printk(KERN_INFO "(scsi%d) Please verify driver detected settings are " - "correct.\n", p->host_no); - printk(KERN_INFO "(scsi%d) If not, then please properly set the device " - "termination\n", p->host_no); - printk(KERN_INFO "(scsi%d) in the Adaptec SCSI BIOS by hitting CTRL-A " - "when prompted\n", p->host_no); - printk(KERN_INFO "(scsi%d) during machine bootup.\n", p->host_no); + aic7xxx_ultra2_term_detect(p, &enableSE_low, &enableSE_high, + &enableLVD_low, &enableLVD_high, + &eprom_present); + } + + /* + * If the user is overriding settings, then they have been preserved + * to here as fake adapter_control entries. Parse them and allow + * them to override the detected settings (if we even did detection). + */ + if (!(p->adapter_control & CFSEAUTOTERM)) + { + enableSE_low = (p->adapter_control & CFSTERM); + enableSE_high = (p->adapter_control & CFWSTERM); + } + if (!(p->adapter_control & CFAUTOTERM)) + { + enableLVD_low = enableLVD_high = (p->adapter_control & CFLVDSTERM); } - /* Configure auto termination. */ - if (p->features & AHC_NEW_AUTOTERM) + /* + * Now take those settings that we have and translate them into the + * values that must be written into the registers. + * + * Flash Enable = BRDDAT7 + * Secondary High Term Enable = BRDDAT6 + * Secondary Low Term Enable = BRDDAT5 + * LVD/Primary High Term Enable = BRDDAT4 + * LVD/Primary Low Term Enable = STPWEN bit in SXFRCTL1 + */ + if (enableLVD_low != 0) + { + sxfrctl1 |= STPWEN; + p->flags |= AHC_TERM_ENB_LVD; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) LVD/Primary Low byte termination " + "Enabled\n", p->host_no); + } + + if (enableLVD_high != 0) + { + brddat |= BRDDAT4; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) LVD/Primary High byte termination " + "Enabled\n", p->host_no); + } + + if (enableSE_low != 0) + { + brddat |= BRDDAT5; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) Secondary Low byte termination " + "Enabled\n", p->host_no); + } + + if (enableSE_high != 0) { - if (aic7xxx_override_term == -1) - aic7xxx_ultra2_term_detect(p, &enableSE_low, &enableSE_high, - &enableLVD_low, &enableLVD_high, - &eprom_present); - if (!(p->adapter_control & CFSEAUTOTERM)) + brddat |= BRDDAT6; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) Secondary High byte termination " + "Enabled\n", p->host_no); + } + } + else if (p->features & AHC_NEW_AUTOTERM) + { + /* + * The 50 pin connector termination is controlled by STPWEN in the + * SXFRCTL1 register. Since the Adaptec docs typically say the + * controller is not allowed to be in the middle of a cable and + * this is the only connection on that stub of the bus, there is + * no need to even check for narrow termination, it's simply + * always on. + */ + sxfrctl1 |= STPWEN; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) Narrow channel termination Enabled\n", + p->host_no); + + if (p->adapter_control & CFAUTOTERM) + { + aic2940_uwpro_wide_cable_detect(p, &internal68_present, + &external_present, + &eprom_present); + printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Int-68 %s, " + "Ext-68 %s)\n", p->host_no, + "Don't Care", + internal68_present ? "YES" : "NO", + external_present ? "YES" : "NO"); + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) EEPROM %s present.\n", p->host_no, + eprom_present ? "is" : "is not"); + if (internal68_present && external_present) { - enableSE_low = (p->adapter_control & CFSTERM); - enableSE_high = (p->adapter_control & CFWSTERM); + brddat = 0; + p->flags &= ~AHC_TERM_ENB_SE_HIGH; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) Wide channel termination Disabled\n", + p->host_no); } - if (!(p->adapter_control & CFAUTOTERM)) + else { - enableLVD_low = enableLVD_high = (p->adapter_control & CFLVDSTERM); + brddat = BRDDAT6; + p->flags |= AHC_TERM_ENB_SE_HIGH; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) Wide channel termination Enabled\n", + p->host_no); } - internal50_present = 0; - internal68_present = 1; - external_present = 1; - } - else if ( (p->chip & AHC_CHIPID_MASK) >= AHC_AIC7870 ) - { - aic787x_cable_detect(p, &internal50_present, &internal68_present, - &external_present, &eprom_present); } else { - aic785x_cable_detect(p, &internal50_present, &external_present, - &eprom_present); + /* + * The termination of the Wide channel is done more like normal + * though, and the setting of this termination is done by writing + * either a 0 or 1 to BRDDAT6 of the BRDDAT register + */ + if (p->adapter_control & CFWSTERM) + { + brddat = BRDDAT6; + p->flags |= AHC_TERM_ENB_SE_HIGH; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) Wide channel termination Enabled\n", + p->host_no); + } + else + { + brddat = 0; + } } - - if (max_target <= 8) - internal68_present = 0; - - if ( !(p->features & AHC_NEW_AUTOTERM) ) + } + else + { + if (p->adapter_control & CFAUTOTERM) { + if (p->flags & AHC_MOTHERBOARD) + { + printk(KERN_INFO "(scsi%d) Warning - detected auto-termination\n", + p->host_no); + printk(KERN_INFO "(scsi%d) Please verify driver detected settings " + "are correct.\n", p->host_no); + printk(KERN_INFO "(scsi%d) If not, then please properly set the " + "device termination\n", p->host_no); + printk(KERN_INFO "(scsi%d) in the Adaptec SCSI BIOS by hitting " + "CTRL-A when prompted\n", p->host_no); + printk(KERN_INFO "(scsi%d) during machine bootup.\n", p->host_no); + } + /* Configure auto termination. */ + + if ( (p->chip & AHC_CHIPID_MASK) >= AHC_AIC7870 ) + { + aic787x_cable_detect(p, &internal50_present, &internal68_present, + &external_present, &eprom_present); + } + else + { + aic785x_cable_detect(p, &internal50_present, &external_present, + &eprom_present); + } + + if (max_target <= 8) + internal68_present = 0; + if (max_target > 8) { printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Int-68 %s, " @@ -7955,100 +8083,73 @@ internal50_present ? "YES" : "NO", external_present ? "YES" : "NO"); } - } - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) EEPROM %s present.\n", p->host_no, - eprom_present ? "is" : "is not"); + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) EEPROM %s present.\n", p->host_no, + eprom_present ? "is" : "is not"); - /* - * Now set the termination based on what we found. BRDDAT6 - * controls wide termination enable. - * Flash Enable = BRDDAT7 - * SE High Term Enable = BRDDAT6 - * SE Low Term Enable = BRDDAT5 (7890) - * LVD High Term Enable = BRDDAT4 (7890) - */ - if ( !(p->features & AHC_NEW_AUTOTERM) && - (internal50_present && internal68_present && external_present) ) - { - printk(KERN_INFO "(scsi%d) Illegal cable configuration!! Only two\n", - p->host_no); - printk(KERN_INFO "(scsi%d) connectors on the SCSI controller may be " - "in use at a time!\n", p->host_no); /* - * Force termination (low and high byte) on. This is safer than - * leaving it completely off, especially since this message comes - * most often from motherboard controllers that don't even have 3 - * connectors, but instead are failing the cable detection. + * Now set the termination based on what we found. BRDDAT6 + * controls wide termination enable. + * Flash Enable = BRDDAT7 + * SE High Term Enable = BRDDAT6 */ - internal50_present = external_present = 0; - enableSE_high = enableSE_low = 1; - } - - if ((max_target > 8) && - ((external_present == 0) || (internal68_present == 0) || - (enableSE_high != 0))) - { - brddat |= BRDDAT6; - p->flags |= AHC_TERM_ENB_SE_HIGH; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n", + if (internal50_present && internal68_present && external_present) + { + printk(KERN_INFO "(scsi%d) Illegal cable configuration!! Only two\n", p->host_no); - } + printk(KERN_INFO "(scsi%d) connectors on the SCSI controller may be " + "in use at a time!\n", p->host_no); + /* + * Force termination (low and high byte) on. This is safer than + * leaving it completely off, especially since this message comes + * most often from motherboard controllers that don't even have 3 + * connectors, but instead are failing the cable detection. + */ + internal50_present = external_present = 0; + enableSE_high = enableSE_low = 1; + } - if ( (((internal50_present ? 1 : 0) + - (internal68_present ? 1 : 0) + - (external_present ? 1 : 0)) <= 1) || - (enableSE_low != 0) ) - { - if (p->features & AHC_NEW_AUTOTERM) - brddat |= BRDDAT5; - else - sxfrctl1 |= STPWEN; - p->flags |= AHC_TERM_ENB_SE_LOW; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n", - p->host_no); - } + if ((max_target > 8) && + ((external_present == 0) || (internal68_present == 0)) ) + { + brddat |= BRDDAT6; + p->flags |= AHC_TERM_ENB_SE_HIGH; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n", + p->host_no); + } - if (enableLVD_low != 0) - { - sxfrctl1 |= STPWEN; - p->flags |= AHC_TERM_ENB_LVD; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) LVD Low byte termination Enabled\n", - p->host_no); - } - - if (enableLVD_high != 0) - { - brddat |= BRDDAT4; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) LVD High byte termination Enabled\n", - p->host_no); + if ( ((internal50_present ? 1 : 0) + + (internal68_present ? 1 : 0) + + (external_present ? 1 : 0)) <= 1 ) + { + sxfrctl1 |= STPWEN; + p->flags |= AHC_TERM_ENB_SE_LOW; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n", + p->host_no); + } } - } - else - { - if (p->adapter_control & CFSTERM) + else /* p->adapter_control & CFAUTOTERM */ { - if (p->features & AHC_NEW_AUTOTERM) - brddat |= BRDDAT5; - else + if (p->adapter_control & CFSTERM) + { sxfrctl1 |= STPWEN; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n", - p->host_no); - } + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n", + p->host_no); + } - if (p->adapter_control & CFWSTERM) - { - brddat |= BRDDAT6; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n", - p->host_no); + if (p->adapter_control & CFWSTERM) + { + brddat |= BRDDAT6; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n", + p->host_no); + } } } + aic_outb(p, sxfrctl1, SXFRCTL1); write_brdctl(p, brddat); release_seeprom(p); @@ -8236,23 +8337,8 @@ } aic_outb(p, 0, SEQ_FLAGS); - /* - * We are starting to do real work on the card....it's possible we could - * generate some spurious interrupts at this point, especially in the - * event of a PCI error or some such. If there are other devices already - * registered on the same interrupt as us, this could cause the machine - * to lock up. So, we disable the interrupt this card is on until we - * finish our card setup. We only need to do this for modules, if we are - * compiled into the kernel then interrupts are already off during this - * part of the code. - */ -#ifdef MODULE - disable_irq(p->irq); -#endif - detect_maxscb(p); - printk("%d/%d SCBs\n", p->scb_data->maxhscbs, p->scb_data->maxscbs); if (aic7xxx_verbose & VERBOSE_PROBE2) { @@ -8277,12 +8363,7 @@ { unsigned char devconfig; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) pci_read_config_byte(p->pdev, DEVCONFIG, &devconfig); -#else - pcibios_read_config_byte(p->pci_bus, p->pci_device_fn, - DEVCONFIG, &devconfig); -#endif if ( (aic7xxx_stpwlev >> p->instance) & 0x01 ) { devconfig |= STPWLEVEL; @@ -8295,12 +8376,7 @@ if (aic7xxx_verbose & VERBOSE_PROBE2) printk("(scsi%d) Force clearing STPWLEVEL bit\n", p->host_no); } -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) pci_write_config_byte(p->pdev, DEVCONFIG, devconfig); -#else - pcibios_write_config_byte(p->pci_bus, p->pci_device_fn, - DEVCONFIG, devconfig); -#endif } } #endif @@ -8404,7 +8480,7 @@ * we won't have a power source for the SCSI termination, which means * we'll see infinite incoming bus resets. */ - if(p->flags & AHC_NO_STPWR) + if(p->flags & AHC_NO_STPWEN) aic_outb(p, ENSELTIMO | ENSCSIPERR, SIMODE1); else aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1); @@ -8484,9 +8560,6 @@ printk("(scsi%d) Unable to allocate hardware SCB array; " "failing detection.\n", p->host_no); aic_outb(p, 0, SIMODE1); -#ifdef MODULE - enable_irq(p->irq); -#endif p->irq = 0; return(0); } @@ -8670,9 +8743,6 @@ printk(KERN_WARNING "(scsi%d) Couldn't register IRQ %d, ignoring " "controller.\n", p->host_no, p->irq); aic_outb(p, 0, SIMODE1); -#ifdef MODULE - enable_irq(p->irq); -#endif p->irq = 0; return (0); } @@ -8682,10 +8752,6 @@ p->host_no, -1, -1 , -1); aic7xxx_clear_intstat(p); -#ifdef MODULE - enable_irq(p->irq); -#endif - unpause_sequencer(p, /* unpause_always */ TRUE); return (found); @@ -8715,10 +8781,10 @@ * In the future, we may call this function as a last resort for * error handling. Let's be nice and not do any unecessary delays. */ - wait = 1000; /* 1 second (1000 * 1 msec) */ + wait = 1000; /* 1 msec (1000 * 1 msec) */ while (--wait && !(aic_inb(p, HCNTRL) & CHIPRSTACK)) { - udelay(1); /* 1 msec */ + udelay(1); /* 1 usec */ } pause_sequencer(p); @@ -8794,7 +8860,7 @@ p->orderedtag = 0; for (i=0; itransinfo[i].goal_period = 0; + p->transinfo[i].goal_period = 255; p->transinfo[i].goal_offset = 0; p->transinfo[i].goal_options = 0; p->transinfo[i].goal_width = MSG_EXT_WDTR_BUS_8_BIT; @@ -9369,11 +9435,7 @@ /* * PCI-bus probe. */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) if (pci_present()) -#else - if (pcibios_present()) -#endif { struct { @@ -9412,7 +9474,7 @@ AHC_AIC7860_FE, 7, 32, C46 }, {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AHC_AIC7860, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MOTHERBOARD, AHC_AIC7860_FE, 7, 32, C46 }, {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AHC_AIC7860, @@ -9420,7 +9482,8 @@ AHC_AIC7860_FE, 8, 32, C46 }, {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AHC_AIC7870, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE, 9, + AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MOTHERBOARD, + AHC_AIC7870_FE, 9, 32, C46 }, {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AHC_AIC7870, AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE, 10, @@ -9437,7 +9500,8 @@ AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE, 13, 32, C46 }, {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7880, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 14, + AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MOTHERBOARD, + AHC_AIC7880_FE, 14, 32, C46 }, {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7881, AHC_AIC7880, AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 15, @@ -9460,105 +9524,93 @@ AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18, 32, C46 }, {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7887, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE | AHC_NEW_AUTOTERM, 18, + AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE | AHC_NEW_AUTOTERM, 19, 32, C46 }, {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7888, AHC_AIC7880, AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18, 32, C46 }, {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7895, AHC_AIC7895, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7895_FE, 19, + AHC_AIC7895_FE, 20, 32, C56_66 }, {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890, AHC_AIC7890, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7890_FE, 20, + AHC_AIC7890_FE, 21, 32, C46 }, {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890B, AHC_AIC7890, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7890_FE, 20, + AHC_AIC7890_FE, 21, 32, C46 }, {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2930U2, AHC_AIC7890, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7890_FE, 21, + AHC_AIC7890_FE, 22, 32, C46 }, {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7890_FE, 22, + AHC_AIC7890_FE, 23, 32, C46 }, {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7896, AHC_AIC7896, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7896_FE, 23, + AHC_AIC7896_FE, 24, 32, C56_66 }, {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3940U2, AHC_AIC7896, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7896_FE, 24, + AHC_AIC7896_FE, 25, 32, C56_66 }, {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3950U2D, AHC_AIC7896, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7896_FE, 25, + AHC_AIC7896_FE, 26, 32, C56_66 }, {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_1480A, AHC_AIC7860, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_NO_STPWR, - AHC_AIC7860_FE, 26, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_NO_STPWEN, + AHC_AIC7860_FE, 27, 32, C46 }, {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892A, AHC_AIC7892, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7892_FE, 27, + AHC_AIC7892_FE, 28, 32, C46 }, {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892B, AHC_AIC7892, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7892_FE, 27, + AHC_AIC7892_FE, 28, 32, C46 }, {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892D, AHC_AIC7892, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7892_FE, 27, + AHC_AIC7892_FE, 28, 32, C46 }, {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892P, AHC_AIC7892, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7892_FE, 27, + AHC_AIC7892_FE, 28, 32, C46 }, {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899A, AHC_AIC7899, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7899_FE, 28, + AHC_AIC7899_FE, 29, 32, C56_66 }, {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899B, AHC_AIC7899, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7899_FE, 28, + AHC_AIC7899_FE, 29, 32, C56_66 }, {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899D, AHC_AIC7899, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7899_FE, 28, + AHC_AIC7899_FE, 29, 32, C56_66 }, {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899P, AHC_AIC7899, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7899_FE, 28, + AHC_AIC7899_FE, 29, 32, C56_66 }, }; unsigned short command; unsigned int devconfig, i, oldverbose; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) struct pci_dev *pdev = NULL; -#else - int index; - unsigned int piobase, mmapbase; - unsigned char pci_bus, pci_devfn, pci_irq; -#endif for (i = 0; i < NUMBER(aic_pdevs); i++) { -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) pdev = NULL; while ((pdev = pci_find_device(aic_pdevs[i].vendor_id, aic_pdevs[i].device_id, - pdev))) -#else - index = 0; - while (!(pcibios_find_device(aic_pdevs[i].vendor_id, - aic_pdevs[i].device_id, - index++, &pci_bus, &pci_devfn)) ) -#endif - { + pdev))) { + if (pci_enable_device(pdev)) + continue; if ( i == 0 ) /* We found one, but it's the 7810 RAID cont. */ { if (aic7xxx_verbose & (VERBOSE_PROBE|VERBOSE_PROBE2)) @@ -9582,19 +9634,19 @@ /* * Read sundry information from PCI BIOS. */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) temp_p->irq = pdev->irq; temp_p->pdev = pdev; temp_p->pci_bus = pdev->bus->number; temp_p->pci_device_fn = pdev->devfn; - temp_p->base = pdev->resource[0].start; - temp_p->mbase = pdev->resource[1].start; + temp_p->base = pci_resource_start(pdev, 0); + temp_p->mbase = pci_resource_start(pdev, 1); current_p = list_p; while(current_p && temp_p) { if ( ((current_p->pci_bus == temp_p->pci_bus) && (current_p->pci_device_fn == temp_p->pci_device_fn)) || - (current_p->base == temp_p->base) ) + (temp_p->base && (current_p->base == temp_p->base)) || + (temp_p->mbase && (current_p->mbase == temp_p->mbase)) ) { /* duplicate PCI entry, skip it */ kfree(temp_p); @@ -9634,69 +9686,8 @@ devconfig |= 0x80000040; pci_write_config_dword(pdev, DEVCONFIG, devconfig); #endif /* AIC7XXX_STRICT_PCI_SETUP */ -#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) */ - temp_p->pci_bus = pci_bus; - temp_p->pci_device_fn = pci_devfn; - pcibios_read_config_byte(pci_bus, pci_devfn, PCI_INTERRUPT_LINE, - &pci_irq); - temp_p->irq = pci_irq; - pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_0, - &piobase); - temp_p->base = piobase; - pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_1, - &mmapbase); - temp_p->mbase = mmapbase; - temp_p->base &= PCI_BASE_ADDRESS_IO_MASK; - temp_p->mbase &= PCI_BASE_ADDRESS_MEM_MASK; - current_p = list_p; - while(current_p) - { - if ( ((current_p->pci_bus == temp_p->pci_bus) && - (current_p->pci_device_fn == temp_p->pci_device_fn)) || - (current_p->base == temp_p->base) ) - { - /* duplicate PCI entry, skip it */ - kfree(temp_p); - temp_p = NULL; - } - current_p = current_p->next; - } - if ( temp_p == NULL ) - continue; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk("aic7xxx: <%s> at PCI %d/%d/%d\n", - board_names[aic_pdevs[i].board_name_index], - temp_p->pci_bus, - PCI_SLOT(temp_p->pci_device_fn), - PCI_FUNC(temp_p->pci_device_fn)); - pcibios_read_config_word(pci_bus, pci_devfn, PCI_COMMAND, &command); - if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk("aic7xxx: Initial PCI_COMMAND value was 0x%x\n", - (int)command); - } -#ifdef AIC7XXX_STRICT_PCI_SETUP - command |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | - PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO; -#else - command |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO; -#endif - command &= ~PCI_COMMAND_INVALIDATE; - if (aic7xxx_pci_parity == 0) - command &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY); - pcibios_write_config_word(pci_bus, pci_devfn, PCI_COMMAND, command); -#ifdef AIC7XXX_STRICT_PCI_SETUP - pcibios_read_config_dword(pci_bus, pci_devfn, DEVCONFIG, &devconfig); - if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk("aic7xxx: Initial DEVCONFIG value was 0x%x\n", devconfig); - } - devconfig |= 0x80000040; - pcibios_write_config_dword(pci_bus, pci_devfn, DEVCONFIG, devconfig); -#endif /* AIC7XXX_STRICT_PCI_SETUP */ -#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) */ - if(check_region(temp_p->base, MAXREG - MINREG)) + if(temp_p->base && check_region(temp_p->base, MAXREG - MINREG)) { printk("aic7xxx: <%s> at PCI %d/%d/%d\n", board_names[aic_pdevs[i].board_name_index], @@ -9727,7 +9718,7 @@ } #ifdef MMAPIO - if ( !(temp_p->flags & AHC_MULTI_CHANNEL) || + if ( !(temp_p->base) || !(temp_p->flags & AHC_MULTI_CHANNEL) || ((temp_p->chip != (AHC_AIC7870 | AHC_PCI)) && (temp_p->chip != (AHC_AIC7880 | AHC_PCI))) ) { @@ -9735,11 +9726,7 @@ base = temp_p->mbase & PAGE_MASK; page_offset = temp_p->mbase - base; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) temp_p->maddr = ioremap_nocache(base, page_offset + 256); -#else - temp_p->maddr = vremap(base, page_offset + 256); -#endif if(temp_p->maddr) { temp_p->maddr += page_offset; @@ -9759,12 +9746,20 @@ PCI_FUNC(temp_p->pci_device_fn)); printk(KERN_INFO "aic7xxx: MMAPed I/O failed, reverting to " "Programmed I/O.\n"); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0) iounmap((void *) (((unsigned long) temp_p->maddr) & PAGE_MASK)); -#else - vfree((void *) (((unsigned long) temp_p->maddr) & PAGE_MASK)); -#endif temp_p->maddr = 0; + if(temp_p->base == 0) + { + printk("aic7xxx: <%s> at PCI %d/%d/%d\n", + board_names[aic_pdevs[i].board_name_index], + temp_p->pci_bus, + PCI_SLOT(temp_p->pci_device_fn), + PCI_FUNC(temp_p->pci_device_fn)); + printk("aic7xxx: Controller disabled by BIOS, ignoring.\n"); + kfree(temp_p); + temp_p = NULL; + continue; + } } } } @@ -9773,7 +9768,8 @@ /* * Lock out other contenders for our i/o space. */ - request_region(temp_p->base, MAXREG - MINREG, "aic7xxx"); + if(temp_p->base) + request_region(temp_p->base, MAXREG - MINREG, "aic7xxx"); /* * We HAVE to make sure the first pause_sequencer() and all other @@ -9825,12 +9821,7 @@ * bit of DEVCONFIG */ aic_outb(temp_p, sxfrctl1, SXFRCTL1); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) - pcibios_write_config_dword(temp_p->pci_bus, temp_p->pci_device_fn, - DEVCONFIG, devconfig); -#else pci_write_config_dword(temp_p->pdev, DEVCONFIG, devconfig); -#endif sxfrctl1 &= STPWEN; /* @@ -9865,7 +9856,6 @@ case AHC_AIC7895: /* 7895 */ case AHC_AIC7896: /* 7896/7 */ case AHC_AIC7899: /* 7899 */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) if (PCI_FUNC(pdev->devfn) != 0) { temp_p->flags |= AHC_CHNLB; @@ -9881,25 +9871,6 @@ devconfig |= SCBSIZE32; pci_write_config_dword(pdev, DEVCONFIG, devconfig); } -#else - if (PCI_FUNC(temp_p->pci_device_fn) != 0) - { - temp_p->flags |= AHC_CHNLB; - } - /* - * The 7895 is the only chipset that sets the SCBSIZE32 param - * in the DEVCONFIG register. The Ultra2 chipsets use - * the DSCOMMAND0 register instead. - */ - if ((temp_p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) - { - pcibios_read_config_dword(pci_bus, pci_devfn, DEVCONFIG, - &devconfig); - devconfig |= SCBSIZE32; - pcibios_write_config_dword(pci_bus, pci_devfn, DEVCONFIG, - devconfig); - } -#endif break; default: break; @@ -9964,12 +9935,7 @@ /* * Check the rev of the chipset before we change DSCOMMAND0 */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) pci_read_config_dword(pdev, DEVCONFIG, &devconfig); -#else - pcibios_read_config_dword(pci_bus, pci_devfn, DEVCONFIG, - &devconfig); -#endif if ((devconfig & 0xff) >= 1) { aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) | @@ -10039,12 +10005,7 @@ case AHC_AIC7895: case AHC_AIC7896: case AHC_AIC7899: -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) pci_read_config_dword(pdev, DEVCONFIG, &devconfig); -#else - pcibios_read_config_dword(pci_bus, pci_devfn, DEVCONFIG, - &devconfig); -#endif if (temp_p->features & AHC_ULTRA2) { if ( (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2) && @@ -10086,12 +10047,7 @@ "but not enabled\n"); } } -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) pci_write_config_dword(pdev, DEVCONFIG, devconfig); -#else - pcibios_write_config_dword(pci_bus, pci_devfn, DEVCONFIG, - devconfig); -#endif if ( (temp_p->flags & AHC_EXTERNAL_SRAM) && (temp_p->flags & AHC_CHNLB) ) aic_outb(temp_p, 1, CCSCBBADDR); @@ -10686,20 +10642,59 @@ (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) ) { p->transinfo[tindex].goal_period = syncrate->period; - if( !(syncrate->sxfr_ultra2 & 0x40) ) + if( p->transinfo[tindex].goal_period > 9 ) { p->transinfo[tindex].goal_options = 0; + p->needppr &= ~(1<needsdtr |= (1<needppr_copy &= ~(1<needsdtr_copy |= (1<transinfo[tindex].goal_width) + { + p->needwdtr |= (1<needwdtr_copy |= (1<transinfo[tindex].goal_width) + { + p->transinfo[tindex].goal_width = 0; + p->needwdtr &= ~(1<needwdtr_copy &= ~(1<transinfo[tindex].goal_offset = + p->transinfo[tindex].user_offset; + p->transinfo[tindex].goal_period = + p->transinfo[tindex].user_period; + p->transinfo[tindex].goal_options = + p->transinfo[tindex].user_options; + if( p->transinfo[tindex].goal_period <= 9 ) + { + p->needppr |= (1<needsdtr &= ~(1<needppr_copy |= (1<needsdtr_copy &= ~(1<needppr &= ~(1<needsdtr |= (1<needppr_copy &= ~(1<needsdtr_copy |= (1<transinfo[tindex].goal_offset = 0; - p->transinfo[tindex].goal_period = 0; + p->transinfo[tindex].goal_period = 255; p->transinfo[tindex].goal_options = 0; + p->transinfo[tindex].goal_width = 0; + p->needppr &= ~(1<needsdtr &= ~(1<needwdtr &= ~(1<needppr_copy &= ~(1<needsdtr_copy &= ~(1<needwdtr_copy &= ~(1<needppr |= (p->needppr_copy & (1<needsdtr |= (p->needsdtr_copy & (1<needwdtr |= (p->needwdtr_copy & (1<needdv &= ~(1<next entry so that the real SCSI command + * can be sent back to the mid layer code with SENSE data intact. We'll + * finish things up when the cmd gets sent back down to us, so no worries. */ - aic7xxx_build_negotiation_cmnd(p, cmd->next, tindex); + if(cmd->next) + { + aic7xxx_build_negotiation_cmnd(p, cmd->next, tindex); + } return; } @@ -10873,13 +10876,13 @@ */ hscb->control = 0; scb->tag_action = 0; + cmd->tag = hscb->tag; if (p->discenable & mask) { hscb->control |= DISCENB; if ( (p->tagenable & mask) && (cmd->cmnd[0] != TEST_UNIT_READY) ) { - cmd->tag = hscb->tag; p->dev_commands_sent[tindex]++; if (p->dev_commands_sent[tindex] < 200) { @@ -11321,13 +11324,6 @@ void aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) - int i, mask, found, need_tag; - struct aic7xxx_scb *scb; - unsigned char qinpos, hscbp; - - found = FALSE; -#endif printk("aic7xxx driver version %s/%s\n", AIC7XXX_C_VERSION, UTS_RELEASE); @@ -11340,121 +11336,7 @@ disable_irq(p->irq); aic7xxx_print_card(p); aic7xxx_print_scratch_ram(p); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) - for(i=0; idev_flags[i] & DEVICE_PRESENT) - { - mask = (0x01 << i); - printk(INFO_LEAD "dev_flags=0x%x, Pending:%c, PPR:%c/%c, WDTR:%c/%c, " - "SDTR:%c/%c, q_depth=%d:%d\n", - p->host_no, 0, i, 0, p->dev_flags[i], - (p->dtr_pending & mask) ? 'Y' : 'N', - (p->needppr & mask) ? 'Y' : 'N', - (p->needppr_copy & mask) ? 'Y' : 'N', - (p->needwdtr & mask) ? 'Y' : 'N', - (p->needwdtr_copy & mask) ? 'Y' : 'N', - (p->needsdtr & mask) ? 'Y' : 'N', - (p->needsdtr_copy & mask) ? 'Y' : 'N', - p->dev_active_cmds[i], - p->dev_max_queue_depth[i] ); - printk(INFO_LEAD "targ_scsirate=0x%x", p->host_no, 0, i, 0, - aic_inb(p, TARG_SCSIRATE + i)); - if (p->features & AHC_ULTRA2) - printk(", targ_offset=%d", aic_inb(p, TARG_OFFSET + i)); - printk("\n"); - } - } - /* - * Search for this command and see if we can't track it down, it's the - * one causing the timeout. Print out this command first, then all other - * active commands afterwords. - */ - need_tag = -1; - if ( cmd ) - { - scb = p->scb_data->scb_array[aic7xxx_position(cmd)]; - if ( (scb->flags & SCB_ACTIVE) && (scb->cmd == cmd) ) - { - printk("Timed out command is scb #%d:\n", scb->hscb->tag); - printk("Tag%d: flags=0x%x, control=0x%x, TCL=0x%x, %s\n", scb->hscb->tag, - scb->flags, scb->hscb->control, scb->hscb->target_channel_lun, - (scb->flags & SCB_WAITINGQ) ? "WAITINGQ" : "Sent" ); - need_tag = scb->hscb->tag; - if (scb->flags & SCB_WAITINGQ) found=TRUE; - } - } - printk("QINFIFO: (TAG) "); - qinpos = aic_inb(p, QINPOS); - while ( qinpos != p->qinfifonext ) - { - if (p->qinfifo[qinpos] == need_tag) - found=TRUE; - printk("%d ", p->qinfifo[qinpos++]); - } - printk("\n"); - printk("Current SCB: (SCBPTR/TAG/CONTROL) %d/%d/0x%x\n", aic_inb(p, SCBPTR), - aic_inb(p, SCB_TAG), aic_inb(p, SCB_CONTROL) ); - if (aic_inb(p, SCB_TAG) == need_tag) found=TRUE; - printk("WAITING_SCBS: (SCBPTR/TAG/CONTROL) %d->", - hscbp = aic_inb(p, WAITING_SCBH)); - while (hscbp != SCB_LIST_NULL) - { - aic_outb(p, hscbp, SCBPTR); - printk("%d/%d/0x%x ", hscbp, aic_inb(p, SCB_TAG), aic_inb(p, SCB_CONTROL)); - hscbp = aic_inb(p, SCB_NEXT); - if (aic_inb(p, SCB_TAG) == need_tag) found=TRUE; - } - printk("\n"); - printk("DISCONNECTED_SCBS: (SCBPTR/TAG/CONTROL) %d->", - hscbp = aic_inb(p, DISCONNECTED_SCBH)); - while (hscbp != SCB_LIST_NULL) - { - aic_outb(p, hscbp, SCBPTR); - printk("%d/%d/0x%x ", hscbp, aic_inb(p, SCB_TAG), aic_inb(p, SCB_CONTROL)); - hscbp = aic_inb(p, SCB_NEXT); - if (aic_inb(p, SCB_TAG) == need_tag) found=TRUE; - } - printk("\n"); - printk("FREE_SCBS: (SCBPTR/TAG/CONTROL) %d->", - hscbp = aic_inb(p, FREE_SCBH)); - while (hscbp != SCB_LIST_NULL) - { - aic_outb(p, hscbp, SCBPTR); - printk("%d/%d/0x%x ", hscbp, aic_inb(p, SCB_TAG), aic_inb(p, SCB_CONTROL)); - hscbp = aic_inb(p, SCB_NEXT); - } - printk("\n"); - - if (found == FALSE) - { - /* - * We haven't found the offending SCB yet, and it should be around - * somewhere, so go look for it in the cards SCBs. - */ - printk("SCBPTR CONTROL TAG NEXT\n"); - for(i=0; iscb_data->maxhscbs; i++) - { - aic_outb(p, i, SCBPTR); - printk(" %3d %02x %02x %02x\n", i, - aic_inb(p, SCB_CONTROL), aic_inb(p, SCB_TAG), - aic_inb(p, SCB_NEXT)); - } - } - - - for (i=0; i < p->scb_data->numscbs; i++) - { - scb = p->scb_data->scb_array[i]; - if ( (scb->flags & SCB_ACTIVE) && (scb->cmd != cmd) ) - { - printk("Tag%d: flags=0x%x, control=0x%x, TCL=0x%x, %s\n", scb->hscb->tag, - scb->flags, scb->hscb->control, scb->hscb->target_channel_lun, - (scb->flags & SCB_WAITINGQ) ? "WAITINGQ" : "Sent" ); - } - } -#endif - sti(); + spin_unlock_irq(&io_request_lock); for(;;) barrier(); } @@ -11500,7 +11382,6 @@ * we are following a straight code path without entering the scheduler * code. */ - pause_sequencer(p); while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR)) { @@ -12163,15 +12044,12 @@ if(p->irq) free_irq(p->irq, p); - release_region(p->base, MAXREG - MINREG); + if(p->base) + release_region(p->base, MAXREG - MINREG); #ifdef MMAPIO if(p->maddr) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) - vfree((void *) (((unsigned long) p->maddr) & PAGE_MASK)); -#else iounmap((void *) (((unsigned long) p->maddr) & PAGE_MASK)); -#endif } #endif /* MMAPIO */ prev = NULL; @@ -12242,31 +12120,7 @@ 0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f, 0xe0, 0xf1, 0xf4, 0xfc} }, }; -#ifdef CONFIG_PCI - static struct register_ranges cards_ns[] = { - { 0, {0,} }, /* none */ - { 0, {0,} }, /* 7771 */ - { 7, {0x04, 0x08, 0x0c, 0x0e, 0x10, 0x17, 0x28, 0x2b, 0x30, 0x33, - 0x3c, 0x41, 0x43, 0x47} }, - { 7, {0x04, 0x08, 0x0c, 0x0e, 0x10, 0x17, 0x28, 0x2b, 0x30, 0x33, - 0x3c, 0x41, 0x43, 0x47} }, - { 5, {0x04, 0x08, 0x0c, 0x0e, 0x10, 0x17, 0x30, 0x33, 0x3c, 0x41} }, - { 5, {0x04, 0x08, 0x0c, 0x0e, 0x10, 0x17, 0x30, 0x34, 0x3c, 0x47} }, - { 5, {0x04, 0x08, 0x0c, 0x1b, 0x30, 0x34, 0x3c, 0x43, 0xdc, 0xe3} }, - { 6, {0x04, 0x08, 0x0c, 0x0e, 0x10, 0x17, 0x30, 0x34, 0x3c, 0x47, - 0xdc, 0xe3} }, - { 6, {0x04, 0x08, 0x0c, 0x1b, 0x30, 0x34, 0x3c, 0x43, 0xdc, 0xe3, - 0xff, 0xff} }, - { 6, {0x04, 0x08, 0x0c, 0x1b, 0x30, 0x34, 0x3c, 0x43, 0xdc, 0xe3, - 0xff, 0xff} }, - { 6, {0x04, 0x08, 0x0c, 0x1b, 0x30, 0x34, 0x3c, 0x43, 0xdc, 0xe3, - 0xff, 0xff} } - }; -#endif chip = p->chip & AHC_CHIPID_MASK; - /* - * Let's run through the PCI space first.... - */ printk("%s at ", board_names[p->board_name_index]); switch(p->chip & ~AHC_CHIPID_MASK) @@ -12284,38 +12138,8 @@ break; } -#ifdef CONFIG_PCI - { - unsigned char temp; - - printk("PCI Dump:\n"); - k=0; - for(i=0; i KERNEL_VERSION(2,1,92) - pci_read_config_byte(p->pdev, j, &temp); -#else - pcibios_read_config_byte(p->pci_bus, p->pci_device_fn, j, &temp); -#endif - printk("%02x:%02x ", j, temp); - if(++k == 13) - { - printk("\n"); - k = 0; - } - } - } - } - if(k != 0) - printk("\n"); -#endif /* CONFIG_PCI */ - /* - * Now the registers on the card.... + * the registers on the card.... */ printk("Card Dump:\n"); k = 0; @@ -12335,21 +12159,6 @@ } if(k != 0) printk("\n"); - if (p->flags & AHC_SEEPROM_FOUND) - { - unsigned short *sc1; - sc1 = (unsigned short *)&p->sc; - - printk("SEEPROM dump.\n"); - for(i=1; i<=32; i++) - { - printk("0x%04x", sc1[i-1]); - if ( (i % 8) == 0 ) - printk("\n"); - else - printk(" "); - } - } /* * If this was an Ultra2 controller, then we just hosed the card in terms diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/aic7xxx.h linux/drivers/scsi/aic7xxx.h --- v2.4.0-test1/linux/drivers/scsi/aic7xxx.h Thu Nov 11 20:11:44 1999 +++ linux/drivers/scsi/aic7xxx.h Wed Jun 21 17:25:03 2000 @@ -23,21 +23,7 @@ #ifndef _aic7xxx_h #define _aic7xxx_h -#define AIC7XXX_H_VERSION "3.2.4" - -#ifndef LINUX_VERSION_CODE -#include -#endif - -#ifndef KERNEL_VERSION -#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) -#endif - -#if defined(__i386__) -# define AIC7XXX_BIOSPARAM aic7xxx_biosparam -#else -# define AIC7XXX_BIOSPARAM NULL -#endif +#define AIC7XXX_H_VERSION "5.2.0" /* * Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields @@ -61,7 +47,7 @@ abort: aic7xxx_abort, \ reset: aic7xxx_reset, \ slave_attach: NULL, \ - bios_param: AIC7XXX_BIOSPARAM, \ + bios_param: aic7xxx_biosparam, \ can_queue: 255, /* max simultaneous cmds */\ this_id: -1, /* scsi id of host adapter */\ sg_tablesize: 0, /* max scatter-gather cmds */\ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/aic7xxx_proc.c linux/drivers/scsi/aic7xxx_proc.c --- v2.4.0-test1/linux/drivers/scsi/aic7xxx_proc.c Sat Feb 12 11:22:11 2000 +++ linux/drivers/scsi/aic7xxx_proc.c Wed Jun 21 17:25:03 2000 @@ -172,7 +172,6 @@ #else size += sprintf(BLS, " AIC7XXX_PROC_STATS : Disabled\n"); #endif - size += sprintf(BLS, " AIC7XXX_RESET_DELAY : %d\n", AIC7XXX_RESET_DELAY); size += sprintf(BLS, "\n"); size += sprintf(BLS, "Adapter Configuration:\n"); size += sprintf(BLS, " SCSI Adapter: %s\n", diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/aic7xxx_seq.c linux/drivers/scsi/aic7xxx_seq.c --- v2.4.0-test1/linux/drivers/scsi/aic7xxx_seq.c Sat Feb 12 11:22:11 2000 +++ linux/drivers/scsi/aic7xxx_seq.c Wed Jun 21 17:25:03 2000 @@ -4,34 +4,33 @@ static unsigned char seqprog[] = { 0xff, 0x6a, 0x06, 0x08, 0x7f, 0x02, 0x04, 0x08, - 0x32, 0x6a, 0x00, 0x00, 0x12, 0x6a, 0x00, 0x00, 0xff, 0x6a, 0xd6, 0x09, 0xff, 0x6a, 0xdc, 0x09, - 0x00, 0x65, 0x42, 0x59, + 0x00, 0x65, 0xca, 0x58, 0xf7, 0x01, 0x02, 0x08, 0xff, 0x4e, 0xc8, 0x08, 0xbf, 0x60, 0xc0, 0x08, 0x60, 0x0b, 0x86, 0x68, - 0x40, 0x00, 0x0e, 0x68, + 0x40, 0x00, 0x0c, 0x68, 0x08, 0x1f, 0x3e, 0x10, 0x60, 0x0b, 0x86, 0x68, - 0x40, 0x00, 0x0e, 0x68, + 0x40, 0x00, 0x0c, 0x68, 0x08, 0x1f, 0x3e, 0x10, - 0xff, 0x3e, 0x4a, 0x60, - 0x40, 0xfa, 0x12, 0x78, + 0xff, 0x3e, 0x48, 0x60, + 0x40, 0xfa, 0x10, 0x78, 0xff, 0xf6, 0xd4, 0x08, 0x01, 0x4e, 0x9c, 0x18, 0x40, 0x60, 0xc0, 0x00, - 0x00, 0x4d, 0x12, 0x70, + 0x00, 0x4d, 0x10, 0x70, 0x01, 0x4e, 0x9c, 0x18, 0xbf, 0x60, 0xc0, 0x08, - 0x00, 0x6a, 0xbe, 0x5c, + 0x00, 0x6a, 0x3e, 0x5c, 0xff, 0x4e, 0xc8, 0x18, - 0x02, 0x6a, 0xd4, 0x5b, + 0x02, 0x6a, 0x54, 0x5b, 0xff, 0x52, 0x20, 0x09, 0x0d, 0x6a, 0x6a, 0x00, - 0x00, 0x52, 0x4a, 0x5c, + 0x00, 0x52, 0xca, 0x5b, 0x03, 0xb0, 0x52, 0x31, 0xff, 0xb0, 0x52, 0x09, 0xff, 0xb1, 0x54, 0x09, @@ -40,8 +39,8 @@ 0xff, 0x3e, 0x74, 0x09, 0xff, 0x90, 0x7c, 0x08, 0xff, 0x3e, 0x20, 0x09, - 0x00, 0x65, 0x50, 0x58, - 0x00, 0x65, 0x0e, 0x40, + 0x00, 0x65, 0x4e, 0x58, + 0x00, 0x65, 0x0c, 0x40, 0xf7, 0x1f, 0xca, 0x08, 0x08, 0xa1, 0xc8, 0x08, 0x00, 0x65, 0xca, 0x00, @@ -52,6 +51,7 @@ 0xf0, 0xa1, 0xc8, 0x08, 0x0f, 0x05, 0x0a, 0x08, 0x00, 0x05, 0x0a, 0x00, + 0xff, 0x6a, 0x0c, 0x08, 0x5a, 0x6a, 0x00, 0x04, 0x12, 0x65, 0x02, 0x00, 0x31, 0x6a, 0xca, 0x00, @@ -69,74 +69,14 @@ 0xff, 0x6c, 0x0a, 0x08, 0x20, 0x64, 0xca, 0x18, 0xff, 0x6c, 0x08, 0x0c, - 0x40, 0x0b, 0x0e, 0x69, - 0x80, 0x0b, 0x00, 0x79, - 0xa4, 0x6a, 0x06, 0x00, - 0x40, 0x6a, 0x16, 0x00, - 0x10, 0x03, 0xfc, 0x78, - 0xff, 0x50, 0xc8, 0x08, - 0x88, 0x6a, 0xcc, 0x00, - 0x49, 0x6a, 0x3a, 0x5c, - 0x01, 0x6a, 0x26, 0x01, - 0xff, 0x6a, 0xca, 0x08, - 0x08, 0x01, 0x02, 0x00, - 0x02, 0x0b, 0x9c, 0x78, - 0xf7, 0x01, 0x02, 0x08, - 0xff, 0x06, 0xcc, 0x08, - 0xff, 0x66, 0x32, 0x09, - 0x01, 0x65, 0xca, 0x18, - 0x80, 0x66, 0xaa, 0x78, - 0xff, 0x66, 0xa2, 0x08, - 0x10, 0x03, 0x9a, 0x68, - 0xfc, 0x65, 0xc8, 0x18, - 0x00, 0x65, 0xb2, 0x48, - 0xff, 0x6a, 0x32, 0x01, - 0x01, 0x64, 0x18, 0x19, - 0xff, 0x6a, 0x1a, 0x09, - 0xff, 0x6a, 0x1c, 0x09, - 0x84, 0x6a, 0x06, 0x00, - 0x08, 0x01, 0x02, 0x00, - 0x02, 0x0b, 0xbc, 0x78, - 0xff, 0x06, 0xc8, 0x08, - 0xff, 0x64, 0x32, 0x09, - 0xff, 0x6a, 0xca, 0x08, - 0x5b, 0x64, 0xc8, 0x28, - 0x00, 0x62, 0xc4, 0x18, - 0xfc, 0x65, 0xca, 0x18, - 0xff, 0x6a, 0xd4, 0x08, - 0xfa, 0x65, 0xca, 0x18, - 0xff, 0x6a, 0xd4, 0x08, - 0x04, 0x65, 0xca, 0x18, - 0x0b, 0x65, 0xca, 0x18, - 0xff, 0x65, 0xc8, 0x08, - 0x00, 0x8c, 0x18, 0x19, - 0x02, 0x0b, 0xd8, 0x78, - 0x01, 0x65, 0xde, 0x60, - 0xf7, 0x01, 0x02, 0x08, - 0xff, 0x06, 0x32, 0x09, - 0xff, 0x65, 0xca, 0x18, - 0xff, 0x65, 0xd8, 0x68, - 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xb0, 0x5c, - 0x40, 0x51, 0xf0, 0x78, - 0xe4, 0x6a, 0x06, 0x00, - 0x08, 0x01, 0x02, 0x00, - 0x04, 0x6a, 0x6c, 0x5b, - 0x01, 0x50, 0xa0, 0x18, - 0x00, 0x50, 0xf6, 0xe0, - 0xff, 0x6a, 0xa0, 0x08, - 0xff, 0x6a, 0x3a, 0x01, - 0x02, 0x6a, 0x22, 0x01, - 0x40, 0x51, 0xfc, 0x68, - 0xff, 0x6a, 0x06, 0x08, - 0x00, 0x65, 0x0e, 0x40, + 0x40, 0x0b, 0x96, 0x68, 0x20, 0x6a, 0x16, 0x00, 0xf0, 0x19, 0x6e, 0x08, 0x08, 0x6a, 0x18, 0x00, 0x08, 0x11, 0x22, 0x00, 0x08, 0x6a, 0x66, 0x58, 0x08, 0x6a, 0x68, 0x00, - 0x00, 0x65, 0x22, 0x41, + 0x00, 0x65, 0xaa, 0x40, 0x12, 0x6a, 0x00, 0x00, 0x40, 0x6a, 0x16, 0x00, 0xff, 0x3e, 0x20, 0x09, @@ -147,21 +87,21 @@ 0x08, 0x6a, 0x66, 0x58, 0x80, 0x6a, 0x68, 0x00, 0x80, 0x36, 0x6c, 0x00, - 0x00, 0x65, 0x1e, 0x5c, + 0x00, 0x65, 0x9e, 0x5b, 0xff, 0x3d, 0xc8, 0x08, - 0xbf, 0x64, 0x5a, 0x79, - 0x80, 0x64, 0x22, 0x72, - 0xa0, 0x64, 0x52, 0x72, - 0xc0, 0x64, 0x4a, 0x72, - 0xe0, 0x64, 0x92, 0x72, + 0xbf, 0x64, 0xe2, 0x78, + 0x80, 0x64, 0xac, 0x71, + 0xa0, 0x64, 0xdc, 0x71, + 0xc0, 0x64, 0xd4, 0x71, + 0xe0, 0x64, 0x1c, 0x72, 0x01, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0x22, 0x41, + 0x00, 0x65, 0xaa, 0x40, 0xf7, 0x11, 0x22, 0x08, - 0x00, 0x65, 0x42, 0x59, + 0x00, 0x65, 0xca, 0x58, 0xff, 0x06, 0xd4, 0x08, 0xf7, 0x01, 0x02, 0x08, - 0x09, 0x0c, 0x3c, 0x79, - 0x08, 0x0c, 0x0e, 0x68, + 0x09, 0x0c, 0xc4, 0x78, + 0x08, 0x0c, 0x0c, 0x68, 0x01, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0x26, 0x09, 0x02, 0x6a, 0x08, 0x30, @@ -173,25 +113,25 @@ 0x03, 0xa9, 0x18, 0x31, 0x03, 0xa9, 0x10, 0x30, 0x08, 0x6a, 0xcc, 0x00, - 0xa9, 0x6a, 0x34, 0x5c, - 0x00, 0x65, 0x7a, 0x41, + 0xa9, 0x6a, 0xb4, 0x5b, + 0x00, 0x65, 0x02, 0x41, 0xa8, 0x6a, 0x6a, 0x00, 0x79, 0x6a, 0x6a, 0x00, - 0x40, 0x3d, 0x62, 0x69, + 0x40, 0x3d, 0xea, 0x68, 0x04, 0x35, 0x6a, 0x00, - 0x00, 0x65, 0x8e, 0x5b, + 0x00, 0x65, 0x0e, 0x5b, 0x80, 0x6a, 0xd4, 0x01, - 0x10, 0x36, 0x4e, 0x69, + 0x10, 0x36, 0xd6, 0x68, 0x10, 0x36, 0x6c, 0x00, 0x07, 0xac, 0x10, 0x31, 0x03, 0x8c, 0x10, 0x30, 0x05, 0xa3, 0x70, 0x30, 0x88, 0x6a, 0xcc, 0x00, - 0xac, 0x6a, 0x2c, 0x5c, - 0x00, 0x65, 0x26, 0x5c, + 0xac, 0x6a, 0xac, 0x5b, + 0x00, 0x65, 0xa6, 0x5b, 0x38, 0x6a, 0xcc, 0x00, - 0xa3, 0x6a, 0x30, 0x5c, - 0xff, 0x38, 0x8a, 0x69, + 0xa3, 0x6a, 0xb0, 0x5b, + 0xff, 0x38, 0x12, 0x69, 0x80, 0x02, 0x04, 0x00, 0xe7, 0x35, 0x6a, 0x08, 0x03, 0x69, 0x18, 0x31, @@ -199,338 +139,334 @@ 0xff, 0x6a, 0x10, 0x00, 0xff, 0x6a, 0x12, 0x00, 0xff, 0x6a, 0x14, 0x00, - 0x01, 0x38, 0x90, 0x61, + 0x01, 0x38, 0x18, 0x61, 0xbf, 0x35, 0x6a, 0x08, 0x02, 0x6a, 0xf8, 0x01, 0xff, 0x69, 0xca, 0x08, 0xff, 0x35, 0x26, 0x09, - 0x04, 0x0b, 0x94, 0x69, - 0x04, 0x0b, 0xa0, 0x69, - 0x10, 0x0c, 0x96, 0x79, - 0x04, 0x0b, 0xa0, 0x69, + 0x04, 0x0b, 0x1c, 0x69, + 0x04, 0x0b, 0x28, 0x69, + 0x10, 0x0c, 0x1e, 0x79, + 0x04, 0x0b, 0x28, 0x69, 0xff, 0x6a, 0xca, 0x08, - 0x00, 0x35, 0x76, 0x5b, - 0x80, 0x02, 0xf4, 0x69, - 0xff, 0x65, 0xe4, 0x79, + 0x00, 0x35, 0xee, 0x5a, + 0x80, 0x02, 0x7c, 0x69, + 0xff, 0x65, 0x6c, 0x79, 0xff, 0x38, 0x70, 0x18, - 0xff, 0x38, 0xe4, 0x79, - 0x80, 0xea, 0xc0, 0x61, + 0xff, 0x38, 0x6c, 0x79, + 0x80, 0xea, 0x48, 0x61, 0xef, 0x38, 0xc8, 0x18, 0x80, 0x6a, 0xc8, 0x00, - 0x00, 0x65, 0xb2, 0x49, + 0x00, 0x65, 0x3a, 0x49, 0x33, 0x38, 0xc8, 0x28, 0xff, 0x64, 0xd0, 0x09, 0x04, 0x39, 0xc0, 0x31, 0x09, 0x6a, 0xd6, 0x01, - 0x80, 0xeb, 0xb8, 0x79, + 0x80, 0xeb, 0x40, 0x79, 0xf7, 0xeb, 0xd6, 0x09, - 0x08, 0xeb, 0xbc, 0x69, + 0x08, 0xeb, 0x44, 0x69, 0x01, 0x6a, 0xd6, 0x01, 0x08, 0xe9, 0x10, 0x31, 0x03, 0x8c, 0x10, 0x30, 0x88, 0x6a, 0xcc, 0x00, - 0x39, 0x6a, 0x32, 0x5c, + 0x39, 0x6a, 0xb2, 0x5b, 0x08, 0x6a, 0x18, 0x01, 0xff, 0x6a, 0x1a, 0x09, 0xff, 0x6a, 0x1c, 0x09, 0x0d, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xb0, 0x5c, - 0x88, 0x6a, 0xa0, 0x5c, - 0x00, 0x65, 0x26, 0x5c, + 0x00, 0x65, 0x30, 0x5c, + 0x88, 0x6a, 0x20, 0x5c, + 0x00, 0x65, 0xa6, 0x5b, 0xff, 0x6a, 0xc8, 0x08, 0x08, 0x39, 0x72, 0x18, 0x00, 0x3a, 0x74, 0x20, - 0x01, 0x0c, 0xdc, 0x79, - 0x10, 0x0c, 0x7a, 0x79, + 0x01, 0x0c, 0x64, 0x79, + 0x10, 0x0c, 0x02, 0x79, 0xff, 0x35, 0x26, 0x09, - 0x04, 0x0b, 0xe2, 0x69, - 0x00, 0x65, 0xfc, 0x59, + 0x04, 0x0b, 0x6a, 0x69, + 0x00, 0x65, 0x84, 0x59, 0x03, 0x08, 0x52, 0x31, 0xff, 0x38, 0x50, 0x09, 0xff, 0x08, 0x52, 0x09, 0xff, 0x09, 0x54, 0x09, 0xff, 0x0a, 0x56, 0x09, 0xff, 0x38, 0x50, 0x09, - 0x00, 0x65, 0x22, 0x41, - 0x00, 0x65, 0xfc, 0x59, + 0x00, 0x65, 0xaa, 0x40, + 0x00, 0x65, 0x84, 0x59, 0x7f, 0x02, 0x04, 0x08, 0xe1, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0x22, 0x41, - 0x04, 0x93, 0x12, 0x6a, + 0x00, 0x65, 0xaa, 0x40, + 0x04, 0x93, 0x9a, 0x69, 0xdf, 0x93, 0x26, 0x09, - 0x20, 0x93, 0x00, 0x6a, + 0x20, 0x93, 0x88, 0x69, 0x02, 0x93, 0x26, 0x01, - 0x01, 0x94, 0x02, 0x7a, - 0x01, 0x94, 0x02, 0x7a, - 0x01, 0x94, 0x02, 0x7a, - 0x01, 0x94, 0x02, 0x7a, - 0x01, 0x94, 0x02, 0x7a, - 0x01, 0x94, 0x02, 0x7a, - 0x10, 0x94, 0x10, 0x6a, - 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0x14, 0x6a, - 0xdf, 0x93, 0x26, 0x09, - 0x20, 0x93, 0x18, 0x6a, + 0x01, 0x94, 0x8a, 0x79, + 0x01, 0x94, 0x8a, 0x79, + 0x01, 0x94, 0x8a, 0x79, + 0x01, 0x94, 0x8a, 0x79, + 0x01, 0x94, 0x8a, 0x79, + 0x01, 0x94, 0x8a, 0x79, + 0x10, 0x94, 0x98, 0x69, + 0x7f, 0x05, 0xa0, 0x69, + 0x02, 0x03, 0xa0, 0x79, + 0x11, 0x0c, 0x9c, 0x79, + 0xd7, 0x93, 0x26, 0x09, + 0x28, 0x93, 0xa2, 0x69, 0x03, 0x08, 0x52, 0x31, 0xff, 0x38, 0x50, 0x09, 0x12, 0x01, 0x02, 0x00, 0xff, 0x6a, 0xd4, 0x0c, - 0x00, 0x65, 0x8e, 0x5b, + 0x00, 0x65, 0x0e, 0x5b, 0x05, 0xb4, 0x10, 0x31, 0x02, 0x6a, 0x1a, 0x31, 0x03, 0x8c, 0x10, 0x30, 0x88, 0x6a, 0xcc, 0x00, - 0xb4, 0x6a, 0x30, 0x5c, + 0xb4, 0x6a, 0xb0, 0x5b, 0xff, 0x6a, 0x1a, 0x09, 0xff, 0x6a, 0x1c, 0x09, - 0x00, 0x65, 0x26, 0x5c, - 0x3d, 0x6a, 0x76, 0x5b, + 0x00, 0x65, 0xa6, 0x5b, + 0x3d, 0x6a, 0xee, 0x5a, 0xac, 0x6a, 0x26, 0x01, - 0x04, 0x0b, 0x38, 0x6a, - 0x04, 0x0b, 0x3e, 0x6a, - 0x10, 0x0c, 0x3a, 0x7a, - 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0x40, 0x6a, - 0xdf, 0x93, 0x26, 0x09, - 0x20, 0x93, 0x44, 0x6a, + 0x04, 0x0b, 0xc2, 0x69, + 0x04, 0x0b, 0xc8, 0x69, + 0x10, 0x0c, 0xc4, 0x79, + 0x02, 0x03, 0xcc, 0x79, + 0x11, 0x0c, 0xc8, 0x79, + 0xd7, 0x93, 0x26, 0x09, + 0x28, 0x93, 0xce, 0x69, 0x12, 0x01, 0x02, 0x00, - 0x00, 0x65, 0x22, 0x41, - 0x00, 0x65, 0x8e, 0x5b, + 0x00, 0x65, 0xaa, 0x40, + 0x00, 0x65, 0x0e, 0x5b, 0xff, 0x06, 0x44, 0x09, - 0x00, 0x65, 0x22, 0x41, + 0x00, 0x65, 0xaa, 0x40, 0x10, 0x3d, 0x06, 0x00, 0xff, 0x34, 0xca, 0x08, - 0x80, 0x65, 0x76, 0x62, + 0x80, 0x65, 0x00, 0x62, 0x0f, 0xa1, 0xca, 0x08, 0x07, 0xa1, 0xca, 0x08, 0x40, 0xa0, 0xc8, 0x08, 0x00, 0x65, 0xca, 0x00, 0x80, 0x65, 0xca, 0x00, - 0x80, 0xa0, 0x66, 0x7a, + 0x80, 0xa0, 0xf0, 0x79, 0xff, 0x65, 0x0c, 0x08, - 0x00, 0x65, 0x78, 0x42, - 0x20, 0xa0, 0x7e, 0x7a, + 0x00, 0x65, 0x02, 0x42, + 0x20, 0xa0, 0x08, 0x7a, 0xff, 0x65, 0x0c, 0x08, - 0x00, 0x65, 0x1e, 0x5c, - 0xa0, 0x3d, 0x86, 0x62, + 0x00, 0x65, 0x9e, 0x5b, + 0xa0, 0x3d, 0x10, 0x62, 0x23, 0xa0, 0x0c, 0x08, - 0x00, 0x65, 0x1e, 0x5c, - 0xa0, 0x3d, 0x86, 0x62, - 0x00, 0xb9, 0x7e, 0x42, - 0xff, 0x65, 0x7e, 0x62, + 0x00, 0x65, 0x9e, 0x5b, + 0xa0, 0x3d, 0x10, 0x62, + 0x00, 0xb9, 0x08, 0x42, + 0xff, 0x65, 0x08, 0x62, 0xa1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, - 0x10, 0x51, 0x86, 0x72, + 0x10, 0x51, 0x10, 0x72, 0x40, 0x6a, 0x18, 0x00, 0xff, 0x65, 0x0c, 0x08, - 0x00, 0x65, 0x1e, 0x5c, - 0xa0, 0x3d, 0x50, 0x72, + 0x00, 0x65, 0x9e, 0x5b, + 0xa0, 0x3d, 0xda, 0x71, 0x40, 0x6a, 0x18, 0x00, 0xff, 0x34, 0xa6, 0x08, - 0x80, 0x34, 0x8e, 0x62, + 0x80, 0x34, 0x18, 0x62, 0x7f, 0xa0, 0x40, 0x09, 0x08, 0x6a, 0x68, 0x00, - 0x00, 0x65, 0x22, 0x41, - 0x64, 0x6a, 0x66, 0x5b, - 0x80, 0x64, 0x04, 0x6b, - 0x04, 0x64, 0xe6, 0x72, - 0x02, 0x64, 0xec, 0x72, - 0x00, 0x6a, 0xae, 0x72, - 0x03, 0x64, 0x00, 0x73, - 0x01, 0x64, 0xe2, 0x72, - 0x07, 0x64, 0x42, 0x73, - 0x08, 0x64, 0xaa, 0x72, - 0x23, 0x64, 0x46, 0x73, + 0x00, 0x65, 0xaa, 0x40, + 0x64, 0x6a, 0xe4, 0x5a, + 0x80, 0x64, 0x8e, 0x6a, + 0x04, 0x64, 0x70, 0x72, + 0x02, 0x64, 0x76, 0x72, + 0x00, 0x6a, 0x38, 0x72, + 0x03, 0x64, 0x8a, 0x72, + 0x01, 0x64, 0x6c, 0x72, + 0x07, 0x64, 0xcc, 0x72, + 0x08, 0x64, 0x34, 0x72, + 0x23, 0x64, 0xd0, 0x72, 0x11, 0x6a, 0x22, 0x01, - 0x07, 0x6a, 0x58, 0x5b, + 0x07, 0x6a, 0xd6, 0x5a, 0xff, 0x06, 0xd4, 0x08, - 0x00, 0x65, 0x22, 0x41, - 0xff, 0xa8, 0xb2, 0x6a, - 0xff, 0xa2, 0xca, 0x7a, + 0x00, 0x65, 0xaa, 0x40, + 0xff, 0xa8, 0x3c, 0x6a, + 0xff, 0xa2, 0x54, 0x7a, 0x01, 0x6a, 0x6a, 0x00, - 0x00, 0xb9, 0x4a, 0x5c, - 0xff, 0xa2, 0xca, 0x7a, + 0x00, 0xb9, 0xca, 0x5b, + 0xff, 0xa2, 0x54, 0x7a, 0x71, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, - 0x40, 0x51, 0xca, 0x62, + 0x40, 0x51, 0x54, 0x62, 0x0d, 0x6a, 0x6a, 0x00, - 0x00, 0xb9, 0x4a, 0x5c, + 0x00, 0xb9, 0xca, 0x5b, 0xff, 0x3e, 0x74, 0x09, 0xff, 0x90, 0x7c, 0x08, - 0x00, 0x65, 0x50, 0x58, - 0x00, 0x65, 0x34, 0x41, - 0x20, 0xa0, 0xd2, 0x6a, + 0x00, 0x65, 0x4e, 0x58, + 0x00, 0x65, 0xbc, 0x40, + 0x20, 0xa0, 0x5c, 0x6a, 0xff, 0x37, 0xc8, 0x08, - 0x00, 0x6a, 0xf4, 0x5b, - 0xff, 0x6a, 0x0a, 0x5c, + 0x00, 0x6a, 0x74, 0x5b, + 0xff, 0x6a, 0x8a, 0x5b, 0xff, 0xf8, 0xc8, 0x08, 0xff, 0x4f, 0xc8, 0x08, - 0x01, 0x6a, 0xf4, 0x5b, - 0x00, 0xb9, 0x0a, 0x5c, + 0x01, 0x6a, 0x74, 0x5b, + 0x00, 0xb9, 0x8a, 0x5b, 0x01, 0x4f, 0x9e, 0x18, 0x02, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0xb8, 0x5c, - 0x00, 0x65, 0x34, 0x41, + 0x00, 0x65, 0x38, 0x5c, + 0x00, 0x65, 0xbc, 0x40, 0x41, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0x22, 0x41, + 0x00, 0x65, 0xaa, 0x40, 0x04, 0xa0, 0x40, 0x01, - 0x00, 0x65, 0xd0, 0x5c, - 0x00, 0x65, 0x34, 0x41, - 0x10, 0x36, 0xaa, 0x7a, + 0x00, 0x65, 0x50, 0x5c, + 0x00, 0x65, 0xbc, 0x40, + 0x10, 0x36, 0x34, 0x7a, 0x05, 0x38, 0x46, 0x31, 0x04, 0x14, 0x58, 0x31, 0x03, 0xa9, 0x60, 0x31, 0xa3, 0x6a, 0xcc, 0x00, - 0x38, 0x6a, 0x30, 0x5c, + 0x38, 0x6a, 0xb0, 0x5b, 0xac, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0x32, 0x5c, - 0xa9, 0x6a, 0x34, 0x5c, - 0x00, 0x65, 0xaa, 0x42, + 0x14, 0x6a, 0xb2, 0x5b, + 0xa9, 0x6a, 0xb4, 0x5b, + 0x00, 0x65, 0x34, 0x42, 0xef, 0x36, 0x6c, 0x08, - 0x00, 0x65, 0xaa, 0x42, + 0x00, 0x65, 0x34, 0x42, 0x0f, 0x64, 0xc8, 0x08, 0x07, 0x64, 0xc8, 0x08, 0x00, 0x37, 0x6e, 0x00, 0xff, 0x6a, 0xa4, 0x00, - 0x00, 0x65, 0xc4, 0x5b, - 0xff, 0x51, 0x16, 0x73, - 0x20, 0x36, 0x20, 0x7b, - 0x00, 0x90, 0xb2, 0x5b, - 0x00, 0x65, 0x22, 0x43, + 0x00, 0x65, 0x44, 0x5b, + 0xff, 0x51, 0xa0, 0x72, + 0x20, 0x36, 0xaa, 0x7a, + 0x00, 0x90, 0x32, 0x5b, + 0x00, 0x65, 0xac, 0x42, 0xff, 0x06, 0xd4, 0x08, - 0x00, 0x65, 0x1e, 0x5c, - 0xe0, 0x3d, 0x3c, 0x63, - 0x20, 0x12, 0x3c, 0x63, - 0x51, 0x6a, 0x5c, 0x5b, - 0x00, 0x65, 0xac, 0x5b, + 0x00, 0x65, 0x9e, 0x5b, + 0xe0, 0x3d, 0xc6, 0x62, + 0x20, 0x12, 0xc6, 0x62, + 0x51, 0x6a, 0xda, 0x5a, + 0x00, 0x65, 0x2c, 0x5b, 0xff, 0x37, 0xc8, 0x08, - 0x00, 0xa1, 0x34, 0x63, - 0x04, 0xa0, 0x34, 0x7b, + 0x00, 0xa1, 0xbe, 0x62, + 0x04, 0xa0, 0xbe, 0x7a, 0xfb, 0xa0, 0x40, 0x09, 0x80, 0x36, 0x6c, 0x00, - 0x80, 0xa0, 0xaa, 0x7a, + 0x80, 0xa0, 0x34, 0x7a, 0x7f, 0xa0, 0x40, 0x09, - 0xff, 0x6a, 0x58, 0x5b, - 0x00, 0x65, 0xaa, 0x42, - 0x04, 0xa0, 0x3a, 0x7b, - 0x00, 0x65, 0xd0, 0x5c, - 0x00, 0x65, 0x3c, 0x43, - 0x00, 0x65, 0xb8, 0x5c, + 0xff, 0x6a, 0xd6, 0x5a, + 0x00, 0x65, 0x34, 0x42, + 0x04, 0xa0, 0xc4, 0x7a, + 0x00, 0x65, 0x50, 0x5c, + 0x00, 0x65, 0xc6, 0x42, + 0x00, 0x65, 0x38, 0x5c, 0x31, 0x6a, 0x22, 0x01, - 0x0c, 0x6a, 0x58, 0x5b, - 0x00, 0x65, 0xaa, 0x42, + 0x0c, 0x6a, 0xd6, 0x5a, + 0x00, 0x65, 0x34, 0x42, 0x61, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0xaa, 0x42, - 0x51, 0x6a, 0x5c, 0x5b, - 0x20, 0x0d, 0xaa, 0x6a, - 0xff, 0xa8, 0x54, 0x6b, - 0xff, 0xa9, 0x54, 0x6b, - 0xff, 0xaa, 0x54, 0x6b, - 0xff, 0xab, 0x54, 0x6b, - 0x00, 0x65, 0xaa, 0x42, + 0x00, 0x65, 0x34, 0x42, + 0x51, 0x6a, 0xda, 0x5a, 0x51, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0xaa, 0x42, + 0x00, 0x65, 0x34, 0x42, 0x10, 0x3d, 0x06, 0x00, 0xff, 0x65, 0x68, 0x0c, 0xff, 0x06, 0xd4, 0x08, - 0x01, 0x0c, 0x5e, 0x7b, - 0x04, 0x0c, 0x60, 0x6b, + 0x01, 0x0c, 0xdc, 0x7a, + 0x04, 0x0c, 0xde, 0x6a, 0xe0, 0x03, 0x7a, 0x08, - 0xe0, 0x3d, 0x72, 0x63, + 0xe0, 0x3d, 0xea, 0x62, 0xff, 0x65, 0xcc, 0x08, 0xff, 0x12, 0xda, 0x0c, 0xff, 0x06, 0xd4, 0x0c, - 0xff, 0x65, 0x0c, 0x08, - 0x02, 0x0b, 0x6e, 0x7b, - 0xff, 0x6a, 0xd4, 0x0c, 0xd1, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0x22, 0x41, + 0x00, 0x65, 0xaa, 0x40, 0xff, 0x65, 0x26, 0x09, - 0x01, 0x0b, 0x86, 0x6b, - 0x10, 0x0c, 0x78, 0x7b, - 0x04, 0x0b, 0x80, 0x6b, + 0x01, 0x0b, 0xfe, 0x6a, + 0x10, 0x0c, 0xf0, 0x7a, + 0x04, 0x0b, 0xf8, 0x6a, 0xff, 0x6a, 0xca, 0x08, - 0x04, 0x93, 0x84, 0x6b, - 0x01, 0x94, 0x82, 0x7b, - 0x10, 0x94, 0x84, 0x6b, + 0x04, 0x93, 0xfc, 0x6a, + 0x01, 0x94, 0xfa, 0x7a, + 0x10, 0x94, 0xfc, 0x6a, + 0x80, 0x3d, 0x02, 0x73, + 0x0f, 0x04, 0x06, 0x6b, + 0x02, 0x03, 0x06, 0x7b, + 0x11, 0x0c, 0x02, 0x7b, 0xc7, 0x93, 0x26, 0x09, 0xff, 0x99, 0xd4, 0x08, - 0x38, 0x93, 0x88, 0x6b, + 0x38, 0x93, 0x08, 0x6b, 0xff, 0x6a, 0xd4, 0x0c, - 0x80, 0x36, 0x8c, 0x6b, + 0x80, 0x36, 0x0c, 0x6b, 0x21, 0x6a, 0x22, 0x05, 0xff, 0x65, 0x20, 0x09, - 0xff, 0x51, 0x9a, 0x63, + 0xff, 0x51, 0x1a, 0x63, 0xff, 0x37, 0xc8, 0x08, - 0xa1, 0x6a, 0xa6, 0x43, + 0xa1, 0x6a, 0x26, 0x43, 0xff, 0x51, 0xc8, 0x08, - 0xb9, 0x6a, 0xa6, 0x43, + 0xb9, 0x6a, 0x26, 0x43, 0xff, 0x90, 0xa4, 0x08, - 0xff, 0xba, 0xaa, 0x73, + 0xff, 0xba, 0x2a, 0x73, 0xff, 0xba, 0x20, 0x09, 0xff, 0x65, 0xca, 0x18, - 0x00, 0x6c, 0x9e, 0x63, + 0x00, 0x6c, 0x1e, 0x63, 0xff, 0x90, 0xca, 0x0c, 0xff, 0x6a, 0xca, 0x04, - 0x20, 0x36, 0xbe, 0x7b, - 0x00, 0x90, 0x92, 0x5b, - 0xff, 0x65, 0xbe, 0x73, - 0xff, 0x52, 0xbc, 0x73, + 0x20, 0x36, 0x3e, 0x7b, + 0x00, 0x90, 0x12, 0x5b, + 0xff, 0x65, 0x3e, 0x73, + 0xff, 0x52, 0x3c, 0x73, 0xff, 0xba, 0xcc, 0x08, 0xff, 0x52, 0x20, 0x09, 0xff, 0x66, 0x74, 0x09, 0xff, 0x65, 0x20, 0x0d, 0xff, 0xba, 0x7e, 0x0c, - 0x00, 0x6a, 0xbe, 0x5c, + 0x00, 0x6a, 0x3e, 0x5c, 0x0d, 0x6a, 0x6a, 0x00, - 0x00, 0x51, 0x4a, 0x44, - 0xff, 0x3f, 0x18, 0x74, + 0x00, 0x51, 0xca, 0x43, + 0xff, 0x3f, 0x98, 0x73, 0xff, 0x6a, 0xa2, 0x00, - 0x00, 0x3f, 0x92, 0x5b, - 0xff, 0x65, 0x18, 0x74, + 0x00, 0x3f, 0x12, 0x5b, + 0xff, 0x65, 0x98, 0x73, 0x20, 0x36, 0x6c, 0x00, - 0x20, 0xa0, 0xd2, 0x6b, + 0x20, 0xa0, 0x52, 0x6b, 0xff, 0xb9, 0xa2, 0x0c, 0xff, 0x6a, 0xa2, 0x04, 0xff, 0x65, 0xa4, 0x08, 0xe0, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0x3e, 0x5c, + 0x45, 0x6a, 0xbe, 0x5b, 0x01, 0x6a, 0xd0, 0x01, 0x09, 0x6a, 0xd6, 0x01, - 0x80, 0xeb, 0xde, 0x7b, + 0x80, 0xeb, 0x5e, 0x7b, 0x01, 0x6a, 0xd6, 0x01, 0x01, 0xe9, 0xa4, 0x34, 0x88, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0x3e, 0x5c, + 0x45, 0x6a, 0xbe, 0x5b, 0x01, 0x6a, 0x18, 0x01, 0xff, 0x6a, 0x1a, 0x09, 0xff, 0x6a, 0x1c, 0x09, 0x0d, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0xb0, 0x5c, + 0x00, 0x65, 0x30, 0x5c, 0xff, 0x99, 0xa4, 0x0c, 0xff, 0x65, 0xa4, 0x08, 0xe0, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0x3e, 0x5c, + 0x45, 0x6a, 0xbe, 0x5b, 0x01, 0x6a, 0xd0, 0x01, 0x01, 0x6a, 0xdc, 0x05, 0x88, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0x3e, 0x5c, + 0x45, 0x6a, 0xbe, 0x5b, 0x01, 0x6a, 0x18, 0x01, 0xff, 0x6a, 0x1a, 0x09, 0xff, 0x6a, 0x1c, 0x09, 0x01, 0x6a, 0x26, 0x05, 0x01, 0x65, 0xd8, 0x31, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0x0e, 0x7c, + 0x80, 0xee, 0x8e, 0x7b, 0xff, 0x6a, 0xdc, 0x0d, 0xff, 0x65, 0x32, 0x09, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xb0, 0x44, + 0x00, 0x65, 0x30, 0x44, 0xff, 0x37, 0xc8, 0x08, - 0x00, 0x6a, 0xd4, 0x5b, + 0x00, 0x6a, 0x54, 0x5b, 0xff, 0x52, 0xa2, 0x0c, - 0x01, 0x0c, 0x1e, 0x7c, - 0x04, 0x0c, 0x1e, 0x6c, + 0x01, 0x0c, 0x9e, 0x7b, + 0x04, 0x0c, 0x9e, 0x6b, 0xe0, 0x03, 0x06, 0x08, 0xe0, 0x03, 0x7a, 0x0c, 0xff, 0x8c, 0x10, 0x08, @@ -553,29 +489,29 @@ 0x00, 0x6c, 0xda, 0x24, 0xff, 0x65, 0xc8, 0x08, 0xe0, 0x6a, 0xcc, 0x00, - 0x41, 0x6a, 0x3a, 0x5c, + 0x41, 0x6a, 0xba, 0x5b, 0xff, 0x90, 0xe2, 0x09, 0x20, 0x6a, 0xd0, 0x01, - 0x04, 0x35, 0x5c, 0x7c, + 0x04, 0x35, 0xdc, 0x7b, 0x1d, 0x6a, 0xdc, 0x01, - 0xdc, 0xee, 0x58, 0x64, - 0x00, 0x65, 0x68, 0x44, + 0xdc, 0xee, 0xd8, 0x63, + 0x00, 0x65, 0xe8, 0x43, 0x01, 0x6a, 0xdc, 0x01, 0x20, 0xa0, 0xd8, 0x31, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0x62, 0x7c, + 0x80, 0xee, 0xe2, 0x7b, 0x19, 0x6a, 0xdc, 0x01, - 0xd8, 0xee, 0x66, 0x64, + 0xd8, 0xee, 0xe6, 0x63, 0xff, 0x6a, 0xdc, 0x09, - 0x18, 0xee, 0x6a, 0x6c, + 0x18, 0xee, 0xea, 0x6b, 0xff, 0x6a, 0xd4, 0x0c, 0x88, 0x6a, 0xcc, 0x00, - 0x41, 0x6a, 0x3a, 0x5c, + 0x41, 0x6a, 0xba, 0x5b, 0x20, 0x6a, 0x18, 0x01, 0xff, 0x6a, 0x1a, 0x09, 0xff, 0x6a, 0x1c, 0x09, 0xff, 0x35, 0x26, 0x09, - 0x04, 0x35, 0x94, 0x6c, + 0x04, 0x35, 0x14, 0x6c, 0xa0, 0x6a, 0xca, 0x00, 0x20, 0x65, 0xc8, 0x18, 0xff, 0x6c, 0x32, 0x09, @@ -586,14 +522,14 @@ 0xff, 0x6c, 0x32, 0x09, 0xff, 0x6c, 0x32, 0x09, 0xff, 0x6c, 0x32, 0x09, - 0x00, 0x65, 0x80, 0x64, + 0x00, 0x65, 0x00, 0x64, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xb0, 0x5c, - 0x04, 0x35, 0x8c, 0x7b, - 0xa0, 0x6a, 0xa0, 0x5c, - 0x00, 0x65, 0xa2, 0x5c, - 0x00, 0x65, 0xa2, 0x5c, - 0x00, 0x65, 0xa2, 0x44, + 0x00, 0x65, 0x30, 0x5c, + 0x04, 0x35, 0x0c, 0x7b, + 0xa0, 0x6a, 0x20, 0x5c, + 0x00, 0x65, 0x22, 0x5c, + 0x00, 0x65, 0x22, 0x5c, + 0x00, 0x65, 0x22, 0x44, 0xff, 0x65, 0xcc, 0x08, 0xff, 0x99, 0xda, 0x08, 0xff, 0x99, 0xda, 0x08, @@ -602,19 +538,19 @@ 0xff, 0x99, 0xda, 0x08, 0xff, 0x99, 0xda, 0x08, 0xff, 0x99, 0xda, 0x0c, - 0x08, 0x94, 0xb0, 0x7c, + 0x08, 0x94, 0x30, 0x7c, 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0xb4, 0x6c, + 0x08, 0x93, 0x34, 0x6c, 0xff, 0x6a, 0xd4, 0x0c, 0xff, 0x40, 0x74, 0x09, 0xff, 0x90, 0x80, 0x08, 0xff, 0x6a, 0x72, 0x05, - 0xff, 0x40, 0xcc, 0x64, - 0xff, 0x3f, 0xc4, 0x64, + 0xff, 0x40, 0x4c, 0x64, + 0xff, 0x3f, 0x44, 0x64, 0xff, 0x6a, 0xca, 0x04, 0xff, 0x3f, 0x20, 0x09, 0x01, 0x6a, 0x6a, 0x00, - 0x00, 0xb9, 0x4a, 0x5c, + 0x00, 0xb9, 0xca, 0x5b, 0xff, 0xba, 0x7e, 0x0c, 0xff, 0x40, 0x20, 0x09, 0xff, 0xba, 0x80, 0x0c, @@ -622,20 +558,12 @@ 0xff, 0x90, 0x7e, 0x0c, }; -static int aic7xxx_patch13_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch13_func(struct aic7xxx_host *p) -{ - return ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895); -} - static int aic7xxx_patch12_func(struct aic7xxx_host *p); static int aic7xxx_patch12_func(struct aic7xxx_host *p) { - return ((p->features & AHC_CMD_CHAN) == 0); + return ((p->features & AHC_WIDE) != 0); } static int aic7xxx_patch11_func(struct aic7xxx_host *p); @@ -643,7 +571,7 @@ static int aic7xxx_patch11_func(struct aic7xxx_host *p) { - return ((p->features & AHC_WIDE) != 0); + return ((p->features & AHC_ULTRA2) == 0); } static int aic7xxx_patch10_func(struct aic7xxx_host *p); @@ -651,7 +579,7 @@ static int aic7xxx_patch10_func(struct aic7xxx_host *p) { - return ((p->features & AHC_ULTRA2) == 0); + return ((p->features & AHC_CMD_CHAN) == 0); } static int aic7xxx_patch9_func(struct aic7xxx_host *p); @@ -659,7 +587,7 @@ static int aic7xxx_patch9_func(struct aic7xxx_host *p) { - return ((p->features & AHC_ULTRA) != 0); + return ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895); } static int aic7xxx_patch8_func(struct aic7xxx_host *p); @@ -667,7 +595,7 @@ static int aic7xxx_patch8_func(struct aic7xxx_host *p) { - return ((p->features & AHC_ULTRA2) != 0); + return ((p->features & AHC_ULTRA) != 0); } static int aic7xxx_patch7_func(struct aic7xxx_host *p); @@ -675,7 +603,7 @@ static int aic7xxx_patch7_func(struct aic7xxx_host *p) { - return ((p->flags & AHC_PAGESCBS) == 0); + return ((p->features & AHC_ULTRA2) != 0); } static int aic7xxx_patch6_func(struct aic7xxx_host *p); @@ -683,7 +611,7 @@ static int aic7xxx_patch6_func(struct aic7xxx_host *p) { - return ((p->flags & AHC_PAGESCBS) != 0); + return ((p->flags & AHC_PAGESCBS) == 0); } static int aic7xxx_patch5_func(struct aic7xxx_host *p); @@ -691,7 +619,7 @@ static int aic7xxx_patch5_func(struct aic7xxx_host *p) { - return ((p->features & AHC_QUEUE_REGS) != 0); + return ((p->flags & AHC_PAGESCBS) != 0); } static int aic7xxx_patch4_func(struct aic7xxx_host *p); @@ -699,7 +627,7 @@ static int aic7xxx_patch4_func(struct aic7xxx_host *p) { - return ((p->features & AHC_TWIN) != 0); + return ((p->features & AHC_QUEUE_REGS) != 0); } static int aic7xxx_patch3_func(struct aic7xxx_host *p); @@ -707,7 +635,7 @@ static int aic7xxx_patch3_func(struct aic7xxx_host *p) { - return ((p->features & AHC_QUEUE_REGS) == 0); + return ((p->features & AHC_TWIN) != 0); } static int aic7xxx_patch2_func(struct aic7xxx_host *p); @@ -715,7 +643,7 @@ static int aic7xxx_patch2_func(struct aic7xxx_host *p) { - return ((p->features & AHC_CMD_CHAN) != 0); + return ((p->features & AHC_QUEUE_REGS) == 0); } static int aic7xxx_patch1_func(struct aic7xxx_host *p); @@ -723,7 +651,7 @@ static int aic7xxx_patch1_func(struct aic7xxx_host *p) { - return ((p->flags & AHC_TARGETMODE) != 0); + return ((p->features & AHC_CMD_CHAN) != 0); } static int aic7xxx_patch0_func(struct aic7xxx_host *p); @@ -740,84 +668,78 @@ skip_instr :10, skip_patch :12; } sequencer_patches[] = { - { aic7xxx_patch1_func, 2, 1, 2 }, - { aic7xxx_patch0_func, 3, 1, 1 }, - { aic7xxx_patch2_func, 4, 2, 1 }, - { aic7xxx_patch3_func, 8, 1, 1 }, - { aic7xxx_patch3_func, 9, 1, 1 }, - { aic7xxx_patch4_func, 12, 4, 1 }, - { aic7xxx_patch5_func, 17, 3, 2 }, - { aic7xxx_patch0_func, 20, 4, 1 }, - { aic7xxx_patch6_func, 24, 1, 1 }, - { aic7xxx_patch7_func, 27, 1, 1 }, - { aic7xxx_patch2_func, 30, 1, 2 }, - { aic7xxx_patch0_func, 31, 3, 1 }, - { aic7xxx_patch4_func, 40, 4, 1 }, - { aic7xxx_patch8_func, 44, 3, 2 }, - { aic7xxx_patch0_func, 47, 3, 1 }, - { aic7xxx_patch9_func, 52, 7, 1 }, - { aic7xxx_patch4_func, 60, 3, 1 }, - { aic7xxx_patch8_func, 63, 2, 1 }, - { aic7xxx_patch1_func, 68, 60, 1 }, - { aic7xxx_patch8_func, 162, 1, 2 }, - { aic7xxx_patch0_func, 163, 2, 1 }, - { aic7xxx_patch2_func, 167, 3, 3 }, - { aic7xxx_patch8_func, 167, 2, 1 }, - { aic7xxx_patch0_func, 170, 2, 1 }, - { aic7xxx_patch8_func, 173, 1, 2 }, - { aic7xxx_patch0_func, 174, 1, 1 }, - { aic7xxx_patch2_func, 178, 1, 1 }, - { aic7xxx_patch2_func, 181, 3, 2 }, - { aic7xxx_patch0_func, 184, 5, 1 }, - { aic7xxx_patch2_func, 192, 2, 3 }, - { aic7xxx_patch8_func, 192, 1, 1 }, - { aic7xxx_patch0_func, 194, 3, 1 }, - { aic7xxx_patch10_func, 198, 1, 2 }, - { aic7xxx_patch0_func, 199, 1, 1 }, - { aic7xxx_patch8_func, 200, 7, 2 }, - { aic7xxx_patch0_func, 207, 1, 1 }, - { aic7xxx_patch2_func, 212, 14, 3 }, - { aic7xxx_patch10_func, 225, 1, 1 }, - { aic7xxx_patch0_func, 226, 9, 1 }, - { aic7xxx_patch8_func, 240, 2, 1 }, - { aic7xxx_patch8_func, 242, 1, 1 }, - { aic7xxx_patch10_func, 243, 6, 3 }, - { aic7xxx_patch2_func, 243, 2, 2 }, - { aic7xxx_patch0_func, 245, 4, 1 }, - { aic7xxx_patch8_func, 250, 1, 1 }, - { aic7xxx_patch8_func, 254, 19, 1 }, - { aic7xxx_patch2_func, 274, 3, 3 }, - { aic7xxx_patch10_func, 276, 1, 1 }, - { aic7xxx_patch0_func, 277, 5, 1 }, - { aic7xxx_patch10_func, 282, 1, 2 }, - { aic7xxx_patch0_func, 283, 9, 1 }, - { aic7xxx_patch11_func, 299, 1, 2 }, - { aic7xxx_patch0_func, 300, 1, 1 }, - { aic7xxx_patch5_func, 361, 1, 2 }, - { aic7xxx_patch0_func, 362, 1, 1 }, - { aic7xxx_patch3_func, 365, 1, 1 }, - { aic7xxx_patch2_func, 375, 3, 2 }, - { aic7xxx_patch0_func, 378, 5, 1 }, - { aic7xxx_patch11_func, 386, 1, 2 }, - { aic7xxx_patch0_func, 387, 1, 1 }, - { aic7xxx_patch6_func, 392, 1, 1 }, - { aic7xxx_patch8_func, 420, 1, 2 }, - { aic7xxx_patch0_func, 421, 5, 1 }, - { aic7xxx_patch1_func, 438, 3, 1 }, - { aic7xxx_patch10_func, 443, 11, 1 }, - { aic7xxx_patch2_func, 491, 7, 2 }, - { aic7xxx_patch0_func, 498, 8, 1 }, - { aic7xxx_patch2_func, 507, 4, 2 }, - { aic7xxx_patch0_func, 511, 6, 1 }, - { aic7xxx_patch2_func, 517, 4, 2 }, - { aic7xxx_patch0_func, 521, 3, 1 }, - { aic7xxx_patch12_func, 531, 10, 1 }, - { aic7xxx_patch2_func, 550, 17, 4 }, - { aic7xxx_patch13_func, 558, 4, 2 }, - { aic7xxx_patch0_func, 562, 2, 1 }, - { aic7xxx_patch0_func, 567, 33, 1 }, - { aic7xxx_patch12_func, 600, 4, 1 }, - { aic7xxx_patch6_func, 604, 2, 1 }, - { aic7xxx_patch6_func, 607, 9, 1 }, + { aic7xxx_patch1_func, 3, 2, 1 }, + { aic7xxx_patch2_func, 7, 1, 1 }, + { aic7xxx_patch2_func, 8, 1, 1 }, + { aic7xxx_patch3_func, 11, 4, 1 }, + { aic7xxx_patch4_func, 16, 3, 2 }, + { aic7xxx_patch0_func, 19, 4, 1 }, + { aic7xxx_patch5_func, 23, 1, 1 }, + { aic7xxx_patch6_func, 26, 1, 1 }, + { aic7xxx_patch1_func, 29, 1, 2 }, + { aic7xxx_patch0_func, 30, 3, 1 }, + { aic7xxx_patch3_func, 39, 4, 1 }, + { aic7xxx_patch7_func, 43, 3, 2 }, + { aic7xxx_patch0_func, 46, 3, 1 }, + { aic7xxx_patch8_func, 52, 7, 1 }, + { aic7xxx_patch3_func, 60, 3, 1 }, + { aic7xxx_patch7_func, 63, 2, 1 }, + { aic7xxx_patch7_func, 102, 1, 2 }, + { aic7xxx_patch0_func, 103, 2, 1 }, + { aic7xxx_patch7_func, 107, 2, 1 }, + { aic7xxx_patch9_func, 109, 1, 1 }, + { aic7xxx_patch10_func, 110, 2, 1 }, + { aic7xxx_patch7_func, 113, 1, 2 }, + { aic7xxx_patch0_func, 114, 1, 1 }, + { aic7xxx_patch1_func, 118, 1, 1 }, + { aic7xxx_patch1_func, 121, 3, 2 }, + { aic7xxx_patch0_func, 124, 5, 1 }, + { aic7xxx_patch1_func, 132, 2, 3 }, + { aic7xxx_patch7_func, 132, 1, 1 }, + { aic7xxx_patch0_func, 134, 3, 1 }, + { aic7xxx_patch11_func, 138, 1, 2 }, + { aic7xxx_patch0_func, 139, 1, 1 }, + { aic7xxx_patch7_func, 140, 7, 2 }, + { aic7xxx_patch0_func, 147, 1, 1 }, + { aic7xxx_patch1_func, 152, 14, 3 }, + { aic7xxx_patch11_func, 165, 1, 1 }, + { aic7xxx_patch0_func, 166, 9, 1 }, + { aic7xxx_patch7_func, 180, 2, 1 }, + { aic7xxx_patch7_func, 182, 1, 1 }, + { aic7xxx_patch11_func, 183, 6, 3 }, + { aic7xxx_patch1_func, 183, 2, 2 }, + { aic7xxx_patch0_func, 185, 4, 1 }, + { aic7xxx_patch7_func, 190, 1, 1 }, + { aic7xxx_patch7_func, 194, 20, 1 }, + { aic7xxx_patch1_func, 215, 3, 3 }, + { aic7xxx_patch11_func, 217, 1, 1 }, + { aic7xxx_patch0_func, 218, 5, 1 }, + { aic7xxx_patch11_func, 223, 1, 2 }, + { aic7xxx_patch0_func, 224, 9, 1 }, + { aic7xxx_patch12_func, 240, 1, 2 }, + { aic7xxx_patch0_func, 241, 1, 1 }, + { aic7xxx_patch4_func, 302, 1, 2 }, + { aic7xxx_patch0_func, 303, 1, 1 }, + { aic7xxx_patch2_func, 306, 1, 1 }, + { aic7xxx_patch1_func, 316, 3, 2 }, + { aic7xxx_patch0_func, 319, 5, 1 }, + { aic7xxx_patch12_func, 327, 1, 2 }, + { aic7xxx_patch0_func, 328, 1, 1 }, + { aic7xxx_patch5_func, 333, 1, 1 }, + { aic7xxx_patch11_func, 375, 15, 1 }, + { aic7xxx_patch1_func, 427, 7, 2 }, + { aic7xxx_patch0_func, 434, 8, 1 }, + { aic7xxx_patch1_func, 443, 4, 2 }, + { aic7xxx_patch0_func, 447, 6, 1 }, + { aic7xxx_patch1_func, 453, 4, 2 }, + { aic7xxx_patch0_func, 457, 3, 1 }, + { aic7xxx_patch10_func, 467, 10, 1 }, + { aic7xxx_patch1_func, 486, 17, 4 }, + { aic7xxx_patch9_func, 494, 4, 2 }, + { aic7xxx_patch0_func, 498, 2, 1 }, + { aic7xxx_patch0_func, 503, 33, 1 }, + { aic7xxx_patch10_func, 536, 4, 1 }, + { aic7xxx_patch5_func, 540, 2, 1 }, + { aic7xxx_patch5_func, 543, 9, 1 }, }; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/atp870u.c linux/drivers/scsi/atp870u.c --- v2.4.0-test1/linux/drivers/scsi/atp870u.c Tue Mar 14 19:10:40 2000 +++ linux/drivers/scsi/atp870u.c Mon Jun 19 13:42:40 2000 @@ -1,11 +1,15 @@ /* $Id: atp870u.c,v 1.0 1997/05/07 15:22:00 root Exp root $ * linux/kernel/atp870u.c * - * Copyright (C) 1997 Wu Ching Chen + * Copyright (C) 1997 Wu Ching Chen * 2.1.x update (C) 1998 Krzysztof G. Baranowski - * - * Marcelo Tosatti : SMP fixes - * + * + * Marcelo Tosatti : SMP fixes + * + * Wu Ching Chen : NULL pointer fixes 2000/06/02 + * support atp876 chip + * enable 32 bit fifo transfer + * support cdrom & remove device run ultra speed */ #include @@ -100,19 +104,19 @@ dev->in_int = 1; workportu = dev->ioport; tmport = workportu; - - if (dev->working != 0) + + if (dev->working != 0) { tmport += 0x1f; j = inb(tmport); - if((j&0x80)==0) + if ((j & 0x80) == 0) { - dev->in_int=0; + dev->in_int = 0; return; } tmpcip = dev->pciport; - if ((inb(tmpcip) & 0x08) != 0) + if ((inb(tmpcip) & 0x08) != 0) { tmpcip += 0x2; for (k=0; k < 1000; k++) @@ -124,7 +128,7 @@ if ((inb(tmpcip) & 0x01) == 0) { goto stop_dma; - } + } } } stop_dma: @@ -133,9 +137,9 @@ tmport -= 0x08; i = inb(tmport); - if ((j & 0x40) == 0) + if ((j & 0x40) == 0) { - if ((dev->last_cmd & 0x40) == 0) + if ((dev->last_cmd & 0x40) == 0) { dev->last_cmd = 0xff; } @@ -149,30 +153,32 @@ /* * Remap wide devices onto id numbers */ - + if ((target_id & 0x40) != 0) { target_id = (target_id & 0x07) | 0x08; } else { target_id &= 0x07; } - - if (i == 0x85) + + if (i == 0x85) { /* * Flip wide */ - if (dev->wide_idu != 0) + if (dev->wide_idu != 0) { tmport = workportu + 0x1b; - j = inb(tmport) & 0x0e; - j |= 0x01; - outb(j, tmport); + outb(0x01,tmport); + while ((inb(tmport) & 0x01) != 0x01) + { + outb(0x01,tmport); + } } /* * Issue more commands */ if (((dev->quhdu != dev->quendu) || (dev->last_cmd != 0xff)) && - (dev->in_snd == 0)) + (dev->in_snd == 0)) { send_s870(h); } @@ -182,7 +188,7 @@ dev->in_int = 0; return; } - if (i == 0x21) + if (i == 0x21) { tmport -= 0x05; adrcntu = 0; @@ -200,7 +206,7 @@ dev->in_int = 0; return; } - if ((i == 0x80) || (i == 0x8f)) + if ((i == 0x80) || (i == 0x8f)) { lun = 0; tmport -= 0x07; @@ -209,7 +215,7 @@ tmport += 0x0d; lun = inb(tmport) & 0x07; } else { - if (j == 0x41) + if (j == 0x41) { tmport += 0x02; adrcntu = 0; @@ -225,7 +231,7 @@ dev->in_int = 0; return; } - else + else { outb(0x46, tmport); dev->id[target_id].dirctu = 0x00; @@ -246,7 +252,7 @@ /* * Remap wide identifiers */ - if ((target_id & 0x10) != 0) + if ((target_id & 0x10) != 0) { target_id = (target_id & 0x07) | 0x08; } else { @@ -271,8 +277,21 @@ j |= dev->id[target_id].dirctu; outb(j, tmport++); outb(0x80, tmport); + + /* enable 32 bit fifo transfer */ + tmport = workportu + 0x3a; + if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) || + (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a)) + { + outb((unsigned char)((inb(tmport) & 0xf3) | 0x08),tmport); + } + else + { + outb((unsigned char)(inb(tmport) & 0xf3),tmport); + } + tmport = workportu + 0x1b; - j = inb(tmport) & 0x0e; + j = 0; id = 1; id = id << target_id; /* @@ -282,7 +301,11 @@ j |= 0x01; } outb(j, tmport); - + while ((inb(tmport) & 0x01) != j) + { + outb(j,tmport); + } + if (dev->id[target_id].last_lenu == 0) { tmport = workportu + 0x18; outb(0x08, tmport); @@ -290,7 +313,7 @@ return; } prd = dev->id[target_id].prd_posu; - while (adrcntu != 0) + while (adrcntu != 0) { id = ((unsigned short int *) (prd))[2]; if (id == 0) { @@ -334,19 +357,19 @@ dev->in_int = 0; return; } - + /* * Current scsi request on this target */ - + workrequ = dev->id[target_id].curr_req; - + if (i == 0x42) { errstus = 0x02; workrequ->result = errstus; goto go_42; } - if (i == 0x16) + if (i == 0x16) { errstus = 0; tmport -= 0x08; @@ -370,15 +393,17 @@ */ if (dev->wide_idu != 0) { tmport = workportu + 0x1b; - j = inb(tmport) & 0x0e; - j |= 0x01; - outb(j, tmport); + outb(0x01,tmport); + while ((inb(tmport) & 0x01) != 0x01) + { + outb(0x01,tmport); + } } /* * If there is stuff to send and nothing going then send it */ if (((dev->last_cmd != 0xff) || (dev->quhdu != dev->quendu)) && - (dev->in_snd == 0)) + (dev->in_snd == 0)) { send_s870(h); } @@ -439,9 +464,9 @@ dev->in_int = 0; return; } else { - tmport = workportu + 0x17; - inb(tmport); - dev->working = 0; +// tmport = workportu + 0x17; +// inb(tmport); +// dev->working = 0; dev->in_int = 0; return; } @@ -474,7 +499,7 @@ /* * Fake a timeout for missing targets */ - + if ((m & dev->active_idu) == 0) { req_p->result = 0x00040000; done(req_p); @@ -550,7 +575,17 @@ if ((dev->last_cmd != 0xff) && ((dev->last_cmd & 0x40) != 0)) { dev->last_cmd &= 0x0f; workrequ = dev->id[dev->last_cmd].curr_req; - goto cmd_subp; + if (workrequ != NULL) /* check NULL pointer */ + { + goto cmd_subp; + } + dev->last_cmd = 0xff; + if (dev->quhdu == dev->quendu) + { + dev->in_snd = 0; + restore_flags(flags); + return ; + } } dev->working++; j = dev->quhdu; @@ -591,6 +626,9 @@ workrequ->request_bufflen = 0x08; } } + if (dev->ata_cdbu[0] == 0x00) { + workrequ->request_bufflen = 0; + } /* * Why limit this ???? */ @@ -600,11 +638,11 @@ dev->ata_cdbu[4] = 0x24; } } - + tmport = workportu + 0x1b; - j = inb(tmport) & 0x0e; + j = 0; target_id = workrequ->target; - + /* * Wide ? */ @@ -612,13 +650,17 @@ w = w << target_id; if ((w & dev->wide_idu) != 0) { j |= 0x01; - } + } outb(j, tmport); - + while ((inb(tmport) & 0x01) != j) + { + outb(j,tmport); + } + /* * Write the command */ - + tmport = workportu; outb(workrequ->cmd_len, tmport++); outb(0x2c, tmport++); @@ -633,17 +675,17 @@ * Write the target */ outb(dev->id[target_id].devspu, tmport++); - + /* * Figure out the transfer size */ - if (workrequ->use_sg) + if (workrequ->use_sg) { l = 0; sgpnt = (struct scatterlist *) workrequ->request_buffer; - for (i = 0; i < workrequ->use_sg; i++) + for (i = 0; i < workrequ->use_sg; i++) { - if (sgpnt[i].length == 0 || workrequ->use_sg > ATP870U_SCATTER) + if (sgpnt[i].length == 0 || workrequ->use_sg > ATP870U_SCATTER) { panic("Foooooooood fight!"); } @@ -694,13 +736,13 @@ tmpcip = dev->pciport; prd = dev->id[target_id].prd_tableu; dev->id[target_id].prd_posu = prd; - + /* * Now write the request list. Either as scatter/gather or as * a linear chain. */ - - if (workrequ->use_sg) + + if (workrequ->use_sg) { sgpnt = (struct scatterlist *) workrequ->request_buffer; i = 0; @@ -737,8 +779,21 @@ outb(0x06, tmpcip); outb(0x00, tmpcip); tmpcip = tmpcip - 2; + + tmport = workportu + 0x3a; + if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) || + (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a)) + { + outb((unsigned char)((inb(tmport) & 0xf3) | 0x08),tmport); + } + else + { + outb((unsigned char)(inb(tmport) & 0xf3),tmport); + } + tmport = workportu + 0x1c; + if ((dev->ata_cdbu[0] == WRITE_6) || (dev->ata_cdbu[0] == WRITE_10) || - (dev->ata_cdbu[0] == WRITE_12) || (dev->ata_cdbu[0] == MODE_SELECT)) + (dev->ata_cdbu[0] == WRITE_12) || (dev->ata_cdbu[0] == MODE_SELECT)) { dev->id[target_id].dirctu = 0x20; if (inb(tmport) == 0) { @@ -752,7 +807,7 @@ restore_flags(flags); return; } - if (inb(tmport) == 0) + if (inb(tmport) == 0) { tmport = workportu + 0x18; outb(0x08, tmport); @@ -798,20 +853,20 @@ goto FUN_D7; } } - *val |= 0x4000; /* assert DB6 */ + *val |= 0x4000; /* assert DB6 */ outw(*val, tmport); - *val &= 0xdfff; /* assert DB5 */ + *val &= 0xdfff; /* assert DB5 */ outw(*val, tmport); FUN_D5: for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */ - if ((inw(tmport) & 0x2000) != 0) { /* DB5 all release? */ + if ((inw(tmport) & 0x2000) != 0) { /* DB5 all release? */ goto FUN_D5; } } - *val |= 0x8000; /* no DB4-0, assert DB7 */ + *val |= 0x8000; /* no DB4-0, assert DB7 */ *val &= 0xe0ff; outw(*val, tmport); - *val &= 0xbfff; /* release DB6 */ + *val &= 0xbfff; /* release DB6 */ outw(*val, tmport); FUN_D6: for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */ @@ -887,9 +942,9 @@ outb(k, tmport++); tmport = dev->ioport + 0x1b; if (dev->chip_veru == 4) { - outb((unsigned char) ((inb(tmport) & 0x0e) | 0x01), tmport); + outb(0x01, tmport); } else { - outb((unsigned char) (inb(tmport) & 0x0e), tmport); + outb(0x00, tmport); } wait_rdyok: tmport = dev->ioport + 0x18; @@ -917,17 +972,17 @@ outb(0, 0x80); - val = 0x0080; /* bsy */ + val = 0x0080; /* bsy */ tmport = dev->ioport + 0x1c; outw(val, tmport); - val |= 0x0040; /* sel */ + val |= 0x0040; /* sel */ outw(val, tmport); - val |= 0x0004; /* msg */ + val |= 0x0004; /* msg */ outw(val, tmport); inb(0x80); /* 2 deskew delay(45ns*2=90ns) */ val &= 0x007f; /* no bsy */ outw(val, tmport); - mydlyu(0xffff); /* recommanded SCAM selection response time */ + mydlyu(0xffff); /* recommanded SCAM selection response time */ mydlyu(0xffff); val &= 0x00fb; /* after 1ms no msg */ outw(val, tmport); @@ -977,7 +1032,7 @@ val |= 0x3f00; fun_scam(dev, &val); outb(3, 0x80); - val &= 0x00ff; /* isolation */ + val &= 0x00ff; /* isolation */ val |= 0x2000; fun_scam(dev, &val); outb(4, 0x80); @@ -1012,10 +1067,10 @@ printk(" \n%x %x %x %s\n ",assignid_map,mbuf[0],mbuf[1],&mbuf[2]); */ i = 15; j = mbuf[0]; - if ((j & 0x20) != 0) { /* bit5=1:ID upto 7 */ + if ((j & 0x20) != 0) { /* bit5=1:ID upto 7 */ i = 7; } - if ((j & 0x06) == 0) { /* IDvalid? */ + if ((j & 0x06) == 0) { /* IDvalid? */ goto G2Q5; } k = mbuf[1]; @@ -1030,7 +1085,7 @@ goto small_id; } G2Q5: /* srch from max acceptable ID# */ - k = i; /* max acceptable ID# */ + k = i; /* max acceptable ID# */ G2Q_LP: m = 1; m <<= k; @@ -1041,12 +1096,12 @@ k--; goto G2Q_LP; } -G2Q_QUIN: /* k=binID#, */ +G2Q_QUIN: /* k=binID#, */ assignid_map |= m; if (k < 8) { quintet[0] = 0x38; /* 1st dft ID<8 */ } else { - quintet[0] = 0x31; /* 1st ID>=8 */ + quintet[0] = 0x31; /* 1st ID>=8 */ } k &= 0x07; quintet[1] = g2q_tab[k]; @@ -1067,15 +1122,15 @@ void is870(unsigned long host, unsigned int wkport) { unsigned int tmport; - unsigned char i, j, k, rmb; + unsigned char i, j, k, rmb, n; unsigned short int m; static unsigned char mbuf[512]; - static unsigned char satn[9] = {0, 0, 0, 0, 0, 0, 0, 6, 6}; + static unsigned char satn[9] = {0, 0, 0, 0, 0, 0, 0, 6, 6}; static unsigned char inqd[9] = {0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6}; - static unsigned char synn[6] = {0x80, 1, 3, 1, 0x19, 0x0e}; + static unsigned char synn[6] = {0x80, 1, 3, 1, 0x19, 0x0e}; static unsigned char synu[6] = {0x80, 1, 3, 1, 0x0c, 0x0e}; static unsigned char synw[6] = {0x80, 1, 3, 1, 0x0c, 0x07}; - static unsigned char wide[6] = {0x80, 1, 2, 3, 1, 0}; + static unsigned char wide[6] = {0x80, 1, 2, 3, 1, 0}; struct atp_unit *dev = &atp_unit[host]; sync_idu = 0; @@ -1095,10 +1150,13 @@ printk(KERN_INFO " ID: %2d Host Adapter\n", dev->host_idu); continue; } + tmport = wkport + 0x1b; if (dev->chip_veru == 4) { - tmport = wkport + 0x1b; - j = (inb(tmport) & 0x0e) | 0x01; - outb(j, tmport); + outb(0x01, tmport); + } + else + { + outb(0x00, tmport); } tmport = wkport + 1; outb(0x08, tmport++); @@ -1174,10 +1232,9 @@ continue; } while (inb(tmport) != 0x8e); + tmport = wkport + 0x1b; if (dev->chip_veru == 4) { - tmport = wkport + 0x1b; - j = inb(tmport) & 0x0e; - outb(j, tmport); + outb(0x00, tmport); } tmport = wkport + 0x18; outb(0x08, tmport); @@ -1218,6 +1275,7 @@ printk(KERN_INFO " ID: %2d %s\n", i, &mbuf[8]); dev->id[i].devtypeu = mbuf[0]; rmb = mbuf[1]; + n = mbuf[7]; if (dev->chip_veru != 4) { goto not_wide; } @@ -1228,8 +1286,7 @@ goto not_wide; } tmport = wkport + 0x1b; - j = (inb(tmport) & 0x0e) | 0x01; - outb(j, tmport); + outb(0x01, tmport); tmport = wkport + 3; outb(satn[0], tmport++); outb(satn[1], tmport++); @@ -1368,13 +1425,15 @@ m = m << i; dev->wide_idu |= m; not_wide: - if ((dev->id[i].devtypeu == 0x00) || (dev->id[i].devtypeu == 0x07)) { + if ((dev->id[i].devtypeu == 0x00) || (dev->id[i].devtypeu == 0x07) || + ((dev->id[i].devtypeu == 0x05) && ((n & 0x10) != 0))) + { goto set_sync; } continue; set_sync: tmport = wkport + 0x1b; - j = inb(tmport) & 0x0e; + j = 0; if ((m & dev->wide_idu) != 0) { j |= 0x01; } @@ -1414,17 +1473,13 @@ while ((inb(tmport) & 0x80) == 0) { if ((inb(tmport) & 0x01) != 0) { tmport -= 0x06; - if (rmb != 0) { - outb(synn[j++], tmport); + if ((m & dev->wide_idu) != 0) { + outb(synw[j++], tmport); } else { - if ((m & dev->wide_idu) != 0) { - outb(synw[j++], tmport); + if ((m & dev->ultra_map) != 0) { + outb(synu[j++], tmport); } else { - if ((m & dev->ultra_map) != 0) { - outb(synu[j++], tmport); - } else { - outb(synn[j++], tmport); - } + outb(synn[j++], tmport); } } tmport += 0x06; @@ -1573,9 +1628,9 @@ int tmpcnt = 0; int count = 0; int result; - - static unsigned short devid[7] = { - 0x8002, 0x8010, 0x8020, 0x8030, 0x8040, 0x8050, 0 + + static unsigned short devid[8] = { + 0x8002, 0x8010, 0x8020, 0x8030, 0x8040, 0x8050, 0x8060, 0 }; printk(KERN_INFO "aec671x_detect: \n"); @@ -1615,7 +1670,7 @@ h = 0; while (devid[h] != 0) { pdev[2] = pci_find_device(0x1191, devid[h], pdev[2]); - if (pdev[2] == NULL) { + if (pdev[2] == NULL || pci_enable_device(pdev[2])) { h++; index = 0; continue; @@ -1650,7 +1705,7 @@ } /* Found an atp870u/w. */ - base_io = pdev[h]->resource[0].start; + base_io = pci_resource_start(pdev[h], 0); irq = pdev[h]->irq; error = pci_read_config_byte(pdev[h],0x49,&host_id); @@ -1687,6 +1742,13 @@ printk(KERN_ERR "Unable to allocate IRQ for Acard controller.\n"); goto unregister; } + + if (chip_ver[h] > 0x07) /* check if atp876 chip */ + { /* then enable terminator */ + tmport = base_io + 0x3e; + outb(0x30, tmport); + } + tmport = base_io + 0x3a; k = (inb(tmport) & 0xf3) | 0x10; outb(k, tmport); @@ -1725,7 +1787,7 @@ shpnt->n_io_port = 0x40; /* Number of bytes of I/O space used */ shpnt->irq = irq; restore_flags(flags); - request_region(base_io, 0x40, "atp870u"); /* Register the IO ports that we use */ + request_region(base_io, 0x40, "atp870u"); /* Register the IO ports that we use */ count++; index++; continue; @@ -1788,7 +1850,7 @@ } panic("Reset bus host not found !"); find_host: -/* SCpnt->result = 0x00080000; +/* SCpnt->result = 0x00080000; SCpnt->scsi_done(SCpnt); dev->working=0; dev->quhdu=0; @@ -1801,14 +1863,14 @@ { static char buffer[128]; - strcpy(buffer, "ACARD AEC-6710/6712 PCI Ultra/W SCSI-3 Adapter Driver V2.0+ac "); + strcpy(buffer, "ACARD AEC-6710/6712 PCI Ultra/W SCSI-3 Adapter Driver V2.1+ac "); return buffer; } int atp870u_set_info(char *buffer, int length, struct Scsi_Host *HBAptr) { - return -ENOSYS; /* Currently this is a no-op */ + return -ENOSYS; /* Currently this is a no-op */ } #define BLS buffer + len + size @@ -1846,7 +1908,7 @@ if (offset == 0) { memset(buff, 0, sizeof(buff)); } - size += sprintf(BLS, "ACARD AEC-671X Driver Version: 2.0+ac\n"); + size += sprintf(BLS, "ACARD AEC-671X Driver Version: 2.1+ac\n"); len += size; pos = begin + len; size = 0; @@ -1894,7 +1956,7 @@ int atp870u_release (struct Scsi_Host *pshost) { int h; - for (h = 0; h <= admaxu; h++) + for (h = 0; h <= admaxu; h++) { if (pshost == atp_host[h]) { int k; @@ -1907,7 +1969,7 @@ } } panic("atp870u: bad scsi host passed.\n"); - + } #ifdef MODULE diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/dmx3191d.c linux/drivers/scsi/dmx3191d.c --- v2.4.0-test1/linux/drivers/scsi/dmx3191d.c Tue Apr 11 15:09:18 2000 +++ linux/drivers/scsi/dmx3191d.c Mon Jun 19 13:42:40 2000 @@ -68,11 +68,10 @@ while ((pdev = pci_find_device(PCI_VENDOR_ID_DOMEX, PCI_DEVICE_ID_DOMEX_DMX3191D, pdev))) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13) - unsigned long port = pdev->base_address[0] & PCI_IOADDRESS_MASK; -#else - unsigned long port = pdev->resource[0].start; -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13) */ + unsigned long port = pci_resource_start (pdev, 0); + + if (pci_enable_device(pdev)) + continue; if (check_region(port, DMX3191D_REGION)) { dmx3191d_printk("region 0x%lx-0x%lx already reserved\n", diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c --- v2.4.0-test1/linux/drivers/scsi/eata.c Mon Mar 27 08:08:27 2000 +++ linux/drivers/scsi/eata.c Mon Jun 19 13:42:40 2000 @@ -829,7 +829,9 @@ if (!(dev = pci_find_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) break; - if (pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &addr)) continue; + addr = pci_resource_start (dev, 0); + + pci_enable_device (dev); /* XXX handle error */ #if defined(DEBUG_PCI_DETECT) printk("%s: tune_pci_port, bus %d, devfn 0x%x, addr 0x%x.\n", diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/eata_dma.c linux/drivers/scsi/eata_dma.c --- v2.4.0-test1/linux/drivers/scsi/eata_dma.c Thu Feb 10 17:11:13 2000 +++ linux/drivers/scsi/eata_dma.c Mon Jun 19 13:42:40 2000 @@ -1388,20 +1388,22 @@ #ifndef CONFIG_PCI printk("eata_dma: kernel PCI support not enabled. Skipping scan for PCI HBAs.\n"); #else - struct pci_dev *dev; + struct pci_dev *dev = NULL; u32 base, x; u8 pal1, pal2, pal3; - for(dev=NULL; dev = pci_find_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, dev);) { + while ((dev = pci_find_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, dev)) != NULL) { DBG(DBG_PROBE && DBG_PCI, printk("eata_dma: find_PCI, HBA at %s\n", dev->name)); + if (pci_enable_device(dev)) + continue; pci_set_master(dev); - base = dev->resource[0].flags; - if (!(base & PCI_BASE_ADDRESS_SPACE_IO)) { + base = pci_resource_flags(dev, 0); + if (base & IORESOURCE_MEM) { printk("eata_dma: invalid base address of device %s\n", dev->name); continue; } - base = dev->resource[0].start; + base = pci_resource_start(dev, 0); /* EISA tag there ? */ pal1 = inb(base); pal2 = inb(base + 1); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/eata_pio.c linux/drivers/scsi/eata_pio.c --- v2.4.0-test1/linux/drivers/scsi/eata_pio.c Tue Nov 23 22:42:21 1999 +++ linux/drivers/scsi/eata_pio.c Mon Jun 19 13:42:40 2000 @@ -878,19 +878,21 @@ #ifndef CONFIG_PCI printk("eata_dma: kernel PCI support not enabled. Skipping scan for PCI HBAs.\n"); #else - struct pci_dev *dev; + struct pci_dev *dev = NULL; u32 base, x; - for(dev=NULL; dev = pci_find_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, dev);) { + while ((dev = pci_find_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, dev)) != NULL) { DBG(DBG_PROBE && DBG_PCI, printk("eata_pio: find_PCI, HBA at %s\n", dev->name)); + if (pci_enable_device(dev)) + continue; pci_set_master(dev); - base = dev->resource[0].flags; - if (!(base & PCI_BASE_ADDRESS_SPACE_IO)) { + base = pci_resource_flags(dev, 0); + if (base & IORESOURCE_MEM) { printk("eata_pio: invalid base address of device %s\n", dev->name); continue; } - base = dev->resource[0].start; + base = pci_resource_start(dev, 0); /* EISA tag there ? */ if ((inb(base) == 0x12) && (inb(base + 1) == 0x14)) continue; /* Jep, it's forced, so move on */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c --- v2.4.0-test1/linux/drivers/scsi/fdomain.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/scsi/fdomain.c Mon Jun 19 13:42:40 2000 @@ -828,6 +828,7 @@ PCI_DEVICE_ID_FD_36C70, pdev)) == NULL) return 0; + if (pci_enable_device(pdev)) return 0; #if DEBUG_DETECT printk( "scsi: TMC-3260 detect:" @@ -840,7 +841,7 @@ /* We now have the appropriate device function for the FD board so we just read the PCI config info from the registers. */ - pci_base = pdev->resource[0].start; + pci_base = pci_resource_start(pdev, 0); pci_irq = pdev->irq; /* Now we have the I/O base address and interrupt from the PCI diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/gdth.c linux/drivers/scsi/gdth.c --- v2.4.0-test1/linux/drivers/scsi/gdth.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/scsi/gdth.c Mon Jun 19 13:42:40 2000 @@ -533,6 +533,8 @@ pdev = NULL; while ((pdev = pci_find_device(PCI_VENDOR_ID_VORTEX,device_id,pdev)) != NULL) { + if (pci_enable_device(pdev)) + continue; if (cnt >= MAXHA) return cnt; /* GDT PCI controller found, resources are already in pdev */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c --- v2.4.0-test1/linux/drivers/scsi/hosts.c Tue Apr 11 15:09:18 2000 +++ linux/drivers/scsi/hosts.c Tue Jun 20 14:14:51 2000 @@ -345,6 +345,14 @@ #include "../acorn/scsi/powertec.h" #endif +#ifdef CONFIG_SCSI_ARXESCSI +#include "../acorn/scsi/arxescsi.h" +#endif + +#ifdef CONFIG_I2O_SCSI +#include "../i2o/i2o_scsi.h" +#endif + #ifdef CONFIG_JAZZ_ESP #include "jazz_esp.h" #endif @@ -636,6 +644,9 @@ #ifdef CONFIG_SCSI_CUMANA_2 CUMANA_FAS216, #endif +#ifdef CONFIG_SCSI_ARXESCSI + ARXEScsi, +#endif #ifdef CONFIG_SCSI_ECOSCSI ECOSCSI_NCR5380, #endif @@ -655,6 +666,10 @@ #ifdef CONFIG_BLK_DEV_3W_XXXX_RAID TWXXXX, #endif +/* Put I2O last so that host specific controllers always win */ +#ifdef CONFIG_I2O_SCSI + I2OSCSI +#endif /* "Removable host adapters" below this line (Parallel Port/USB/other) */ #ifdef CONFIG_SCSI_PPA PPA, @@ -732,38 +747,41 @@ */ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){ - struct Scsi_Host * retval, *shpnt; + struct Scsi_Host * retval, *shpnt, *o_shp; Scsi_Host_Name *shn, *shn2; - int new = 1; + int flag_new = 1; + const char * hname; + size_t hname_len; retval = (struct Scsi_Host *)kmalloc(sizeof(struct Scsi_Host) + j, - (tpnt->unchecked_isa_dma && j ? GFP_DMA : 0) | GFP_ATOMIC); + (tpnt->unchecked_isa_dma && j ? + GFP_DMA : 0) | GFP_ATOMIC); memset(retval, 0, sizeof(struct Scsi_Host) + j); /* trying to find a reserved entry (host_no) */ - for (shn = scsi_host_no_list;shn;shn = shn->next) - if (!(shn->host_registered) && shn->loaded_as_module && tpnt->proc_dir && - tpnt->proc_dir->name && !strncmp(tpnt->proc_dir->name, shn->name, strlen(tpnt->proc_dir->name))) { - new = 0; + hname = (tpnt->proc_name) ? tpnt->proc_name : ""; + hname_len = strlen(hname); + for (shn = scsi_host_no_list;shn;shn = shn->next) { + if (!(shn->host_registered) && shn->loaded_as_module && + (hname_len > 0) && (0 == strncmp(hname, shn->name, hname_len))) { + flag_new = 0; retval->host_no = shn->host_no; shn->host_registered = 1; shn->loaded_as_module = scsi_loadable_module_flag; break; } + } atomic_set(&retval->host_active,0); retval->host_busy = 0; retval->host_failed = 0; if(j > 0xffff) panic("Too many extra bytes requested\n"); retval->extra_bytes = j; retval->loaded_as_module = scsi_loadable_module_flag; - if (new) { - int len = 0; + if (flag_new) { shn = (Scsi_Host_Name *) kmalloc(sizeof(Scsi_Host_Name), GFP_ATOMIC); - if (tpnt->proc_dir) - len = strlen(tpnt->proc_dir->name); - shn->name = kmalloc(len+1, GFP_ATOMIC); - if (tpnt->proc_dir) - strncpy(shn->name, tpnt->proc_dir->name, len); - shn->name[len] = 0; + shn->name = kmalloc(hname_len + 1, GFP_ATOMIC); + if (hname_len > 0) + strncpy(shn->name, hname, hname_len); + shn->name[hname_len] = 0; shn->host_no = max_scsi_hosts++; shn->host_registered = 1; shn->loaded_as_module = scsi_loadable_module_flag; @@ -827,11 +845,26 @@ if(!scsi_hostlist) scsi_hostlist = retval; - else - { + else { shpnt = scsi_hostlist; - while(shpnt->next) shpnt = shpnt->next; - shpnt->next = retval; + if (retval->host_no < shpnt->host_no) { + retval->next = shpnt; + wmb(); /* want all to see these writes in this order */ + scsi_hostlist = retval; + } + else { + for (o_shp = shpnt, shpnt = shpnt->next; shpnt; + o_shp = shpnt, shpnt = shpnt->next) { + if (retval->host_no < shpnt->host_no) { + retval->next = shpnt; + wmb(); + o_shp->next = retval; + break; + } + } + if (! shpnt) + o_shp->next = retval; + } } return retval; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/in2000.h linux/drivers/scsi/in2000.h --- v2.4.0-test1/linux/drivers/scsi/in2000.h Thu Nov 11 20:11:47 1999 +++ linux/drivers/scsi/in2000.h Fri Jun 23 21:31:58 2000 @@ -34,8 +34,10 @@ #define DEBUGGING_ON /* enable command-line debugging bitmask */ #define DEBUG_DEFAULTS 0 /* default bitmask - change from command-line */ +#ifdef __i386__ #define FAST_READ_IO /* No problems with these on my machine */ #define FAST_WRITE_IO +#endif #ifdef DEBUGGING_ON #define DB(f,a) if (hostdata->args & (f)) a; @@ -52,6 +54,7 @@ #define write1_io(b,a) (outb((b),hostdata->io_base+(a))) #define write2_io(w,a) (outw((w),hostdata->io_base+(a))) +#ifdef __i386__ /* These inline assembly defines are derived from a patch * sent to me by Bill Earnest. He's done a lot of very * valuable thinking, testing, and coding during his effort @@ -90,6 +93,7 @@ : "2" (f), "0" (sp), "1" (i) /* input */ \ ); /* trashed */ \ }) +#endif /* IN2000 io_port offsets */ #define IO_WD_ASR 0x00 /* R - 3393 auxstat reg */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/ini9100u.c linux/drivers/scsi/ini9100u.c --- v2.4.0-test1/linux/drivers/scsi/ini9100u.c Thu May 11 15:30:07 2000 +++ linux/drivers/scsi/ini9100u.c Mon Jun 19 13:42:40 2000 @@ -290,6 +290,8 @@ for (i = 0; i < TULSZ(i91u_pci_devices); i++) { while ((pDev = pci_find_device(i91u_pci_devices[i].vendor_id, i91u_pci_devices[i].device_id, pDev)) != NULL) { + if (pci_enable_device(pDev)) + continue; pci_read_config_dword(pDev, 0x44, (u32 *) & dRegValue); wBIOS = (UWORD) (dRegValue & 0xFF); if (((dRegValue & 0xFF00) >> 8) == 0xFF) @@ -377,8 +379,6 @@ pHCB->pSRB_head = NULL; /* Initial SRB save queue */ pHCB->pSRB_tail = NULL; /* Initial SRB save queue */ pHCB->pSRB_lock = SPIN_LOCK_UNLOCKED; /* SRB save queue lock */ - request_region(pHCB->HCS_Base, 0x100, "i91u"); /* Register */ - get_tulipPCIConfig(pHCB, i); dBiosAdr = pHCB->HCS_BIOS; @@ -387,6 +387,8 @@ pbBiosAdr = phys_to_virt(dBiosAdr); init_tulip(pHCB, tul_scb + (i * tul_num_scb), tul_num_scb, pbBiosAdr, 10); + request_region(pHCB->HCS_Base, 256, "i91u"); /* Register */ + pHCB->HCS_Index = i; /* 7/29/98 */ hreg = scsi_register(tpnt, sizeof(HCS)); hreg->io_port = pHCB->HCS_Base; @@ -812,4 +814,14 @@ { printk("\ni91u_panic: %s\n", msg); panic("i91u panic"); +} + +/* + * Release ressources + */ +int i91u_release(struct Scsi_Host *hreg) +{ + free_irq(hreg->irq, hreg); + release_region(hreg->io_port, 256); + return 0; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/ini9100u.h linux/drivers/scsi/ini9100u.h --- v2.4.0-test1/linux/drivers/scsi/ini9100u.h Thu Nov 18 20:25:37 1999 +++ linux/drivers/scsi/ini9100u.h Fri Jun 23 21:32:00 2000 @@ -78,6 +78,7 @@ #include "sd.h" extern int i91u_detect(Scsi_Host_Template *); +extern int i91u_release(struct Scsi_Host *); extern int i91u_command(Scsi_Cmnd *); extern int i91u_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); extern int i91u_abort(Scsi_Cmnd *); @@ -93,7 +94,7 @@ proc_info: NULL, \ name: i91u_REVID, \ detect: i91u_detect, \ - release: NULL, \ + release: i91u_release, \ info: NULL, \ command: i91u_command, \ queuecommand: i91u_queue, \ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/inia100.c linux/drivers/scsi/inia100.c --- v2.4.0-test1/linux/drivers/scsi/inia100.c Tue Dec 14 01:27:24 1999 +++ linux/drivers/scsi/inia100.c Mon Jun 19 13:42:40 2000 @@ -247,6 +247,8 @@ inia100_pci_devices[i].device_id, pdev))) { + if (pci_enable_device(pdev)) + continue; if (iAdapters >= MAX_SUPPORTED_ADAPTERS) break; /* Never greater than maximum */ @@ -261,24 +263,23 @@ */ bPCIBusNum = pdev->bus->number; bPCIDeviceNum = pdev->devfn; - dRegValue = pdev->resource[0].start; + dRegValue = pci_resource_start(pdev, 0); if (dRegValue == -1) { /* Check return code */ printk("\n\rinia100: orchid read configuration error.\n"); return (0); /* Read configuration space error */ } + /* <02> read from base address + 0x50 offset to get the wBIOS balue. */ wBASE = (WORD) dRegValue; - /* Now read the interrupt line */ + /* Now read the interrupt line value */ dRegValue = pdev->irq; - bInterrupt = dRegValue & 0xFF; /* Assign interrupt line */ - pci_read_config_word(pdev, PCI_COMMAND, &command); - pci_write_config_word(pdev, PCI_COMMAND, - command | PCI_COMMAND_MASTER | PCI_COMMAND_IO); + bInterrupt = dRegValue; /* Assign interrupt line */ - wBASE &= PCI_BASE_ADDRESS_IO_MASK; wBIOS = ORC_RDWORD(wBASE, 0x50); + pci_set_master(pdev); + #ifdef MMAPIO base = wBASE & PAGE_MASK; page_offset = wBASE - base; @@ -370,7 +371,6 @@ memset((unsigned char *) pHCB->HCS_virEscbArray, 0, sz); pHCB->HCS_physEscbArray = (U32) VIRT_TO_BUS(pHCB->HCS_virEscbArray); - request_region(pHCB->HCS_Base, 0x100, "inia100"); /* Register */ get_orcPCIConfig(pHCB, i); dBiosAdr = pHCB->HCS_BIOS; @@ -382,6 +382,8 @@ printk("inia100: initial orchid fail!!\n"); return (0); } + request_region(pHCB->HCS_Base, 256, "inia100"); /* Register */ + hreg = scsi_register(tpnt, sizeof(ORC_HCS)); if (hreg == NULL) { printk("Invalid scsi_register pointer.\n"); @@ -411,28 +413,28 @@ /* Initial orc chip */ switch (i) { case 0: - ok = request_irq(pHCB->HCS_Intr, inia100_intr0, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL); + ok = request_irq(pHCB->HCS_Intr, inia100_intr0, SA_INTERRUPT | SA_SHIRQ, "inia100", hreg); break; case 1: - ok = request_irq(pHCB->HCS_Intr, inia100_intr1, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL); + ok = request_irq(pHCB->HCS_Intr, inia100_intr1, SA_INTERRUPT | SA_SHIRQ, "inia100", hreg); break; case 2: - ok = request_irq(pHCB->HCS_Intr, inia100_intr2, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL); + ok = request_irq(pHCB->HCS_Intr, inia100_intr2, SA_INTERRUPT | SA_SHIRQ, "inia100", hreg); break; case 3: - ok = request_irq(pHCB->HCS_Intr, inia100_intr3, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL); + ok = request_irq(pHCB->HCS_Intr, inia100_intr3, SA_INTERRUPT | SA_SHIRQ, "inia100", hreg); break; case 4: - ok = request_irq(pHCB->HCS_Intr, inia100_intr4, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL); + ok = request_irq(pHCB->HCS_Intr, inia100_intr4, SA_INTERRUPT | SA_SHIRQ, "inia100", hreg); break; case 5: - ok = request_irq(pHCB->HCS_Intr, inia100_intr5, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL); + ok = request_irq(pHCB->HCS_Intr, inia100_intr5, SA_INTERRUPT | SA_SHIRQ, "inia100", hreg); break; case 6: - ok = request_irq(pHCB->HCS_Intr, inia100_intr6, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL); + ok = request_irq(pHCB->HCS_Intr, inia100_intr6, SA_INTERRUPT | SA_SHIRQ, "inia100", hreg); break; case 7: - ok = request_irq(pHCB->HCS_Intr, inia100_intr7, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL); + ok = request_irq(pHCB->HCS_Intr, inia100_intr7, SA_INTERRUPT | SA_SHIRQ, "inia100", hreg); break; default: inia100_panic("inia100: Too many host adapters\n"); @@ -784,5 +786,15 @@ printk("\ninia100_panic: %s\n", msg); panic("inia100 panic"); } + +/* + * Release ressources + */ +int inia100_release(struct Scsi_Host *hreg) +{ + free_irq(hreg->irq, hreg); + release_region(hreg->io_port, 256); + return 0; +} /*#include "inia100scsi.c" */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/inia100.h linux/drivers/scsi/inia100.h --- v2.4.0-test1/linux/drivers/scsi/inia100.h Thu Nov 11 20:11:47 1999 +++ linux/drivers/scsi/inia100.h Fri Jun 23 21:32:00 2000 @@ -71,6 +71,7 @@ #include "sd.h" extern int inia100_detect(Scsi_Host_Template *); +extern int inia100_release(struct Scsi_Host *); extern int inia100_command(Scsi_Cmnd *); extern int inia100_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); extern int inia100_abort(Scsi_Cmnd *); @@ -87,7 +88,7 @@ proc_info: NULL, \ name: inia100_REVID, \ detect: inia100_detect, \ - release: NULL, \ + release: inia100_release, \ info: NULL, \ command: inia100_command, \ queuecommand: inia100_queue, \ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/ips.c linux/drivers/scsi/ips.c --- v2.4.0-test1/linux/drivers/scsi/ips.c Thu Feb 10 17:11:13 2000 +++ linux/drivers/scsi/ips.c Mon Jun 19 13:42:40 2000 @@ -325,12 +325,13 @@ if (!(dev = pci_find_device(IPS_VENDORID, IPS_DEVICEID, dev))) break; - + if (pci_enable_device(dev)) + break; /* stuff that we get in dev */ irq = dev->irq; bus = dev->bus->number; func = dev->devfn; - io_addr = dev->resource[0].start; + io_addr = pci_resource_start(dev, 0); /* get planer status */ if (pci_read_config_word(dev, 0x04, &planer)) { @@ -341,7 +342,7 @@ } /* check I/O address */ - if ((dev->resource[0].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO) + if (pci_resource_flags(dev, 0) & IORESOURCE_MEM) continue; /* check to see if an onboard planer controller is disabled */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/mac_esp.c linux/drivers/scsi/mac_esp.c --- v2.4.0-test1/linux/drivers/scsi/mac_esp.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/scsi/mac_esp.c Mon Jun 19 17:59:41 2000 @@ -148,7 +148,7 @@ #define DRIVER_SETUP /* - * Function : mac_scsi_setup(char *str, int *ints) + * Function : mac_esp_setup(char *str, int *ints) * * Purpose : booter command line initialization of the overrides array, * @@ -160,7 +160,7 @@ * */ -void mac_esp_setup(char *str, int *ints) { +static int __init mac_esp_setup(char *str, int *ints) { #ifdef DRIVER_SETUP /* Format of mac53c9x parameter is: * mac53c9x=,,,,,,, @@ -186,7 +186,7 @@ if (ints[0] < 1) { printk( "mac_esp_setup: no arguments!\n" ); - return; + return 0; } if (ints[0] >= 1) { @@ -237,6 +237,7 @@ } #endif #endif + return 1; } __setup("mac53c9x=", mac_esp_setup); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/mac_scsi.c linux/drivers/scsi/mac_scsi.c --- v2.4.0-test1/linux/drivers/scsi/mac_scsi.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/scsi/mac_scsi.c Mon Jun 19 17:59:41 2000 @@ -133,7 +133,7 @@ * */ -void mac_scsi_setup(char *str, int *ints) { +static int __init mac_scsi_setup(char *str, int *ints) { #ifdef DRIVER_SETUP /* Format of mac5380 parameter is: * mac5380=,,,, @@ -159,7 +159,7 @@ if (ints[0] < 1) { printk( "mac_scsi_setup: no arguments!\n" ); - return; + return 0; } if (ints[0] >= 1) { @@ -193,6 +193,7 @@ } #endif #endif + return 1; } __setup("mac5380=", mac_scsi_setup); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c --- v2.4.0-test1/linux/drivers/scsi/megaraid.c Tue May 23 15:31:35 2000 +++ linux/drivers/scsi/megaraid.c Mon Jun 19 13:42:40 2000 @@ -1478,6 +1478,8 @@ struct pci_dev *pdev = NULL; while ((pdev = pci_find_device (pciVendor, pciDev, pdev))) { + if (pci_enable_device(pdev)) + continue; if ((flag & BOARD_QUARTZ) && (skip_id == -1)) { u16 magic; pci_read_config_word(pdev, PCI_CONF_AMISIG, &magic); @@ -1505,18 +1507,13 @@ } /* Read the base port and IRQ from PCI */ - megaBase = pdev->resource[0].start; + megaBase = pci_resource_start (pdev, 0); megaIrq = pdev->irq; - if (flag & BOARD_QUARTZ) { - - megaBase &= PCI_BASE_ADDRESS_MEM_MASK; + if (flag & BOARD_QUARTZ) megaBase = (long) ioremap (megaBase, 128); - } - else { - megaBase &= PCI_BASE_ADDRESS_IO_MASK; + else megaBase += 0x10; - } /* Initialize SCSI Host structure */ host = scsi_register (pHostTmpl, sizeof (mega_host_config)); @@ -1589,7 +1586,7 @@ "megaraid: to protect your data, please upgrade your firmware to version\n" "megaraid: 3.10 or later, available from the Dell Technical Support web\n" "megaraid: site at\n" -"http://support.dell.com/us/en/filelib/download/index.asp?fileid=2489\n"); +"http://support.dell.com/us/en/filelib/download/index.asp?fileid=2940\n"); megaraid_release (host); #ifdef MODULE continue; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c --- v2.4.0-test1/linux/drivers/scsi/ncr53c8xx.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/scsi/ncr53c8xx.c Mon Jun 19 17:59:41 2000 @@ -73,7 +73,7 @@ */ /* -** April 24 2000, version 3.2i +** May 11 2000, version 3.3b ** ** Supported SCSI-II features: ** Synchronous negotiation @@ -93,6 +93,7 @@ ** 53C895 (Wide, Fast 40, on board rom BIOS) ** 53C895A (Wide, Fast 40, on board rom BIOS) ** 53C896 (Wide, Fast 40, on board rom BIOS) +** 53C897 (Wide, Fast 40, on board rom BIOS) ** 53C1510D (Wide, Fast 40, on board rom BIOS) ** ** Other features: @@ -104,7 +105,7 @@ /* ** Name and version of the driver */ -#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - version 3.2i" +#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - version 3.3b" #define SCSI_NCR_DEBUG_FLAGS (0) @@ -187,6 +188,14 @@ typedef u_long vm_offset_t; #include "ncr53c8xx.h" +/* +** Donnot compile integrity checking code for Linux-2.3.0 +** and above since SCSI data structures are not ready yet. +*/ +#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,0) +#define SCSI_NCR_INTEGRITY_CHECKING +#endif + #define NAME53C "ncr53c" #define NAME53C8XX "ncr53c8xx" #define DRIVER_SMP_LOCK ncr53c8xx_lock @@ -472,8 +481,10 @@ **========================================================== */ +#define NS_NOCHANGE (0) #define NS_SYNC (1) #define NS_WIDE (2) +#define NS_PPR (4) /*========================================================== ** @@ -666,6 +677,13 @@ /*2*/ u_char widedone; /*3*/ u_char wval; +#ifdef SCSI_NCR_INTEGRITY_CHECKING + u_char ic_min_sync; + u_char ic_max_width; + u_char ic_maximums_set; + u_char ic_done; +#endif + /*---------------------------------------------------------------- ** User settable limits and options. ** These limits are read from the NVRAM if present. @@ -1204,6 +1222,17 @@ struct ccb *ccb; /* Global CCB */ struct usrcmd user; /* Command from user */ u_char release_stage; /* Synchronisation stage on release */ + +#ifdef SCSI_NCR_INTEGRITY_CHECKING + /*---------------------------------------------------------------- + ** Fields that are used for integrity check + **---------------------------------------------------------------- + */ + unsigned char check_integrity; /* Enable midlayer integ.check on + * bus scan. */ + unsigned char check_integ_par; /* Set if par or Init. Det. error + * used only during integ check */ +#endif }; #define NCB_SCRIPT_PHYS(np,lbl) (np->p_script + offsetof (struct script, lbl)) @@ -1382,6 +1411,10 @@ static void ncr_int_sto (ncb_p np); static u_long ncr_lookup (char* id); static void ncr_negotiate (struct ncb* np, struct tcb* tp); +static int ncr_prepare_nego(ncb_p np, ccb_p cp, u_char *msgptr); +#ifdef SCSI_NCR_INTEGRITY_CHECKING +static int ncr_ic_nego(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd, u_char *msgptr); +#endif #ifdef SCSI_NCR_PROFILE_SUPPORT static void ncb_profile (ncb_p np, ccb_p cp); @@ -1396,6 +1429,7 @@ static void ncr_setup_tags (ncb_p np, u_char tn, u_char ln); static void ncr_setwide (ncb_p np, ccb_p cp, u_char wide, u_char ack); static int ncr_show_msg (u_char * msg); +static void ncr_print_msg (ccb_p cp, char *label, u_char *msg); static int ncr_snooptest (ncb_p np); static void ncr_timeout (ncb_p np); static void ncr_wakeup (ncb_p np, u_long code); @@ -3792,6 +3826,17 @@ instance->can_queue = (MAX_START-4); instance->select_queue_depths = ncr53c8xx_select_queue_depths; +#ifdef SCSI_NCR_INTEGRITY_CHECKING + np->check_integrity = 0; + instance->check_integrity = 0; + +#ifdef SCSI_NCR_ENABLE_INTEGRITY_CHECK + if ( !(driver_setup.bus_check & 0x04) ) { + np->check_integrity = 1; + instance->check_integrity = 1; + } +#endif +#endif /* ** Patch script to physical addresses */ @@ -4020,6 +4065,270 @@ } } +/*========================================================== +** +** +** Prepare the next negotiation message for integrity check, +** if needed. +** +** Fill in the part of message buffer that contains the +** negotiation and the nego_status field of the CCB. +** Returns the size of the message in bytes. +** +** +**========================================================== +*/ + +#ifdef SCSI_NCR_INTEGRITY_CHECKING +static int ncr_ic_nego(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd, u_char *msgptr) +{ + tcb_p tp = &np->target[cp->target]; + int msglen = 0; + int nego = 0; + u_char no_increase; + + if (tp->inq_done) { + + if (!tp->ic_maximums_set) { + tp->ic_maximums_set = 1; + + /* check target and host adapter capabilities */ + if ( (tp->inq_byte7 & INQ7_WIDE16) && + np->maxwide && tp->usrwide ) + tp->ic_max_width = 1; + else + tp->ic_max_width = 0; + + if ((tp->inq_byte7 & INQ7_SYNC) && tp->maxoffs) { + tp->ic_min_sync = (tp->minsync < np->minsync) ? + np->minsync : tp->minsync; + } + else + tp->ic_min_sync = 255; + + tp->period = 1; + tp->widedone = 1; + } + + if (DEBUG_FLAGS & DEBUG_IC) { + printk("%s: cmd->ic_nego %d, 1st byte 0x%2X\n", + ncr_name(np), cmd->ic_nego, cmd->cmnd[0]); + } + + /* First command from integrity check routine will request + * a PPR message. Disable. + */ + if ((cmd->ic_nego & NS_PPR) == NS_PPR) + cmd->ic_nego &= ~NS_PPR; + /* Previous command recorded a parity or an initiator + * detected error condition. Force bus to narrow for this + * target. Clear flag. Negotation on request sense. + * Note: kernel forces 2 bus resets :o( but clears itself out. + * Minor bug? in scsi_obsolete.c (ugly) + */ + if (np->check_integ_par) { + printk("%s: Parity Error. Target set to narrow.\n", + ncr_name(np)); + tp->ic_max_width = 0; + tp->widedone = tp->period = 0; + } + + /* In case of a bus reset, ncr_negotiate will reset + * the flags tp->widedone and tp->period to 0, forcing + * a new negotiation. + */ + no_increase = 0; + if (tp->widedone == 0) { + cmd->ic_nego = NS_WIDE; + tp->widedone = 1; + no_increase = 1; + } + else if (tp->period == 0) { + cmd->ic_nego = NS_SYNC; + tp->period = 1; + no_increase = 1; + } + + switch (cmd->ic_nego) { + case NS_WIDE: + /* + ** negotiate wide transfers ? + ** Do NOT negotiate if device only supports + ** narrow. + */ + if (tp->ic_max_width | np->check_integ_par) { + nego = NS_WIDE; + + msgptr[msglen++] = M_EXTENDED; + msgptr[msglen++] = 2; + msgptr[msglen++] = M_X_WIDE_REQ; + msgptr[msglen++] = cmd->ic_nego_width & tp->ic_max_width; + } + else + cmd->ic_nego_width &= tp->ic_max_width; + + break; + + case NS_SYNC: + /* + ** negotiate synchronous transfers? + ** Target must support sync transfers. + ** + ** If period becomes longer than max, reset to async + */ + + if (tp->inq_byte7 & INQ7_SYNC) { + + nego = NS_SYNC; + + msgptr[msglen++] = M_EXTENDED; + msgptr[msglen++] = 3; + msgptr[msglen++] = M_X_SYNC_REQ; + + switch (cmd->ic_nego_sync) { + case 2: /* increase the period */ + if (!no_increase) { + if (tp->ic_min_sync <= 0x0A) + tp->ic_min_sync = 0x0C; + else if (tp->ic_min_sync <= 0x0C) + tp->ic_min_sync = 0x19; + else if (tp->ic_min_sync <= 0x19) + tp->ic_min_sync *= 2; + else { + tp->ic_min_sync = 255; + cmd->ic_nego_sync = 0; + tp->maxoffs = 0; + } + } + msgptr[msglen++] = tp->maxoffs?tp->ic_min_sync:0; + msgptr[msglen++] = tp->maxoffs; + break; + + case 1: /* nego. to maximum */ + msgptr[msglen++] = tp->maxoffs?tp->ic_min_sync:0; + msgptr[msglen++] = tp->maxoffs; + break; + + case 0: /* nego to async */ + default: + msgptr[msglen++] = 0; + msgptr[msglen++] = 0; + break; + }; + } + else + cmd->ic_nego_sync = 0; + break; + + case NS_NOCHANGE: + default: + break; + }; + }; + + cp->nego_status = nego; + np->check_integ_par = 0; + + if (nego) { + tp->nego_cp = cp; + if (DEBUG_FLAGS & DEBUG_NEGO) { + ncr_print_msg(cp, nego == NS_WIDE ? + "wide/narrow msgout": "sync/async msgout", msgptr); + }; + }; + + return msglen; +} +#endif /* SCSI_NCR_INTEGRITY_CHECKING */ + +/*========================================================== +** +** +** Prepare the next negotiation message if needed. +** +** Fill in the part of message buffer that contains the +** negotiation and the nego_status field of the CCB. +** Returns the size of the message in bytes. +** +** +**========================================================== +*/ + + +static int ncr_prepare_nego(ncb_p np, ccb_p cp, u_char *msgptr) +{ + tcb_p tp = &np->target[cp->target]; + int msglen = 0; + int nego = 0; + + if (tp->inq_done) { + + /* + ** negotiate wide transfers ? + */ + + if (!tp->widedone) { + if (tp->inq_byte7 & INQ7_WIDE16) { + nego = NS_WIDE; +#ifdef SCSI_NCR_INTEGRITY_CHECKING + if (tp->ic_done) + tp->usrwide &= tp->ic_max_width; +#endif + } else + tp->widedone=1; + + }; + + /* + ** negotiate synchronous transfers? + */ + + if (!nego && !tp->period) { + if (tp->inq_byte7 & INQ7_SYNC) { + nego = NS_SYNC; +#ifdef SCSI_NCR_INTEGRITY_CHECKING + if ((tp->ic_done) && + (tp->minsync < tp->ic_min_sync)) + tp->minsync = tp->ic_min_sync; +#endif + } else { + tp->period =0xffff; + PRINT_TARGET(np, cp->target); + printk ("target did not report SYNC.\n"); + }; + }; + }; + + switch (nego) { + case NS_SYNC: + msgptr[msglen++] = M_EXTENDED; + msgptr[msglen++] = 3; + msgptr[msglen++] = M_X_SYNC_REQ; + msgptr[msglen++] = tp->maxoffs ? tp->minsync : 0; + msgptr[msglen++] = tp->maxoffs; + break; + case NS_WIDE: + msgptr[msglen++] = M_EXTENDED; + msgptr[msglen++] = 2; + msgptr[msglen++] = M_X_WIDE_REQ; + msgptr[msglen++] = tp->usrwide; + break; + }; + + cp->nego_status = nego; + + if (nego) { + tp->nego_cp = cp; + if (DEBUG_FLAGS & DEBUG_NEGO) { + ncr_print_msg(cp, nego == NS_WIDE ? + "wide msgout":"sync_msgout", msgptr); + }; + }; + + return msglen; +} + + /*========================================================== ** @@ -4038,7 +4347,7 @@ ccb_p cp; int segments; - u_char nego, idmsg, *msgptr; + u_char idmsg, *msgptr; u_int msglen; int direction; u_int32 lastp, goalp; @@ -4120,51 +4429,6 @@ cp->phys.header.stamp.start = jiffies; #endif - /*--------------------------------------------------- - ** - ** negotiation required? - ** - **--------------------------------------------------- - */ - - nego = 0; - - if ((!tp->widedone || !tp->period) && !tp->nego_cp && tp->inq_done && lp) { - - /* - ** negotiate wide transfers ? - */ - - if (!tp->widedone) { - if (tp->inq_byte7 & INQ7_WIDE16) { - nego = NS_WIDE; - } else - tp->widedone=1; - }; - - /* - ** negotiate synchronous transfers? - */ - - if (!nego && !tp->period) { - if (tp->inq_byte7 & INQ7_SYNC) { - nego = NS_SYNC; - } else { - tp->period =0xffff; - PRINT_TARGET(np, cmd->target); - printk ("device did not report SYNC.\n"); - }; - }; - - /* - ** remember nego is pending for the target. - ** Avoid to start a nego for all queued commands - ** when tagged command queuing is enabled. - */ - - if (nego) - tp->nego_cp = cp; - }; /*---------------------------------------------------- ** @@ -4225,34 +4489,6 @@ msgptr[msglen++] = (cp->tag << 1) + 1; } - switch (nego) { - case NS_SYNC: - msgptr[msglen++] = M_EXTENDED; - msgptr[msglen++] = 3; - msgptr[msglen++] = M_X_SYNC_REQ; - msgptr[msglen++] = tp->maxoffs ? tp->minsync : 0; - msgptr[msglen++] = tp->maxoffs; - if (DEBUG_FLAGS & DEBUG_NEGO) { - PRINT_ADDR(cp->cmd); - printk ("sync msgout: "); - ncr_show_msg (&cp->scsi_smsg [msglen-5]); - printk (".\n"); - }; - break; - case NS_WIDE: - msgptr[msglen++] = M_EXTENDED; - msgptr[msglen++] = 2; - msgptr[msglen++] = M_X_WIDE_REQ; - msgptr[msglen++] = tp->usrwide; - if (DEBUG_FLAGS & DEBUG_NEGO) { - PRINT_ADDR(cp->cmd); - printk ("wide msgout: "); - ncr_show_msg (&cp->scsi_smsg [msglen-4]); - printk (".\n"); - }; - break; - }; - /*---------------------------------------------------- ** ** Build the data descriptors @@ -4273,6 +4509,84 @@ segments = 0; } + /*--------------------------------------------------- + ** + ** negotiation required? + ** + ** (nego_status is filled by ncr_prepare_nego()) + ** + **--------------------------------------------------- + */ + + cp->nego_status = 0; + +#ifdef SCSI_NCR_INTEGRITY_CHECKING + if ((np->check_integrity && tp->ic_done) || !np->check_integrity) { + if ((!tp->widedone || !tp->period) && !tp->nego_cp && lp) { + msglen += ncr_prepare_nego (np, cp, msgptr + msglen); + } + } + else if (np->check_integrity && (cmd->ic_in_progress)) { + msglen += ncr_ic_nego (np, cp, cmd, msgptr + msglen); + } + else if (np->check_integrity && cmd->ic_complete) { + /* + * Midlayer signal to the driver that all of the scsi commands + * for the integrity check have completed. Save the negotiated + * parameters (extracted from sval and wval). + */ + + { + u_char idiv; + idiv = (tp->wval>>4) & 0x07; + if ((tp->sval&0x1f) && idiv ) + tp->period = (((tp->sval>>5)+4) + *div_10M[idiv-1])/np->clock_khz; + else + tp->period = 0xffff; + } + /* + * tp->period contains 10 times the transfer period, + * which itself is 4 * the requested negotiation rate. + */ + if (tp->period <= 250) tp->ic_min_sync = 10; + else if (tp->period <= 303) tp->ic_min_sync = 11; + else if (tp->period <= 500) tp->ic_min_sync = 12; + else + tp->ic_min_sync = (tp->period + 40 - 1) / 40; + + + /* + * Negotiation for this target it complete. + */ + tp->ic_max_width = (tp->wval & EWS) ? 1: 0; + tp->ic_done = 1; + tp->widedone = 1; + + printk("%s: Integrity Check Complete: \n", ncr_name(np)); + + printk("%s: %s %s SCSI", ncr_name(np), + (tp->sval&0x1f)?"SYNC":"ASYNC", + tp->ic_max_width?"WIDE":"NARROW"); + + if (tp->sval&0x1f) { + u_long mbs = 10000 * (tp->ic_max_width + 1); + + printk(" %d.%d MB/s", + (int) (mbs / tp->period), (int) (mbs % tp->period)); + + printk(" (%d ns, %d offset)\n", + tp->period/10, tp->sval&0x1f); + } + else + printk(" %d MB/s. \n ", (tp->ic_max_width+1)*5); + } +#else + if ((!tp->widedone || !tp->period) && !tp->nego_cp && lp) { + msglen += ncr_prepare_nego (np, cp, msgptr + msglen); + } +#endif /* SCSI_NCR_INTEGRITY_CHECKING */ + /*---------------------------------------------------- ** ** Determine xfer direction. @@ -4376,12 +4690,11 @@ ** status */ cp->actualquirks = tp->quirks; - cp->host_status = nego ? HS_NEGOTIATE : HS_BUSY; + cp->host_status = cp->nego_status ? HS_NEGOTIATE : HS_BUSY; cp->scsi_status = S_ILLEGAL; cp->parity_status = 0; cp->xerr_status = XE_OK; - cp->nego_status = nego; #if 0 cp->sync_status = tp->sval; cp->wide_status = tp->wval; @@ -5041,7 +5354,13 @@ for (i=0; i<14; i++) printk (" %x", *p++); printk (".\n"); } - + } else if ((cp->host_status == HS_COMPLETE) + && (cp->scsi_status == S_CONFLICT)) { + /* + ** Reservation Conflict condition code + */ + cmd->result = ScsiResult(DID_OK, S_CONFLICT); + } else if ((cp->host_status == HS_COMPLETE) && (cp->scsi_status == S_BUSY || cp->scsi_status == S_QUEUE_FULL)) { @@ -6398,6 +6717,14 @@ else msg = M_ID_ERROR; +#ifdef SCSI_NCR_INTEGRITY_CHECKING + /* + ** Save error message. For integrity check use only. + */ + if (np->check_integrity) + np->check_integ_par = msg; +#endif + /* * If the NCR stopped on a MOVE ^ DATA_IN, we jump to a * script that will ignore all data in bytes until phase @@ -6908,6 +7235,16 @@ return (1); } +static void ncr_print_msg ( ccb_p cp, char *label, u_char *msg) +{ + if (cp) + PRINT_ADDR(cp->cmd); + if (label) + printk("%s: ", label); + + (void) ncr_show_msg (msg); + printk(".\n"); +} void ncr_int_sir (ncb_p np) { @@ -8275,6 +8612,7 @@ static unsigned __init ncrgetfreq (ncb_p np, int gen) { unsigned ms = 0; + char count = 0; /* * Measure GEN timer delay in order @@ -8299,8 +8637,10 @@ OUTB (nc_scntl3, 4); /* set pre-scaler to divide by 3 */ OUTB (nc_stime1, 0); /* disable general purpose timer */ OUTB (nc_stime1, gen); /* set to nominal delay of 1<basePort = pdev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK; + padapter->basePort = pci_resource_start (pdev, 1); DEB (printk ("\nBase Regs = %#04X", padapter->basePort)); // get the base I/O port address padapter->mb0 = padapter->basePort + RTR_MAILBOX; // get the 32 bit mail boxes padapter->mb1 = padapter->basePort + RTR_MAILBOX + 4; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/pci2220i.c linux/drivers/scsi/pci2220i.c --- v2.4.0-test1/linux/drivers/scsi/pci2220i.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/scsi/pci2220i.c Mon Jun 19 13:42:40 2000 @@ -2386,8 +2386,8 @@ memset (&DaleSetup, 0, sizeof (DaleSetup)); memset (DiskMirror, 0, sizeof (DiskMirror)); - zr = pcidev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK; - zl = pcidev->resource[2].start & PCI_BASE_ADDRESS_IO_MASK; + zr = pci_resource_start (pcidev, 1); + zl = pci_resource_start (pcidev, 2); padapter->basePort = zr; padapter->regRemap = zr + RTR_LOCAL_REMAP; // 32 bit local space remap @@ -2542,6 +2542,8 @@ while ( (pcidev = pci_find_device (VENDOR_PSI, DEVICE_DALE_1, pcidev)) != NULL ) { + if (pci_enable_device(pcidev)) + continue; pshost = scsi_register (tpnt, sizeof(ADAPTER2220I)); padapter = HOSTDATA(pshost); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/qla1280.c linux/drivers/scsi/qla1280.c --- v2.4.0-test1/linux/drivers/scsi/qla1280.c Sat Feb 26 22:31:48 2000 +++ linux/drivers/scsi/qla1280.c Mon Jun 19 13:42:40 2000 @@ -801,13 +801,13 @@ for( i=0; bdp->device_id != 0 && i < NUM_OF_ISP_DEVICES; i++, bdp++ ) { #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) while ((pdev = pci_find_device(QLA1280_VENDOR_ID, - bdp->device_id, pdev ) )) + bdp->device_id, pdev ) )) { + if (pci_enable_device(pdev)) continue; #else while (!(pcibios_find_device(QLA1280_VENDOR_ID, bdp->device_id, - index++, &pci_bus, &pci_devfn)) ) + index++, &pci_bus, &pci_devfn)) ) { #endif - { /* found a adapter */ host = scsi_register(template, sizeof(scsi_qla_host_t)); ha = (scsi_qla_host_t *) host->hostdata; @@ -817,9 +817,7 @@ /* Sanitize the information from PCI BIOS. */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) host->irq = pdev->irq; -/* this depends on release 2.3.18 */ - host->io_port = pdev->resource[0].start; -/* MRS host->io_port = (unsigned int) pdev->base_address[0]; */ + host->io_port = pci_resource_start(pdev, 0); ha->pci_bus = pdev->bus->number; ha->pci_device_fn = pdev->devfn; ha->pdev = pdev; @@ -828,14 +826,13 @@ pcibios_read_config_dword(pci_bus, pci_devfn, OFFSET(cfgp->base_port), &piobase); host->irq = pci_irq; host->io_port = (unsigned int) piobase; + host->io_port &= PCI_BASE_ADDRESS_IO_MASK; ha->pci_bus = pci_bus; ha->pci_device_fn = pci_devfn; #endif ha->device_id = bdp->device_id; - host->io_port &= PCI_BASE_ADDRESS_IO_MASK; ha->devnum = i; - host->io_port &= PCI_BASE_ADDRESS_IO_MASK; if( qla1280_mem_alloc(ha) ) { printk(KERN_INFO "qla1280: Failed to allocate memory for adapter\n"); } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/qlogicfc.c linux/drivers/scsi/qlogicfc.c --- v2.4.0-test1/linux/drivers/scsi/qlogicfc.c Sat Feb 26 22:31:48 2000 +++ linux/drivers/scsi/qlogicfc.c Mon Jun 19 13:42:40 2000 @@ -746,6 +746,8 @@ for (i=0; i<2; i++){ while ((pdev = pci_find_device(PCI_VENDOR_ID_QLOGIC, device_ids[i], pdev))) { + if (pci_enable_device(pdev)) + continue; host = scsi_register(tmpt, sizeof(struct isp2x00_hostdata)); host->max_id = QLOGICFC_MAX_ID + 1; @@ -2004,7 +2006,7 @@ printk("qlogicfc%d : error reading PCI configuration\n", hostdata->host_id); return 1; } - io_base = pdev->resource[0].start; + io_base = pci_resource_start(pdev, 0); irq = pdev->irq; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c --- v2.4.0-test1/linux/drivers/scsi/qlogicisp.c Tue Apr 11 15:09:18 2000 +++ linux/drivers/scsi/qlogicisp.c Mon Jun 19 13:42:41 2000 @@ -678,6 +678,9 @@ while ((pdev = pci_find_device(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1020, pdev))) { + if (pci_enable_device(pdev)) + continue; + host = scsi_register(tmpt, sizeof(struct isp1020_hostdata)); hostdata = (struct isp1020_hostdata *) host->hostdata; @@ -1371,10 +1374,10 @@ return 1; } - io_base = pdev->resource[0].start; - mem_base = pdev->resource[1].start; - io_flags = pdev->resource[0].flags; - mem_flags = pdev->resource[1].flags; + io_base = pci_resource_start(pdev, 0); + mem_base = pci_resource_start(pdev, 1); + io_flags = pci_resource_flags(pdev, 0); + mem_flags = pci_resource_flags(pdev, 1); irq = pdev->irq; if (pdev->vendor != PCI_VENDOR_ID_QLOGIC) { diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.4.0-test1/linux/drivers/scsi/scsi.c Thu May 11 15:30:07 2000 +++ linux/drivers/scsi/scsi.c Thu Jun 22 07:15:10 2000 @@ -176,6 +176,8 @@ */ void scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt) { blk_init_queue(&SDpnt->request_queue, scsi_request_fn); + blk_queue_headactive(&SDpnt->request_queue, 0); + SDpnt->request_queue.queuedata = (void *) SDpnt; } #ifdef MODULE @@ -2567,7 +2569,6 @@ } } } - printk("wait_for_request = %p\n", &wait_for_request); #endif /* CONFIG_SCSI_LOGGING */ /* } */ } #endif /* CONFIG_PROC_FS */ @@ -2728,8 +2729,6 @@ scsi_build_commandblocks(SDpnt); scsi_initialize_queue(SDpnt, SHpnt); - blk_queue_headactive(&SDpnt->request_queue, 0); - SDpnt->request_queue.queuedata = (void *) SDpnt; SDpnt->online = TRUE; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/scsi_lib.c linux/drivers/scsi/scsi_lib.c --- v2.4.0-test1/linux/drivers/scsi/scsi_lib.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/scsi/scsi_lib.c Thu Jun 22 07:15:10 2000 @@ -855,10 +855,9 @@ * if the device itself is blocked, or if the host is fully * occupied. */ - if (SHpnt->in_recovery - || q->plugged) { + if (SHpnt->in_recovery || q->plugged) return; - } + /* * To start with, we keep looping until the queue is empty, or until * the host is no longer able to accept any more requests. @@ -869,10 +868,8 @@ * released the lock and grabbed it again, so each time * we need to check to see if the queue is plugged or not. */ - if (SHpnt->in_recovery - || q->plugged) { + if (SHpnt->in_recovery || q->plugged) return; - } /* * If the device cannot accept another request, then quit. @@ -1019,8 +1016,7 @@ * We have copied the data out of the request block - it is now in * a field in SCpnt. Release the request block. */ - req->rq_status = RQ_INACTIVE; - wake_up(&wait_for_request); + blkdev_release_request(req); } /* * Now it is finally safe to release the lock. We are diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/scsi_scan.c linux/drivers/scsi/scsi_scan.c --- v2.4.0-test1/linux/drivers/scsi/scsi_scan.c Thu May 11 15:30:07 2000 +++ linux/drivers/scsi/scsi_scan.c Thu Jun 22 07:15:10 2000 @@ -38,7 +38,6 @@ #define BLIST_MAX5LUN 0x080 #define BLIST_ISDISK 0x100 #define BLIST_ISROM 0x200 -#define BLIST_GHOST 0x400 static void print_inquiry(unsigned char *data); static int scan_scsis_single(int channel, int dev, int lun, int *max_scsi_dev, @@ -137,13 +136,7 @@ {"NEC", "PD-1 ODX654P", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"MATSHITA", "PD-1", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN}, - {"CREATIVE","DVD-RAM RAM","*", BLIST_GHOST}, - {"MATSHITA","PD-2 LF-D100","*", BLIST_GHOST}, - {"AOpen", "PD-2 DVD-520S", "*", BLIST_GHOST}, - {"HITACHI", "GF-1050","*", BLIST_GHOST}, /* Hitachi SCSI DVD-RAM */ {"TOSHIBA","CDROM","*", BLIST_ISROM}, - {"TOSHIBA","DVD-RAM SD-W1101","*", BLIST_GHOST}, - {"TOSHIBA","DVD-RAM SD-W1111","*", BLIST_GHOST}, {"MegaRAID", "LD", "*", BLIST_FORCELUN}, /* @@ -278,8 +271,8 @@ if (SDpnt) { memset(SDpnt, 0, sizeof(Scsi_Device)); /* - * Register the queue for the device. All I/O requests will come - * in through here. We also need to register a pointer to + * Register the queue for the device. All I/O requests will + * come in through here. We also need to register a pointer to * ourselves, since the queue handler won't know what device * the queue actually represents. We could look it up, but it * is pointless work. @@ -468,8 +461,6 @@ Scsi_Device *SDtail, *SDpnt = *SDpnt2; Scsi_Request * SRpnt; int bflags, type = -1; - static int ghost_channel=-1, ghost_dev=-1; - int org_lun = lun; extern devfs_handle_t scsi_devfs_handle; SDpnt->host = shpnt; @@ -480,13 +471,6 @@ scsi_build_commandblocks(SDpnt); - if ((channel == ghost_channel) && (dev == ghost_dev) && (lun == 1)) { - SDpnt->lun = 0; - } else { - ghost_channel = ghost_dev = -1; - } - - /* Some low level driver could use device->type (DB) */ SDpnt->type = -1; @@ -499,39 +483,14 @@ SDpnt->expecting_cc_ua = 0; SDpnt->starved = 0; - scsi_cmd[0] = TEST_UNIT_READY; - scsi_cmd[1] = lun << 5; - scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0; - SRpnt = scsi_allocate_request(SDpnt); - SRpnt->sr_data_direction = SCSI_DATA_NONE; - - scsi_wait_req (SRpnt, (void *) scsi_cmd, - (void *) NULL, - 0, SCSI_TIMEOUT + 4 * HZ, 5); - - SCSI_LOG_SCAN_BUS(3, printk("scsi: scan_scsis_single id %d lun %d. Return code 0x%08x\n", - dev, lun, SRpnt->sr_result)); - SCSI_LOG_SCAN_BUS(3, print_driverbyte(SRpnt->sr_result)); - SCSI_LOG_SCAN_BUS(3, print_hostbyte(SRpnt->sr_result)); - SCSI_LOG_SCAN_BUS(3, printk("\n")); + /* + * We used to do a TEST_UNIT_READY before the INQUIRY but that was + * not really necessary. Spec recommends using INQUIRY to scan for + * devices (and TEST_UNIT_READY to poll for media change). - Paul G. + */ - if (SRpnt->sr_result) { - if (((driver_byte(SRpnt->sr_result) & DRIVER_SENSE) || - (status_byte(SRpnt->sr_result) & CHECK_CONDITION)) && - ((SRpnt->sr_sense_buffer[0] & 0x70) >> 4) == 7) { - if (((SRpnt->sr_sense_buffer[2] & 0xf) != NOT_READY) && - ((SRpnt->sr_sense_buffer[2] & 0xf) != UNIT_ATTENTION) && - ((SRpnt->sr_sense_buffer[2] & 0xf) != ILLEGAL_REQUEST || lun > 0)) { - scsi_release_request(SRpnt); - return 1; - } - } else { - scsi_release_request(SRpnt); - return 0; - } - } SCSI_LOG_SCAN_BUS(3, printk("scsi: performing INQUIRY\n")); /* * Build an INQUIRY command block. @@ -547,7 +506,7 @@ scsi_wait_req (SRpnt, (void *) scsi_cmd, (void *) scsi_result, - 256, SCSI_TIMEOUT, 3); + 256, SCSI_TIMEOUT+4*HZ, 3); SCSI_LOG_SCAN_BUS(3, printk("scsi: INQUIRY %s with code 0x%x\n", SRpnt->sr_result ? "failed" : "successful", SRpnt->sr_result)); @@ -588,18 +547,6 @@ scsi_result[1] |= 0x80; /* removable */ } - if (bflags & BLIST_GHOST) { - if ((ghost_channel == channel) && (ghost_dev == dev) && (org_lun == 1)) { - lun=1; - } else { - ghost_channel = channel; - ghost_dev = dev; - scsi_result[0] = TYPE_MOD; - scsi_result[1] |= 0x80; /* removable */ - } - } - - memcpy(SDpnt->vendor, scsi_result + 8, 8); memcpy(SDpnt->model, scsi_result + 16, 16); memcpy(SDpnt->rev, scsi_result + 32, 4); @@ -808,19 +755,9 @@ } /* - * If this device is Ghosted, scan upto two luns. (It physically only - * has one). -- REW - */ - if (bflags & BLIST_GHOST) { - *max_dev_lun = 2; - return 1; - } - - - /* - * We assume the device can't handle lun!=0 if: - it reports scsi-0 (ANSI - * SCSI Revision 0) (old drives like MAXTOR XT-3280) or - it reports scsi-1 - * (ANSI SCSI Revision 1) and Response Data Format 0 + * We assume the device can't handle lun!=0 if: - it reports scsi-0 + * (ANSI SCSI Revision 0) (old drives like MAXTOR XT-3280) or - it + * reports scsi-1 (ANSI SCSI Revision 1) and Response Data Format 0 */ if (((scsi_result[2] & 0x07) == 0) || diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v2.4.0-test1/linux/drivers/scsi/sd.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/scsi/sd.c Mon Jun 19 13:42:41 2000 @@ -338,6 +338,15 @@ this_count = this_count >> 2; } } + if (dpnt->device->sector_size == 4096) { + if ((block & 7) || (SCpnt->request.nr_sectors & 7)) { + printk("sd.c:Bad block number requested"); + return 0; + } else { + block = block >> 3; + this_count = this_count >> 3; + } + } switch (SCpnt->request.cmd) { case WRITE: if (!dpnt->device->writeable) { @@ -588,6 +597,11 @@ if (block_sectors < 4) block_sectors = 4; break; + case 4096: + error_sector <<=3; + if (block_sectors < 8) + block_sectors = 8; + break; case 256: error_sector >>= 1; break; @@ -889,7 +903,7 @@ */ rscsi_disks[i].capacity = 0; } - if (sector_size == 2048) { + if (sector_size > 1024) { int m; /* @@ -899,7 +913,7 @@ * of partial sectors. */ for (m = i << 4; m < ((i + 1) << 4); m++) { - sd_blocksizes[m] = 2048; + sd_blocksizes[m] = sector_size; } } { /* diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/seagate.c linux/drivers/scsi/seagate.c --- v2.4.0-test1/linux/drivers/scsi/seagate.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/scsi/seagate.c Mon Jun 19 13:42:41 2000 @@ -311,6 +311,8 @@ {"FUTURE DOMAIN CORP. (C) 1992 V8.00.004/02/92", 5, 44, FD}, {"IBM F1 BIOS V1.1004/30/92", 5, 25, FD}, {"FUTURE DOMAIN TMC-950", 5, 21, FD}, + /* Added for 2.2.16 by Matthias_Heidbrink@b.maus.de */ + {"IBM F1 V1.2009/22/93", 5, 25, FD}, }; #define NUM_SIGNATURES (sizeof(signatures) / sizeof(Signature)) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c --- v2.4.0-test1/linux/drivers/scsi/sg.c Tue Apr 11 15:09:19 2000 +++ linux/drivers/scsi/sg.c Wed Jun 21 22:31:02 2000 @@ -17,8 +17,8 @@ * any later version. * */ - static char * sg_version_str = "Version: 3.1.13 (20000323)"; - static int sg_version_num = 30113; /* 2 digits for each component */ + static char * sg_version_str = "Version: 3.1.15 (20000528)"; + static int sg_version_num = 30115; /* 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 @@ -113,7 +113,8 @@ static Scsi_Cmnd * dummy_cmdp = 0; /* only used for sizeof */ -static rwlock_t sg_dev_arr_lock = RW_LOCK_UNLOCKED; +static rwlock_t sg_dev_arr_lock = RW_LOCK_UNLOCKED; /* Also used to lock + file descriptor list for device */ struct Scsi_Device_Template sg_template = { @@ -155,7 +156,7 @@ char res_used; /* 1 -> using reserve buffer, 0 -> not ... */ char orphan; /* 1 -> drop on sight, 0 -> normal */ char sg_io_owned; /* 1 -> packet belongs to SG_IO */ - char done; /* 1 -> bh handler done, 0 -> prior to bh */ + char done; /* 0->before bh, 1->before read, 2->read */ } Sg_request; /* 168 bytes long on i386 */ typedef struct sg_fd /* holds the state of a file descriptor */ @@ -163,6 +164,7 @@ struct sg_fd * nextfp; /* NULL when last opened fd on this device */ struct sg_device * parentdp; /* owning device */ wait_queue_head_t read_wait; /* queue read until command done */ + rwlock_t rq_list_lock; /* protect access to list in req_arr */ int timeout; /* defaults to SG_DEFAULT_TIMEOUT */ Sg_scatter_hold reserve; /* buffer held for this file descriptor */ unsigned save_scat_len; /* original length of trunc. scat. element */ @@ -176,7 +178,7 @@ char cmd_q; /* 1 -> allow command queuing, 0 -> don't */ char next_cmd_len; /* 0 -> automatic (def), >0 -> use on next write() */ char keep_orphan; /* 0 -> drop orphan (def), 1 -> keep for read() */ -} Sg_fd; /* 2760 bytes long on i386 */ +} Sg_fd; /* 2768 bytes long on i386 */ typedef struct sg_device /* holds the state of each scsi generic device */ { @@ -189,7 +191,7 @@ char exclude; /* opened for exclusive access */ char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */ char detached; /* 0->attached, 1->detached pending removal */ -} Sg_device; /* 40 bytes long on i386 */ +} Sg_device; /* 44 bytes long on i386 */ static int sg_fasync(int fd, struct file * filp, int mode); @@ -222,11 +224,11 @@ static void sg_low_free(char * buff, int size, int mem_src); static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev); static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp); -static Sg_request * sg_get_request(const Sg_fd * sfp, int pack_id); +static Sg_request * sg_get_rq_mark(Sg_fd * sfp, int pack_id); static Sg_request * sg_add_request(Sg_fd * sfp); static int sg_remove_request(Sg_fd * sfp, Sg_request * srp); -static int sg_res_in_use(const Sg_fd * sfp); -static int sg_dio_in_use(const Sg_fd * sfp); +static int sg_res_in_use(Sg_fd * sfp); +static int sg_dio_in_use(Sg_fd * sfp); static void sg_clr_scpnt(Scsi_Cmnd * SCpnt); static void sg_shorten_timeout(Scsi_Cmnd * scpnt); static int sg_ms_to_jif(unsigned int msecs); @@ -364,7 +366,7 @@ else req_pack_id = old_hdr.pack_id; } - srp = sg_get_request(sfp, req_pack_id); + srp = sg_get_rq_mark(sfp, req_pack_id); if (! srp) { /* now wait on packet to arrive */ if (filp->f_flags & O_NONBLOCK) return -EAGAIN; @@ -372,7 +374,7 @@ int dio = sg_dio_in_use(sfp); res = 0; /* following is a macro that beats race condition */ __wait_event_interruptible(sfp->read_wait, - (srp = sg_get_request(sfp, req_pack_id)), + (srp = sg_get_rq_mark(sfp, req_pack_id)), res); if (0 == res) break; @@ -550,7 +552,7 @@ hp->cmd_len = (unsigned char)cmd_size; hp->iovec_count = 0; hp->mx_sb_len = 0; -#if 1 +#if 0 hp->dxfer_direction = SG_DXFER_UNKNOWN; #else if (input_size > 0) @@ -686,7 +688,7 @@ srp->data.sglist_len = 0; srp->data.bufflen = 0; srp->data.buffer = NULL; - hp->duration = jiffies; + hp->duration = jiffies; /* unit jiffies now, millisecs after done */ /* Now send everything of to mid-level. The next time we hear about this packet is when sg_cmd_done_bh() is called (i.e. a callback). */ scsi_do_cmd(SCpnt, (void *)cmnd, @@ -703,6 +705,7 @@ Sg_device * sdp; Sg_fd * sfp; Sg_request * srp; + unsigned long iflags; if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) return -ENXIO; @@ -740,6 +743,7 @@ return result; /* -ERESTARTSYS because signal hit process */ } } + srp->done = 2; result = sg_new_read(sfp, (char *)arg, size_sg_io_hdr, srp); return (result < 0) ? result : 0; } @@ -794,24 +798,24 @@ case SG_GET_PACK_ID: result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int)); if (result) return result; - srp = sfp->headrp; - while (srp) { - if (srp->done && (! srp->sg_io_owned)) { + read_lock_irqsave(&sfp->rq_list_lock, iflags); + for (srp = sfp->headrp; srp; srp = srp->nextrp) { + if ((1 == srp->done) && (! srp->sg_io_owned)) { + read_unlock_irqrestore(&sfp->rq_list_lock, iflags); __put_user(srp->header.pack_id, (int *)arg); return 0; } - srp = srp->nextrp; } + read_unlock_irqrestore(&sfp->rq_list_lock, iflags); __put_user(-1, (int *)arg); return 0; case SG_GET_NUM_WAITING: - srp = sfp->headrp; - val = 0; - while (srp) { - if (srp->done && (! srp->sg_io_owned)) + read_lock_irqsave(&sfp->rq_list_lock, iflags); + for (val = 0, srp = sfp->headrp; srp; srp = srp->nextrp) { + if ((1 == srp->done) && (! srp->sg_io_owned)) ++val; - srp = srp->nextrp; } + read_unlock_irqrestore(&sfp->rq_list_lock, iflags); return put_user(val, (int *)arg); case SG_GET_SG_TABLESIZE: return put_user(sdp->sg_tablesize, (int *)arg); @@ -855,16 +859,17 @@ if (result) return result; else { sg_req_info_t rinfo[SG_MAX_QUEUE]; - Sg_request * srp = sfp->headrp; - for (val = 0; val < SG_MAX_QUEUE; + Sg_request * srp; + read_lock_irqsave(&sfp->rq_list_lock, iflags); + for (srp = sfp->headrp, val = 0; val < SG_MAX_QUEUE; ++val, srp = srp ? srp->nextrp : srp) { memset(&rinfo[val], 0, size_sg_req_info); if (srp) { - rinfo[val].req_state = srp->done ? 2 : 1; + rinfo[val].req_state = srp->done + 1; rinfo[val].problem = srp->header.masked_status & srp->header.host_status & srp->header.driver_status; rinfo[val].duration = srp->done ? - sg_jif_to_ms(srp->header.duration) : + srp->header.duration : sg_jif_to_ms(jiffies - srp->header.duration); rinfo[val].orphan = srp->orphan; rinfo[val].sg_io_owned = srp->sg_io_owned; @@ -872,6 +877,7 @@ rinfo[val].usr_ptr = srp->header.usr_ptr; } } + read_unlock_irqrestore(&sfp->rq_list_lock, iflags); __copy_to_user((void *)arg, rinfo, size_sg_req_info * SG_MAX_QUEUE); return 0; } @@ -882,8 +888,29 @@ return -EBUSY; result = get_user(val, (int *)arg); if (result) return result; - /* Don't do anything till scsi mid level visibility */ - return 0; + if (SG_SCSI_RESET_NOTHING == val) + return 0; +#ifdef SCSI_TRY_RESET_DEVICE + switch (val) + { + case SG_SCSI_RESET_DEVICE: + val = SCSI_TRY_RESET_DEVICE; + break; + case SG_SCSI_RESET_BUS: + val = SCSI_TRY_RESET_BUS; + break; + case SG_SCSI_RESET_HOST: + val = SCSI_TRY_RESET_HOST; + break; + default: + return -EINVAL; + } + if(! capable(CAP_SYS_ADMIN)) return -EACCES; + return (scsi_reset_provider(sdp->device, val) == SUCCESS) ? 0 : -EIO; +#else + SCSI_LOG_TIMEOUT(1, printk("sg_ioctl: SG_RESET_SCSI not supported\n")); + result = -EINVAL; +#endif case SCSI_IOCTL_SEND_COMMAND: if (read_only) { unsigned char opcode = WRITE_6; @@ -918,17 +945,19 @@ Sg_fd * sfp; Sg_request * srp; int count = 0; + unsigned long iflags; if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) return POLLERR; poll_wait(filp, &sfp->read_wait, wait); - srp = sfp->headrp; - while (srp) { /* if any read waiting, flag it */ - if ((0 == res) && srp->done && (! srp->sg_io_owned)) + read_lock_irqsave(&sfp->rq_list_lock, iflags); + for (srp = sfp->headrp; srp; srp = srp->nextrp) { + /* if any read waiting, flag it */ + if ((0 == res) && (1 == srp->done) && (! srp->sg_io_owned)) res = POLLIN | POLLRDNORM; ++count; - srp = srp->nextrp; } + read_unlock_irqrestore(&sfp->rq_list_lock, iflags); if (! sfp->cmd_q) { if (0 == count) res |= POLLOUT | POLLWRNORM; @@ -960,11 +989,17 @@ static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt) { int dev = MINOR(SCpnt->request.rq_dev); - Sg_device * sdp; + Sg_device * sdp = NULL; Sg_fd * sfp; Sg_request * srp = NULL; - if (NULL == (sdp = sg_get_dev(dev))) { + read_lock(&sg_dev_arr_lock); + if (sg_dev_arr && (dev >= 0)) { + if (dev < sg_template.dev_max) + sdp = sg_dev_arr[dev]; + } + if (NULL == sdp) { + read_unlock(&sg_dev_arr_lock); SCSI_LOG_TIMEOUT(1, printk("sg...bh: bad args dev=%d\n", dev)); scsi_release_command(SCpnt); SCpnt = NULL; @@ -972,16 +1007,17 @@ } sfp = sdp->headfp; while (sfp) { - srp = sfp->headrp; - while (srp) { + read_lock(&sfp->rq_list_lock); + for (srp = sfp->headrp; srp; srp = srp->nextrp) { if (SCpnt == srp->my_cmdp) break; - srp = srp->nextrp; } + read_unlock(&sfp->rq_list_lock); if (srp) break; sfp = sfp->nextfp; } + read_unlock(&sg_dev_arr_lock); if (! srp) { SCSI_LOG_TIMEOUT(1, printk("sg...bh: req missing, dev=%d\n", dev)); scsi_release_command(SCpnt); @@ -1001,6 +1037,7 @@ dev, srp->header.pack_id, (int)SCpnt->result)); srp->header.resid = SCpnt->resid; /* sg_unmap_and(&srp->data, 0); */ /* unmap locked pages a.s.a.p. */ + /* N.B. unit of duration changes here from jiffies to millisecs */ srp->header.duration = sg_jif_to_ms(jiffies - (int)srp->header.duration); if (0 != SCpnt->result) { memcpy(srp->sense_b, SCpnt->sense_buffer, sizeof(srp->sense_b)); @@ -1052,8 +1089,7 @@ if (sfp && srp) { /* Now wake up any sg_read() that is waiting for this packet. */ wake_up_interruptible(&sfp->read_wait); - if (sfp->async_qp) - kill_fasync(sfp->async_qp, SIGPOLL, POLL_IN); + kill_fasync(&sfp->async_qp, SIGPOLL, POLL_IN); } } @@ -1091,18 +1127,18 @@ static int sg_init() { static int sg_registered = 0; - unsigned long flags = 0; + unsigned long iflags; if ((sg_template.dev_noticed == 0) || sg_dev_arr) return 0; - write_lock_irqsave(&sg_dev_arr_lock, flags); + write_lock_irqsave(&sg_dev_arr_lock, iflags); if(!sg_registered) { if (devfs_register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops)) { printk("Unable to get major %d for generic SCSI device\n", SCSI_GENERIC_MAJOR); - write_unlock_irqrestore(&sg_dev_arr_lock, flags); + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); return 1; } sg_registered++; @@ -1114,11 +1150,11 @@ sizeof(Sg_device *), GFP_ATOMIC); if (NULL == sg_dev_arr) { printk("sg_init: no space for sg_dev_arr\n"); - write_unlock_irqrestore(&sg_dev_arr_lock, flags); + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); return 1; } memset(sg_dev_arr, 0, sg_template.dev_max * sizeof(Sg_device *)); - write_unlock_irqrestore(&sg_dev_arr_lock, flags); + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); #ifdef CONFIG_PROC_FS sg_proc_init(); #endif /* CONFIG_PROC_FS */ @@ -1149,10 +1185,10 @@ static int sg_attach(Scsi_Device * scsidp) { Sg_device * sdp; - unsigned long flags = 0; + unsigned long iflags; int k; - write_lock_irqsave(&sg_dev_arr_lock, flags); + write_lock_irqsave(&sg_dev_arr_lock, iflags); if (sg_template.nr_dev >= sg_template.dev_max) { /* try to resize */ Sg_device ** tmp_da; int tmp_dev_max = sg_template.nr_dev + SG_DEV_ARR_LUMP; @@ -1161,7 +1197,7 @@ sizeof(Sg_device *), GFP_ATOMIC); if (NULL == tmp_da) { scsidp->attached--; - write_unlock_irqrestore(&sg_dev_arr_lock, flags); + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); printk("sg_attach: device array cannot be resized\n"); return 1; } @@ -1180,7 +1216,7 @@ sdp = NULL; if (NULL == sdp) { scsidp->attached--; - write_unlock_irqrestore(&sg_dev_arr_lock, flags); + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); printk("sg_attach: Sg_device cannot be allocated\n"); return 1; } @@ -1194,13 +1230,13 @@ sdp->detached = 0; sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0; sdp->i_rdev = MKDEV(SCSI_GENERIC_MAJOR, k); - sdp->de = devfs_register (scsidp->de, "generic", 7, DEVFS_FL_NONE, + sdp->de = devfs_register (scsidp->de, "generic", DEVFS_FL_DEFAULT, SCSI_GENERIC_MAJOR, k, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, &sg_fops, NULL); sg_template.nr_dev++; sg_dev_arr[k] = sdp; - write_unlock_irqrestore(&sg_dev_arr_lock, flags); + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); return 0; } @@ -1214,37 +1250,36 @@ static void sg_detach(Scsi_Device * scsidp) { Sg_device * sdp; - unsigned long flags = 0; + unsigned long iflags; Sg_fd * sfp; Sg_request * srp; int k; if (NULL == sg_dev_arr) return; - write_lock_irqsave(&sg_dev_arr_lock, flags); -/* Need to stop sg_cmd_done_bh() playing with this list during this loop */ + write_lock_irqsave(&sg_dev_arr_lock, iflags); for (k = 0; k < sg_template.dev_max; k++) { sdp = sg_dev_arr[k]; if ((NULL == sdp) || (sdp->device != scsidp)) continue; /* dirty but lowers nesting */ if (sdp->headfp) { - sfp = sdp->headfp; - while (sfp) { - srp = sfp->headrp; - while (srp) { - if (! srp->done) + for (sfp = sdp->headfp; sfp; sfp = sfp->nextfp) { + /* no lock on request list here */ + for (srp = sfp->headrp; srp; srp = srp->nextrp) { + if (! srp->done) { + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); sg_shorten_timeout(srp->my_cmdp); - srp = srp->nextrp; + write_lock_irqsave(&sg_dev_arr_lock, iflags); } - sfp = sfp->nextfp; } - write_unlock_irqrestore(&sg_dev_arr_lock, flags); + } + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty, sleep(3)\n", k)); scsi_sleep(3); /* sleep 3 jiffies, hoping for timeout to go off */ devfs_unregister (sdp->de); sdp->de = NULL; sdp->detached = 1; - write_lock_irqsave(&sg_dev_arr_lock, flags); + write_lock_irqsave(&sg_dev_arr_lock, iflags); } else { SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k)); @@ -1259,7 +1294,7 @@ sg_template.dev_noticed--; break; } - write_unlock_irqrestore(&sg_dev_arr_lock, flags); + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); return; } @@ -1277,12 +1312,11 @@ void cleanup_module( void) { - scsi_unregister_module(MODULE_SCSI_DEV, &sg_template); - devfs_unregister_chrdev(SCSI_GENERIC_MAJOR, "sg"); - #ifdef CONFIG_PROC_FS sg_proc_cleanup(); #endif /* CONFIG_PROC_FS */ + scsi_unregister_module(MODULE_SCSI_DEV, &sg_template); + devfs_unregister_chrdev(SCSI_GENERIC_MAJOR, "sg"); if(sg_dev_arr != NULL) { /* Really worrying situation of writes still pending and get here */ /* Strategy: shorten timeout on release + wait on detach ... */ @@ -1301,7 +1335,7 @@ /* Can't see clean way to abort a command so shorten timeout to 1 jiffy */ static void sg_shorten_timeout(Scsi_Cmnd * scpnt) -{ /* assumed to be called with sg_dev_arr_lock held */ +{ #if 0 /* scsi_syms.c is very miserly about exported functions */ scsi_delete_timer(scpnt); if (! scpnt) @@ -1313,11 +1347,7 @@ scsi_add_timer(scpnt, scpnt->timeout_per_command, scsi_old_times_out); #else - unsigned long flags = 0; - - write_unlock_irqrestore(&sg_dev_arr_lock, flags); scsi_sleep(HZ); /* just sleep 1 second and hope ... */ - write_lock_irqsave(&sg_dev_arr_lock, flags); #endif } @@ -1859,6 +1889,8 @@ Sg_scatter_hold * rsv_schp = &sfp->reserve; SCSI_LOG_TIMEOUT(4, printk("sg_link_reserve: size=%d\n", size)); + /* round request up to next highest SG_SECTOR_SZ byte boundary */ + size = (size + SG_SECTOR_MSK) & (~SG_SECTOR_MSK); if (rsv_schp->k_use_sg > 0) { int k, num; int rem = size; @@ -1921,17 +1953,35 @@ srp->res_used = 0; } -static Sg_request * sg_get_request(const Sg_fd * sfp, int pack_id) +static Sg_request * sg_get_rq_mark(Sg_fd * sfp, int pack_id) { - Sg_request * resp = NULL; + Sg_request * resp; + unsigned long iflags; - resp = sfp->headrp; - while (resp) { /* look for requests that are ready + not SG_IO owned */ - if (resp->done && (! resp->sg_io_owned) && - ((-1 == pack_id) || (resp->header.pack_id == pack_id))) - return resp; - resp = resp->nextrp; + write_lock_irqsave(&sfp->rq_list_lock, iflags); + for (resp = sfp->headrp; resp; resp = resp->nextrp) { + /* look for requests that are ready + not SG_IO owned */ + if ((1 == resp->done) && (! resp->sg_io_owned) && + ((-1 == pack_id) || (resp->header.pack_id == pack_id))) { + resp->done = 2; /* guard against other readers */ + break; + } } + write_unlock_irqrestore(&sfp->rq_list_lock, iflags); + return resp; +} + +static Sg_request * sg_get_nth_request(Sg_fd * sfp, int nth) +{ + Sg_request * resp; + unsigned long iflags; + int k; + + read_lock_irqsave(&sfp->rq_list_lock, iflags); + for (k = 0, resp = sfp->headrp; resp && (k < nth); + ++k, resp = resp->nextrp) + ; + read_unlock_irqrestore(&sfp->rq_list_lock, iflags); return resp; } @@ -1939,46 +1989,45 @@ static Sg_request * sg_add_request(Sg_fd * sfp) { int k; - Sg_request * resp = NULL; - Sg_request * rp; + unsigned long iflags; + Sg_request * resp; + Sg_request * rp = sfp->req_arr; + write_lock_irqsave(&sfp->rq_list_lock, iflags); resp = sfp->headrp; - rp = sfp->req_arr; if (! resp) { - resp = rp; - sfp->headrp = resp; + memset(rp, 0, sizeof(Sg_request)); + rp->parentfp = sfp; + resp = rp; + sfp->headrp = resp; } else { if (0 == sfp->cmd_q) resp = NULL; /* command queuing disallowed */ else { - for (k = 0, rp; k < SG_MAX_QUEUE; ++k, ++rp) { + for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) { if (! rp->parentfp) break; } if (k < SG_MAX_QUEUE) { - while (resp->nextrp) resp = resp->nextrp; - resp->nextrp = rp; - resp = rp; + memset(rp, 0, sizeof(Sg_request)); + rp->parentfp = sfp; + while (resp->nextrp) + resp = resp->nextrp; + resp->nextrp = rp; + resp = rp; } else resp = NULL; } } if (resp) { - resp->parentfp = sfp; resp->nextrp = NULL; - resp->res_used = 0; - resp->orphan = 0; - resp->sg_io_owned = 0; - resp->done = 0; - memset(&resp->data, 0, sizeof(Sg_scatter_hold)); - memset(&resp->header, 0, size_sg_io_hdr); resp->header.duration = jiffies; resp->my_cmdp = NULL; resp->data.kiobp = NULL; - resp->data.mapped = 0; } + write_unlock_irqrestore(&sfp->rq_list_lock, iflags); return resp; } @@ -1987,29 +2036,51 @@ { Sg_request * prev_rp; Sg_request * rp; + unsigned long iflags; + int res = 0; if ((! sfp) || (! srp) || (! sfp->headrp)) - return 0; + return res; + write_lock_irqsave(&sfp->rq_list_lock, iflags); prev_rp = sfp->headrp; if (srp == prev_rp) { - prev_rp->parentfp = NULL; sfp->headrp = prev_rp->nextrp; - return 1; + prev_rp->parentfp = NULL; + res = 1; } - while ((rp = prev_rp->nextrp)) { - if (srp == rp) { - rp->parentfp = NULL; - prev_rp->nextrp = rp->nextrp; - return 1; - } - prev_rp = rp; + else { + while ((rp = prev_rp->nextrp)) { + if (srp == rp) { + prev_rp->nextrp = rp->nextrp; + rp->parentfp = NULL; + res = 1; + break; + } + prev_rp = rp; + } } - return 0; + write_unlock_irqrestore(&sfp->rq_list_lock, iflags); + return res; +} + +static Sg_fd * sg_get_nth_sfp(Sg_device * sdp, int nth) +{ + Sg_fd * resp; + unsigned long iflags; + int k; + + read_lock_irqsave(&sg_dev_arr_lock, iflags); + for (k = 0, resp = sdp->headfp; resp && (k < nth); + ++k, resp = resp->nextfp) + ; + read_unlock_irqrestore(&sg_dev_arr_lock, iflags); + return resp; } static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev) { Sg_fd * sfp; + unsigned long iflags; sfp = (Sg_fd *)sg_low_malloc(sizeof(Sg_fd), 0, SG_HEAP_KMAL, 0); if (! sfp) @@ -2017,6 +2088,7 @@ memset(sfp, 0, sizeof(Sg_fd)); sfp->fd_mem_src = SG_HEAP_KMAL; init_waitqueue_head(&sfp->read_wait); + sfp->rq_list_lock = RW_LOCK_UNLOCKED; sfp->timeout = SG_DEFAULT_TIMEOUT; sfp->force_packid = SG_DEF_FORCE_PACK_ID; @@ -2025,14 +2097,16 @@ sfp->cmd_q = SG_DEF_COMMAND_Q; sfp->keep_orphan = SG_DEF_KEEP_ORPHAN; sfp->parentdp = sdp; + write_lock_irqsave(&sg_dev_arr_lock, iflags); if (! sdp->headfp) sdp->headfp = sfp; else { /* add to tail of existing list */ - Sg_fd * pfp = sdp->headfp; - while (pfp->nextfp) - pfp = pfp->nextfp; - pfp->nextfp = sfp; + Sg_fd * pfp = sdp->headfp; + while (pfp->nextfp) + pfp = pfp->nextfp; + pfp->nextfp = sfp; } + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p, m_s=%d\n", sfp, (int)sfp->fd_mem_src)); sg_build_reserve(sfp, sg_big_buff); @@ -2048,36 +2122,41 @@ int dirty = 0; int res = 0; + /* no lock since not expecting any parallel action on this fd */ srp = sfp->headrp; if (srp) { - while (srp) { - tsrp = srp->nextrp; + while (srp) { + tsrp = srp->nextrp; if (srp->done) sg_finish_rem_req(srp); - else - ++dirty; - srp = tsrp; - } + else + ++dirty; + srp = tsrp; + } } if (0 == dirty) { - Sg_fd * fp; - Sg_fd * prev_fp = sdp->headfp; - - if (sfp == prev_fp) - sdp->headfp = prev_fp->nextfp; - else { - while ((fp = prev_fp->nextfp)) { - if (sfp == fp) { - prev_fp->nextfp = fp->nextfp; - break; - } - prev_fp = fp; - } - } - if (sfp->reserve.bufflen > 0) { + Sg_fd * fp; + Sg_fd * prev_fp; + unsigned long iflags; + + write_lock_irqsave(&sg_dev_arr_lock, iflags); + prev_fp = sdp->headfp; + if (sfp == prev_fp) + sdp->headfp = prev_fp->nextfp; + else { + while ((fp = prev_fp->nextfp)) { + if (sfp == fp) { + prev_fp->nextfp = fp->nextfp; + break; + } + prev_fp = fp; + } + } + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); + if (sfp->reserve.bufflen > 0) { SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: bufflen=%d, k_use_sg=%d\n", (int)sfp->reserve.bufflen, (int)sfp->reserve.k_use_sg)); - sg_remove_scat(&sfp->reserve); + sg_remove_scat(&sfp->reserve); } sfp->parentdp = NULL; SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: sfp=0x%p\n", sfp)); @@ -2104,28 +2183,28 @@ return res; } -static int sg_res_in_use(const Sg_fd * sfp) +static int sg_res_in_use(Sg_fd * sfp) { - const Sg_request * srp = sfp->headrp; + const Sg_request * srp; + unsigned long iflags; - while (srp) { - if (srp->res_used) - return 1; - srp = srp->nextrp; - } - return 0; + read_lock_irqsave(&sfp->rq_list_lock, iflags); + for (srp = sfp->headrp; srp; srp = srp->nextrp) + if (srp->res_used) break; + read_unlock_irqrestore(&sfp->rq_list_lock, iflags); + return srp ? 1 : 0; } -static int sg_dio_in_use(const Sg_fd * sfp) +static int sg_dio_in_use(Sg_fd * sfp) { - const Sg_request * srp = sfp->headrp; + const Sg_request * srp; + unsigned long iflags; - while (srp) { - if ((! srp->done) && srp->data.kiobp) - return 1; - srp = srp->nextrp; - } - return 0; + read_lock_irqsave(&sfp->rq_list_lock, iflags); + for (srp = sfp->headrp; srp; srp = srp->nextrp) + if ((! srp->done) && srp->data.kiobp) break; + read_unlock_irqrestore(&sfp->rq_list_lock, iflags); + return srp ? 1 : 0; } /* If retSzp==NULL want exact size or fail */ @@ -2314,7 +2393,8 @@ } static unsigned char allow_ops[] = {TEST_UNIT_READY, INQUIRY, -READ_CAPACITY, READ_BUFFER, READ_6, READ_10, READ_12}; +READ_CAPACITY, READ_BUFFER, READ_6, READ_10, READ_12, +MODE_SENSE, MODE_SENSE_10}; static int sg_allow_access(unsigned char opcode, char dev_type) { @@ -2331,28 +2411,29 @@ static int sg_last_dev() -{ /* assumed to be called with sg_dev_arr_lock held */ +{ int k; + unsigned long iflags; - for (k = sg_template.dev_max - 1; k >= 0; --k) { - if (sg_dev_arr[k] && sg_dev_arr[k]->device) - return k + 1; - } - return 0; /* origin 1 */ + read_lock_irqsave(&sg_dev_arr_lock, iflags); + for (k = sg_template.dev_max - 1; k >= 0; --k) + if (sg_dev_arr[k] && sg_dev_arr[k]->device) break; + read_unlock_irqrestore(&sg_dev_arr_lock, iflags); + return k + 1; /* origin 1 */ } static Sg_device * sg_get_dev(int dev) { - Sg_device * sdp; + Sg_device * sdp = NULL; + unsigned long iflags; - if ((NULL == sg_dev_arr) || (dev < 0)) - return NULL; - read_lock(&sg_dev_arr_lock); + if (sg_dev_arr && (dev >= 0)) + { + read_lock_irqsave(&sg_dev_arr_lock, iflags); if (dev < sg_template.dev_max) sdp = sg_dev_arr[dev]; - else - sdp = NULL; - read_unlock(&sg_dev_arr_lock); + read_unlock_irqrestore(&sg_dev_arr_lock, iflags); + } return sdp; } @@ -2429,8 +2510,7 @@ *eof = infofp(buffer, &len, &begin, offset, size); \ if (offset >= (begin + len)) \ return 0; \ - *start = buffer + ((begin > offset) ? \ - (begin - offset) : (offset - begin)); \ + *start = buffer + offset - begin; \ return (size < (begin + len - offset)) ? \ size : begin + len - offset; \ } while(0) @@ -2520,7 +2600,6 @@ PRINT_PROC("sg_dev_arr NULL, driver not initialized\n"); return 1; } - read_lock(&sg_dev_arr_lock); max_dev = sg_last_dev(); PRINT_PROC("dev_max(currently)=%d max_active_device=%d (origin 1)\n", sg_template.dev_max, max_dev); @@ -2528,11 +2607,11 @@ "def_reserved_size=%d\n", scsi_dma_free_sectors, sg_pool_secs_avail, sg_big_buff); for (j = 0; j < max_dev; ++j) { - if ((sdp = sg_dev_arr[j])) { + if ((sdp = sg_get_dev(j))) { Sg_fd * fp; Sg_request * srp; struct scsi_device * scsidp; - int dev, k, blen, usg; + int dev, k, m, blen, usg; if (! (scsidp = sdp->device)) { PRINT_PROC("device %d detached ??\n", j); @@ -2540,48 +2619,45 @@ } dev = MINOR(sdp->i_rdev); - if ((fp = sdp->headfp)) { - PRINT_PROC(" >>> device=%d(sg%d) ", dev, dev); + if (sg_get_nth_sfp(sdp, 0)) { + PRINT_PROC(" >>> device=sg%d ", dev); PRINT_PROC("scsi%d chan=%d id=%d lun=%d em=%d sg_tablesize=%d" " excl=%d\n", scsidp->host->host_no, scsidp->channel, scsidp->id, scsidp->lun, scsidp->host->hostt->emulated, sdp->sg_tablesize, sdp->exclude); } - for (k = 1; fp; fp = fp->nextfp, ++k) { - PRINT_PROC(" FD(%d): timeout=%d bufflen=%d " - "(res)sgat=%d low_dma=%d\n", - k, fp->timeout, fp->reserve.bufflen, + for (k = 0; (fp = sg_get_nth_sfp(sdp, k)); ++k) { + PRINT_PROC(" FD(%d): timeout=%dms bufflen=%d " + "(res)sgat=%d low_dma=%d\n", k + 1, + sg_jif_to_ms(fp->timeout), fp->reserve.bufflen, (int)fp->reserve.k_use_sg, (int)fp->low_dma); PRINT_PROC(" cmd_q=%d f_packid=%d k_orphan=%d closed=%d\n", (int)fp->cmd_q, (int)fp->force_packid, (int)fp->keep_orphan, (int)fp->closed); - srp = fp->headrp; - if (NULL == srp) - PRINT_PROC(" No requests active\n"); - while (srp) { + for (m = 0; (srp = sg_get_nth_request(fp, m)); ++m) { hp = &srp->header; /* stop indenting so far ... */ PRINT_PROC(srp->res_used ? " rb>> " : ((SG_INFO_DIRECT_IO_MASK & hp->info) ? " dio>> " : " ")); blen = srp->my_cmdp ? srp->my_cmdp->bufflen : srp->data.bufflen; usg = srp->my_cmdp ? srp->my_cmdp->use_sg : srp->data.k_use_sg; - PRINT_PROC(srp->done ? "rcv: id=%d" : (srp->my_cmdp ? "act: id=%d" : - "prior: id=%d"), srp->header.pack_id); - PRINT_PROC(" blen=%d", blen); + PRINT_PROC(srp->done ? ((1 == srp->done) ? "rcv:" : "fin:") + : (srp->my_cmdp ? "act:" : "prior:")); + PRINT_PROC(" id=%d blen=%d", srp->header.pack_id, blen); if (srp->done) - PRINT_PROC(" dur=%d", sg_jif_to_ms(hp->duration)); + PRINT_PROC(" dur=%d", hp->duration); else PRINT_PROC(" t_o/elap=%d/%d", ((hp->interface_id == '\0') ? sg_jif_to_ms(fp->timeout) : hp->timeout), sg_jif_to_ms(hp->duration ? (jiffies - hp->duration) : 0)); - PRINT_PROC(" sgat=%d op=0x%02x\n", usg, (int)srp->data.cmd_opcode); - srp = srp->nextrp; + PRINT_PROC("ms sgat=%d op=0x%02x\n", usg, (int)srp->data.cmd_opcode); /* reset indenting */ } + if (0 == m) + PRINT_PROC(" No requests active\n"); } } } - read_unlock(&sg_dev_arr_lock); return 1; } @@ -2596,19 +2672,17 @@ int j, max_dev; struct scsi_device * scsidp; - read_lock(&sg_dev_arr_lock); max_dev = sg_last_dev(); for (j = 0; j < max_dev; ++j) { - sdp = sg_dev_arr[j]; + sdp = sg_get_dev(j); if (sdp && (scsidp = sdp->device)) PRINT_PROC("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", scsidp->host->host_no, scsidp->channel, scsidp->id, - scsidp->lun, (int)scsidp->type, (int)scsidp->disconnect, - (int)scsidp->queue_depth, (int)scsidp->tagged_queue); + scsidp->lun, (int)scsidp->type, (int)scsidp->access_count, + (int)scsidp->queue_depth, (int)scsidp->device_busy); else PRINT_PROC("-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n"); } - read_unlock(&sg_dev_arr_lock); return 1; } @@ -2619,7 +2693,7 @@ static int sg_proc_devhdr_info(char * buffer, int * len, off_t * begin, off_t offset, int size) { - PRINT_PROC("host\tchan\tid\tlun\ttype\tdiscon\tqdepth\ttq\n"); + PRINT_PROC("host\tchan\tid\tlun\ttype\tbopens\tqdepth\tbusy\n"); return 1; } @@ -2634,17 +2708,15 @@ int j, max_dev; struct scsi_device * scsidp; - read_lock(&sg_dev_arr_lock); max_dev = sg_last_dev(); for (j = 0; j < max_dev; ++j) { - sdp = sg_dev_arr[j]; + sdp = sg_get_dev(j); if (sdp && (scsidp = sdp->device)) PRINT_PROC("%8.8s\t%16.16s\t%4.4s\n", scsidp->vendor, scsidp->model, scsidp->rev); else PRINT_PROC("\n"); } - read_unlock(&sg_dev_arr_lock); return 1; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v2.4.0-test1/linux/drivers/scsi/sr.c Tue Mar 14 19:10:40 2000 +++ linux/drivers/scsi/sr.c Thu Jun 22 07:15:10 2000 @@ -25,6 +25,9 @@ * * Modified by Richard Gooch to support devfs * + * Modified by Jens Axboe - support DVD-RAM + * transparently and loose the GHOST hack + * */ #include @@ -297,9 +300,10 @@ else printk("sr: can't switch blocksize: in interrupt\n"); } - if (SCpnt->request.cmd == WRITE) { + + if ((SCpnt->request.cmd == WRITE) && !scsi_CDs[dev].device->writeable) return 0; - } + if (scsi_CDs[dev].device->sector_size == 1024) { if ((block & 1) || (SCpnt->request.nr_sectors & 1)) { printk("sr.c:Bad 1K block number requested (%d %ld)", @@ -322,9 +326,6 @@ } switch (SCpnt->request.cmd) { case WRITE: - if (!scsi_CDs[dev].device->writeable) { - return 0; - } SCpnt->cmnd[0] = WRITE_10; SCpnt->sc_data_direction = SCSI_DATA_WRITE; break; @@ -587,10 +588,11 @@ scsi_CDs[i].readcd_known = 1; scsi_CDs[i].readcd_cdda = buffer[n + 5] & 0x01; /* print some capability bits */ - printk("sr%i: scsi3-mmc drive: %dx/%dx %s%s%s%s%s\n", i, + printk("sr%i: scsi3-mmc drive: %dx/%dx %s%s%s%s%s%s\n", i, ((buffer[n + 14] << 8) + buffer[n + 15]) / 176, scsi_CDs[i].cdi.speed, buffer[n + 3] & 0x01 ? "writer " : "", /* CD Writer */ + buffer[n + 3] & 0x20 ? "dvd-ram " : "", buffer[n + 2] & 0x02 ? "cd/rw " : "", /* can read rewriteable */ buffer[n + 4] & 0x20 ? "xa/form2 " : "", /* can read xa/from2 */ buffer[n + 5] & 0x01 ? "cdda " : "", /* can read audio data */ @@ -601,9 +603,12 @@ if ((buffer[n + 2] & 0x8) == 0) /* not a DVD drive */ scsi_CDs[i].cdi.mask |= CDC_DVD; - if ((buffer[n + 3] & 0x20) == 0) + if ((buffer[n + 3] & 0x20) == 0) { /* can't write DVD-RAM media */ scsi_CDs[i].cdi.mask |= CDC_DVD_RAM; + } else { + scsi_CDs[i].device->writeable = 1; + } if ((buffer[n + 3] & 0x10) == 0) /* can't write DVD-R media */ scsi_CDs[i].cdi.mask |= CDC_DVD_R; @@ -627,7 +632,6 @@ /*else I don't think it can close its tray scsi_CDs[i].cdi.mask |= CDC_CLOSE_TRAY; */ - scsi_free(buffer, 512); } @@ -773,9 +777,9 @@ sprintf(name, "sr%d", i); strcpy(scsi_CDs[i].cdi.name, name); scsi_CDs[i].cdi.de = - devfs_register (scsi_CDs[i].device->de, "cd", 2, + devfs_register (scsi_CDs[i].device->de, "cd", DEVFS_FL_DEFAULT, MAJOR_NR, i, - S_IFBLK | S_IRUGO | S_IWUGO, 0, 0, + S_IFBLK | S_IRUGO | S_IWUGO, &cdrom_fops, NULL); register_cdrom(&scsi_CDs[i].cdi); } @@ -853,7 +857,6 @@ } blksize_size[MAJOR_NR] = NULL; hardsect_size[MAJOR_NR] = NULL; - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); blk_size[MAJOR_NR] = NULL; read_ahead[MAJOR_NR] = 0; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/st.c linux/drivers/scsi/st.c --- v2.4.0-test1/linux/drivers/scsi/st.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/scsi/st.c Wed Jun 21 22:31:02 2000 @@ -3509,17 +3509,17 @@ /* Rewind entry */ sprintf (name, "mt%s", formats[mode]); tpnt->de_r[mode] = - devfs_register (SDp->de, name, 0, DEVFS_FL_DEFAULT, + devfs_register (SDp->de, name, DEVFS_FL_DEFAULT, MAJOR_NR, i + (mode << 5), S_IFCHR | S_IRUGO | S_IWUGO, - 0, 0, &st_fops, NULL); + &st_fops, NULL); /* No-rewind entry */ sprintf (name, "mt%sn", formats[mode]); tpnt->de_n[mode] = - devfs_register (SDp->de, name, 0, DEVFS_FL_DEFAULT, + devfs_register (SDp->de, name, DEVFS_FL_DEFAULT, MAJOR_NR, i + (mode << 5) + 128, S_IFCHR | S_IRUGO | S_IWUGO, - 0, 0, &st_fops, NULL); + &st_fops, NULL); } devfs_register_tape (tpnt->de_r[0]); tpnt->device = SDp; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/sym53c8xx.c linux/drivers/scsi/sym53c8xx.c --- v2.4.0-test1/linux/drivers/scsi/sym53c8xx.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/scsi/sym53c8xx.c Mon Jun 19 17:59:42 2000 @@ -55,7 +55,7 @@ */ /* -** April 24 2000, sym53c8xx 1.5m +** May 11 2000, sym53c8xx 1.6b ** ** Supported SCSI features: ** Synchronous data transfers @@ -73,7 +73,10 @@ ** 53C895 (Wide, Fast 40, on-board rom BIOS) ** 53C895A (Wide, Fast 40, on-board rom BIOS) ** 53C896 (Wide, Fast 40 Dual, on-board rom BIOS) +** 53C897 (Wide, Fast 40 Dual, on-board rom BIOS) ** 53C1510D (Wide, Fast 40 Dual, on-board rom BIOS) +** 53C1010 (Wide, Fast 80 Dual, on-board rom BIOS) +** 53C1010_66(Wide, Fast 80 Dual, on-board rom BIOS, 33/66MHz PCI) ** ** Other features: ** Memory mapped IO @@ -84,7 +87,7 @@ /* ** Name and version of the driver */ -#define SCSI_NCR_DRIVER_NAME "sym53c8xx - version 1.5m" +#define SCSI_NCR_DRIVER_NAME "sym53c8xx - version 1.6b" /* #define DEBUG_896R1 */ #define SCSI_NCR_OPTIMIZE_896 @@ -174,6 +177,14 @@ #include "sym53c8xx.h" +/* +** Donnot compile integrity checking code for Linux-2.3.0 +** and above since SCSI data structures are not ready yet. +*/ +#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,0) +#define SCSI_NCR_INTEGRITY_CHECKING +#endif + #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define MAX(a,b) (((a) > (b)) ? (a) : (b)) @@ -606,6 +617,7 @@ #define DEBUG_TIMING (0x0100) #define DEBUG_NEGO (0x0200) #define DEBUG_TAGS (0x0400) +#define DEBUG_IC (0x0800) /* ** Enable/Disable debug messages. @@ -1654,6 +1666,8 @@ #define XE_EXTRA_DATA (1) /* unexpected data phase */ #define XE_BAD_PHASE (2) /* illegal phase (4/5) */ #define XE_PARITY_ERR (4) /* unrecovered SCSI parity error */ +#define XE_SODL_UNRUN (1<<3) +#define XE_SWIDE_OVRUN (1<<4) /*========================================================== ** @@ -1663,8 +1677,10 @@ **========================================================== */ +#define NS_NOCHANGE (0) #define NS_SYNC (1) #define NS_WIDE (2) +#define NS_PPR (4) /*========================================================== ** @@ -1819,7 +1835,7 @@ /*---------------------------------------------------------------- ** negotiation of wide and synch transfer and device quirks. - ** sval and wval are read from SCRIPTS and so have alignment + ** sval, wval and uval are read from SCRIPTS and so have alignment ** constraints. **---------------------------------------------------------------- */ @@ -1830,6 +1846,15 @@ /*1*/ u_char quirks; /*2*/ u_char widedone; /*3*/ u_char wval; +/*0*/ u_char uval; + +#ifdef SCSI_NCR_INTEGRITY_CHECKING + u_char ic_min_sync; + u_char ic_max_width; + u_char ic_done; +#endif + u_char ic_maximums_set; + u_char ppr_negotiation; /*---------------------------------------------------------------- ** User settable limits and options. @@ -1838,8 +1863,8 @@ */ u_char usrsync; u_char usrwide; - u_char usrflag; u_short usrtags; + u_char usrflag; }; /*======================================================================== @@ -2049,6 +2074,7 @@ #define HF_AUTO_SENSE (1u<<4) #define HF_DATA_IN (1u<<5) #define HF_PM_TO_C (1u<<6) +#define HF_EXT_ERR (1u<<7) #ifdef SCSI_NCR_IARB_SUPPORT #define HF_HINT_IARB (1u<<7) @@ -2106,6 +2132,7 @@ struct scr_tblmove smsg_ext ; struct scr_tblmove cmd ; struct scr_tblmove sense ; + struct scr_tblmove wresid; struct scr_tblmove data [MAX_SCATTER]; /* @@ -2269,7 +2296,7 @@ **---------------------------------------------------------------- */ u_char sv_scntl0, sv_scntl3, sv_dmode, sv_dcntl, sv_ctest3, sv_ctest4, - sv_ctest5, sv_gpcntl, sv_stest2, sv_stest4, sv_stest1; + sv_ctest5, sv_gpcntl, sv_stest2, sv_stest4, sv_stest1, sv_scntl4; /*---------------------------------------------------------------- ** Actual initial value of IO register bits used by the @@ -2278,7 +2305,7 @@ **---------------------------------------------------------------- */ u_char rv_scntl0, rv_scntl3, rv_dmode, rv_dcntl, rv_ctest3, rv_ctest4, - rv_ctest5, rv_stest2, rv_ccntl0, rv_ccntl1; + rv_ctest5, rv_stest2, rv_ccntl0, rv_ccntl1, rv_scntl4; /*---------------------------------------------------------------- ** Target data. @@ -2393,8 +2420,8 @@ ** written with a script command. **---------------------------------------------------------------- */ - u_char msgout[8]; /* Buffer for MESSAGE OUT */ - u_char msgin [8]; /* Buffer for MESSAGE IN */ + u_char msgout[12]; /* Buffer for MESSAGE OUT */ + u_char msgin [12]; /* Buffer for MESSAGE IN */ u_int32 lastmsg; /* Last SCSI message sent */ u_char scratch; /* Scratch for SCSI receive */ @@ -2466,6 +2493,17 @@ */ struct usrcmd user; /* Command from user */ u_char release_stage; /* Synchronisation stage on release */ + + /*---------------------------------------------------------------- + ** Fields that are used (primarily) for integrity check + **---------------------------------------------------------------- + */ + unsigned char check_integrity; /* Enable midlayer integ. check on + * bus scan. */ +#ifdef SCSI_NCR_INTEGRITY_CHECKING + unsigned char check_integ_par; /* Set if par or Init. Det. error + * used only during integ check */ +#endif }; #define NCB_PHYS(np, lbl) (np->p_ncb + offsetof(struct ncb, lbl)) @@ -2511,20 +2549,20 @@ ncrcmd select2 [ 2]; #endif ncrcmd command [ 2]; - ncrcmd dispatch [ 28]; + ncrcmd dispatch [ 30]; ncrcmd sel_no_cmd [ 10]; ncrcmd init [ 6]; ncrcmd clrack [ 4]; - ncrcmd disp_msg_in [ 2]; ncrcmd disp_status [ 4]; - ncrcmd datai_done [ 16]; - ncrcmd datao_done [ 10]; + ncrcmd datai_done [ 26]; + ncrcmd datao_done [ 12]; ncrcmd ign_i_w_r_msg [ 4]; #ifdef SCSI_NCR_PROFILE_SUPPORT - ncrcmd dataphase [ 4]; + ncrcmd datai_phase [ 4]; #else - ncrcmd dataphase [ 2]; + ncrcmd datai_phase [ 2]; #endif + ncrcmd datao_phase [ 4]; ncrcmd msg_in [ 2]; ncrcmd msg_in2 [ 10]; #ifdef SCSI_NCR_IARB_SUPPORT @@ -2562,16 +2600,17 @@ ncrcmd ungetjob [ 4]; #endif ncrcmd reselect [ 4]; - ncrcmd reselected [ 48]; + ncrcmd reselected [ 20]; + ncrcmd resel_scntl4 [ 30]; #if MAX_TASKS*4 > 512 - ncrcmd resel_tag [ 16]; + ncrcmd resel_tag [ 18]; #elif MAX_TASKS*4 > 256 - ncrcmd resel_tag [ 10]; + ncrcmd resel_tag [ 12]; #else - ncrcmd resel_tag [ 6]; + ncrcmd resel_tag [ 8]; #endif ncrcmd resel_go [ 6]; - ncrcmd resel_notag [ 4]; + ncrcmd resel_notag [ 2]; ncrcmd resel_dsa [ 8]; ncrcmd data_in [MAX_SCATTER * SCR_SG_SIZE]; ncrcmd data_in2 [ 4]; @@ -2591,6 +2630,7 @@ */ struct scripth { ncrcmd start64 [ 2]; + ncrcmd no_data [ 2]; ncrcmd sel_for_abort [ 18]; ncrcmd sel_for_abort_1 [ 2]; ncrcmd select_no_atn [ 8]; @@ -2608,11 +2648,13 @@ ncrcmd send_wdtr [ 4]; ncrcmd sdtr_resp [ 6]; ncrcmd send_sdtr [ 4]; + ncrcmd ppr_resp [ 6]; + ncrcmd send_ppr [ 4]; ncrcmd nego_bad_phase [ 4]; - ncrcmd msg_out_abort [ 12]; - ncrcmd msg_out [ 6]; + ncrcmd msg_out [ 4]; ncrcmd msg_out_done [ 4]; - ncrcmd no_data [ 28]; + ncrcmd data_ovrun [ 18]; + ncrcmd data_ovrun1 [ 20]; ncrcmd abort_resel [ 16]; ncrcmd resend_ident [ 4]; ncrcmd ident_break [ 4]; @@ -2621,7 +2663,7 @@ ncrcmd data_io [ 2]; ncrcmd data_io_com [ 8]; ncrcmd data_io_out [ 12]; - ncrcmd bad_identify [ 12]; + ncrcmd resel_bad_lun [ 4]; ncrcmd bad_i_t_l [ 4]; ncrcmd bad_i_t_l_q [ 4]; ncrcmd bad_status [ 6]; @@ -2632,14 +2674,13 @@ ncrcmd pm0_save [ 14]; ncrcmd pm1_save [ 14]; - /* SWIDE handling */ - ncrcmd swide_ma_32 [ 4]; - ncrcmd swide_ma_64 [ 6]; - ncrcmd swide_scr_64 [ 26]; - ncrcmd swide_scr_64_1 [ 12]; - ncrcmd swide_com_64 [ 6]; - ncrcmd swide_common [ 10]; - ncrcmd swide_fin_32 [ 24]; + /* WSR handling */ +#ifdef SYM_DEBUG_PM_WITH_WSR + ncrcmd pm_wsr_handle [ 44]; +#else + ncrcmd pm_wsr_handle [ 42]; +#endif + ncrcmd wsr_ma_helper [ 4]; /* Data area */ ncrcmd zero [ 1]; @@ -2697,6 +2738,9 @@ static void ncr_int_udc (ncb_p np); static void ncr_negotiate (ncb_p np, tcb_p tp); static int ncr_prepare_nego(ncb_p np, ccb_p cp, u_char *msgptr); +#ifdef SCSI_NCR_INTEGRITY_CHECKING +static int ncr_ic_nego(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd, u_char *msgptr); +#endif #ifdef SCSI_NCR_PROFILE_SUPPORT static void ncb_profile (ncb_p np, ccb_p cp); #endif @@ -2706,9 +2750,12 @@ static int ncr_scatter_896R1 (ncb_p np, ccb_p cp, Scsi_Cmnd *cmd); static int ncr_scatter (ncb_p np, ccb_p cp, Scsi_Cmnd *cmd); static void ncr_getsync (ncb_p np, u_char sfac, u_char *fakp, u_char *scntl3p); -static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer); +static void ncr_get_xfer_info(ncb_p np, tcb_p tp, u_char *factor, u_char *offset, u_char *width); +static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer, u_char scntl4); +static void ncr_set_sync_wide_status (ncb_p np, u_char target); static void ncr_setup_tags (ncb_p np, u_char tn, u_char ln); static void ncr_setwide (ncb_p np, ccb_p cp, u_char wide, u_char ack); +static void ncr_setsyncwide (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer, u_char scntl4, u_char wide); static int ncr_show_msg (u_char * msg); static void ncr_print_msg (ccb_p cp, char *label, u_char * msg); static int ncr_snooptest (ncb_p np); @@ -2978,9 +3025,9 @@ SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)), PADDR (msg_in), SCR_JUMP ^ IFTRUE (IF (SCR_DATA_OUT)), - PADDR (dataphase), + PADDR (datao_phase), SCR_JUMP ^ IFTRUE (IF (SCR_DATA_IN)), - PADDR (dataphase), + PADDR (datai_phase), SCR_JUMP ^ IFTRUE (IF (SCR_STATUS)), PADDR (status), SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND)), @@ -2988,6 +3035,12 @@ SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)), PADDRH (msg_out), /* + * Set the extended error flag. + */ + SCR_REG_REG (HF_REG, SCR_OR, HF_EXT_ERR), + 0, + + /* ** Discard one illegal phase byte, if required. */ SCR_LOAD_REL (scratcha, 1), @@ -3056,17 +3109,6 @@ SCR_JUMP, PADDR (dispatch), -}/*-------------------------< DISP_MSG_IN >----------------------*/,{ - /* - ** Anticipate MSG_IN phase then STATUS phase. - ** - ** May spare 2 SCRIPTS instructions when we have - ** completed the OUTPUT of the data and the device - ** goes directly to STATUS phase. - */ - SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)), - PADDR (msg_in), - }/*-------------------------< DISP_STATUS >----------------------*/,{ /* ** Anticipate STATUS phase. @@ -3081,6 +3123,12 @@ }/*-------------------------< DATAI_DONE >-------------------*/,{ /* + * If the device wants us to send more data, + * we must count the extra bytes. + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_DATA_IN)), + PADDRH (data_ovrun), + /* ** If the SWIDE is not full, jump to dispatcher. ** We anticipate a STATUS phase. ** If we get later an IGNORE WIDE RESIDUE, we @@ -3097,36 +3145,56 @@ SCR_REG_REG (scntl2, SCR_OR, WSR), 0, /* - ** Since the device is required to send any - ** IGNORE WIDE RESIDUE message prior to any - ** other information, we just snoop the SCSI - ** BUS to check for such a message. + * We are expecting an IGNORE RESIDUE message + * from the device, otherwise we are in data + * overrun condition. Check against MSG_IN phase. */ + SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)), + SIR_SWIDE_OVERRUN, SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), PADDR (disp_status), - SCR_FROM_REG (sbdl), - 0, + /* + * We are in MSG_IN phase, + * Read the first byte of the message. + * If it is not an IGNORE RESIDUE message, + * signal overrun and jump to message + * processing. + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin[0]), + SCR_INT ^ IFFALSE (DATA (M_IGN_RESIDUE)), + SIR_SWIDE_OVERRUN, SCR_JUMP ^ IFFALSE (DATA (M_IGN_RESIDUE)), - PADDR (disp_status), + PADDR (msg_in2), + /* - ** We have been ODD at the end of the transfer, - ** but the device hasn't be so. - ** Signal a DATA OVERRUN condition to the C code. - */ - SCR_INT, - SIR_SWIDE_OVERRUN, + * We got the message we expected. + * Read the 2nd byte, and jump to dispatcher. + */ + SCR_CLR (SCR_ACK), + 0, + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin[1]), + SCR_CLR (SCR_ACK), + 0, SCR_JUMP, - PADDR (dispatch), + PADDR (disp_status), }/*-------------------------< DATAO_DONE >-------------------*/,{ /* + * If the device wants us to send more data, + * we must count the extra bytes. + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_DATA_OUT)), + PADDRH (data_ovrun), + /* ** If the SODL is not full jump to dispatcher. ** We anticipate a MSG IN phase or a STATUS phase. */ SCR_FROM_REG (scntl2), 0, SCR_JUMP ^ IFFALSE (MASK (WSS, WSS)), - PADDR (disp_msg_in), + PADDR (disp_status), /* ** The SODL is full, clear this condition. */ @@ -3157,13 +3225,25 @@ SCR_JUMP, PADDR (clrack), -}/*-------------------------< DATAPHASE >------------------*/,{ +}/*-------------------------< DATAI_PHASE >------------------*/,{ #ifdef SCSI_NCR_PROFILE_SUPPORT SCR_REG_REG (QU_REG, SCR_OR, HF_DATA_ST), 0, #endif SCR_RETURN, 0, +}/*-------------------------< DATAO_PHASE >------------------*/,{ + /* + ** Patch for 53c1010_66 only - to allow A0 part + ** to operate properly in a 33MHz PCI bus. + ** + ** SCR_REG_REG(scntl4, SCR_OR, 0x0c), + ** 0, + */ + SCR_NO_OP, + 0, + SCR_RETURN, + 0, }/*-------------------------< MSG_IN >--------------------*/,{ /* ** Get the first byte of the message. @@ -3524,31 +3604,42 @@ offsetof(struct tcb, wval), SCR_LOAD_REL (sxfer, 1), offsetof(struct tcb, sval), +}/*-------------------------< RESEL_SCNTL4 >------------------*/,{ /* - ** If MESSAGE IN phase as expected, - ** read the data directly from the BUS DATA lines. - ** This helps to support very old SCSI devices that - ** may reselect without sending an IDENTIFY. + ** Write with uval value. Patch if device + ** does not support Ultra3. + ** + ** SCR_LOAD_REL (scntl4, 1), + ** offsetof(struct tcb, uval), */ + + SCR_NO_OP, + 0, + /* + * We expect MESSAGE IN phase. + * If not, get help from the C code. + */ SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)), SIR_RESEL_NO_MSG_IN, - SCR_FROM_REG (sbdl), - 0, + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin), + /* - ** If message phase but not an IDENTIFY, - ** get some help from the C code. - ** Old SCSI device may behave so. - */ + * If IDENTIFY LUN #0, use a faster path + * to find the LCB structure. + */ + SCR_JUMPR ^ IFTRUE (MASK (0x80, 0xbf)), + 56, + /* + * If message isn't an IDENTIFY, + * tell the C code about. + */ SCR_INT ^ IFFALSE (MASK (0x80, 0x80)), SIR_RESEL_NO_IDENTIFY, /* - ** It is an IDENTIFY message, - ** Load the LUN control block address. - ** If LUN 0, avoid a PCI BUS ownership by loading - ** directly 'b_lun0' from the TCB. - */ - SCR_JUMPR ^ IFTRUE (MASK (0x0, 0x3f)), - 48, + * It is an IDENTIFY message, + * Load the LUN control block address. + */ SCR_LOAD_REL (dsa, 4), offsetof(struct tcb, b_luntbl), SCR_SFBR_REG (dsa, SCR_SHL, 0), @@ -3578,15 +3669,20 @@ offsetof(struct lcb, b_tasktbl), SCR_RETURN, 0, - }/*-------------------------< RESEL_TAG >-------------------*/,{ /* + ** ACK the IDENTIFY or TAG previously received + */ + + SCR_CLR (SCR_ACK), + 0, + /* ** Read IDENTIFY + SIMPLE + TAG using a single MOVE. ** Agressive optimization, is'nt it? ** No need to test the SIMPLE TAG message, since the ** driver only supports conformant devices for tags. ;-) */ - SCR_MOVE_ABS (3) ^ SCR_MSG_IN, + SCR_MOVE_ABS (2) ^ SCR_MSG_IN, NADDR (msgin), /* ** Read the TAG from the SIDL. @@ -3627,14 +3723,9 @@ offsetof(struct ccb, phys.header.go.restart), SCR_RETURN, 0, + /* In normal situations we branch to RESEL_DSA */ }/*-------------------------< RESEL_NOTAG >-------------------*/,{ /* - ** No tag expected. - ** Read an throw away the IDENTIFY. - */ - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - NADDR (msgin), - /* ** JUMP indirectly to the restart point of the CCB. */ SCR_JUMP, @@ -3681,7 +3772,7 @@ SCR_CALL, PADDR (datai_done), SCR_JUMP, - PADDRH (no_data), + PADDRH (data_ovrun), }/*-------------------------< DATA_OUT >--------------------*/,{ /* ** Because the size depends on the @@ -3700,7 +3791,7 @@ SCR_CALL, PADDR (datao_done), SCR_JUMP, - PADDRH (no_data), + PADDRH (data_ovrun), }/*-------------------------< PM0_DATA >--------------------*/,{ /* @@ -3719,7 +3810,7 @@ ** Check against expected direction. */ SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)), - PADDRH (no_data), + PADDRH (data_ovrun), /* ** Keep track we are moving data from the ** PM0 DATA mini-script. @@ -3739,7 +3830,7 @@ ** Check against expected direction. */ SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)), - PADDRH (no_data), + PADDRH (data_ovrun), /* ** Keep track we are moving data from the ** PM0 DATA mini-script. @@ -3784,7 +3875,7 @@ ** Check against expected direction. */ SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)), - PADDRH (no_data), + PADDRH (data_ovrun), /* ** Keep track we are moving data from the ** PM1 DATA mini-script. @@ -3804,7 +3895,7 @@ ** Check against expected direction. */ SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)), - PADDRH (no_data), + PADDRH (data_ovrun), /* ** Keep track we are moving data from the ** PM1 DATA mini-script. @@ -3835,6 +3926,7 @@ }/*---------------------------------------------------------*/ }; + static struct scripth scripth0 __initdata = { /*------------------------< START64 >-----------------------*/{ /* @@ -3844,7 +3936,9 @@ */ SCR_JUMP, PADDR (init), - +}/*-------------------------< NO_DATA >-------------------*/,{ + SCR_JUMP, + PADDRH (data_ovrun), }/*-----------------------< SEL_FOR_ABORT >------------------*/,{ /* ** We are jumped here by the C code, if we have @@ -4078,33 +4172,31 @@ SCR_JUMP, PADDRH (msg_out_done), -}/*-------------------------< NEGO_BAD_PHASE >------------*/,{ - SCR_INT, - SIR_NEGO_PROTO, - SCR_JUMP, - PADDR (dispatch), - -}/*-------------------------< MSG_OUT_ABORT >-------------*/,{ +}/*-------------------------< PPR_RESP >-------------*/,{ /* - ** After ABORT message, - ** - ** expect an immediate disconnect, ... + ** let the target fetch our answer. */ - SCR_REG_REG (scntl2, SCR_AND, 0x7f), - 0, - SCR_CLR (SCR_ACK|SCR_ATN), + SCR_SET (SCR_ATN), 0, - SCR_WAIT_DISC, + SCR_CLR (SCR_ACK), 0, - SCR_INT, - SIR_MSG_OUT_DONE, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)), + PADDRH (nego_bad_phase), + +}/*-------------------------< SEND_PPR >-------------*/,{ /* - ** ... and set the status to "ABORTED" + ** Send the M_X_PPR_REQ */ - SCR_LOAD_REG (HS_REG, HS_ABORTED), - 0, + SCR_MOVE_ABS (8) ^ SCR_MSG_OUT, + NADDR (msgout), + SCR_JUMP, + PADDRH (msg_out_done), + +}/*-------------------------< NEGO_BAD_PHASE >------------*/,{ + SCR_INT, + SIR_NEGO_PROTO, SCR_JUMP, - PADDR (complete2), + PADDR (dispatch), }/*-------------------------< MSG_OUT >-------------------*/,{ /* @@ -4113,11 +4205,6 @@ SCR_MOVE_ABS (1) ^ SCR_MSG_OUT, NADDR (msgout), /* - ** If it was no ABORT message ... - */ - SCR_JUMP ^ IFTRUE (DATA (M_ABORT)), - PADDRH (msg_out_abort), - /* ** ... wait for the next phase ** if it's a message out, send it again, ... */ @@ -4135,34 +4222,56 @@ SCR_JUMP, PADDR (dispatch), -}/*-------------------------< NO_DATA >--------------------*/,{ +}/*-------------------------< DATA_OVRUN >--------------------*/,{ /* - ** The target wants to tranfer too much data - ** or in the wrong direction. - ** Remember that in extended error. - */ + * The target may want to transfer too much data. + * + * If phase is DATA OUT write 1 byte and count it. + */ + SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_OUT)), + 16, + SCR_CHMOV_ABS (1) ^ SCR_DATA_OUT, + NADDR (scratch), + SCR_JUMP, + PADDRH (data_ovrun1), + /* + * If WSR is set, clear this condition, and + * count this byte. + */ + SCR_FROM_REG (scntl2), + 0, + SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)), + 16, + SCR_REG_REG (scntl2, SCR_OR, WSR), + 0, + SCR_JUMP, + PADDRH (data_ovrun1), + /* + * Finally check against DATA IN phase. + * Jump to dispatcher if not so. + * Read 1 byte otherwise and count it. + */ + SCR_JUMP ^ IFFALSE (IF (SCR_DATA_IN)), + PADDR (dispatch), + SCR_CHMOV_ABS (1) ^ SCR_DATA_IN, + NADDR (scratch), +}/*-------------------------< DATA_OVRUN1 >--------------------*/,{ + /* + * Set the extended error flag. + */ + SCR_REG_REG (HF_REG, SCR_OR, HF_EXT_ERR), + 0, SCR_LOAD_REL (scratcha, 1), offsetof (struct ccb, xerr_status), - SCR_REG_REG (scratcha, SCR_OR, XE_EXTRA_DATA), + SCR_REG_REG (scratcha, SCR_OR, XE_EXTRA_DATA), 0, SCR_STORE_REL (scratcha, 1), offsetof (struct ccb, xerr_status), /* - ** Discard one data byte, if required. - */ - SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_OUT)), - 8, - SCR_MOVE_ABS (1) ^ SCR_DATA_OUT, - NADDR (scratch), - SCR_JUMPR ^ IFFALSE (IF (SCR_DATA_IN)), - 8, - SCR_MOVE_ABS (1) ^ SCR_DATA_IN, - NADDR (scratch), - /* - ** Count this byte. - ** This will allow to return a positive - ** residual to user. - */ + * Count this byte. + * This will allow to return a negative + * residual to user. + */ SCR_LOAD_REL (scratcha, 4), offsetof (struct ccb, phys.extra_bytes), SCR_REG_REG (scratcha, SCR_ADD, 0x01), @@ -4174,12 +4283,10 @@ SCR_STORE_REL (scratcha, 4), offsetof (struct ccb, phys.extra_bytes), /* - ** .. and repeat as required. - */ - SCR_CALL, - PADDR (dispatch), + * .. and repeat as required. + */ SCR_JUMP, - PADDRH (no_data), + PADDRH (data_ovrun), }/*-------------------------< ABORT_RESEL >----------------*/,{ SCR_SET (SCR_ATN), @@ -4227,10 +4334,9 @@ SCR_CHMOV_TBL ^ SCR_DATA_IN, offsetof (struct dsb, sense), SCR_CALL, - PADDR (dispatch), + PADDR (datai_done), SCR_JUMP, - PADDRH (no_data), - + PADDRH (data_ovrun), }/*-------------------------< DATA_IO >--------------------*/,{ /* ** We jump here if the data direction was unknown at the @@ -4280,29 +4386,14 @@ SCR_JUMP, PADDRH(data_io_com), -}/*-------------------------< BAD_IDENTIFY >---------------*/,{ - /* - ** If message phase but not an IDENTIFY, - ** get some help from the C code. - ** Old SCSI device may behave so. - */ - SCR_JUMPR ^ IFTRUE (MASK (0x80, 0x80)), - 16, - SCR_INT, - SIR_RESEL_NO_IDENTIFY, - SCR_JUMP, - PADDRH (abort_resel), +}/*-------------------------< RESEL_BAD_LUN >---------------*/,{ /* ** Message is an IDENTIFY, but lun is unknown. - ** Read the message, since we got it directly - ** from the SCSI BUS data lines. ** Signal problem to C code for logging the event. ** Send a M_ABORT to clear all pending tasks. */ SCR_INT, SIR_RESEL_BAD_LUN, - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - NADDR (msgin), SCR_JUMP, PADDRH (abort_resel), }/*-------------------------< BAD_I_T_L >------------------*/,{ @@ -4441,7 +4532,7 @@ SCR_FROM_REG (scntl2), 0, SCR_CALL ^ IFTRUE (MASK (WSR, WSR)), - PADDRH (swide_scr_64), + PADDRH (pm_wsr_handle), /* ** Save the remaining byte count, the updated ** address and the return address. @@ -4468,7 +4559,7 @@ SCR_FROM_REG (scntl2), 0, SCR_CALL ^ IFTRUE (MASK (WSR, WSR)), - PADDRH (swide_scr_64), + PADDRH (pm_wsr_handle), /* ** Save the remaining byte count, the updated ** address and the return address. @@ -4484,101 +4575,32 @@ PADDRH (pm1_data_addr), SCR_JUMP, PADDR (dispatch), - -}/*--------------------------< SWIDE_MA_32 >-----------------------*/,{ - /* - ** Handling of the SWIDE for 32 bit chips. - ** - ** We jump here from the C code with SCRATCHA - ** containing the address to write the SWIDE. - ** - Save 32 bit address in . - */ - SCR_STORE_ABS (scratcha, 4), - PADDRH (scratch), - SCR_JUMP, - PADDRH (swide_common), -}/*--------------------------< SWIDE_MA_64 >-----------------------*/,{ - /* - ** Handling of the SWIDE for 64 bit chips when the - ** hardware handling of phase mismatch is disabled. - ** - ** We jump here from the C code with SCRATCHA - ** containing the address to write the SWIDE and - ** SBR containing bit 32..39 of this address. - ** - Save 32 bit address in . - ** - Move address bit 32..39 to SFBR. - */ - SCR_STORE_ABS (scratcha, 4), - PADDRH (scratch), - SCR_FROM_REG (sbr), - 0, - SCR_JUMP, - PADDRH (swide_com_64), -}/*--------------------------< SWIDE_SCR_64 >-----------------------*/,{ - /* - ** Handling of the SWIDE for 64 bit chips when - ** hardware phase mismatch is enabled. - ** We are entered with a SCR_CALL from PMO_SAVE - ** and PM1_SAVE sub-scripts. - ** - ** Snoop the SCSI BUS in case of the device - ** willing to ignore this residue. - ** If it does, we must only increment the RBC, - ** since this register does reflect all bytes - ** received from the SCSI BUS including the SWIDE. - */ - SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), - PADDRH (swide_scr_64_1), - SCR_FROM_REG (sbdl), - 0, - SCR_JUMP ^ IFFALSE (DATA (M_IGN_RESIDUE)), - PADDRH (swide_scr_64_1), - SCR_REG_REG (rbc, SCR_ADD, 1), - 0, - SCR_REG_REG (rbc1, SCR_ADDC, 0), - 0, - SCR_REG_REG (rbc2, SCR_ADDC, 0), - 0, +}/*--------------------------< PM_WSR_HANDLE >-----------------------*/,{ /* - ** Save UA and RBC, since the PM0/1_SAVE - ** sub-scripts haven't moved them to the - ** context yet and the below MOV may just - ** change their value. - */ - SCR_STORE_ABS (ua, 4), - PADDRH (scratch), - SCR_STORE_ABS (rbc, 4), - PADDRH (scratch1), + * Phase mismatch handling from SCRIPT with WSR set. + * Such a condition can occur if the chip wants to + * execute a CHMOV(size > 1) when the WSR bit is + * set and the target changes PHASE. + */ +#ifdef SYM_DEBUG_PM_WITH_WSR /* - ** Throw away the IGNORE WIDE RESIDUE message. - ** since we just did take care of it. - */ - SCR_MOVE_ABS (2) ^ SCR_MSG_IN, - NADDR (scratch), - SCR_CLR (SCR_ACK), - 0, + * Some debugging may still be needed.:) + */ + SCR_INT, + SIR_PM_WITH_WSR, +#endif /* - ** Restore UA and RBC registers and return. - */ - SCR_LOAD_ABS (ua, 4), - PADDRH (scratch), - SCR_LOAD_ABS (rbc, 4), - PADDRH (scratch1), - SCR_RETURN, - 0, -}/*--------------------------< SWIDE_SCR_64_1 >---------------------*/,{ + * We must move the residual byte to memory. + * + * UA contains bit 0..31 of the address to + * move the residual byte. + * Move it to the table indirect. + */ + SCR_STORE_REL (ua, 4), + offsetof (struct ccb, phys.wresid.addr), /* - ** We must grab the SWIDE and move it to - ** memory. - ** - ** - Save UA (32 bit address) in . - ** - Move address bit 32..39 to SFBR. - ** - Increment UA (updated address). - */ - SCR_STORE_ABS (ua, 4), - PADDRH (scratch), - SCR_FROM_REG (rbc3), - 0, + * Increment UA (move address to next position). + */ SCR_REG_REG (ua, SCR_ADD, 1), 0, SCR_REG_REG (ua1, SCR_ADDC, 0), @@ -4587,70 +4609,45 @@ 0, SCR_REG_REG (ua3, SCR_ADDC, 0), 0, -}/*--------------------------< SWIDE_COM_64 >-----------------------*/,{ /* - ** - Save DRS. - ** - Load DRS with address bit 32..39 of the - ** location to write the SWIDE. - ** SFBR has been loaded with these bits. - ** (Look above). - */ - SCR_STORE_ABS (drs, 4), - PADDRH (saved_drs), - SCR_LOAD_ABS (drs, 4), + * Compute SCRATCHA as: + * - size to transfer = 1 byte. + * - bit 24..31 = high address bit [32...39]. + */ + SCR_LOAD_ABS (scratcha, 4), PADDRH (zero), - SCR_TO_REG (drs), + SCR_REG_REG (scratcha, SCR_OR, 1), 0, -}/*--------------------------< SWIDE_COMMON >-----------------------*/,{ - /* - ** - Save current DSA - ** - Load DSA with bit 0..31 of the memory - ** location to write the SWIDE. - */ - SCR_STORE_ABS (dsa, 4), - PADDRH (saved_dsa), - SCR_LOAD_ABS (dsa, 4), - PADDRH (scratch), - /* - ** Move the SWIDE to memory. - ** Clear the WSR bit. - */ - SCR_STORE_REL (swide, 1), + SCR_FROM_REG (rbc3), 0, - SCR_REG_REG (scntl2, SCR_OR, WSR), + SCR_TO_REG (scratcha3), 0, /* - ** Restore the original DSA. - */ - SCR_LOAD_ABS (dsa, 4), - PADDRH (saved_dsa), -}/*--------------------------< SWIDE_FIN_32 >-----------------------*/,{ - /* - ** For 32 bit chip, the following SCRIPTS - ** instruction is patched with a JUMP to dispatcher. - ** (Look into the C code). - */ - SCR_LOAD_ABS (drs, 4), - PADDRH (saved_drs), + * Move this value to the table indirect. + */ + SCR_STORE_REL (scratcha, 4), + offsetof (struct ccb, phys.wresid.size), /* - ** 64 bit chip only. - ** If PM handling from SCRIPTS, we are just - ** a helper for the C code, so jump to - ** dispatcher now. - */ - SCR_FROM_REG (ccntl0), + * Wait for a valid phase. + * While testing with bogus QUANTUM drives, the C1010 + * sometimes raised a spurious phase mismatch with + * WSR and the CHMOV(1) triggered another PM. + * Waiting explicitely for the PHASE seemed to avoid + * the nested phase mismatch. Btw, this didn't happen + * using my IBM drives. + */ + SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)), 0, - SCR_JUMP ^ IFFALSE (MASK (ENPMJ, ENPMJ)), - PADDR (dispatch), /* - ** 64 bit chip with hardware PM handling enabled. - ** - ** Since we are paranoid:), we donnot want - ** a SWIDE followed by a CHMOV(1) to lead to - ** a CHMOV(0) in our PM context. - ** We check against such a condition. - ** Also does the C code. - */ + * Perform the move of the residual byte. + */ + SCR_CHMOV_TBL ^ SCR_DATA_IN, + offsetof (struct ccb, phys.wresid), + /* + * We can now handle the phase mismatch with UA fixed. + * RBC[0..23]=0 is a special case that does not require + * a PM context. The C code also checks against this. + */ SCR_FROM_REG (rbc), 0, SCR_RETURN ^ IFFALSE (DATA (0)), @@ -4664,19 +4661,29 @@ SCR_RETURN ^ IFFALSE (DATA (0)), 0, /* - ** If we are there, RBC(0..23) is zero, - ** and we just have to load the current - ** DATA SCRIPTS address (register TEMP) - ** with the IA and go to dispatch. - ** No PM context is needed. - */ + * RBC[0..23]=0. + * Not only we donnot need a PM context, but this would + * lead to a bogus CHMOV(0). This condition means that + * the residual was the last byte to move from this CHMOV. + * So, we just have to move the current data script pointer + * (i.e. TEMP) to the SCRIPTS address following the + * interrupted CHMOV and jump to dispatcher. + */ SCR_STORE_ABS (ia, 4), PADDRH (scratch), SCR_LOAD_ABS (temp, 4), PADDRH (scratch), SCR_JUMP, PADDR (dispatch), - +}/*--------------------------< WSR_MA_HELPER >-----------------------*/,{ + /* + * Helper for the C code when WSR bit is set. + * Perform the move of the residual byte. + */ + SCR_CHMOV_TBL ^ SCR_DATA_IN, + offsetof (struct ccb, phys.wresid), + SCR_JUMP, + PADDR (dispatch), }/*-------------------------< ZERO >------------------------*/,{ SCR_DATA_ZERO, }/*-------------------------< SCRATCH >---------------------*/,{ @@ -4792,6 +4799,7 @@ assert ((u_long)p == (u_long)&scr->data_in + sizeof (scr->data_in)); p = scr->data_out; + for (i=0; i SCRIPT_KVAR_LAST)) panic("ncr KVAR out of range"); @@ -5152,16 +5161,30 @@ static void __init ncr_save_initial_setting(ncb_p np) { np->sv_scntl0 = INB(nc_scntl0) & 0x0a; - np->sv_scntl3 = INB(nc_scntl3) & 0x07; np->sv_dmode = INB(nc_dmode) & 0xce; np->sv_dcntl = INB(nc_dcntl) & 0xa8; np->sv_ctest3 = INB(nc_ctest3) & 0x01; np->sv_ctest4 = INB(nc_ctest4) & 0x80; - np->sv_ctest5 = INB(nc_ctest5) & 0x24; np->sv_gpcntl = INB(nc_gpcntl); np->sv_stest2 = INB(nc_stest2) & 0x20; np->sv_stest4 = INB(nc_stest4); np->sv_stest1 = INB(nc_stest1); + + np->sv_scntl3 = INB(nc_scntl3) & 0x07; + + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66) ){ + /* + ** C1010 always uses large fifo, bit 5 rsvd + ** scntl4 used ONLY with C1010 + */ + np->sv_ctest5 = INB(nc_ctest5) & 0x04 ; + np->sv_scntl4 = INB(nc_scntl4); + } + else { + np->sv_ctest5 = INB(nc_ctest5) & 0x24 ; + np->sv_scntl4 = 0; + } } /* @@ -5200,15 +5223,35 @@ /* * Divisor to be used for async (timer pre-scaler). + * + * Note: For C1010 the async divisor is 2(8) if he + * quadrupler is disabled (enabled). */ - i = np->clock_divn - 1; - while (--i >= 0) { - if (10ul * SCSI_NCR_MIN_ASYNC * np->clock_khz > div_10M[i]) { - ++i; - break; + + if ( (np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) { + + np->rv_scntl3 = 0; + } + else + { + i = np->clock_divn - 1; + while (--i >= 0) { + if (10ul * SCSI_NCR_MIN_ASYNC * np->clock_khz + > div_10M[i]) { + ++i; + break; + } } + np->rv_scntl3 = i+1; } - np->rv_scntl3 = i+1; + + + /* + * Save the ultra3 register for the C1010/C1010_66 + */ + + np->rv_scntl4 = np->sv_scntl4; /* * Minimum synchronous period factor supported by the chip. @@ -5222,13 +5265,28 @@ else np->minsync = (period + 40 - 1) / 40; /* + * Fix up. If sync. factor is 10 (160000Khz clock) and chip + * supports ultra3, then min. sync. period 12.5ns and the factor is 9 + */ + + if ((np->minsync == 10) && (np->features & FE_ULTRA3)) + np->minsync = 9; + + /* * Check against chip SCSI standard support (SCSI-2,ULTRA,ULTRA2). + * + * Transfer period minimums: SCSI-1 200 (50); Fast 100 (25) + * Ultra 50 (12); Ultra2 (6); Ultra3 (3) */ - if (np->minsync < 25 && !(np->features & (FE_ULTRA|FE_ULTRA2))) + if (np->minsync < 25 && !(np->features & (FE_ULTRA|FE_ULTRA2|FE_ULTRA3))) np->minsync = 25; - else if (np->minsync < 12 && !(np->features & FE_ULTRA2)) + else if (np->minsync < 12 && (np->features & FE_ULTRA)) np->minsync = 12; + else if (np->minsync < 10 && (np->features & FE_ULTRA2)) + np->minsync = 10; + else if (np->minsync < 9 && (np->features & FE_ULTRA3)) + np->minsync = 9; /* * Maximum synchronous period factor supported by the chip. @@ -5248,7 +5306,7 @@ #endif /* - ** Phase mismatch handled by SCRIPTS (53C895A or 53C896) ? + ** Phase mismatch handled by SCRIPTS (53C895A, 53C896 or C1010) ? */ if (np->features & FE_NOPM) np->rv_ccntl0 |= (ENPMJ); @@ -5292,6 +5350,14 @@ np->features &= ~(FE_WRIE|FE_ERL|FE_ERMP); /* + ** DEL ? - 53C1010 Rev 1 - Part Number 609-0393638 + ** 64-bit Slave Cycles must be disabled. + */ + if ( ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) && (np->revision_id < 0x02) ) + || (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66 ) ) + np->rv_ccntl1 |= 0x10; + + /* ** Select all supported special features. ** If we are using on-board RAM for scripts, prefetch (PFEN) ** does not help, but burst op fetch (BOF) does. @@ -5313,8 +5379,13 @@ np->rv_dcntl |= CLSE; /* Cache Line Size Enable */ if (np->features & FE_WRIE) np->rv_ctest3 |= WRIE; /* Write and Invalidate */ - if (np->features & FE_DFS) + + + if ( (np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66) && + (np->features & FE_DFS)) np->rv_ctest5 |= DFS; /* Dma Fifo Size */ + /* C1010/C1010_66 always large fifo */ /* ** Select some other @@ -5362,14 +5433,15 @@ /* ** Set SCSI BUS mode. ** - ** - ULTRA2 chips (895/895A/896) report the current + ** - ULTRA2 chips (895/895A/896) + ** and ULTRA 3 chips (1010) report the current ** BUS mode through the STEST4 IO register. ** - For previous generation chips (825/825A/875), ** user has to tell us how to check against HVD, ** since a 100% safe algorithm is not possible. */ np->scsi_mode = SMODE_SE; - if (np->features & FE_ULTRA2) + if (np->features & (FE_ULTRA2 | FE_ULTRA3)) np->scsi_mode = (np->sv_stest4 & SMODE); else if (np->features & FE_DIFF) { switch(driver_setup.diff_support) { @@ -5471,7 +5543,8 @@ i == SCSI_NCR_SYMBIOS_NVRAM ? "Symbios format NVRAM, " : (i == SCSI_NCR_TEKRAM_NVRAM ? "Tekram format NVRAM, " : ""), np->myaddr, - np->minsync < 12 ? 40 : (np->minsync < 25 ? 20 : 10), + np->minsync < 10 ? 80 : + (np->minsync < 12 ? 40 : (np->minsync < 25 ? 20 : 10) ), (np->rv_scntl0 & 0xa) ? ", Parity Checking" : ", NO Parity", (np->rv_stest2 & 0x20) ? ", Differential" : ""); @@ -5864,14 +5937,6 @@ ncr_script_copy_and_bind (np, (ncrcmd *) &scripth0, (ncrcmd *) np->scripth0, sizeof(struct scripth)); /* - ** If not 64 bit chip, patch some places in SCRIPTS. - */ - if (!(np->features & FE_64BIT)) { - np->scripth0->swide_fin_32[0] = cpu_to_scr(SCR_JUMP); - np->scripth0->swide_fin_32[1] = - cpu_to_scr(NCB_SCRIPT_PHYS(np, dispatch)); - } - /* ** Patch some variables in SCRIPTS */ np->scripth0->pm0_data_addr[0] = @@ -5879,6 +5944,15 @@ np->scripth0->pm1_data_addr[0] = cpu_to_scr(NCB_SCRIPT_PHYS(np, pm1_data)); + /* + ** Patch if not Ultra 3 - Do not write to scntl4 + */ + if (np->features & FE_ULTRA3) { + np->script0->resel_scntl4[0] = cpu_to_scr(SCR_LOAD_REL (scntl4, 1)); + np->script0->resel_scntl4[1] = cpu_to_scr(offsetof(struct tcb, uval)); + } + + #ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED np->scripth0->script0_ba[0] = cpu_to_scr(vtobus(np->script0)); np->scripth0->script0_ba64[0] = cpu_to_scr(vtobus(np->script0)); @@ -5912,7 +5986,7 @@ goto attach_error; assert (offsetof(struct lcb, resel_task) == 0); - np->resel_badlun = cpu_to_scr(NCB_SCRIPTH_PHYS(np, bad_identify)); + np->resel_badlun = cpu_to_scr(NCB_SCRIPTH_PHYS(np, resel_bad_lun)); for (i = 0 ; i < 64 ; i++) np->badluntbl[i] = cpu_to_scr(NCB_PHYS(np, resel_badlun)); @@ -5940,6 +6014,15 @@ cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe)); } + /* + ** Patch the script to provide an extra clock cycle on + ** data out phase - 53C1010_66MHz part only. + */ + if (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66){ + np->script0->datao_phase[0] = + cpu_to_scr(SCR_REG_REG(scntl4, SCR_OR, 0x0c)); + } + #ifdef SCSI_NCR_IARB_SUPPORT /* ** If user does not want to use IMMEDIATE ARBITRATION @@ -5968,8 +6051,11 @@ #else #define XXX 2 #endif - np->script0->dataphase[XXX] = cpu_to_scr(SCR_JUMP); - np->script0->dataphase[XXX+1] = + np->script0->datai_phase[XXX] = cpu_to_scr(SCR_JUMP); + np->script0->datai_phase[XXX+1] = + cpu_to_scr(NCB_SCRIPTH_PHYS (np, tweak_pmj)); + np->script0->datao_phase[0] = cpu_to_scr(SCR_JUMP); + np->script0->datao_phase[1] = cpu_to_scr(NCB_SCRIPTH_PHYS (np, tweak_pmj)); #undef XXX } @@ -5985,6 +6071,9 @@ ** We should use ncr_soft_reset(), but we donnot want to do ** so, since we may not be safe if ABRT interrupt occurs due ** to the BIOS or previous O/S having enable this interrupt. + ** + ** For C1010 need to set ABRT bit prior to SRST if SCRIPTs + ** are running. Not true in this case. */ ncr_chip_reset(np); @@ -6089,6 +6178,19 @@ instance->dma_channel = 0; instance->cmd_per_lun = MAX_TAGS; instance->can_queue = (MAX_START-4); + + np->check_integrity = 0; + +#ifdef SCSI_NCR_INTEGRITY_CHECKING + instance->check_integrity = 0; + +#ifdef SCSI_NCR_ENABLE_INTEGRITY_CHECK + if ( !(driver_setup.bus_check & 0x04) ) { + np->check_integrity = 1; + instance->check_integrity = 1; + } +#endif +#endif instance->select_queue_depths = sym53c8xx_select_queue_depths; @@ -6214,6 +6316,299 @@ /*========================================================== ** ** +** Prepare the next negotiation message for integrity check, +** if needed. +** +** Fill in the part of message buffer that contains the +** negotiation and the nego_status field of the CCB. +** Returns the size of the message in bytes. +** +** If tp->ppr_negotiation is 1 and a M_REJECT occurs, then +** we disable ppr_negotiation. If the first ppr_negotiation is +** successful, set this flag to 2. +** +**========================================================== +*/ +#ifdef SCSI_NCR_INTEGRITY_CHECKING +static int ncr_ic_nego(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd, u_char *msgptr) +{ + tcb_p tp = &np->target[cp->target]; + int msglen = 0; + int nego = 0; + u_char new_width, new_offset, new_period; + u_char no_increase; + + if (tp->ppr_negotiation == 1) /* PPR message successful */ + tp->ppr_negotiation = 2; + + if (tp->inq_done) { + + if (!tp->ic_maximums_set) { + tp->ic_maximums_set = 1; + + /* + * Check against target, host and user limits + */ + if ( (tp->inq_byte7 & INQ7_WIDE16) && + np->maxwide && tp->usrwide) + tp->ic_max_width = 1; + else + tp->ic_max_width = 0; + + + if ((tp->inq_byte7 & INQ7_SYNC) && tp->maxoffs) + tp->ic_min_sync = (tp->minsync < np->minsync) ? + np->minsync : tp->minsync; + else + tp->ic_min_sync = 255; + + tp->period = 1; + tp->widedone = 1; + + /* + * Enable PPR negotiation - only if Ultra3 support + * is accessible. + */ + +#if 0 + if (tp->ic_max_width && (tp->ic_min_sync != 255 )) + tp->ppr_negotiation = 1; +#endif + tp->ppr_negotiation = 0; + if (np->features & FE_ULTRA3) { + if (tp->ic_max_width && (tp->ic_min_sync == 0x09)) + tp->ppr_negotiation = 1; + } + + if (!tp->ppr_negotiation) + cmd->ic_nego &= ~NS_PPR; + } + + if (DEBUG_FLAGS & DEBUG_IC) { + printk("%s: cmd->ic_nego %d, 1st byte 0x%2X\n", + ncr_name(np), cmd->ic_nego, cmd->cmnd[0]); + } + + /* Previous command recorded a parity or an initiator + * detected error condition. Force bus to narrow for this + * target. Clear flag. Negotation on request sense. + * Note: kernel forces 2 bus resets :o( but clears itself out. + * Minor bug? in scsi_obsolete.c (ugly) + */ + if (np->check_integ_par) { + printk("%s: Parity Error. Target set to narrow.\n", + ncr_name(np)); + tp->ic_max_width = 0; + tp->widedone = tp->period = 0; + } + + /* Initializing: + * If ic_nego == NS_PPR, we are in the initial test for + * PPR messaging support. If driver flag is clear, then + * either we don't support PPR nego (narrow or async device) + * or this is the second TUR and we have had a M. REJECT + * or unexpected disconnect on the first PPR negotiation. + * Do not negotiate, reset nego flags (in case a reset has + * occurred), clear ic_nego and return. + * General case: Kernel will clear flag on a fallback. + * Do only SDTR or WDTR in the future. + */ + if (!tp->ppr_negotiation && (cmd->ic_nego == NS_PPR )) { + tp->ppr_negotiation = 0; + cmd->ic_nego &= ~NS_PPR; + tp->widedone = tp->period = 1; + return msglen; + } + else if (( tp->ppr_negotiation && !(cmd->ic_nego & NS_PPR )) || + (!tp->ppr_negotiation && (cmd->ic_nego & NS_PPR )) ) { + tp->ppr_negotiation = 0; + cmd->ic_nego &= ~NS_PPR; + } + + /* + * Always check the PPR nego. flag bit if ppr_negotiation + * is set. If the ic_nego PPR bit is clear, + * there must have been a fallback. Do only + * WDTR / SDTR in the future. + */ + if ((tp->ppr_negotiation) && (!(cmd->ic_nego & NS_PPR))) + tp->ppr_negotiation = 0; + + /* In case of a bus reset, ncr_negotiate will reset + * the flags tp->widedone and tp->period to 0, forcing + * a new negotiation. Do WDTR then SDTR. If PPR, do both. + * Do NOT increase the period. It is possible for the Scsi_Cmnd + * flags to be set to increase the period when a bus reset + * occurs - we don't want to change anything. + */ + + no_increase = 0; + + if (tp->ppr_negotiation && (!tp->widedone) && (!tp->period) ) { + cmd->ic_nego = NS_PPR; + tp->widedone = tp->period = 1; + no_increase = 1; + } + else if (!tp->widedone) { + cmd->ic_nego = NS_WIDE; + tp->widedone = 1; + no_increase = 1; + } + else if (!tp->period) { + cmd->ic_nego = NS_SYNC; + tp->period = 1; + no_increase = 1; + } + + new_width = cmd->ic_nego_width & tp->ic_max_width; + + switch (cmd->ic_nego_sync) { + case 2: /* increase the period */ + if (!no_increase) { + if (tp->ic_min_sync <= 0x09) + tp->ic_min_sync = 0x0A; + else if (tp->ic_min_sync <= 0x0A) + tp->ic_min_sync = 0x0C; + else if (tp->ic_min_sync <= 0x0C) + tp->ic_min_sync = 0x19; + else if (tp->ic_min_sync <= 0x19) + tp->ic_min_sync *= 2; + else { + tp->ic_min_sync = 255; + cmd->ic_nego_sync = 0; + tp->maxoffs = 0; + } + } + new_period = tp->maxoffs?tp->ic_min_sync:0; + new_offset = tp->maxoffs; + break; + + case 1: /* nego. to maximum */ + new_period = tp->maxoffs?tp->ic_min_sync:0; + new_offset = tp->maxoffs; + break; + + case 0: /* nego to async */ + default: + new_period = 0; + new_offset = 0; + break; + }; + + + nego = NS_NOCHANGE; + if (tp->ppr_negotiation) { + u_char options_byte = 0; + + /* + ** Must make sure data is consistent. + ** If period is 9 and sync, must be wide and DT bit set. + ** else period must be larger. If the width is 0, + ** reset bus to wide but increase the period to 0x0A. + ** Note: The strange else clause is due to the integrity check. + ** If fails at 0x09, wide, the I.C. code will redo at the same + ** speed but a narrow bus. The driver must take care of slowing + ** the bus speed down. + ** + ** The maximum offset in ST mode is 31, in DT mode 62 (1010/1010_66 only) + */ + if ( (new_period==0x09) && new_offset) { + if (new_width) + options_byte = 0x02; + else { + tp->ic_min_sync = 0x0A; + new_period = 0x0A; + cmd->ic_nego_width = 1; + new_width = 1; + new_offset &= 0x1f; + } + } + else if (new_period > 0x09) + new_offset &= 0x1f; + + nego = NS_PPR; + + msgptr[msglen++] = M_EXTENDED; + msgptr[msglen++] = 6; + msgptr[msglen++] = M_X_PPR_REQ; + msgptr[msglen++] = new_period; + msgptr[msglen++] = 0; + msgptr[msglen++] = new_offset; + msgptr[msglen++] = new_width; + msgptr[msglen++] = options_byte; + + } + else { + switch (cmd->ic_nego & ~NS_PPR) { + case NS_WIDE: + /* + ** WDTR negotiation on if device supports + ** wide or if wide device forced narrow + ** due to a parity error. + */ + + cmd->ic_nego_width &= tp->ic_max_width; + + if (tp->ic_max_width | np->check_integ_par) { + nego = NS_WIDE; + msgptr[msglen++] = M_EXTENDED; + msgptr[msglen++] = 2; + msgptr[msglen++] = M_X_WIDE_REQ; + msgptr[msglen++] = new_width; + } + break; + + case NS_SYNC: + /* + ** negotiate synchronous transfers + ** Target must support sync transfers. + ** Min. period = 0x0A, maximum offset of 31=0x1f. + */ + + if (tp->inq_byte7 & INQ7_SYNC) { + + if (new_offset && (new_period < 0x0A)) { + tp->ic_min_sync = 0x0A; + new_period = 0x0A; + } + nego = NS_SYNC; + msgptr[msglen++] = M_EXTENDED; + msgptr[msglen++] = 3; + msgptr[msglen++] = M_X_SYNC_REQ; + msgptr[msglen++] = new_period; + msgptr[msglen++] = new_offset & 0x1f; + } + else + cmd->ic_nego_sync = 0; + break; + + case NS_NOCHANGE: + break; + } + } + + }; + + cp->nego_status = nego; + np->check_integ_par = 0; + + if (nego) { + tp->nego_cp = cp; + if (DEBUG_FLAGS & DEBUG_NEGO) { + ncr_print_msg(cp, nego == NS_WIDE ? + "wide/narrow msgout": + (nego == NS_SYNC ? "sync/async msgout" : "ppr msgout"), + msgptr); + }; + }; + + return msglen; +} +#endif /* SCSI_NCR_INTEGRITY_CHECKING */ + +/*========================================================== +** +** ** Prepare the next negotiation message if needed. ** ** Fill in the part of message buffer that contains the @@ -6224,13 +6619,42 @@ **========================================================== */ + static int ncr_prepare_nego(ncb_p np, ccb_p cp, u_char *msgptr) { tcb_p tp = &np->target[cp->target]; int msglen = 0; int nego = 0; + u_char width, offset, factor, last_byte; + + if (!np->check_integrity) { + /* If integrity checking disabled, enable PPR messaging + * if device supports wide, sync and ultra 3 + */ + if (tp->ppr_negotiation == 1) /* PPR message successful */ + tp->ppr_negotiation = 2; + + if ((tp->inq_done) && (!tp->ic_maximums_set)) { + tp->ic_maximums_set = 1; + + /* + * Issue PPR only if board is capable + * and set-up for Ultra3 transfers. + */ + tp->ppr_negotiation = 0; + if ( (np->features & FE_ULTRA3) && + (tp->usrwide) && (tp->maxoffs) && + (tp->minsync == 0x09) ) + tp->ppr_negotiation = 1; + } + } if (tp->inq_done) { + /* + * Get the current width, offset and period + */ + ncr_get_xfer_info( np, tp, &factor, + &offset, &width); /* ** negotiate wide transfers ? @@ -6238,19 +6662,50 @@ if (!tp->widedone) { if (tp->inq_byte7 & INQ7_WIDE16) { - nego = NS_WIDE; + if (tp->ppr_negotiation) + nego = NS_PPR; + else + nego = NS_WIDE; + + width = tp->usrwide; +#ifdef SCSI_NCR_INTEGRITY_CHECKING + if (tp->ic_done) + width &= tp->ic_max_width; +#endif } else tp->widedone=1; + }; /* ** negotiate synchronous transfers? */ - if (!nego && !tp->period) { + if ((nego != NS_WIDE) && !tp->period) { if (tp->inq_byte7 & INQ7_SYNC) { - nego = NS_SYNC; + if (tp->ppr_negotiation) + nego = NS_PPR; + else + nego = NS_SYNC; + + /* Check for async flag */ + if (tp->maxoffs == 0) { + offset = 0; + factor = 0; + } + else { + offset = tp->maxoffs; + factor = tp->minsync; +#ifdef SCSI_NCR_INTEGRITY_CHECKING + if ((tp->ic_done) && + (factor < tp->ic_min_sync)) + factor = tp->ic_min_sync; +#endif + } + } else { + offset = 0; + factor = 0; tp->period =0xffff; PRINT_TARGET(np, cp->target); printk ("target did not report SYNC.\n"); @@ -6259,18 +6714,54 @@ }; switch (nego) { + case NS_PPR: + /* + ** Must make sure data is consistent. + ** If period is 9 and sync, must be wide and DT bit set + ** else period must be larger. + ** Maximum offset is 31=0x1f is ST mode, 62 if DT mode + */ + last_byte = 0; + if ( (factor==9) && offset) { + if (!width) { + factor = 0x0A; + offset &= 0x1f; + } + else + last_byte = 0x02; + } + else if (factor > 0x09) + offset &= 0x1f; + + msgptr[msglen++] = M_EXTENDED; + msgptr[msglen++] = 6; + msgptr[msglen++] = M_X_PPR_REQ; + msgptr[msglen++] = factor; + msgptr[msglen++] = 0; + msgptr[msglen++] = offset; + msgptr[msglen++] = width; + msgptr[msglen++] = last_byte; + break; case NS_SYNC: + /* + ** Never negotiate faster than Ultra 2 (25ns periods) + */ + if (offset && (factor < 0x0A)) { + factor = 0x0A; + tp->minsync = 0x0A; + } + msgptr[msglen++] = M_EXTENDED; msgptr[msglen++] = 3; msgptr[msglen++] = M_X_SYNC_REQ; - msgptr[msglen++] = tp->maxoffs ? tp->minsync : 0; - msgptr[msglen++] = tp->maxoffs; + msgptr[msglen++] = factor; + msgptr[msglen++] = offset & 0x1f; break; case NS_WIDE: msgptr[msglen++] = M_EXTENDED; msgptr[msglen++] = 2; msgptr[msglen++] = M_X_WIDE_REQ; - msgptr[msglen++] = tp->usrwide; + msgptr[msglen++] = width; break; }; @@ -6280,7 +6771,9 @@ tp->nego_cp = cp; if (DEBUG_FLAGS & DEBUG_NEGO) { ncr_print_msg(cp, nego == NS_WIDE ? - "wide msgout":"sync_msgout", msgptr); + "wide msgout": + (nego == NS_SYNC ? "sync msgout" : "ppr msgout"), + msgptr); }; }; @@ -6464,6 +6957,73 @@ cp->segments = 0; } + /*--------------------------------------------------- + ** + ** negotiation required? + ** + ** (nego_status is filled by ncr_prepare_nego()) + ** + **--------------------------------------------------- + */ + + cp->nego_status = 0; + +#ifdef SCSI_NCR_INTEGRITY_CHECKING + if ((np->check_integrity && tp->ic_done) || !np->check_integrity) { + if ((!tp->widedone || !tp->period) && !tp->nego_cp && lp) { + msglen += ncr_prepare_nego (np, cp, msgptr + msglen); + } + } + else if (np->check_integrity && (cmd->ic_in_progress)) { + msglen += ncr_ic_nego (np, cp, cmd, msgptr + msglen); + } + else if (np->check_integrity && cmd->ic_complete) { + u_long current_period; + u_char current_offset, current_width, current_factor; + + ncr_get_xfer_info (np, tp, ¤t_factor, + ¤t_offset, ¤t_width); + + tp->ic_max_width = current_width; + tp->ic_min_sync = current_factor; + + if (current_factor == 9) current_period = 125; + else if (current_factor == 10) current_period = 250; + else if (current_factor == 11) current_period = 303; + else if (current_factor == 12) current_period = 500; + else current_period = current_factor * 40; + + /* + * Negotiation for this target is complete. Update flags. + */ + tp->period = current_period; + tp->widedone = 1; + tp->ic_done = 1; + + printk("%s: Integrity Check Complete: \n", ncr_name(np)); + + printk("%s: %s %s SCSI", ncr_name(np), + current_offset?"SYNC":"ASYNC", + tp->ic_max_width?"WIDE":"NARROW"); + if (current_offset) { + u_long mbs = 10000 * (tp->ic_max_width + 1); + + printk(" %d.%d MB/s", + (int) (mbs / current_period), (int) (mbs % current_period)); + + printk(" (%d ns, %d offset)\n", + (int) current_period/10, current_offset); + } + else + printk(" %d MB/s. \n ", (tp->ic_max_width+1)*5); + } +#else + if ((!tp->widedone || !tp->period) && !tp->nego_cp && lp) { + msglen += ncr_prepare_nego (np, cp, msgptr + msglen); + } +#endif /* SCSI_NCR_INTEGRITY_CHECKING */ + + /*---------------------------------------------------- ** ** Determine xfer direction. @@ -6524,19 +7084,6 @@ cp->startp = cp->phys.header.savep; cp->lastp0 = cp->phys.header.lastp; - /*--------------------------------------------------- - ** - ** negotiation required? - ** - ** (nego_status is filled by ncr_prepare_nego()) - ** - **--------------------------------------------------- - */ - - cp->nego_status = 0; - if ((!tp->widedone || !tp->period) && !tp->nego_cp && lp) - msglen += ncr_prepare_nego (np, cp, msgptr + msglen); - /*---------------------------------------------------- ** ** fill in ccb @@ -6559,6 +7106,7 @@ cp->phys.select.sel_id = cp->target; cp->phys.select.sel_scntl3 = tp->wval; cp->phys.select.sel_sxfer = tp->sval; + cp->phys.select.sel_scntl4 = tp->uval; /* ** message */ @@ -7091,6 +7639,14 @@ PRINT_ADDR(cmd); printk ("illegal scsi phase (4/5).\n"); } + if (cp->xerr_status & XE_SODL_UNRUN) { + PRINT_ADDR(cmd); + printk ("ODD transfer in DATA OUT phase.\n"); + } + if (cp->xerr_status & XE_SWIDE_OVRUN){ + PRINT_ADDR(cmd); + printk ("ODD transfer in DATA IN phase.\n"); + } if (cp->host_status==HS_COMPLETE) cp->host_status = HS_FAIL; @@ -7167,6 +7723,12 @@ PRINT_ADDR(cmd); ncr_printl_hex("sense data:", cmd->sense_buffer, 14); } + } else if ((cp->host_status == HS_COMPLETE) + && (cp->scsi_status == S_CONFLICT)) { + /* + ** Reservation Conflict condition code + */ + SetScsiResult(cmd, DID_OK, S_CONFLICT); } else if ((cp->host_status == HS_COMPLETE) && (cp->scsi_status == S_BUSY || @@ -7418,7 +7980,11 @@ OUTB (nc_ctest3, np->rv_ctest3); /* Write and invalidate */ OUTB (nc_ctest4, np->rv_ctest4); /* Master parity checking */ - OUTB (nc_stest2, EXT|np->rv_stest2); /* Extended Sreq/Sack filtering */ + if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66)){ + OUTB (nc_stest2, EXT|np->rv_stest2); + /* Extended Sreq/Sack filtering, not supported in C1010/C1010_66 */ + } OUTB (nc_stest3, TE); /* TolerANT enable */ OUTB (nc_stime0, 0x0c); /* HTH disabled STO 0.25 sec */ @@ -7427,14 +7993,24 @@ ** Disable overlapped arbitration for all dual-function ** devices, regardless revision id. ** We may consider it is a post-chip-design feature. ;-) + ** + ** Errata applies to all 896 and 1010 parts. */ if (np->device_id == PCI_DEVICE_ID_NCR_53C875) OUTB (nc_ctest0, (1<<5)); - else if (np->device_id == PCI_DEVICE_ID_NCR_53C896) + else if (np->device_id == PCI_DEVICE_ID_NCR_53C896 || + np->device_id == PCI_DEVICE_ID_LSI_53C1010 || + np->device_id == PCI_DEVICE_ID_LSI_53C1010_66 ) np->rv_ccntl0 |= DPR; /* - ** If 64 bit (895A/896/1010) write the CCNTL1 register to + ** C1010_66MHz rev 0 part requies AIPCNTL1 bit 3 to be set. + */ + if (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66) + OUTB(nc_aipcntl1, (1<<3)); + + /* + ** If 64 bit (895A/896/1010/1010_66) write the CCNTL1 register to ** enable 40 bit address table indirect addressing for MOVE. ** Also write CCNTL0 if 64 bit chip, since this register seems ** to only be used by 64 bit cores. @@ -7445,8 +8021,8 @@ } /* - ** If phase mismatch handled by scripts (53C895A or 53C896), - ** set PM jump addresses. + ** If phase mismatch handled by scripts (53C895A or 53C896 + ** or 53C1010 or 53C1010_66), set PM jump addresses. */ if (np->features & FE_NOPM) { @@ -7475,9 +8051,10 @@ OUTB (nc_dien , MDPE|BF|SSI|SIR|IID); /* - ** For 895/6 enable SBMC interrupt and save current SCSI bus mode. + ** For 895/895A/896/c1010 + ** Enable SBMC interrupt and save current SCSI bus mode. */ - if (np->features & FE_ULTRA2) { + if ( (np->features & FE_ULTRA2) || (np->features & FE_ULTRA3) ) { OUTONW (nc_sien, SBMC); np->scsi_mode = INB (nc_stest4) & SMODE; } @@ -7496,6 +8073,7 @@ tp->sval = 0; tp->wval = np->rv_scntl3; + tp->uval = np->rv_scntl4; if (tp->usrsync != 255) { if (tp->usrsync <= np->maxsync) { @@ -7626,6 +8204,10 @@ /* ** Compute the synchronous period in tenths of nano-seconds + ** from sfac. + ** + ** Note, if sfac == 9, DT is being used. Double the period of 125 + ** to 250. */ if (sfac <= 10) per = 250; else if (sfac == 11) per = 303; @@ -7673,7 +8255,76 @@ ** Compute and return sync parameters for the ncr */ *fakp = fak - 4; - *scntl3p = ((div+1) << 4) + (sfac < 25 ? 0x80 : 0); + + /* + ** If sfac < 25, and 8xx parts, desire that the chip operate at + ** least at Ultra speeds. Must set bit 7 of scntl3. + ** For C1010, do not set this bit. If operating at Ultra3 speeds, + ** set the U3EN bit instead. + */ + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) { + *scntl3p = (div+1) << 4; + *fakp = 0; + } + else { + *scntl3p = ((div+1) << 4) + (sfac < 25 ? 0x80 : 0); + *fakp = fak - 4; + } +} + +/*========================================================== +** +** Utility routine to return the current bus width +** synchronous period and offset. +** Utilizes target sval, wval and uval +** +**========================================================== +*/ +static void ncr_get_xfer_info(ncb_p np, tcb_p tp, u_char *factor, + u_char *offset, u_char *width) +{ + + u_char idiv; + u_long period; + + *width = (tp->wval & EWS) ? 1 : 0; + + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) + *offset = (tp->sval & 0x3f); + else + *offset = (tp->sval & 0x1f); + + /* + * Midlayer signal to the driver that all of the scsi commands + * for the integrity check have completed. Save the negotiated + * parameters (extracted from sval, wval and uval). + * See ncr_setsync for alg. details. + */ + + idiv = (tp->wval>>4) & 0x07; + + if ( *offset && idiv ) { + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)){ + if (tp->uval & 0x80) + period = (2*div_10M[idiv-1])/np->clock_khz; + else + period = (4*div_10M[idiv-1])/np->clock_khz; + } + else + period = (((tp->sval>>5)+4)*div_10M[idiv-1])/np->clock_khz; + } + else + period = 0xffff; + + if (period <= 125) *factor = 9; + else if (period <= 250) *factor = 10; + else if (period <= 303) *factor = 11; + else if (period <= 500) *factor = 12; + else *factor = (period + 40 - 1) / 40; + } @@ -7687,14 +8338,20 @@ static void ncr_set_sync_wide_status (ncb_p np, u_char target) { - ccb_p cp; + ccb_p cp = np->ccbc; tcb_p tp = &np->target[target]; /* ** set actual value and sync_status + ** + ** TEMP register contains current scripts address + ** which is data type/direction/dependent. */ OUTB (nc_sxfer, tp->sval); OUTB (nc_scntl3, tp->wval); + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) + OUTB (nc_scntl4, tp->uval); /* ** patch ALL ccbs of this target. @@ -7706,6 +8363,9 @@ continue; cp->phys.select.sel_scntl3 = tp->wval; cp->phys.select.sel_sxfer = tp->sval; + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) + cp->phys.select.sel_scntl4 = tp->uval; }; } @@ -7716,11 +8376,13 @@ **========================================================== */ -static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer) +static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer, + u_char scntl4) { tcb_p tp; u_char target = INB (nc_sdid) & 0x0f; u_char idiv; + u_char offset; assert (cp); if (!cp) return; @@ -7729,9 +8391,21 @@ tp = &np->target[target]; - if (!scntl3 || !(sxfer & 0x1f)) - scntl3 = np->rv_scntl3; - scntl3 = (scntl3 & 0xf0) | (tp->wval & EWS) | (np->rv_scntl3 & 0x07); + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) { + offset = sxfer & 0x3f; /* bits 5-0 */ + scntl3 = (scntl3 & 0xf0) | (tp->wval & EWS); + scntl4 = (scntl4 & 0x80); + } + else { + offset = sxfer & 0x1f; /* bits 4-0 */ + if (!scntl3 || !offset) + scntl3 = np->rv_scntl3; + + scntl3 = (scntl3 & 0xf0) | (tp->wval & EWS) | + (np->rv_scntl3 & 0x07); + } + /* ** Deduce the value of controller sync period from scntl3. @@ -7739,27 +8413,42 @@ */ idiv = ((scntl3 >> 4) & 0x7); - if ((sxfer & 0x1f) && idiv) - tp->period = (((sxfer>>5)+4)*div_10M[idiv-1])/np->clock_khz; + if ( offset && idiv) { + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) { + /* Note: If extra data hold clocks are used, + * the formulas below must be modified. + * When scntl4 == 0, ST mode. + */ + if (scntl4 & 0x80) + tp->period = (2*div_10M[idiv-1])/np->clock_khz; + else + tp->period = (4*div_10M[idiv-1])/np->clock_khz; + } + else + tp->period = (((sxfer>>5)+4)*div_10M[idiv-1])/np->clock_khz; + } else tp->period = 0xffff; + /* ** Stop there if sync parameters are unchanged */ - if (tp->sval == sxfer && tp->wval == scntl3) return; + if (tp->sval == sxfer && tp->wval == scntl3 && tp->uval == scntl4) return; tp->sval = sxfer; tp->wval = scntl3; + tp->uval = scntl4; /* ** Bells and whistles ;-) ** Donnot announce negotiations due to auto-sense, ** unless user really want us to be verbose. :) */ - if (bootverbose < 2 && (cp->host_flags & HF_AUTO_SENSE)) + if ( bootverbose < 2 && (cp->host_flags & HF_AUTO_SENSE)) goto next; PRINT_TARGET(np, target); - if (sxfer & 0x01f) { + if (offset) { unsigned f10 = 100000 << (tp->widedone ? tp->widedone -1 : 0); unsigned mb10 = (f10 + tp->period/2) / tp->period; char *scsi; @@ -7767,19 +8456,23 @@ /* ** Disable extended Sreq/Sack filtering */ - if (tp->period <= 2000) OUTOFFB (nc_stest2, EXT); + if ((tp->period <= 2000) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66)) + OUTOFFB (nc_stest2, EXT); /* ** Bells and whistles ;-) */ - if (tp->period < 500) scsi = "FAST-40"; + if (tp->period < 250) scsi = "FAST-80"; + else if (tp->period < 500) scsi = "FAST-40"; else if (tp->period < 1000) scsi = "FAST-20"; else if (tp->period < 2000) scsi = "FAST-10"; else scsi = "FAST-5"; printk ("%s %sSCSI %d.%d MB/s (%d ns, offset %d)\n", scsi, tp->widedone > 1 ? "WIDE " : "", - mb10 / 10, mb10 % 10, tp->period / 10, sxfer & 0x1f); + mb10 / 10, mb10 % 10, tp->period / 10, offset); } else printk ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : ""); next: @@ -7790,6 +8483,7 @@ ncr_set_sync_wide_status(np, target); } + /*========================================================== ** ** Switch wide mode for current job and it's target @@ -7843,6 +8537,126 @@ ncr_set_sync_wide_status(np, target); } + +/*========================================================== +** +** Switch sync/wide mode for current job and it's target +** PPR negotiations only +** +**========================================================== +*/ + +static void ncr_setsyncwide (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer, + u_char scntl4, u_char wide) +{ + tcb_p tp; + u_char target = INB (nc_sdid) & 0x0f; + u_char idiv; + u_char offset; + + assert (cp); + if (!cp) return; + + assert (target == (cp->target & 0xf)); + + tp = &np->target[target]; + tp->widedone = wide+1; + + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) { + offset = sxfer & 0x3f; /* bits 5-0 */ + scntl3 = (scntl3 & 0xf0) | (wide ? EWS : 0); + scntl4 = (scntl4 & 0x80); + } + else { + offset = sxfer & 0x1f; /* bits 4-0 */ + if (!scntl3 || !offset) + scntl3 = np->rv_scntl3; + + scntl3 = (scntl3 & 0xf0) | (wide ? EWS : 0) | + (np->rv_scntl3 & 0x07); + } + + + /* + ** Deduce the value of controller sync period from scntl3. + ** period is in tenths of nano-seconds. + */ + + idiv = ((scntl3 >> 4) & 0x7); + if ( offset && idiv) { + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) { + /* Note: If extra data hold clocks are used, + * the formulas below must be modified. + * When scntl4 == 0, ST mode. + */ + if (scntl4 & 0x80) + tp->period = (2*div_10M[idiv-1])/np->clock_khz; + else + tp->period = (4*div_10M[idiv-1])/np->clock_khz; + } + else + tp->period = (((sxfer>>5)+4)*div_10M[idiv-1])/np->clock_khz; + } + else + tp->period = 0xffff; + + + /* + ** Stop there if sync parameters are unchanged + */ + if (tp->sval == sxfer && tp->wval == scntl3 && tp->uval == scntl4) return; + tp->sval = sxfer; + tp->wval = scntl3; + tp->uval = scntl4; + + /* + ** Bells and whistles ;-) + ** Donnot announce negotiations due to auto-sense, + ** unless user really want us to be verbose. :) + */ + if ( bootverbose < 2 && (cp->host_flags & HF_AUTO_SENSE)) + goto next; + PRINT_TARGET(np, target); + if (offset) { + unsigned f10 = 100000 << (tp->widedone ? tp->widedone -1 : 0); + unsigned mb10 = (f10 + tp->period/2) / tp->period; + char *scsi; + + /* + ** Disable extended Sreq/Sack filtering + */ + if ((tp->period <= 2000) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66)) + OUTOFFB (nc_stest2, EXT); + + /* + ** Bells and whistles ;-) + */ + if (tp->period < 250) scsi = "FAST-80"; + else if (tp->period < 500) scsi = "FAST-40"; + else if (tp->period < 1000) scsi = "FAST-20"; + else if (tp->period < 2000) scsi = "FAST-10"; + else scsi = "FAST-5"; + + printk ("%s %sSCSI %d.%d MB/s (%d ns, offset %d)\n", scsi, + tp->widedone > 1 ? "WIDE " : "", + mb10 / 10, mb10 % 10, tp->period / 10, offset); + } else + printk ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : ""); +next: + /* + ** set actual value and sync_status + ** patch ALL ccbs of this target. + */ + ncr_set_sync_wide_status(np, target); +} + + + + /*========================================================== ** ** Switch tagged mode for a target. @@ -8452,6 +9266,28 @@ ncr_log_hard_error(np, sist, dstat); + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) { + u_char ctest4_o, ctest4_m; + u_char shadow; + + /* + * Get shadow register data + * Write 1 to ctest4 + */ + ctest4_o = INB(nc_ctest4); + + OUTB(nc_ctest4, ctest4_o | 0x10); + + ctest4_m = INB(nc_ctest4); + shadow = INW_OFF(0x42); + + OUTB(nc_ctest4, ctest4_o); + + printk("%s: ctest4/sist original 0x%x/0x%X mod: 0x%X/0x%x\n", + ncr_name(np), ctest4_o, sist, ctest4_m, shadow); + } + if ((sist & (GEN|HTH|SGE)) || (dstat & (MDPE|BF|ABRT|IID))) { ncr_start_reset(np); @@ -8577,6 +9413,20 @@ */ void ncr_int_udc (ncb_p np) { + u_int32 dsa = INL (nc_dsa); + ccb_p cp = ncr_ccb_from_dsa(np, dsa); + tcb_p tp = &np->target[cp->target]; + + /* + * Fix Up. Some disks respond to a PPR negotation with + * a bus free instead of a message reject. + * Disable ppr negotiation if this is first time + * tried ppr negotiation. + */ + + if (tp->ppr_negotiation == 1) + tp->ppr_negotiation = 0; + printk ("%s: unexpected disconnect\n", ncr_name(np)); ncr_recover_scsi_int(np, HS_UNEXPECTED); } @@ -8688,6 +9538,7 @@ /* ** Keep track of the parity error. */ + OUTONB (HF_PRT, HF_EXT_ERR); cp->xerr_status |= XE_PARITY_ERR; /* @@ -8695,14 +9546,22 @@ */ np->msgout[0] = (phase == 7) ? M_PARITY : M_ID_ERROR; +#ifdef SCSI_NCR_INTEGRITY_CHECKING + /* + ** Save error message. For integrity check use only. + */ + if (np->check_integrity) + np->check_integ_par = np->msgout[0]; +#endif + /* - ** If the old phase was DATA IN phase, we have to deal with - ** the 3 situations described above. + ** If the old phase was DATA IN or DT DATA IN phase, + ** we have to deal with the 3 situations described above. ** For other input phases (MSG IN and STATUS), the device ** must resend the whole thing that failed parity checking ** or signal error. So, jumping to dispatcher should be OK. */ - if (phase == 1) { + if ((phase == 1) || (phase == 5)) { /* Phase mismatch handled by SCRIPTS */ if (dsp == NCB_SCRIPTH_PHYS (np, pm_handle)) OUTL (nc_dsp, dsp); @@ -8772,45 +9631,64 @@ */ cp = ncr_ccb_from_dsa(np, dsa); + if (DEBUG_FLAGS & DEBUG_PHASE) + printk("CCB = %2x %2x %2x %2x %2x %2x\n", + cp->cmd->cmnd[0], cp->cmd->cmnd[1], cp->cmd->cmnd[2], + cp->cmd->cmnd[3], cp->cmd->cmnd[4], cp->cmd->cmnd[5]); + /* ** Donnot take into account dma fifo and various buffers in ** INPUT phase since the chip flushes everything before ** raising the MA interrupt for interrupted INPUT phases. ** For DATA IN phase, we will check for the SWIDE later. */ - if ((cmd & 7) != 1) { + if ( !(((cmd & 7) == 1) || ((cmd & 7) == 5) ) ) { u_int32 dfifo; u_char ss0, ss2; /* - ** Read DFIFO, CTEST[4-6] using 1 PCI bus ownership. + ** If C1010, DFBC contains number of bytes in DMA fifo. + ** else read DFIFO, CTEST[4-6] using 1 PCI bus ownership. */ - dfifo = INL(nc_dfifo); + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) + delta = INL(nc_dfbc) & 0xffff; + else { + dfifo = INL(nc_dfifo); - /* - ** Calculate remaining bytes in DMA fifo. - ** (CTEST5 = dfifo >> 16) - */ - if (dfifo & (DFS << 16)) - delta = ((((dfifo >> 8) & 0x300) | - (dfifo & 0xff)) - rest) & 0x3ff; - else - delta = ((dfifo & 0xff) - rest) & 0x7f; + /* + ** Calculate remaining bytes in DMA fifo. + ** C1010 - always large fifo, value in dfbc + ** Otherwise, (CTEST5 = dfifo >> 16) + */ + if (dfifo & (DFS << 16)) + delta = ((((dfifo >> 8) & 0x300) | + (dfifo & 0xff)) - rest) & 0x3ff; + else + delta = ((dfifo & 0xff) - rest) & 0x7f; - /* - ** The data in the dma fifo has not been transfered to - ** the target -> add the amount to the rest - ** and clear the data. - ** Check the sstat2 register in case of wide transfer. - */ + /* + ** The data in the dma fifo has not been + ** transferred to the target -> add the amount + ** to the rest and clear the data. + ** Check the sstat2 register in case of wide + ** transfer. + */ + + } + rest += delta; ss0 = INB (nc_sstat0); if (ss0 & OLF) rest++; - if (ss0 & ORF) rest++; + if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66) && (ss0 & ORF)) + rest++; if (cp && (cp->phys.select.sel_scntl3 & EWS)) { ss2 = INB (nc_sstat2); if (ss2 & OLF1) rest++; - if (ss2 & ORF1) rest++; + if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66) && (ss2 & ORF)) + rest++; }; /* @@ -8902,9 +9780,10 @@ /* ** if old phase not dataphase, leave here. + ** C/D line is low if data. */ - if (cmd & 0x06) { + if (cmd & 0x02) { PRINT_ADDR(cp->cmd); printk ("phase change %x-%x %d@%08x resid=%d.\n", cmd&7, INB(nc_sbcl)&7, (unsigned)olen, @@ -8962,45 +9841,42 @@ ** - move current data pointer context by one byte. */ nxtdsp = NCB_SCRIPT_PHYS (np, dispatch); - if ((cmd & 7) == 1 && cp && (cp->phys.select.sel_scntl3 & EWS) && + if ( ((cmd & 7) == 1 || (cmd & 7) == 5) + && cp && (cp->phys.select.sel_scntl3 & EWS) && (INB (nc_scntl2) & WSR)) { - /* - ** Hmmm... The device may want to also ignore - ** this residue but it must send immediately the - ** appropriate message. We snoop the SCSI BUS - ** and will just throw away this message from - ** SCRIPTS if the SWIDE is to be ignored. - */ - if ((INB (nc_sbcl) & 7) == 7 && - INB (nc_sbdl) == M_IGN_RESIDUE) { - nxtdsp = NCB_SCRIPT_PHYS (np, ign_i_w_r_msg); - } - /* - ** We must grab the SWIDE. - ** We will use some complex SCRIPTS for that. - */ - else { - OUTL (nc_scratcha, pm->sg.addr); - nxtdsp = NCB_SCRIPTH_PHYS (np, swide_ma_32); - if (np->features & FE_64BIT) { - OUTB (nc_sbr, (pm->sg.size >> 24)); - nxtdsp = NCB_SCRIPTH_PHYS (np, swide_ma_64); - } - /* - ** Adjust our data pointer context. - */ - ++pm->sg.addr; - --pm->sg.size; - /* - ** Hmmm... Could it be possible that a SWIDE that - ** is followed by a 1 byte CHMOV would lead to - ** a CHMOV(0). Anyway, we handle it by just - ** skipping context that would attempt a CHMOV(0). - */ - if (!pm->sg.size) - newcmd = pm->ret; - } - } + u32 tmp; + +#ifdef SYM_DEBUG_PM_WITH_WSR + PRINT_ADDR(cp); + printf ("MA interrupt with WSR set - " + "pm->sg.addr=%x - pm->sg.size=%d\n", + pm->sg.addr, pm->sg.size); +#endif + /* + * Set up the table indirect for the MOVE + * of the residual byte and adjust the data + * pointer context. + */ + tmp = scr_to_cpu(pm->sg.addr); + cp->phys.wresid.addr = cpu_to_scr(tmp); + pm->sg.addr = cpu_to_scr(tmp + 1); + tmp = scr_to_cpu(pm->sg.size); + cp->phys.wresid.size = cpu_to_scr((tmp&0xff000000) | 1); + pm->sg.size = cpu_to_scr(tmp - 1); + + /* + * If only the residual byte is to be moved, + * no PM context is needed. + */ + if ((tmp&0xffffff) == 1) + newcmd = pm->ret; + + /* + * Prepare the address of SCRIPTS that will + * move the residual byte to memory. + */ + nxtdsp = NCB_SCRIPTH_PHYS (np, wsr_ma_helper); + } if (DEBUG_FLAGS & DEBUG_PHASE) { PRINT_ADDR(cp->cmd); @@ -9076,7 +9952,8 @@ nxtdsp = NCB_SCRIPTH_PHYS (np, ident_break); } else if (dsp == NCB_SCRIPTH_PHYS (np, send_wdtr) || - dsp == NCB_SCRIPTH_PHYS (np, send_sdtr)) { + dsp == NCB_SCRIPTH_PHYS (np, send_sdtr) || + dsp == NCB_SCRIPTH_PHYS (np, send_ppr)) { nxtdsp = NCB_SCRIPTH_PHYS (np, nego_bad_phase); } break; @@ -9277,12 +10154,56 @@ ** to be stuck with WIDE and/or SYNC data transfer. ** ** cp->nego_status is filled by ncr_prepare_nego(). + ** + ** Do NOT negotiate if performing integrity check + ** or if integrity check has completed, all check + ** conditions will have been cleared. + */ + +#ifdef SCSI_NCR_INTEGRITY_CHECKING + if (DEBUG_FLAGS & DEBUG_IC) { + printk("%s: ncr_sir_to_redo: ic_done %2X, in_progress %2X\n", + ncr_name(np), tp->ic_done, cp->cmd->ic_in_progress); + } + + /* + ** If parity error during integrity check, + ** set the target width to narrow. Otherwise, + ** do not negotiate on a request sense. */ + if ( np->check_integ_par && np->check_integrity + && cp->cmd->ic_in_progress ) { + cp->nego_status = 0; + msglen += + ncr_ic_nego (np, cp, cmd ,&cp->scsi_smsg2[msglen]); + } + + if (!np->check_integrity || + (np->check_integrity && + (!cp->cmd->ic_in_progress && !tp->ic_done)) ) { + ncr_negotiate(np, tp); + cp->nego_status = 0; + { + u_char sync_offset; + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) + sync_offset = tp->sval & 0x3f; + else + sync_offset = tp->sval & 0x1f; + + if ((tp->wval & EWS) || sync_offset) + msglen += + ncr_prepare_nego (np, cp, &cp->scsi_smsg2[msglen]); + } + + } +#else ncr_negotiate(np, tp); cp->nego_status = 0; if ((tp->wval & EWS) || (tp->sval & 0x1f)) msglen += ncr_prepare_nego (np, cp, &cp->scsi_smsg2[msglen]); +#endif /* SCSI_NCR_INTEGRITY_CHECKING */ /* ** Message table indirect structure. @@ -9489,6 +10410,7 @@ np->abrt_sel.sel_id = target; np->abrt_sel.sel_scntl3 = tp->wval; np->abrt_sel.sel_sxfer = tp->sval; + np->abrt_sel.sel_scntl4 = tp->uval; OUTL(nc_dsa, np->p_ncb); OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, sel_for_abort)); return; @@ -9696,6 +10618,7 @@ if (np->abrt_msg[0] == M_RESET) { tp->sval = 0; tp->wval = np->rv_scntl3; + tp->uval = np->rv_scntl4; ncr_set_sync_wide_status(np, target); ncr_negotiate(np, tp); } @@ -10014,11 +10937,30 @@ static int ncr_compute_residual(ncb_p np, ccb_p cp) { - int dp_sg, dp_sgmin, resid, tmp; + int dp_sg, dp_sgmin, tmp; + int resid=0; int dp_ofs = 0; /* - ** Should have been checked by the caller. + * Check for some data lost or just thrown away. + * We are not required to be quite accurate in this + * situation. Btw, if we are odd for output and the + * device claims some more data, it may well happen + * than our residual be zero. :-) + */ + if (cp->xerr_status & (XE_EXTRA_DATA|XE_SODL_UNRUN|XE_SWIDE_OVRUN)) { + if (cp->xerr_status & XE_EXTRA_DATA) + resid -= scr_to_cpu(cp->phys.extra_bytes); + if (cp->xerr_status & XE_SODL_UNRUN) + ++resid; + if (cp->xerr_status & XE_SWIDE_OVRUN) + --resid; + } + + + /* + ** If all data has been transferred, + ** there is no residual. */ if (cp->phys.header.lastp == cp->phys.header.goalp) return 0; @@ -10159,7 +11101,7 @@ */ static void ncr_sync_nego(ncb_p np, tcb_p tp, ccb_p cp) { - u_char scntl3; + u_char scntl3, scntl4; u_char chg, ofs, per, fak; /* @@ -10203,6 +11145,7 @@ */ fak = 7; scntl3 = 0; + scntl4 = 0; if (ofs != 0) { ncr_getsync(np, per, &fak, &scntl3); if (fak > 7) { @@ -10214,13 +11157,14 @@ fak = 7; per = 0; scntl3 = 0; + scntl4 = 0; tp->minsync = 0; } if (DEBUG_FLAGS & DEBUG_NEGO) { PRINT_ADDR(cp->cmd); - printk ("sync: per=%d scntl3=0x%x ofs=%d fak=%d chg=%d.\n", - per, scntl3, ofs, fak, chg); + printk ("sync: per=%d scntl3=0x%x scntl4=0x%x ofs=%d fak=%d chg=%d.\n", + per, scntl3, scntl4, ofs, fak, chg); } if (INB (HS_PRT) == HS_NEGOTIATE) { @@ -10234,13 +11178,18 @@ /* ** Answer wasn't acceptable. */ - ncr_setsync (np, cp, 0, 0xe0); + ncr_setsync (np, cp, 0, 0xe0, 0); OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad)); } else { /* ** Answer is ok. */ - ncr_setsync (np, cp, scntl3, (fak<<5)|ofs); + if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66)) + ncr_setsync (np, cp, scntl3, (fak<<5)|ofs,0); + else + ncr_setsync (np, cp, scntl3, ofs, scntl4); + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack)); }; return; @@ -10256,7 +11205,11 @@ ** prepare an answer message */ - ncr_setsync (np, cp, scntl3, (fak<<5)|ofs); + if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66)) + ncr_setsync (np, cp, scntl3, (fak<<5)|ofs,0); + else + ncr_setsync (np, cp, scntl3, ofs, scntl4); np->msgout[0] = M_EXTENDED; np->msgout[1] = 3; @@ -10350,7 +11303,7 @@ return; case NS_SYNC: - ncr_setsync (np, cp, 0, 0xe0); + ncr_setsync (np, cp, 0, 0xe0, 0); break; }; }; @@ -10377,6 +11330,205 @@ OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, wdtr_resp)); } +/*========================================================== +** +** ncr chip handler for PARALLEL PROTOCOL REQUEST +** (PPR) message. +** +**========================================================== +** +** Read comments above. +** +**---------------------------------------------------------- +*/ +static void ncr_ppr_nego(ncb_p np, tcb_p tp, ccb_p cp) +{ + u_char scntl3, scntl4; + u_char chg, ofs, per, fak, wth, dt; + + /* + ** PPR message received. + */ + + if (DEBUG_FLAGS & DEBUG_NEGO) { + ncr_print_msg(cp, "ppr msg in", np->msgin); + }; + + /* + ** get requested values. + */ + + chg = 0; + per = np->msgin[3]; + ofs = np->msgin[5]; + wth = np->msgin[6]; + dt = np->msgin[7]; + if (ofs==0) per=255; + + /* + ** if target sends sync (wide), + ** it CAN transfer synch (wide). + */ + + if (ofs) + tp->inq_byte7 |= INQ7_SYNC; + + if (wth) + tp->inq_byte7 |= INQ7_WIDE16; + + /* + ** check values against driver limits. + */ + + if (wth > tp->usrwide) + {chg = 1; wth = tp->usrwide;} + if (per < np->minsync) + {chg = 1; per = np->minsync;} + if (per < tp->minsync) + {chg = 1; per = tp->minsync;} + if (ofs > tp->maxoffs) + {chg = 1; ofs = tp->maxoffs;} + + /* + ** Check against controller limits. + */ + fak = 7; + scntl3 = 0; + scntl4 = 0; + if (ofs != 0) { + scntl4 = dt ? 0x80 : 0; + ncr_getsync(np, per, &fak, &scntl3); + if (fak > 7) { + chg = 1; + ofs = 0; + } + } + if (ofs == 0) { + fak = 7; + per = 0; + scntl3 = 0; + scntl4 = 0; + tp->minsync = 0; + } + + /* + ** If target responds with Ultra 3 speed + ** but narrow or not DT, reject. + ** If target responds with DT request + ** but not Ultra3 speeds, reject message, + ** reset min sync for target to 0x0A and + ** set flags to re-negotiate. + */ + + if ((per == 0x09) && ofs && (!wth || !dt)) + chg = 1; + else if (( (per > 0x09) && dt) ) + chg = 2; + + + if (DEBUG_FLAGS & DEBUG_NEGO) { + PRINT_ADDR(cp->cmd); + printk ("ppr: wth=%d per=%d scntl3=0x%x scntl4=0x%x ofs=%d fak=%d chg=%d.\n", + wth, per, scntl3, scntl4, ofs, fak, chg); + } + + if (INB (HS_PRT) == HS_NEGOTIATE) { + OUTB (HS_PRT, HS_BUSY); + switch (cp->nego_status) { + case NS_PPR: + /* + ** This was an answer message + */ + if (chg) { + /* + ** Answer wasn't acceptable. + */ + if (chg == 2) { + /* Send message reject and reset flags for + ** host to re-negotiate with min period 0x0A. + */ + tp->minsync = 0x0A; + tp->period = 0; + tp->widedone = 0; + } + ncr_setsyncwide (np, cp, 0, 0xe0, 0, 0); + OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad)); + } else { + /* + ** Answer is ok. + */ + + if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66)) + ncr_setsyncwide (np, cp, scntl3, (fak<<5)|ofs,0, wth); + else + ncr_setsyncwide (np, cp, scntl3, ofs, scntl4, wth); + + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack)); + + }; + return; + + case NS_SYNC: + ncr_setsync (np, cp, 0, 0xe0, 0); + break; + + case NS_WIDE: + ncr_setwide (np, cp, 0, 0); + break; + }; + }; + + /* + ** It was a request. Set value and + ** prepare an answer message + ** + ** If narrow or not DT and requesting Ultra3 + ** slow the bus down and force ST. If not + ** requesting Ultra3, force ST. + ** Max offset is 31=0x1f if ST mode. + */ + + if ((per == 0x09) && ofs && (!wth || !dt)) { + per = 0x0A; + dt = 0; + ofs &= 0x1f; + } + else if ( (per > 0x09) && dt) { + dt = 0; + ofs &= 0x1f; + } + + if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66)) + ncr_setsyncwide (np, cp, scntl3, (fak<<5)|ofs,0, wth); + else + ncr_setsyncwide (np, cp, scntl3, ofs, scntl4, wth); + + np->msgout[0] = M_EXTENDED; + np->msgout[1] = 6; + np->msgout[2] = M_X_PPR_REQ; + np->msgout[3] = per; + np->msgout[4] = 0; + np->msgout[5] = ofs; + np->msgout[6] = wth; + np->msgout[7] = dt; + + cp->nego_status = NS_PPR; + + if (DEBUG_FLAGS & DEBUG_NEGO) { + ncr_print_msg(cp, "ppr msgout", np->msgout); + } + + np->msgin [0] = M_NOOP; + + if (!ofs) + OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad)); + else + OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, ppr_resp)); +} + + /* ** Reset SYNC or WIDE to default settings. @@ -10392,13 +11544,45 @@ switch (cp->nego_status) { case NS_SYNC: - ncr_setsync (np, cp, 0, 0xe0); + ncr_setsync (np, cp, 0, 0xe0, 0); break; case NS_WIDE: ncr_setwide (np, cp, 0, 0); break; + case NS_PPR: + /* + * ppr_negotiation is set to 1 on the first ppr nego command. + * If ppr is successful, it is reset to 2. + * If unsuccessful it is reset to 0. + */ + if (DEBUG_FLAGS & DEBUG_NEGO) { + tcb_p tp=&np->target[cp->target]; + u_char factor, offset, width; + + ncr_get_xfer_info ( np, tp, &factor, &offset, &width); + + printk("Current factor %d offset %d width %d\n", + factor, offset, width); + } + if (tp->ppr_negotiation == 2) + ncr_setsyncwide (np, cp, 0, 0xe0, 0, 0); + else if (tp->ppr_negotiation == 1) { + + /* First ppr command has received a M REJECT. + * Do not change the existing wide/sync parameter + * values (asyn/narrow if this as the first nego; + * may be different if target initiates nego.). + */ + tp->ppr_negotiation = 0; + } + else + { + tp->ppr_negotiation = 0; + ncr_setwide (np, cp, 0, 0); + } + break; }; np->msgin [0] = M_NOOP; np->msgout[0] = M_NOOP; @@ -10410,6 +11594,9 @@ ** ncr chip handler for MESSAGE REJECT received for ** a WIDE or SYNCHRONOUS negotiation. ** +** clear the PPR negotiation flag, all future nego. +** will be SDTR and WDTR +** **========================================================== ** ** Read comments above. @@ -10451,6 +11638,7 @@ case SIR_DUMMY_INTERRUPT: goto out; #endif + /* ** The C code is currently trying to recover from something. ** Typically, user want to abort some command. @@ -10529,8 +11717,11 @@ np->msgout[0] = M_NOOP; /* Should we really care of that */ if (np->lastmsg == M_PARITY || np->lastmsg == M_ID_ERROR) { - if (cp) + if (cp) { cp->xerr_status &= ~XE_PARITY_ERR; + if (!cp->xerr_status) + OUTOFFB (HF_PRT, HF_EXT_ERR); + } } goto out; /* @@ -10558,8 +11749,10 @@ ** It is a data overrun condition. */ case SIR_SWIDE_OVERRUN: - if (cp) - cp->xerr_status |= XE_EXTRA_DATA; + if (cp) { + OUTONB (HF_PRT, HF_EXT_ERR); + cp->xerr_status |= XE_SWIDE_OVRUN; + } goto out; /* ** We have been ODD at the end of a DATA OUT @@ -10567,8 +11760,10 @@ ** It is a data underrun condition. */ case SIR_SODL_UNDERRUN: - if (cp) - cp->xerr_status |= XE_EXTRA_DATA; + if (cp) { + OUTONB (HF_PRT, HF_EXT_ERR); + cp->xerr_status |= XE_SODL_UNRUN; + } goto out; /* ** We received a message. @@ -10597,6 +11792,9 @@ case M_X_WIDE_REQ: ncr_wide_nego(np, tp, cp); return; + case M_X_PPR_REQ: + ncr_ppr_nego(np, tp, cp); + return; default: goto out_reject; } @@ -10910,6 +12108,11 @@ offsetof(struct tcb , sval )) &3) == 0); assert (( (offsetof(struct ncr_reg, nc_scntl3) ^ offsetof(struct tcb , wval )) &3) == 0); + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)){ + assert (( (offsetof(struct ncr_reg, nc_scntl4) ^ + offsetof(struct tcb , uval )) &3) == 0); + } } /*------------------------------------------------------------------------ @@ -11446,7 +12649,8 @@ ** do not have a clock doubler and so are provided with a ** 80 MHz clock. All other fast20 boards incorporate a doubler ** and so should be delivered with a 40 MHz clock. -** The recent fast40 chips (895/896/895A) use a 40 Mhz base clock +** The recent fast40 chips (895/896/895A) and the +** fast80 chip (C1010) use a 40 Mhz base clock ** and provide a clock quadrupler (160 Mhz). The code below ** tries to deal as cleverly as possible with all this stuff. ** @@ -11467,14 +12671,20 @@ printk ("%s: enabling clock multiplier\n", ncr_name(np)); OUTB(nc_stest1, DBLEN); /* Enable clock multiplier */ - if (np->multiplier > 2) { /* Poll bit 5 of stest4 for quadrupler */ - int i = 20; + + if ( (np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66) && + (np->multiplier > 2)) { + int i = 20; /* Poll bit 5 of stest4 for quadrupler */ while (!(INB(nc_stest4) & LCKFRQ) && --i > 0) UDELAY (20); if (!i) - printk("%s: the chip cannot lock the frequency\n", ncr_name(np)); - } else /* Wait 20 micro-seconds for doubler */ - UDELAY (20); + printk("%s: the chip cannot lock the frequency\n", + ncr_name(np)); + + } else /* Wait 120 micro-seconds for multiplier*/ + UDELAY (120); + OUTB(nc_stest3, HSC); /* Halt the scsi clock */ OUTB(nc_scntl3, scntl3); OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier */ @@ -11489,6 +12699,7 @@ { unsigned int ms = 0; unsigned int f; + int count; /* * Measure GEN timer delay in order @@ -11505,15 +12716,21 @@ * performed trust the higher delay * (lower frequency returned). */ - OUTW (nc_sien , 0); /* mask all scsi interrupts */ + OUTW (nc_sien , 0x0);/* mask all scsi interrupts */ + /* enable general purpose timer */ (void) INW (nc_sist); /* clear pending scsi interrupt */ OUTB (nc_dien , 0); /* mask all dma interrupts */ (void) INW (nc_sist); /* another one, just to be sure :) */ OUTB (nc_scntl3, 4); /* set pre-scaler to divide by 3 */ OUTB (nc_stime1, 0); /* disable general purpose timer */ OUTB (nc_stime1, gen); /* set to nominal delay of 1<device_id == PCI_DEVICE_ID_LSI_53C1010) + f = ms ? ((1 << gen) * 2866 ) / ms : 0; + else +#endif f = ms ? ((1 << gen) * 4340) / ms : 0; if (bootverbose >= 2) @@ -11568,11 +12792,19 @@ } /* + ** If multiplier not found but a C1010, assume a mult of 4. ** If multiplier not found or scntl3 not 7,5,3, ** reset chip and get frequency from general purpose timer. ** Otherwise trust scntl3 BIOS setting. */ - if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) { + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) { + f1=40000; + np->multiplier = mult; + if (bootverbose >= 2) + printk ("%s: clock multiplier assumed\n", ncr_name(np)); + } + else if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) { OUTB (nc_stest1, 0); /* make sure doubler is OFF */ f1 = ncr_getfreq (np); @@ -11587,8 +12819,14 @@ ** to make sure our frequency calculation algorithm ** is not too biased. */ - np->pciclock_min = (33000*55+80-1)/80; - np->pciclock_max = (33000*55)/40; + if (np->features & FE_66MHZ) { + np->pciclock_min = (66000*55+80-1)/80; + np->pciclock_max = (66000*55)/40; + } + else { + np->pciclock_min = (33000*55+80-1)/80; + np->pciclock_max = (33000*55)/40; + } if (f1 == 40000 && mult > 1) { if (bootverbose >= 2) @@ -11728,7 +12966,8 @@ #ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT char *cur = str; char *pc, *pv; - int i, val, c; + unsigned long val; + int i, c; int xi = 0; while (cur != NULL && (pc = strchr(cur, ':')) != NULL) { @@ -12165,7 +13404,7 @@ static int __init sym53c8xx_pci_init(Scsi_Host_Template *tpnt, pcidev_t pdev, ncr_device *device) { - u_short vendor_id, device_id, command; + u_short vendor_id, device_id, command, status_reg; u_char cache_line_size, latency_timer; u_char suggested_cache_line_size = 0; u_char pci_fix_up = driver_setup.pci_fix_up; @@ -12205,6 +13444,7 @@ pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line_size); pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_timer); + pci_read_config_word(pdev, PCI_STATUS, &status_reg); #ifdef SCSI_NCR_PQS_PDS_SUPPORT /* @@ -12402,14 +13642,51 @@ if (driver_setup.special_features & 4) chip->features &= ~FE_NOPM; } + + /* + ** Work around for errant bit in 895A. The 66Mhz + ** capable bit is set erroneously. Clear this bit. + ** (Item 1 DEL 533) + ** + ** Make sure Config space and Features agree. + ** + ** Recall: writes are not normal to status register - + ** write a 1 to clear and a 0 to leave unchanged. + ** Can only reset bits. + */ + if (chip->features & FE_66MHZ) { + if (!(status_reg & PCI_STATUS_66MHZ)) + chip->features &= ~FE_66MHZ; + } + else { + if (status_reg & PCI_STATUS_66MHZ) { + status_reg = PCI_STATUS_66MHZ; + pci_write_config_word(pdev, PCI_STATUS, status_reg); + pci_read_config_word(pdev, PCI_STATUS, &status_reg); + } + } + + if (driver_setup.ultra_scsi < 3 && (chip->features & FE_ULTRA3)) { + chip->features |= FE_ULTRA2; + chip->features &= ~FE_ULTRA3; + } if (driver_setup.ultra_scsi < 2 && (chip->features & FE_ULTRA2)) { chip->features |= FE_ULTRA; chip->features &= ~FE_ULTRA2; } if (driver_setup.ultra_scsi < 1) chip->features &= ~FE_ULTRA; + if (!driver_setup.max_wide) chip->features &= ~FE_WIDE; + + /* + * C1010 Ultra3 support requires 16 bit data transfers. + */ + if (!driver_setup.max_wide && (chip->features & FE_ULTRA3)) { + chip->features |= FE_ULTRA2; + chip->features |= ~FE_ULTRA3; + } /* ** Some features are required to be enabled in order to diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/sym53c8xx_comm.h linux/drivers/scsi/sym53c8xx_comm.h --- v2.4.0-test1/linux/drivers/scsi/sym53c8xx_comm.h Wed Apr 26 16:34:08 2000 +++ linux/drivers/scsi/sym53c8xx_comm.h Mon Jun 19 17:59:42 2000 @@ -155,6 +155,7 @@ #define DEBUG_NEGO (0x0200) #define DEBUG_TAGS (0x0400) #define DEBUG_SCATTER (0x0800) +#define DEBUG_IC (0x1000) /* ** Enable/Disable debug messages. @@ -2414,6 +2415,11 @@ /* ** Check if the chip is supported */ + if ((device_id == PCI_DEVICE_ID_LSI_53C1010) || + (device_id == PCI_DEVICE_ID_LSI_53C1010_66)){ + printk(NAME53C8XX ": not initializing, device not supported\n"); + return -1; + } chip = 0; for (i = 0; i < sizeof(ncr_chip_table)/sizeof(ncr_chip_table[0]); i++) { if (device_id != ncr_chip_table[i].device_id) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/sym53c8xx_defs.h linux/drivers/scsi/sym53c8xx_defs.h --- v2.4.0-test1/linux/drivers/scsi/sym53c8xx_defs.h Wed Apr 26 16:34:08 2000 +++ linux/drivers/scsi/sym53c8xx_defs.h Fri Jun 23 21:31:56 2000 @@ -102,6 +102,14 @@ # define SCSI_NCR_USER_INFO_SUPPORT #endif +/* +** To disable integrity checking, do not define the +** following option. +*/ +#ifdef CONFIG_SCSI_NCR53C8XX_INTEGRITY_CHECK +# define SCSI_NCR_ENABLE_INTEGRITY_CHECK +#endif + /*========================================================== ** ** nvram settings - #define SCSI_NCR_NVRAM_SUPPORT to enable @@ -121,10 +129,9 @@ */ /* - * For Ultra2 SCSI support option, use special features and allow 40Mhz - * synchronous data transfers. + * For Ultra2 and Ultra3 SCSI support option, use special features. * - * Value 5 (default) means: + * Value (default) means: * bit 0 : all features enabled, except: * bit 1 : PCI Write And Invalidate. * bit 2 : Data Phase Mismatch handling from SCRIPTS. @@ -133,8 +140,20 @@ * enabled by the driver. */ #define SCSI_NCR_SETUP_SPECIAL_FEATURES (3) -#define SCSI_NCR_SETUP_ULTRA_SCSI (2) -#define SCSI_NCR_MAX_SYNC (40) + +/* + * For Ultra2 and Ultra3 SCSI support allow 80Mhz synchronous data transfers. + * Value means: + * 0 - Ultra speeds disabled + * 1 - Ultra enabled (Maximum 20Mtrans/sec) + * 2 - Ultra2 enabled (Maximum 40Mtrans/sec) + * 3 - Ultra3 enabled (Maximum 80Mtrans/sec) + * + * Use boot options sym53c8xx=ultra:3 to enable Ultra3 support. + */ + +#define SCSI_NCR_SETUP_ULTRA_SCSI (3) +#define SCSI_NCR_MAX_SYNC (80) /* * Allow tags from 2 to 256, default 8 @@ -190,7 +209,7 @@ /* * Sync transfer frequency at startup. - * Allow from 5Mhz to 40Mhz default 20 Mhz. + * Allow from 5Mhz to 80Mhz default 20 Mhz. */ #ifndef CONFIG_SCSI_NCR53C8XX_SYNC #define CONFIG_SCSI_NCR53C8XX_SYNC (20) @@ -207,8 +226,10 @@ #define SCSI_NCR_SETUP_DEFAULT_SYNC (250/(CONFIG_SCSI_NCR53C8XX_SYNC)) #elif CONFIG_SCSI_NCR53C8XX_SYNC <= 33 #define SCSI_NCR_SETUP_DEFAULT_SYNC (11) -#else +#elif CONFIG_SCSI_NCR53C8XX_SYNC <= 40 #define SCSI_NCR_SETUP_DEFAULT_SYNC (10) +#else +#define SCSI_NCR_SETUP_DEFAULT_SYNC (9) #endif /* @@ -469,6 +490,15 @@ #define PCI_DEVICE_ID_NCR_53C1510D 0xa #endif +#ifndef PCI_DEVICE_ID_LSI_53C1010 +#define PCI_DEVICE_ID_LSI_53C1010 0x20 +#endif + +#ifndef PCI_DEVICE_ID_LSI_53C1010_66 +#define PCI_DEVICE_ID_LSI_53C1010_66 0x21 +#endif + + /* ** NCR53C8XX devices features table. */ @@ -502,6 +532,8 @@ #define FE_NOPM (1<<19) /* Scripts handles phase mismatch */ #define FE_LEDC (1<<20) /* Hardware control of LED */ #define FE_DIFF (1<<21) /* Support Differential SCSI */ +#define FE_ULTRA3 (1<<22) /* Ultra-3 80Mtrans/sec */ +#define FE_66MHZ (1<<23) /* 66MHz PCI Support */ #define FE_CACHE_SET (FE_ERL|FE_CLSE|FE_WRIE|FE_ERMP) #define FE_SCSI_SET (FE_WIDE|FE_ULTRA|FE_ULTRA2|FE_DBLR|FE_QUAD|F_CLK80) @@ -586,7 +618,15 @@ , \ {PCI_DEVICE_ID_NCR_53C1510D, 0xff, "1510D", 7, 31, 7, \ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \ - FE_RAM|FE_IO256}\ + FE_RAM|FE_IO256} \ + , \ + {PCI_DEVICE_ID_LSI_53C1010, 0xff, "1010", 6, 62, 7, \ + FE_WIDE|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \ + FE_RAM|FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC|FE_ULTRA3} \ + , \ + {PCI_DEVICE_ID_LSI_53C1010_66, 0xff, "1010_66", 6, 62, 7, \ + FE_WIDE|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \ + FE_RAM|FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC|FE_ULTRA3|FE_66MHZ} \ } /* @@ -605,7 +645,9 @@ PCI_DEVICE_ID_NCR_53C895, \ PCI_DEVICE_ID_NCR_53C896, \ PCI_DEVICE_ID_NCR_53C895A, \ - PCI_DEVICE_ID_NCR_53C1510D \ + PCI_DEVICE_ID_NCR_53C1510D, \ + PCI_DEVICE_ID_LSI_53C1010, \ + PCI_DEVICE_ID_LSI_53C1010_66 \ } /* @@ -640,7 +682,7 @@ u_char recovery; u_char host_id; u_short iarb; - u_int excludes[SCSI_NCR_MAX_EXCLUDES]; + u_long excludes[SCSI_NCR_MAX_EXCLUDES]; char tag_ctrl[100]; }; @@ -662,7 +704,7 @@ 1, \ SCSI_NCR_SETUP_DEFAULT_TAGS, \ SCSI_NCR_SETUP_DEFAULT_SYNC, \ - 0x00, \ + 0x0200, \ 7, \ SCSI_NCR_SETUP_LED_PIN, \ 1, \ @@ -864,12 +906,14 @@ /*03*/ u_char nc_scntl3; /* cnf system clock dependent */ #define EWS 0x08 /* cmd: enable wide scsi [W]*/ #define ULTRA 0x80 /* cmd: ULTRA enable */ + /* bits 0-2, 7 rsvd for C1010 */ /*04*/ u_char nc_scid; /* cnf host adapter scsi address */ #define RRE 0x40 /* r/w:e enable response to resel. */ #define SRE 0x20 /* r/w:e enable response to select */ /*05*/ u_char nc_sxfer; /* ### Sync speed and count */ + /* bits 6-7 rsvd for C1010 */ /*06*/ u_char nc_sdid; /* ### Destination-ID */ @@ -944,12 +988,14 @@ /*1a*/ u_char nc_ctest2; #define CSIGP 0x40 + /* bits 0-2,7 rsvd for C1010 */ /*1b*/ u_char nc_ctest3; #define FLF 0x08 /* cmd: flush dma fifo */ #define CLF 0x04 /* cmd: clear dma fifo */ #define FM 0x02 /* mod: fetch pin mode */ #define WRIE 0x01 /* mod: write and invalidate enable */ + /* bits 4-7 rsvd for C1010 */ /*1c*/ u_int32 nc_temp; /* ### Temporary stack */ @@ -960,6 +1006,7 @@ /*22*/ u_char nc_ctest5; #define DFS 0x20 /* mod: dma fifo size */ + /* bits 0-1, 3-7 rsvd for C1010 */ /*23*/ u_char nc_ctest6; /*24*/ u_int32 nc_dbc; /* ### Byte count and command */ @@ -991,6 +1038,7 @@ #define STD 0x04 /* cmd: start dma mode */ #define IRQD 0x02 /* mod: irq disable */ #define NOCOM 0x01 /* cmd: protect sfbr while reselect */ + /* bits 0-1 rsvd for C1010 */ /*3c*/ u_int32 nc_adder; @@ -1041,6 +1089,7 @@ #define SMODE_SE 0x80 /* Single Ended */ #define SMODE_LVD 0xc0 /* Low Voltage Differential */ #define LCKFRQ 0x20 /* Frequency Lock (895/6 only) */ + /* bits 0-5 rsvd for C1010 */ /*53*/ u_char nc_53_; /*54*/ u_short nc_sodl; /* Lowlevel: data out to scsi data */ @@ -1054,6 +1103,7 @@ /*57*/ u_char nc_ccntl1; /* Chip Control 1 (896) */ #define ZMOD 0x80 /* High Impedance Mode */ + #define DIC 0x10 /* Disable Internal Cycles */ #define DDAC 0x08 /* Disable Dual Address Cycle */ #define XTIMOD 0x04 /* 64-bit Table Ind. Indexing Mode */ #define EXTIBMV 0x02 /* Enable 64-bit Table Ind. BMOV */ @@ -1075,7 +1125,16 @@ /*b0*/ u_int32 nc_sbms; /* Static Block Move Selector */ /*b4*/ u_int32 nc_dbms; /* Dynamic Block Move Selector */ /*b8*/ u_int32 nc_dnad64; /* DMA Next Address 64 */ -/*bc*/ u_int32 nc_bc_; +/*bc*/ u_short nc_scntl4; /* C1010 only */ + #define U3EN 0x80 /* Enable Ultra 3 */ + #define AIPEN 0x40 /* Allow check upper byte lanes */ + #define XCLKH_DT 0x08 /* Extra clock of data hold on DT + transfer edge */ + #define XCLKH_ST 0x04 /* Extra clock of data hold on ST + transfer edge */ + +/*be*/ u_char nc_aipcntl0; /* Epat Control 1 C1010 only */ +/*bf*/ u_char nc_aipcntl1; /* AIP Control C1010_66 Only */ /*c0*/ u_int32 nc_pmjad1; /* Phase Mismatch Jump Address 1 */ /*c4*/ u_int32 nc_pmjad2; /* Phase Mismatch Jump Address 2 */ @@ -1095,6 +1154,17 @@ /*d7*/ u_char nc_ia3; /*d8*/ u_int32 nc_sbc; /* SCSI Byte Count (3 bytes only) */ /*dc*/ u_int32 nc_csbc; /* Cumulative SCSI Byte Count */ + + /* Following for C1010 only */ +/*e0*/ u_short nc_crcpad; /* CRC Value */ +/*e2*/ u_char nc_crccntl0; /* CRC control register */ + #define SNDCRC 0x10 /* Send CRC Request */ +/*e3*/ u_char nc_crccntl1; /* CRC control register */ +/*e4*/ u_int32 nc_crcdata; /* CRC data register */ +/*e8*/ u_int32 nc_e8_; /* rsvd */ +/*ec*/ u_int32 nc_ec_; /* rsvd */ +/*f0*/ u_short nc_dfbc; /* DMA FIFO byte count */ + }; /*----------------------------------------------------------- @@ -1113,6 +1183,8 @@ ** ** SCSI phases ** +** DT phases illegal for ncr driver. +** **----------------------------------------------------------- */ @@ -1120,11 +1192,14 @@ #define SCR_DATA_IN 0x01000000 #define SCR_COMMAND 0x02000000 #define SCR_STATUS 0x03000000 -#define SCR_ILG_OUT 0x04000000 -#define SCR_ILG_IN 0x05000000 +#define SCR_DT_DATA_OUT 0x04000000 +#define SCR_DT_DATA_IN 0x05000000 #define SCR_MSG_OUT 0x06000000 #define SCR_MSG_IN 0x07000000 +#define SCR_ILG_OUT 0x04000000 +#define SCR_ILG_IN 0x05000000 + /*----------------------------------------------------------- ** ** Data transfer via SCSI. @@ -1179,7 +1254,7 @@ #define SCR_SEL_TBL_ATN 0x43000000 struct scr_tblsel { - u_char sel_0; + u_char sel_scntl4; u_char sel_sxfer; u_char sel_id; u_char sel_scntl3; @@ -1463,6 +1538,7 @@ #define M_X_MODIFY_DP (0x00) #define M_X_SYNC_REQ (0x01) #define M_X_WIDE_REQ (0x03) +#define M_X_PPR_REQ (0x04) /* ** Status diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/tmscsim.c linux/drivers/scsi/tmscsim.c --- v2.4.0-test1/linux/drivers/scsi/tmscsim.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/scsi/tmscsim.c Mon Jun 19 13:42:41 2000 @@ -319,7 +319,7 @@ # define PCI_PRESENT pci_present () # define PCI_SET_MASTER pci_set_master (pdev) # define PCI_FIND_DEVICE(vend, id) (pdev = pci_find_device (vend, id, pdev)) -# define PCI_GET_IO_AND_IRQ io_port = pdev->resource[0].start; irq = pdev->irq +# define PCI_GET_IO_AND_IRQ io_port = pci_resource_start(pdev, 0); irq = pdev->irq; #else # include # define PDEV pbus, pdevfn @@ -2002,6 +2002,8 @@ if ( PCI_PRESENT ) while (PCI_FIND_DEVICE (PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD53C974)) { + if (pci_enable_device(pdev)) + continue; DC390_LOCK_IO; /* Remove this when going to new eh */ PCI_GET_IO_AND_IRQ; DEBUG0(printk(KERN_INFO "DC390(%i): IO_PORT=%04x,IRQ=%x\n", dc390_adapterCnt, (UINT) io_port, irq);) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sgi/char/graphics.c linux/drivers/sgi/char/graphics.c --- v2.4.0-test1/linux/drivers/sgi/char/graphics.c Sat Feb 26 22:31:48 2000 +++ linux/drivers/sgi/char/graphics.c Tue Jun 20 07:52:36 2000 @@ -150,9 +150,11 @@ * sgi_graphics_mmap */ disable_gconsole (); + down(¤t->mm->mmap_sem); r = do_mmap (file, (unsigned long)vaddr, cards[board].g_regs_size, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE, 0); + up(¤t->mm->mmap_sem); if (r) return r; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sgi/char/shmiq.c linux/drivers/sgi/char/shmiq.c --- v2.4.0-test1/linux/drivers/sgi/char/shmiq.c Sat Feb 26 22:31:49 2000 +++ linux/drivers/sgi/char/shmiq.c Wed Jun 21 22:31:02 2000 @@ -118,8 +118,7 @@ e->data.device, e->data.which, e->data.type, e->data.flags); s->tail = tail_next; shmiqs [device].tail = tail_next; - if (shmiqs [device].fasync) - kill_fasync (shmiqs [device].fasync, SIGIO, POLL_IN); + kill_fasync (&shmiqs [device].fasync, SIGIO, POLL_IN); wake_up_interruptible (&shmiqs [device].proc_list); } @@ -279,8 +278,10 @@ return -EINVAL; } s = req.arg * sizeof (struct shmqevent) + sizeof (struct sharedMemoryInputQueue); - v = sys_munmap (vaddr, s); + down(¤t->mm->mmap_sem); + do_munmap (current->mm, vaddr, s); do_mmap (filp, vaddr, s, PROT_READ | PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 0); + up(¤t->mm->mmap_sem); shmiqs [minor].events = req.arg; shmiqs [minor].mapped = 1; return 0; @@ -445,11 +446,11 @@ { printk ("SHMIQ setup\n"); devfs_register_chrdev(SHMIQ_MAJOR, "shmiq", &shmiq_fops); - devfs_register (NULL, "shmiq", 0, DEVFS_FL_DEFAULT, - SHMIQ_MAJOR, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + devfs_register (NULL, "shmiq", DEVFS_FL_DEFAULT, + SHMIQ_MAJOR, 0, S_IFCHR | S_IRUSR | S_IWUSR, &shmiq_fops, NULL); devfs_register_series (NULL, "qcntl%u", 2, DEVFS_FL_DEFAULT, SHMIQ_MAJOR, 1, - S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR, &shmiq_fops, NULL); } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/724hwmcode.h linux/drivers/sound/724hwmcode.h --- v2.4.0-test1/linux/drivers/sound/724hwmcode.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/724hwmcode.h Tue Jun 20 07:52:36 2000 @@ -0,0 +1,1575 @@ +//============================================================================= +// Copyright (c) 1997-1999 Yamaha Corporation. All Rights Reserved. +// +// Title: +// hwmcode.c +// Desc: +// micro-code for CTRL & DSP +//============================================================================= +#ifndef _HWMCODE_ +#define _HWMCODE_ + +static unsigned long int DspInst[] = { + 0x00000081, 0x000001a4, 0x0000000a, 0x0000002f, + 0x00080253, 0x01800317, 0x0000407b, 0x0000843f, + 0x0001483c, 0x0001943c, 0x0005d83c, 0x00001c3c, + 0x0000c07b, 0x00050c3f, 0x0121503c, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000 +}; + +static unsigned long int CntrlInst[] = { + 0x000007, 0x240007, 0x0C0007, 0x1C0007, + 0x060007, 0x700002, 0x000020, 0x030040, + 0x007104, 0x004286, 0x030040, 0x000F0D, + 0x000810, 0x20043A, 0x000282, 0x00020D, + 0x000810, 0x20043A, 0x001282, 0x200E82, + 0x001A82, 0x032D0D, 0x000810, 0x10043A, + 0x02D38D, 0x000810, 0x18043A, 0x00010D, + 0x020015, 0x0000FD, 0x000020, 0x038860, + 0x039060, 0x038060, 0x038040, 0x038040, + 0x038040, 0x018040, 0x000A7D, 0x038040, + 0x038040, 0x018040, 0x200402, 0x000882, + 0x08001A, 0x000904, 0x015986, 0x000007, + 0x260007, 0x000007, 0x000007, 0x018A06, + 0x000007, 0x030C8D, 0x000810, 0x18043A, + 0x260007, 0x00087D, 0x018042, 0x00160A, + 0x04A206, 0x000007, 0x00218D, 0x000810, + 0x08043A, 0x21C206, 0x000007, 0x0007FD, + 0x018042, 0x08000A, 0x000904, 0x029386, + 0x000195, 0x090D04, 0x000007, 0x000820, + 0x0000F5, 0x000B7D, 0x01F060, 0x0000FD, + 0x032206, 0x018040, 0x000A7D, 0x038042, + 0x13804A, 0x18000A, 0x001820, 0x059060, + 0x058860, 0x018040, 0x0000FD, 0x018042, + 0x70000A, 0x000115, 0x071144, 0x032386, + 0x030000, 0x007020, 0x034A06, 0x018040, + 0x00348D, 0x000810, 0x08043A, 0x21EA06, + 0x000007, 0x02D38D, 0x000810, 0x18043A, + 0x018206, 0x000007, 0x240007, 0x000F8D, + 0x000810, 0x00163A, 0x002402, 0x005C02, + 0x0028FD, 0x000020, 0x018040, 0x08000D, + 0x000815, 0x510984, 0x000007, 0x00004D, + 0x000E5D, 0x000E02, 0x00418D, 0x000810, + 0x08043A, 0x2C8A06, 0x000007, 0x00008D, + 0x000924, 0x000F02, 0x00458D, 0x000810, + 0x08043A, 0x2C8A06, 0x000007, 0x00387D, + 0x018042, 0x08000A, 0x001015, 0x010984, + 0x018386, 0x000007, 0x01AA06, 0x000007, + 0x0008FD, 0x018042, 0x18000A, 0x001904, + 0x218086, 0x280007, 0x001810, 0x28043A, + 0x280C02, 0x00000D, 0x000810, 0x28143A, + 0x08808D, 0x000820, 0x0002FD, 0x018040, + 0x200007, 0x00020D, 0x189904, 0x000007, + 0x00402D, 0x0000BD, 0x0002FD, 0x018042, + 0x08000A, 0x000904, 0x055A86, 0x000007, + 0x000100, 0x000A20, 0x00047D, 0x018040, + 0x018042, 0x20000A, 0x003015, 0x012144, + 0x034986, 0x000007, 0x002104, 0x034986, + 0x000007, 0x000F8D, 0x000810, 0x280C3A, + 0x023944, 0x06C986, 0x000007, 0x001810, + 0x28043A, 0x08810D, 0x000820, 0x0002FD, + 0x018040, 0x200007, 0x002810, 0x78003A, + 0x00688D, 0x000810, 0x08043A, 0x288A06, + 0x000007, 0x00400D, 0x001015, 0x189904, + 0x292904, 0x393904, 0x000007, 0x060206, + 0x000007, 0x0004F5, 0x00007D, 0x000020, + 0x00008D, 0x010860, 0x018040, 0x00047D, + 0x038042, 0x21804A, 0x18000A, 0x021944, + 0x215886, 0x000007, 0x004075, 0x71F104, + 0x000007, 0x010042, 0x28000A, 0x002904, + 0x212086, 0x000007, 0x003C0D, 0x30A904, + 0x000007, 0x00077D, 0x018042, 0x08000A, + 0x000904, 0x07DA86, 0x00057D, 0x002820, + 0x03B060, 0x07F206, 0x018040, 0x003020, + 0x03A860, 0x018040, 0x0002FD, 0x018042, + 0x08000A, 0x000904, 0x07FA86, 0x000007, + 0x00057D, 0x018042, 0x28040A, 0x000E8D, + 0x000810, 0x280C3A, 0x00000D, 0x000810, + 0x28143A, 0x09000D, 0x000820, 0x0002FD, + 0x018040, 0x200007, 0x003DFD, 0x000020, + 0x018040, 0x00107D, 0x008D8D, 0x000810, + 0x08043A, 0x288A06, 0x000007, 0x000815, + 0x08001A, 0x010984, 0x095186, 0x00137D, + 0x200500, 0x280F20, 0x338F60, 0x3B8F60, + 0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60, + 0x038A60, 0x018040, 0x007FBD, 0x383DC4, + 0x000007, 0x001A7D, 0x001375, 0x018042, + 0x09004A, 0x10000A, 0x0B8D04, 0x139504, + 0x000007, 0x000820, 0x019060, 0x001104, + 0x212086, 0x010040, 0x0017FD, 0x018042, + 0x08000A, 0x000904, 0x212286, 0x000007, + 0x00197D, 0x038042, 0x09804A, 0x10000A, + 0x000924, 0x001664, 0x0011FD, 0x038042, + 0x2B804A, 0x19804A, 0x00008D, 0x218944, + 0x000007, 0x002244, 0x0AE186, 0x000007, + 0x001A64, 0x002A24, 0x00197D, 0x080102, + 0x100122, 0x000820, 0x039060, 0x018040, + 0x003DFD, 0x00008D, 0x000820, 0x018040, + 0x001375, 0x001A7D, 0x010042, 0x09804A, + 0x10000A, 0x00021D, 0x0189E4, 0x2992E4, + 0x309144, 0x000007, 0x00060D, 0x000A15, + 0x000C1D, 0x001025, 0x00A9E4, 0x012BE4, + 0x000464, 0x01B3E4, 0x0232E4, 0x000464, + 0x000464, 0x000464, 0x000464, 0x00040D, + 0x08B1C4, 0x000007, 0x000820, 0x000BF5, + 0x030040, 0x00197D, 0x038042, 0x09804A, + 0x000A24, 0x08000A, 0x080E64, 0x000007, + 0x100122, 0x000820, 0x031060, 0x010040, + 0x0064AC, 0x00027D, 0x000020, 0x018040, + 0x00107D, 0x018042, 0x0011FD, 0x3B804A, + 0x09804A, 0x20000A, 0x000095, 0x1A1144, + 0x00A144, 0x0D2086, 0x00040D, 0x00B984, + 0x0D2186, 0x0018FD, 0x018042, 0x0010FD, + 0x09804A, 0x28000A, 0x000095, 0x010924, + 0x002A64, 0x0D1186, 0x000007, 0x002904, + 0x0D2286, 0x000007, 0x0D2A06, 0x080002, + 0x00008D, 0x00387D, 0x000820, 0x018040, + 0x00127D, 0x018042, 0x10000A, 0x003904, + 0x0DD186, 0x00080D, 0x7FFFB5, 0x00B984, + 0x0DA186, 0x000025, 0x0E7A06, 0x00002D, + 0x000015, 0x00082D, 0x02C78D, 0x000820, + 0x0EC206, 0x00000D, 0x7F8035, 0x00B984, + 0x0E7186, 0x400025, 0x00008D, 0x110944, + 0x000007, 0x00018D, 0x109504, 0x000007, + 0x009164, 0x000424, 0x000424, 0x000424, + 0x100102, 0x280002, 0x02C68D, 0x000820, + 0x0EC206, 0x00018D, 0x00042D, 0x00008D, + 0x109504, 0x000007, 0x00020D, 0x109184, + 0x000007, 0x02C70D, 0x000820, 0x00008D, + 0x0038FD, 0x018040, 0x003BFD, 0x001020, + 0x03A860, 0x000815, 0x313184, 0x212184, + 0x000007, 0x03B060, 0x03A060, 0x018040, + 0x0022FD, 0x000095, 0x010924, 0x000424, + 0x000424, 0x001264, 0x100102, 0x000820, + 0x039060, 0x018040, 0x001924, 0x00FB8D, + 0x00397D, 0x000820, 0x058040, 0x038042, + 0x09844A, 0x000606, 0x08040A, 0x000424, + 0x000424, 0x00117D, 0x018042, 0x08000A, + 0x000A24, 0x280502, 0x280C02, 0x09800D, + 0x000820, 0x0002FD, 0x018040, 0x200007, + 0x0022FD, 0x018042, 0x08000A, 0x000095, + 0x280DC4, 0x011924, 0x00197D, 0x018042, + 0x0011FD, 0x09804A, 0x10000A, 0x0000B5, + 0x113144, 0x0A8D04, 0x000007, 0x080A44, + 0x129504, 0x000007, 0x0023FD, 0x001020, + 0x038040, 0x101244, 0x000007, 0x000820, + 0x039060, 0x018040, 0x0002FD, 0x018042, + 0x08000A, 0x000904, 0x10FA86, 0x000007, + 0x003BFD, 0x000100, 0x000A10, 0x0B807A, + 0x13804A, 0x090984, 0x000007, 0x000095, + 0x013D04, 0x118086, 0x10000A, 0x100002, + 0x090984, 0x000007, 0x038042, 0x11804A, + 0x090D04, 0x000007, 0x10000A, 0x090D84, + 0x000007, 0x00257D, 0x000820, 0x018040, + 0x00010D, 0x000810, 0x28143A, 0x00127D, + 0x018042, 0x20000A, 0x00197D, 0x018042, + 0x00117D, 0x31804A, 0x10000A, 0x003124, + 0x01280D, 0x00397D, 0x000820, 0x058040, + 0x038042, 0x09844A, 0x000606, 0x08040A, + 0x300102, 0x003124, 0x000424, 0x000424, + 0x001224, 0x280502, 0x001A4C, 0x130186, + 0x700002, 0x00002D, 0x030000, 0x00387D, + 0x018042, 0x10000A, 0x132A06, 0x002124, + 0x0000AD, 0x100002, 0x00010D, 0x000924, + 0x006B24, 0x01368D, 0x00397D, 0x000820, + 0x058040, 0x038042, 0x09844A, 0x000606, + 0x08040A, 0x003264, 0x00008D, 0x000A24, + 0x001020, 0x00227D, 0x018040, 0x013C0D, + 0x000810, 0x08043A, 0x29D206, 0x000007, + 0x002820, 0x00207D, 0x018040, 0x00117D, + 0x038042, 0x13804A, 0x33800A, 0x00387D, + 0x018042, 0x08000A, 0x000904, 0x163A86, + 0x000007, 0x00008D, 0x030964, 0x01478D, + 0x00397D, 0x000820, 0x058040, 0x038042, + 0x09844A, 0x000606, 0x08040A, 0x380102, + 0x000424, 0x000424, 0x001224, 0x0002FD, + 0x018042, 0x08000A, 0x000904, 0x14A286, + 0x000007, 0x280502, 0x001A4C, 0x163986, + 0x000007, 0x032164, 0x00632C, 0x003DFD, + 0x018042, 0x08000A, 0x000095, 0x090904, + 0x000007, 0x000820, 0x001A4C, 0x156186, + 0x018040, 0x030000, 0x157A06, 0x002124, + 0x00010D, 0x000924, 0x006B24, 0x015B8D, + 0x00397D, 0x000820, 0x058040, 0x038042, + 0x09844A, 0x000606, 0x08040A, 0x003A64, + 0x000095, 0x001224, 0x0002FD, 0x018042, + 0x08000A, 0x000904, 0x15DA86, 0x000007, + 0x01628D, 0x000810, 0x08043A, 0x29D206, + 0x000007, 0x14D206, 0x000007, 0x007020, + 0x08010A, 0x10012A, 0x0020FD, 0x038860, + 0x039060, 0x018040, 0x00227D, 0x018042, + 0x003DFD, 0x08000A, 0x31844A, 0x000904, + 0x16D886, 0x18008B, 0x00008D, 0x189904, + 0x00312C, 0x17AA06, 0x000007, 0x00324C, + 0x173386, 0x000007, 0x001904, 0x173086, + 0x000007, 0x000095, 0x199144, 0x00222C, + 0x003124, 0x00636C, 0x000E3D, 0x001375, + 0x000BFD, 0x010042, 0x09804A, 0x10000A, + 0x038AEC, 0x0393EC, 0x00224C, 0x17A986, + 0x000007, 0x00008D, 0x189904, 0x00226C, + 0x00322C, 0x30050A, 0x301DAB, 0x002083, + 0x0018FD, 0x018042, 0x08000A, 0x018924, + 0x300502, 0x001083, 0x001875, 0x010042, + 0x10000A, 0x00008D, 0x010924, 0x001375, + 0x330542, 0x330CCB, 0x332CCB, 0x3334CB, + 0x333CCB, 0x3344CB, 0x334CCB, 0x3354CB, + 0x305C8B, 0x006083, 0x0002F5, 0x010042, + 0x08000A, 0x000904, 0x187A86, 0x000007, + 0x001E2D, 0x0005FD, 0x018042, 0x08000A, + 0x028924, 0x280502, 0x00060D, 0x000810, + 0x280C3A, 0x00008D, 0x000810, 0x28143A, + 0x0A808D, 0x000820, 0x0002F5, 0x010040, + 0x220007, 0x001275, 0x030042, 0x21004A, + 0x00008D, 0x1A0944, 0x000007, 0x01980D, + 0x000810, 0x08043A, 0x2B2206, 0x000007, + 0x0001F5, 0x030042, 0x0D004A, 0x10000A, + 0x089144, 0x000007, 0x000820, 0x010040, + 0x0025F5, 0x0A3144, 0x000007, 0x000820, + 0x032860, 0x030040, 0x00217D, 0x038042, + 0x0B804A, 0x10000A, 0x000820, 0x031060, + 0x030040, 0x00008D, 0x000124, 0x00012C, + 0x000E64, 0x001A64, 0x00636C, 0x08010A, + 0x10012A, 0x000820, 0x031060, 0x030040, + 0x0020FD, 0x018042, 0x08000A, 0x00227D, + 0x018042, 0x10000A, 0x000820, 0x031060, + 0x030040, 0x00197D, 0x018042, 0x08000A, + 0x0022FD, 0x038042, 0x10000A, 0x000820, + 0x031060, 0x030040, 0x090D04, 0x000007, + 0x000820, 0x030040, 0x038042, 0x0B804A, + 0x10000A, 0x000820, 0x031060, 0x030040, + 0x038042, 0x13804A, 0x19804A, 0x110D04, + 0x198D04, 0x000007, 0x08000A, 0x001020, + 0x031860, 0x030860, 0x030040, 0x00008D, + 0x0B0944, 0x000007, 0x000820, 0x010040, + 0x0005F5, 0x030042, 0x08000A, 0x000820, + 0x010040, 0x0000F5, 0x010042, 0x08000A, + 0x000904, 0x1C6086, 0x001E75, 0x030042, + 0x01044A, 0x000C0A, 0x1C7206, 0x000007, + 0x000402, 0x000C02, 0x00177D, 0x001AF5, + 0x018042, 0x03144A, 0x031C4A, 0x03244A, + 0x032C4A, 0x03344A, 0x033C4A, 0x03444A, + 0x004C0A, 0x00043D, 0x0013F5, 0x001AFD, + 0x030042, 0x0B004A, 0x1B804A, 0x13804A, + 0x20000A, 0x089144, 0x19A144, 0x0389E4, + 0x0399EC, 0x005502, 0x005D0A, 0x030042, + 0x0B004A, 0x1B804A, 0x13804A, 0x20000A, + 0x089144, 0x19A144, 0x0389E4, 0x0399EC, + 0x006502, 0x006D0A, 0x030042, 0x0B004A, + 0x19004A, 0x2B804A, 0x13804A, 0x21804A, + 0x30000A, 0x089144, 0x19A144, 0x2AB144, + 0x0389E4, 0x0399EC, 0x007502, 0x007D0A, + 0x03A9E4, 0x000702, 0x00107D, 0x000415, + 0x018042, 0x08000A, 0x0109E4, 0x000F02, + 0x002AF5, 0x0019FD, 0x010042, 0x09804A, + 0x10000A, 0x000934, 0x001674, 0x0029F5, + 0x010042, 0x10000A, 0x00917C, 0x002075, + 0x010042, 0x08000A, 0x000904, 0x1ED286, + 0x0026F5, 0x0027F5, 0x030042, 0x09004A, + 0x10000A, 0x000A3C, 0x00167C, 0x001A75, + 0x000BFD, 0x010042, 0x51804A, 0x48000A, + 0x160007, 0x001075, 0x010042, 0x282C0A, + 0x281D12, 0x282512, 0x001F32, 0x1E0007, + 0x0E0007, 0x001975, 0x010042, 0x002DF5, + 0x0D004A, 0x10000A, 0x009144, 0x1FB286, + 0x010042, 0x28340A, 0x000E5D, 0x00008D, + 0x000375, 0x000820, 0x010040, 0x05D2F4, + 0x54D104, 0x00735C, 0x205386, 0x000007, + 0x0C0007, 0x080007, 0x0A0007, 0x02040D, + 0x000810, 0x08043A, 0x332206, 0x000007, + 0x205A06, 0x000007, 0x080007, 0x002275, + 0x010042, 0x20000A, 0x002104, 0x212086, + 0x001E2D, 0x0002F5, 0x010042, 0x08000A, + 0x000904, 0x209286, 0x000007, 0x002010, + 0x30043A, 0x00057D, 0x0180C3, 0x08000A, + 0x028924, 0x280502, 0x280C02, 0x0A810D, + 0x000820, 0x0002F5, 0x010040, 0x220007, + 0x0004FD, 0x018042, 0x70000A, 0x030000, + 0x007020, 0x06FA06, 0x018040, 0x02180D, + 0x000810, 0x08043A, 0x2B2206, 0x000007, + 0x0002FD, 0x018042, 0x08000A, 0x000904, + 0x218A86, 0x000007, 0x01F206, 0x000007, + 0x000875, 0x0009FD, 0x00010D, 0x220A06, + 0x000295, 0x000B75, 0x00097D, 0x00000D, + 0x000515, 0x010042, 0x18000A, 0x001904, + 0x287886, 0x0006F5, 0x001020, 0x010040, + 0x0004F5, 0x000820, 0x010040, 0x000775, + 0x010042, 0x09804A, 0x10000A, 0x001124, + 0x000904, 0x22BA86, 0x000815, 0x080102, + 0x101204, 0x22DA06, 0x000575, 0x081204, + 0x000007, 0x100102, 0x000575, 0x000425, + 0x021124, 0x100102, 0x000820, 0x031060, + 0x010040, 0x001924, 0x287886, 0x00008D, + 0x000464, 0x009D04, 0x278886, 0x180102, + 0x000575, 0x010042, 0x28040A, 0x00018D, + 0x000924, 0x280D02, 0x00000D, 0x000924, + 0x281502, 0x10000D, 0x000820, 0x0002F5, + 0x010040, 0x200007, 0x001175, 0x0002FD, + 0x018042, 0x08000A, 0x000904, 0x23C286, + 0x000007, 0x000100, 0x080B20, 0x130B60, + 0x1B0B60, 0x030A60, 0x010040, 0x050042, + 0x3D004A, 0x35004A, 0x2D004A, 0x20000A, + 0x0006F5, 0x010042, 0x28140A, 0x0004F5, + 0x010042, 0x08000A, 0x000315, 0x010D04, + 0x24CA86, 0x004015, 0x000095, 0x010D04, + 0x24B886, 0x100022, 0x10002A, 0x24E206, + 0x000007, 0x333104, 0x2AA904, 0x000007, + 0x032124, 0x280502, 0x001124, 0x000424, + 0x000424, 0x003224, 0x00292C, 0x00636C, + 0x25F386, 0x000007, 0x02B164, 0x000464, + 0x000464, 0x00008D, 0x000A64, 0x280D02, + 0x10008D, 0x000820, 0x0002F5, 0x010040, + 0x220007, 0x00008D, 0x38B904, 0x000007, + 0x03296C, 0x30010A, 0x0002F5, 0x010042, + 0x08000A, 0x000904, 0x25BA86, 0x000007, + 0x02312C, 0x28050A, 0x00008D, 0x01096C, + 0x280D0A, 0x10010D, 0x000820, 0x0002F5, + 0x010040, 0x220007, 0x001124, 0x000424, + 0x000424, 0x003224, 0x300102, 0x032944, + 0x267A86, 0x000007, 0x300002, 0x0004F5, + 0x010042, 0x08000A, 0x000315, 0x010D04, + 0x26C086, 0x003124, 0x000464, 0x300102, + 0x0002F5, 0x010042, 0x08000A, 0x000904, + 0x26CA86, 0x000007, 0x003124, 0x300502, + 0x003924, 0x300583, 0x000883, 0x0005F5, + 0x010042, 0x28040A, 0x00008D, 0x008124, + 0x280D02, 0x00008D, 0x008124, 0x281502, + 0x10018D, 0x000820, 0x0002F5, 0x010040, + 0x220007, 0x001025, 0x000575, 0x030042, + 0x09004A, 0x10000A, 0x0A0904, 0x121104, + 0x000007, 0x001020, 0x050860, 0x050040, + 0x0006FD, 0x018042, 0x09004A, 0x10000A, + 0x0000A5, 0x0A0904, 0x121104, 0x000007, + 0x000820, 0x019060, 0x010040, 0x0002F5, + 0x010042, 0x08000A, 0x000904, 0x284286, + 0x000007, 0x230A06, 0x000007, 0x000606, + 0x000007, 0x0002F5, 0x010042, 0x08000A, + 0x000904, 0x289286, 0x000007, 0x000100, + 0x080B20, 0x138B60, 0x1B8B60, 0x238B60, + 0x2B8B60, 0x338B60, 0x3B8B60, 0x438B60, + 0x4B8B60, 0x538B60, 0x5B8B60, 0x638B60, + 0x6B8B60, 0x738B60, 0x7B8B60, 0x038F60, + 0x0B8F60, 0x138F60, 0x1B8F60, 0x238F60, + 0x2B8F60, 0x338F60, 0x3B8F60, 0x438F60, + 0x4B8F60, 0x538F60, 0x5B8F60, 0x638F60, + 0x6B8F60, 0x738F60, 0x7B8F60, 0x038A60, + 0x000606, 0x018040, 0x00008D, 0x000A64, + 0x280D02, 0x000A24, 0x00027D, 0x018042, + 0x10000A, 0x001224, 0x0003FD, 0x018042, + 0x08000A, 0x000904, 0x2A8286, 0x000007, + 0x00018D, 0x000A24, 0x000464, 0x000464, + 0x080102, 0x000924, 0x000424, 0x000424, + 0x100102, 0x02000D, 0x009144, 0x2AD986, + 0x000007, 0x0001FD, 0x018042, 0x08000A, + 0x000A44, 0x2ABB86, 0x018042, 0x0A000D, + 0x000820, 0x0002FD, 0x018040, 0x200007, + 0x00027D, 0x001020, 0x000606, 0x018040, + 0x0002F5, 0x010042, 0x08000A, 0x000904, + 0x2B2A86, 0x000007, 0x00037D, 0x018042, + 0x08000A, 0x000904, 0x2B5A86, 0x000007, + 0x000075, 0x002E7D, 0x010042, 0x0B804A, + 0x000020, 0x000904, 0x000686, 0x010040, + 0x31844A, 0x30048B, 0x000883, 0x00008D, + 0x000810, 0x28143A, 0x00008D, 0x000810, + 0x280C3A, 0x000675, 0x010042, 0x08000A, + 0x003815, 0x010924, 0x280502, 0x0B000D, + 0x000820, 0x0002F5, 0x010040, 0x000606, + 0x220007, 0x000464, 0x000464, 0x000606, + 0x000007, 0x000134, 0x007F8D, 0x00093C, + 0x281D12, 0x282512, 0x001F32, 0x0E0007, + 0x00010D, 0x00037D, 0x000820, 0x018040, + 0x05D2F4, 0x000007, 0x080007, 0x00037D, + 0x018042, 0x08000A, 0x000904, 0x2D0286, + 0x000007, 0x000606, 0x000007, 0x000007, + 0x000012, 0x100007, 0x320007, 0x600007, + 0x100080, 0x48001A, 0x004904, 0x2D6186, + 0x000007, 0x001210, 0x58003A, 0x000145, + 0x5C5D04, 0x000007, 0x000080, 0x48001A, + 0x004904, 0x2DB186, 0x000007, 0x001210, + 0x50003A, 0x005904, 0x2E0886, 0x000045, + 0x0000C5, 0x7FFFF5, 0x7FFF7D, 0x07D524, + 0x004224, 0x500102, 0x200502, 0x000082, + 0x40001A, 0x004104, 0x2E3986, 0x000007, + 0x003865, 0x40001A, 0x004020, 0x00104D, + 0x04C184, 0x301B86, 0x000040, 0x040007, + 0x000165, 0x000145, 0x004020, 0x000040, + 0x000765, 0x080080, 0x40001A, 0x004104, + 0x2EC986, 0x000007, 0x001210, 0x40003A, + 0x004104, 0x2F2286, 0x00004D, 0x0000CD, + 0x004810, 0x20043A, 0x000882, 0x40001A, + 0x004104, 0x2F3186, 0x000007, 0x004820, + 0x005904, 0x300886, 0x000040, 0x0007E5, + 0x200480, 0x2816A0, 0x3216E0, 0x3A16E0, + 0x4216E0, 0x021260, 0x000040, 0x000032, + 0x400075, 0x00007D, 0x07D574, 0x200512, + 0x000082, 0x40001A, 0x004104, 0x2FE186, + 0x000007, 0x037206, 0x640007, 0x060007, + 0x0000E5, 0x000020, 0x000040, 0x000A65, + 0x000020, 0x020040, 0x020040, 0x000040, + 0x000165, 0x000042, 0x70000A, 0x007104, + 0x30A286, 0x000007, 0x018206, 0x640007, + 0x050000, 0x007020, 0x000040, 0x037206, + 0x640007, 0x000007, 0x00306D, 0x028860, + 0x029060, 0x08000A, 0x028860, 0x008040, + 0x100012, 0x00100D, 0x009184, 0x314186, + 0x000E0D, 0x009184, 0x325186, 0x000007, + 0x300007, 0x001020, 0x003B6D, 0x008040, + 0x000080, 0x08001A, 0x000904, 0x316186, + 0x000007, 0x001220, 0x000DED, 0x008040, + 0x008042, 0x10000A, 0x40000D, 0x109544, + 0x000007, 0x001020, 0x000DED, 0x008040, + 0x008042, 0x20040A, 0x000082, 0x08001A, + 0x000904, 0x31F186, 0x000007, 0x003B6D, + 0x008042, 0x08000A, 0x000E15, 0x010984, + 0x329B86, 0x600007, 0x08001A, 0x000C15, + 0x010984, 0x328386, 0x000020, 0x1A0007, + 0x0002ED, 0x008040, 0x620007, 0x00306D, + 0x028042, 0x0A804A, 0x000820, 0x0A804A, + 0x000606, 0x10804A, 0x000007, 0x282512, + 0x001F32, 0x05D2F4, 0x54D104, 0x00735C, + 0x000786, 0x000007, 0x0C0007, 0x0A0007, + 0x1C0007, 0x003465, 0x020040, 0x004820, + 0x025060, 0x40000A, 0x024060, 0x000040, + 0x454944, 0x000007, 0x004020, 0x003AE5, + 0x000040, 0x0028E5, 0x000042, 0x48000A, + 0x004904, 0x386886, 0x002C65, 0x000042, + 0x40000A, 0x0000D5, 0x454104, 0x000007, + 0x000655, 0x054504, 0x34F286, 0x0001D5, + 0x054504, 0x34F086, 0x002B65, 0x000042, + 0x003AE5, 0x50004A, 0x40000A, 0x45C3D4, + 0x000007, 0x454504, 0x000007, 0x0000CD, + 0x444944, 0x000007, 0x454504, 0x000007, + 0x00014D, 0x554944, 0x000007, 0x045144, + 0x34E986, 0x002C65, 0x000042, 0x48000A, + 0x4CD104, 0x000007, 0x04C144, 0x34F386, + 0x000007, 0x160007, 0x002CE5, 0x040042, + 0x40000A, 0x004020, 0x000040, 0x002965, + 0x000042, 0x40000A, 0x004104, 0x356086, + 0x000007, 0x002402, 0x36A206, 0x005C02, + 0x0025E5, 0x000042, 0x40000A, 0x004274, + 0x002AE5, 0x000042, 0x40000A, 0x004274, + 0x500112, 0x0029E5, 0x000042, 0x40000A, + 0x004234, 0x454104, 0x000007, 0x004020, + 0x000040, 0x003EE5, 0x000020, 0x000040, + 0x002DE5, 0x400152, 0x50000A, 0x045144, + 0x364A86, 0x0000C5, 0x003EE5, 0x004020, + 0x000040, 0x002BE5, 0x000042, 0x40000A, + 0x404254, 0x000007, 0x002AE5, 0x004020, + 0x000040, 0x500132, 0x040134, 0x005674, + 0x0029E5, 0x020042, 0x42000A, 0x000042, + 0x50000A, 0x05417C, 0x0028E5, 0x000042, + 0x48000A, 0x0000C5, 0x4CC144, 0x371086, + 0x0026E5, 0x0027E5, 0x020042, 0x40004A, + 0x50000A, 0x00423C, 0x00567C, 0x0028E5, + 0x004820, 0x000040, 0x281D12, 0x282512, + 0x001F72, 0x002965, 0x000042, 0x40000A, + 0x004104, 0x37AA86, 0x0E0007, 0x160007, + 0x1E0007, 0x003EE5, 0x000042, 0x40000A, + 0x004104, 0x37E886, 0x002D65, 0x000042, + 0x28340A, 0x003465, 0x020042, 0x42004A, + 0x004020, 0x4A004A, 0x50004A, 0x05D2F4, + 0x54D104, 0x00735C, 0x385186, 0x000007, + 0x000606, 0x080007, 0x0C0007, 0x080007, + 0x0A0007, 0x0001E5, 0x020045, 0x004020, + 0x000060, 0x000365, 0x000040, 0x002E65, + 0x001A20, 0x0A1A60, 0x000040, 0x003465, + 0x020042, 0x42004A, 0x004020, 0x4A004A, + 0x000606, 0x50004A, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000 +}; + +// -------------------------------------------- +// DS-1E Controller InstructionRAM Code +// 1999/06/21 +// Buf441 slot is Enabled. +// -------------------------------------------- +// 04/09?@creat +// 04/12 stop nise fix +// 06/21?@WorkingOff timming +static unsigned long int CntrlInst1E[] = { + 0x000007, 0x240007, 0x0C0007, 0x1C0007, + 0x060007, 0x700002, 0x000020, 0x030040, + 0x007104, 0x004286, 0x030040, 0x000F0D, + 0x000810, 0x20043A, 0x000282, 0x00020D, + 0x000810, 0x20043A, 0x001282, 0x200E82, + 0x00800D, 0x000810, 0x20043A, 0x001A82, + 0x03460D, 0x000810, 0x10043A, 0x02EC0D, + 0x000810, 0x18043A, 0x00010D, 0x020015, + 0x0000FD, 0x000020, 0x038860, 0x039060, + 0x038060, 0x038040, 0x038040, 0x038040, + 0x018040, 0x000A7D, 0x038040, 0x038040, + 0x018040, 0x200402, 0x000882, 0x08001A, + 0x000904, 0x017186, 0x000007, 0x260007, + 0x400007, 0x000007, 0x03258D, 0x000810, + 0x18043A, 0x260007, 0x284402, 0x00087D, + 0x018042, 0x00160A, 0x05A206, 0x000007, + 0x440007, 0x00230D, 0x000810, 0x08043A, + 0x22FA06, 0x000007, 0x0007FD, 0x018042, + 0x08000A, 0x000904, 0x02AB86, 0x000195, + 0x090D04, 0x000007, 0x000820, 0x0000F5, + 0x000B7D, 0x01F060, 0x0000FD, 0x033A06, + 0x018040, 0x000A7D, 0x038042, 0x13804A, + 0x18000A, 0x001820, 0x059060, 0x058860, + 0x018040, 0x0000FD, 0x018042, 0x70000A, + 0x000115, 0x071144, 0x033B86, 0x030000, + 0x007020, 0x036206, 0x018040, 0x00360D, + 0x000810, 0x08043A, 0x232206, 0x000007, + 0x02EC0D, 0x000810, 0x18043A, 0x019A06, + 0x000007, 0x240007, 0x000F8D, 0x000810, + 0x00163A, 0x002402, 0x005C02, 0x0028FD, + 0x000020, 0x018040, 0x08000D, 0x000815, + 0x510984, 0x000007, 0x00004D, 0x000E5D, + 0x000E02, 0x00430D, 0x000810, 0x08043A, + 0x2E1206, 0x000007, 0x00008D, 0x000924, + 0x000F02, 0x00470D, 0x000810, 0x08043A, + 0x2E1206, 0x000007, 0x480480, 0x001210, + 0x28043A, 0x00778D, 0x000810, 0x280C3A, + 0x00068D, 0x000810, 0x28143A, 0x284402, + 0x03258D, 0x000810, 0x18043A, 0x07FF8D, + 0x000820, 0x0002FD, 0x018040, 0x260007, + 0x200007, 0x0002FD, 0x018042, 0x08000A, + 0x000904, 0x051286, 0x000007, 0x240007, + 0x02EC0D, 0x000810, 0x18043A, 0x00387D, + 0x018042, 0x08000A, 0x001015, 0x010984, + 0x019B86, 0x000007, 0x01B206, 0x000007, + 0x0008FD, 0x018042, 0x18000A, 0x001904, + 0x22B886, 0x280007, 0x001810, 0x28043A, + 0x280C02, 0x00000D, 0x000810, 0x28143A, + 0x08808D, 0x000820, 0x0002FD, 0x018040, + 0x200007, 0x00020D, 0x189904, 0x000007, + 0x00402D, 0x0000BD, 0x0002FD, 0x018042, + 0x08000A, 0x000904, 0x065A86, 0x000007, + 0x000100, 0x000A20, 0x00047D, 0x018040, + 0x018042, 0x20000A, 0x003015, 0x012144, + 0x036186, 0x000007, 0x002104, 0x036186, + 0x000007, 0x000F8D, 0x000810, 0x280C3A, + 0x023944, 0x07C986, 0x000007, 0x001810, + 0x28043A, 0x08810D, 0x000820, 0x0002FD, + 0x018040, 0x200007, 0x002810, 0x78003A, + 0x00788D, 0x000810, 0x08043A, 0x2A1206, + 0x000007, 0x00400D, 0x001015, 0x189904, + 0x292904, 0x393904, 0x000007, 0x070206, + 0x000007, 0x0004F5, 0x00007D, 0x000020, + 0x00008D, 0x010860, 0x018040, 0x00047D, + 0x038042, 0x21804A, 0x18000A, 0x021944, + 0x229086, 0x000007, 0x004075, 0x71F104, + 0x000007, 0x010042, 0x28000A, 0x002904, + 0x225886, 0x000007, 0x003C0D, 0x30A904, + 0x000007, 0x00077D, 0x018042, 0x08000A, + 0x000904, 0x08DA86, 0x00057D, 0x002820, + 0x03B060, 0x08F206, 0x018040, 0x003020, + 0x03A860, 0x018040, 0x0002FD, 0x018042, + 0x08000A, 0x000904, 0x08FA86, 0x000007, + 0x00057D, 0x018042, 0x28040A, 0x000E8D, + 0x000810, 0x280C3A, 0x00000D, 0x000810, + 0x28143A, 0x09000D, 0x000820, 0x0002FD, + 0x018040, 0x200007, 0x003DFD, 0x000020, + 0x018040, 0x00107D, 0x009D8D, 0x000810, + 0x08043A, 0x2A1206, 0x000007, 0x000815, + 0x08001A, 0x010984, 0x0A5186, 0x00137D, + 0x200500, 0x280F20, 0x338F60, 0x3B8F60, + 0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60, + 0x038A60, 0x018040, 0x00107D, 0x018042, + 0x08000A, 0x000215, 0x010984, 0x3A8186, + 0x000007, 0x007FBD, 0x383DC4, 0x000007, + 0x001A7D, 0x001375, 0x018042, 0x09004A, + 0x10000A, 0x0B8D04, 0x139504, 0x000007, + 0x000820, 0x019060, 0x001104, 0x225886, + 0x010040, 0x0017FD, 0x018042, 0x08000A, + 0x000904, 0x225A86, 0x000007, 0x00197D, + 0x038042, 0x09804A, 0x10000A, 0x000924, + 0x001664, 0x0011FD, 0x038042, 0x2B804A, + 0x19804A, 0x00008D, 0x218944, 0x000007, + 0x002244, 0x0C1986, 0x000007, 0x001A64, + 0x002A24, 0x00197D, 0x080102, 0x100122, + 0x000820, 0x039060, 0x018040, 0x003DFD, + 0x00008D, 0x000820, 0x018040, 0x001375, + 0x001A7D, 0x010042, 0x09804A, 0x10000A, + 0x00021D, 0x0189E4, 0x2992E4, 0x309144, + 0x000007, 0x00060D, 0x000A15, 0x000C1D, + 0x001025, 0x00A9E4, 0x012BE4, 0x000464, + 0x01B3E4, 0x0232E4, 0x000464, 0x000464, + 0x000464, 0x000464, 0x00040D, 0x08B1C4, + 0x000007, 0x000820, 0x000BF5, 0x030040, + 0x00197D, 0x038042, 0x09804A, 0x000A24, + 0x08000A, 0x080E64, 0x000007, 0x100122, + 0x000820, 0x031060, 0x010040, 0x0064AC, + 0x00027D, 0x000020, 0x018040, 0x00107D, + 0x018042, 0x0011FD, 0x3B804A, 0x09804A, + 0x20000A, 0x000095, 0x1A1144, 0x00A144, + 0x0E5886, 0x00040D, 0x00B984, 0x0E5986, + 0x0018FD, 0x018042, 0x0010FD, 0x09804A, + 0x28000A, 0x000095, 0x010924, 0x002A64, + 0x0E4986, 0x000007, 0x002904, 0x0E5A86, + 0x000007, 0x0E6206, 0x080002, 0x00008D, + 0x00387D, 0x000820, 0x018040, 0x00127D, + 0x018042, 0x10000A, 0x003904, 0x0F0986, + 0x00080D, 0x7FFFB5, 0x00B984, 0x0ED986, + 0x000025, 0x0FB206, 0x00002D, 0x000015, + 0x00082D, 0x02E00D, 0x000820, 0x0FFA06, + 0x00000D, 0x7F8035, 0x00B984, 0x0FA986, + 0x400025, 0x00008D, 0x110944, 0x000007, + 0x00018D, 0x109504, 0x000007, 0x009164, + 0x000424, 0x000424, 0x000424, 0x100102, + 0x280002, 0x02DF0D, 0x000820, 0x0FFA06, + 0x00018D, 0x00042D, 0x00008D, 0x109504, + 0x000007, 0x00020D, 0x109184, 0x000007, + 0x02DF8D, 0x000820, 0x00008D, 0x0038FD, + 0x018040, 0x003BFD, 0x001020, 0x03A860, + 0x000815, 0x313184, 0x212184, 0x000007, + 0x03B060, 0x03A060, 0x018040, 0x0022FD, + 0x000095, 0x010924, 0x000424, 0x000424, + 0x001264, 0x100102, 0x000820, 0x039060, + 0x018040, 0x001924, 0x010F0D, 0x00397D, + 0x000820, 0x058040, 0x038042, 0x09844A, + 0x000606, 0x08040A, 0x000424, 0x000424, + 0x00117D, 0x018042, 0x08000A, 0x000A24, + 0x280502, 0x280C02, 0x09800D, 0x000820, + 0x0002FD, 0x018040, 0x200007, 0x0022FD, + 0x018042, 0x08000A, 0x000095, 0x280DC4, + 0x011924, 0x00197D, 0x018042, 0x0011FD, + 0x09804A, 0x10000A, 0x0000B5, 0x113144, + 0x0A8D04, 0x000007, 0x080A44, 0x129504, + 0x000007, 0x0023FD, 0x001020, 0x038040, + 0x101244, 0x000007, 0x000820, 0x039060, + 0x018040, 0x0002FD, 0x018042, 0x08000A, + 0x000904, 0x123286, 0x000007, 0x003BFD, + 0x000100, 0x000A10, 0x0B807A, 0x13804A, + 0x090984, 0x000007, 0x000095, 0x013D04, + 0x12B886, 0x10000A, 0x100002, 0x090984, + 0x000007, 0x038042, 0x11804A, 0x090D04, + 0x000007, 0x10000A, 0x090D84, 0x000007, + 0x00257D, 0x000820, 0x018040, 0x00010D, + 0x000810, 0x28143A, 0x00127D, 0x018042, + 0x20000A, 0x00197D, 0x018042, 0x00117D, + 0x31804A, 0x10000A, 0x003124, 0x013B8D, + 0x00397D, 0x000820, 0x058040, 0x038042, + 0x09844A, 0x000606, 0x08040A, 0x300102, + 0x003124, 0x000424, 0x000424, 0x001224, + 0x280502, 0x001A4C, 0x143986, 0x700002, + 0x00002D, 0x030000, 0x00387D, 0x018042, + 0x10000A, 0x146206, 0x002124, 0x0000AD, + 0x100002, 0x00010D, 0x000924, 0x006B24, + 0x014A0D, 0x00397D, 0x000820, 0x058040, + 0x038042, 0x09844A, 0x000606, 0x08040A, + 0x003264, 0x00008D, 0x000A24, 0x001020, + 0x00227D, 0x018040, 0x014F8D, 0x000810, + 0x08043A, 0x2B5A06, 0x000007, 0x002820, + 0x00207D, 0x018040, 0x00117D, 0x038042, + 0x13804A, 0x33800A, 0x00387D, 0x018042, + 0x08000A, 0x000904, 0x177286, 0x000007, + 0x00008D, 0x030964, 0x015B0D, 0x00397D, + 0x000820, 0x058040, 0x038042, 0x09844A, + 0x000606, 0x08040A, 0x380102, 0x000424, + 0x000424, 0x001224, 0x0002FD, 0x018042, + 0x08000A, 0x000904, 0x15DA86, 0x000007, + 0x280502, 0x001A4C, 0x177186, 0x000007, + 0x032164, 0x00632C, 0x003DFD, 0x018042, + 0x08000A, 0x000095, 0x090904, 0x000007, + 0x000820, 0x001A4C, 0x169986, 0x018040, + 0x030000, 0x16B206, 0x002124, 0x00010D, + 0x000924, 0x006B24, 0x016F0D, 0x00397D, + 0x000820, 0x058040, 0x038042, 0x09844A, + 0x000606, 0x08040A, 0x003A64, 0x000095, + 0x001224, 0x0002FD, 0x018042, 0x08000A, + 0x000904, 0x171286, 0x000007, 0x01760D, + 0x000810, 0x08043A, 0x2B5A06, 0x000007, + 0x160A06, 0x000007, 0x007020, 0x08010A, + 0x10012A, 0x0020FD, 0x038860, 0x039060, + 0x018040, 0x00227D, 0x018042, 0x003DFD, + 0x08000A, 0x31844A, 0x000904, 0x181086, + 0x18008B, 0x00008D, 0x189904, 0x00312C, + 0x18E206, 0x000007, 0x00324C, 0x186B86, + 0x000007, 0x001904, 0x186886, 0x000007, + 0x000095, 0x199144, 0x00222C, 0x003124, + 0x00636C, 0x000E3D, 0x001375, 0x000BFD, + 0x010042, 0x09804A, 0x10000A, 0x038AEC, + 0x0393EC, 0x00224C, 0x18E186, 0x000007, + 0x00008D, 0x189904, 0x00226C, 0x00322C, + 0x30050A, 0x301DAB, 0x002083, 0x0018FD, + 0x018042, 0x08000A, 0x018924, 0x300502, + 0x001083, 0x001875, 0x010042, 0x10000A, + 0x00008D, 0x010924, 0x001375, 0x330542, + 0x330CCB, 0x332CCB, 0x3334CB, 0x333CCB, + 0x3344CB, 0x334CCB, 0x3354CB, 0x305C8B, + 0x006083, 0x0002F5, 0x010042, 0x08000A, + 0x000904, 0x19B286, 0x000007, 0x001E2D, + 0x0005FD, 0x018042, 0x08000A, 0x028924, + 0x280502, 0x00060D, 0x000810, 0x280C3A, + 0x00008D, 0x000810, 0x28143A, 0x0A808D, + 0x000820, 0x0002F5, 0x010040, 0x220007, + 0x001275, 0x030042, 0x21004A, 0x00008D, + 0x1A0944, 0x000007, 0x01AB8D, 0x000810, + 0x08043A, 0x2CAA06, 0x000007, 0x0001F5, + 0x030042, 0x0D004A, 0x10000A, 0x089144, + 0x000007, 0x000820, 0x010040, 0x0025F5, + 0x0A3144, 0x000007, 0x000820, 0x032860, + 0x030040, 0x00217D, 0x038042, 0x0B804A, + 0x10000A, 0x000820, 0x031060, 0x030040, + 0x00008D, 0x000124, 0x00012C, 0x000E64, + 0x001A64, 0x00636C, 0x08010A, 0x10012A, + 0x000820, 0x031060, 0x030040, 0x0020FD, + 0x018042, 0x08000A, 0x00227D, 0x018042, + 0x10000A, 0x000820, 0x031060, 0x030040, + 0x00197D, 0x018042, 0x08000A, 0x0022FD, + 0x038042, 0x10000A, 0x000820, 0x031060, + 0x030040, 0x090D04, 0x000007, 0x000820, + 0x030040, 0x038042, 0x0B804A, 0x10000A, + 0x000820, 0x031060, 0x030040, 0x038042, + 0x13804A, 0x19804A, 0x110D04, 0x198D04, + 0x000007, 0x08000A, 0x001020, 0x031860, + 0x030860, 0x030040, 0x00008D, 0x0B0944, + 0x000007, 0x000820, 0x010040, 0x0005F5, + 0x030042, 0x08000A, 0x000820, 0x010040, + 0x0000F5, 0x010042, 0x08000A, 0x000904, + 0x1D9886, 0x001E75, 0x030042, 0x01044A, + 0x000C0A, 0x1DAA06, 0x000007, 0x000402, + 0x000C02, 0x00177D, 0x001AF5, 0x018042, + 0x03144A, 0x031C4A, 0x03244A, 0x032C4A, + 0x03344A, 0x033C4A, 0x03444A, 0x004C0A, + 0x00043D, 0x0013F5, 0x001AFD, 0x030042, + 0x0B004A, 0x1B804A, 0x13804A, 0x20000A, + 0x089144, 0x19A144, 0x0389E4, 0x0399EC, + 0x005502, 0x005D0A, 0x030042, 0x0B004A, + 0x1B804A, 0x13804A, 0x20000A, 0x089144, + 0x19A144, 0x0389E4, 0x0399EC, 0x006502, + 0x006D0A, 0x030042, 0x0B004A, 0x19004A, + 0x2B804A, 0x13804A, 0x21804A, 0x30000A, + 0x089144, 0x19A144, 0x2AB144, 0x0389E4, + 0x0399EC, 0x007502, 0x007D0A, 0x03A9E4, + 0x000702, 0x00107D, 0x000415, 0x018042, + 0x08000A, 0x0109E4, 0x000F02, 0x002AF5, + 0x0019FD, 0x010042, 0x09804A, 0x10000A, + 0x000934, 0x001674, 0x0029F5, 0x010042, + 0x10000A, 0x00917C, 0x002075, 0x010042, + 0x08000A, 0x000904, 0x200A86, 0x0026F5, + 0x0027F5, 0x030042, 0x09004A, 0x10000A, + 0x000A3C, 0x00167C, 0x001A75, 0x000BFD, + 0x010042, 0x51804A, 0x48000A, 0x160007, + 0x001075, 0x010042, 0x282C0A, 0x281D12, + 0x282512, 0x001F32, 0x1E0007, 0x0E0007, + 0x001975, 0x010042, 0x002DF5, 0x0D004A, + 0x10000A, 0x009144, 0x20EA86, 0x010042, + 0x28340A, 0x000E5D, 0x00008D, 0x000375, + 0x000820, 0x010040, 0x05D2F4, 0x54D104, + 0x00735C, 0x218B86, 0x000007, 0x0C0007, + 0x080007, 0x0A0007, 0x02178D, 0x000810, + 0x08043A, 0x34B206, 0x000007, 0x219206, + 0x000007, 0x080007, 0x002275, 0x010042, + 0x20000A, 0x002104, 0x225886, 0x001E2D, + 0x0002F5, 0x010042, 0x08000A, 0x000904, + 0x21CA86, 0x000007, 0x002010, 0x30043A, + 0x00057D, 0x0180C3, 0x08000A, 0x028924, + 0x280502, 0x280C02, 0x0A810D, 0x000820, + 0x0002F5, 0x010040, 0x220007, 0x0004FD, + 0x018042, 0x70000A, 0x030000, 0x007020, + 0x07FA06, 0x018040, 0x022B8D, 0x000810, + 0x08043A, 0x2CAA06, 0x000007, 0x0002FD, + 0x018042, 0x08000A, 0x000904, 0x22C286, + 0x000007, 0x020206, 0x000007, 0x000875, + 0x0009FD, 0x00010D, 0x234206, 0x000295, + 0x000B75, 0x00097D, 0x00000D, 0x000515, + 0x010042, 0x18000A, 0x001904, 0x2A0086, + 0x0006F5, 0x001020, 0x010040, 0x0004F5, + 0x000820, 0x010040, 0x000775, 0x010042, + 0x09804A, 0x10000A, 0x001124, 0x000904, + 0x23F286, 0x000815, 0x080102, 0x101204, + 0x241206, 0x000575, 0x081204, 0x000007, + 0x100102, 0x000575, 0x000425, 0x021124, + 0x100102, 0x000820, 0x031060, 0x010040, + 0x001924, 0x2A0086, 0x00008D, 0x000464, + 0x009D04, 0x291086, 0x180102, 0x000575, + 0x010042, 0x28040A, 0x00018D, 0x000924, + 0x280D02, 0x00000D, 0x000924, 0x281502, + 0x10000D, 0x000820, 0x0002F5, 0x010040, + 0x200007, 0x001175, 0x0002FD, 0x018042, + 0x08000A, 0x000904, 0x24FA86, 0x000007, + 0x000100, 0x080B20, 0x130B60, 0x1B0B60, + 0x030A60, 0x010040, 0x050042, 0x3D004A, + 0x35004A, 0x2D004A, 0x20000A, 0x0006F5, + 0x010042, 0x28140A, 0x0004F5, 0x010042, + 0x08000A, 0x000315, 0x010D04, 0x260286, + 0x004015, 0x000095, 0x010D04, 0x25F086, + 0x100022, 0x10002A, 0x261A06, 0x000007, + 0x333104, 0x2AA904, 0x000007, 0x032124, + 0x280502, 0x284402, 0x001124, 0x400102, + 0x000424, 0x000424, 0x003224, 0x00292C, + 0x00636C, 0x277386, 0x000007, 0x02B164, + 0x000464, 0x000464, 0x00008D, 0x000A64, + 0x280D02, 0x10008D, 0x000820, 0x0002F5, + 0x010040, 0x220007, 0x00008D, 0x38B904, + 0x000007, 0x03296C, 0x30010A, 0x0002F5, + 0x010042, 0x08000A, 0x000904, 0x270286, + 0x000007, 0x00212C, 0x28050A, 0x00316C, + 0x00046C, 0x00046C, 0x28450A, 0x001124, + 0x006B64, 0x100102, 0x00008D, 0x01096C, + 0x280D0A, 0x10010D, 0x000820, 0x0002F5, + 0x010040, 0x220007, 0x004124, 0x000424, + 0x000424, 0x003224, 0x300102, 0x032944, + 0x27FA86, 0x000007, 0x300002, 0x0004F5, + 0x010042, 0x08000A, 0x000315, 0x010D04, + 0x284086, 0x003124, 0x000464, 0x300102, + 0x0002F5, 0x010042, 0x08000A, 0x000904, + 0x284A86, 0x000007, 0x284402, 0x003124, + 0x300502, 0x003924, 0x300583, 0x000883, + 0x0005F5, 0x010042, 0x28040A, 0x00008D, + 0x008124, 0x280D02, 0x00008D, 0x008124, + 0x281502, 0x10018D, 0x000820, 0x0002F5, + 0x010040, 0x220007, 0x001025, 0x000575, + 0x030042, 0x09004A, 0x10000A, 0x0A0904, + 0x121104, 0x000007, 0x001020, 0x050860, + 0x050040, 0x0006FD, 0x018042, 0x09004A, + 0x10000A, 0x0000A5, 0x0A0904, 0x121104, + 0x000007, 0x000820, 0x019060, 0x010040, + 0x0002F5, 0x010042, 0x08000A, 0x000904, + 0x29CA86, 0x000007, 0x244206, 0x000007, + 0x000606, 0x000007, 0x0002F5, 0x010042, + 0x08000A, 0x000904, 0x2A1A86, 0x000007, + 0x000100, 0x080B20, 0x138B60, 0x1B8B60, + 0x238B60, 0x2B8B60, 0x338B60, 0x3B8B60, + 0x438B60, 0x4B8B60, 0x538B60, 0x5B8B60, + 0x638B60, 0x6B8B60, 0x738B60, 0x7B8B60, + 0x038F60, 0x0B8F60, 0x138F60, 0x1B8F60, + 0x238F60, 0x2B8F60, 0x338F60, 0x3B8F60, + 0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60, + 0x638F60, 0x6B8F60, 0x738F60, 0x7B8F60, + 0x038A60, 0x000606, 0x018040, 0x00008D, + 0x000A64, 0x280D02, 0x000A24, 0x00027D, + 0x018042, 0x10000A, 0x001224, 0x0003FD, + 0x018042, 0x08000A, 0x000904, 0x2C0A86, + 0x000007, 0x00018D, 0x000A24, 0x000464, + 0x000464, 0x080102, 0x000924, 0x000424, + 0x000424, 0x100102, 0x02000D, 0x009144, + 0x2C6186, 0x000007, 0x0001FD, 0x018042, + 0x08000A, 0x000A44, 0x2C4386, 0x018042, + 0x0A000D, 0x000820, 0x0002FD, 0x018040, + 0x200007, 0x00027D, 0x001020, 0x000606, + 0x018040, 0x0002F5, 0x010042, 0x08000A, + 0x000904, 0x2CB286, 0x000007, 0x00037D, + 0x018042, 0x08000A, 0x000904, 0x2CE286, + 0x000007, 0x000075, 0x002E7D, 0x010042, + 0x0B804A, 0x000020, 0x000904, 0x000686, + 0x010040, 0x31844A, 0x30048B, 0x000883, + 0x00008D, 0x000810, 0x28143A, 0x00008D, + 0x000810, 0x280C3A, 0x000675, 0x010042, + 0x08000A, 0x003815, 0x010924, 0x280502, + 0x0B000D, 0x000820, 0x0002F5, 0x010040, + 0x000606, 0x220007, 0x000464, 0x000464, + 0x000606, 0x000007, 0x000134, 0x007F8D, + 0x00093C, 0x281D12, 0x282512, 0x001F32, + 0x0E0007, 0x00010D, 0x00037D, 0x000820, + 0x018040, 0x05D2F4, 0x000007, 0x080007, + 0x00037D, 0x018042, 0x08000A, 0x000904, + 0x2E8A86, 0x000007, 0x000606, 0x000007, + 0x000007, 0x000012, 0x100007, 0x320007, + 0x600007, 0x460007, 0x100080, 0x48001A, + 0x004904, 0x2EF186, 0x000007, 0x001210, + 0x58003A, 0x000145, 0x5C5D04, 0x000007, + 0x000080, 0x48001A, 0x004904, 0x2F4186, + 0x000007, 0x001210, 0x50003A, 0x005904, + 0x2F9886, 0x000045, 0x0000C5, 0x7FFFF5, + 0x7FFF7D, 0x07D524, 0x004224, 0x500102, + 0x200502, 0x000082, 0x40001A, 0x004104, + 0x2FC986, 0x000007, 0x003865, 0x40001A, + 0x004020, 0x00104D, 0x04C184, 0x31AB86, + 0x000040, 0x040007, 0x000165, 0x000145, + 0x004020, 0x000040, 0x000765, 0x080080, + 0x40001A, 0x004104, 0x305986, 0x000007, + 0x001210, 0x40003A, 0x004104, 0x30B286, + 0x00004D, 0x0000CD, 0x004810, 0x20043A, + 0x000882, 0x40001A, 0x004104, 0x30C186, + 0x000007, 0x004820, 0x005904, 0x319886, + 0x000040, 0x0007E5, 0x200480, 0x2816A0, + 0x3216E0, 0x3A16E0, 0x4216E0, 0x021260, + 0x000040, 0x000032, 0x400075, 0x00007D, + 0x07D574, 0x200512, 0x000082, 0x40001A, + 0x004104, 0x317186, 0x000007, 0x038A06, + 0x640007, 0x0000E5, 0x000020, 0x000040, + 0x000A65, 0x000020, 0x020040, 0x020040, + 0x000040, 0x000165, 0x000042, 0x70000A, + 0x007104, 0x323286, 0x000007, 0x060007, + 0x019A06, 0x640007, 0x050000, 0x007020, + 0x000040, 0x038A06, 0x640007, 0x000007, + 0x00306D, 0x028860, 0x029060, 0x08000A, + 0x028860, 0x008040, 0x100012, 0x00100D, + 0x009184, 0x32D186, 0x000E0D, 0x009184, + 0x33E186, 0x000007, 0x300007, 0x001020, + 0x003B6D, 0x008040, 0x000080, 0x08001A, + 0x000904, 0x32F186, 0x000007, 0x001220, + 0x000DED, 0x008040, 0x008042, 0x10000A, + 0x40000D, 0x109544, 0x000007, 0x001020, + 0x000DED, 0x008040, 0x008042, 0x20040A, + 0x000082, 0x08001A, 0x000904, 0x338186, + 0x000007, 0x003B6D, 0x008042, 0x08000A, + 0x000E15, 0x010984, 0x342B86, 0x600007, + 0x08001A, 0x000C15, 0x010984, 0x341386, + 0x000020, 0x1A0007, 0x0002ED, 0x008040, + 0x620007, 0x00306D, 0x028042, 0x0A804A, + 0x000820, 0x0A804A, 0x000606, 0x10804A, + 0x000007, 0x282512, 0x001F32, 0x05D2F4, + 0x54D104, 0x00735C, 0x000786, 0x000007, + 0x0C0007, 0x0A0007, 0x1C0007, 0x003465, + 0x020040, 0x004820, 0x025060, 0x40000A, + 0x024060, 0x000040, 0x454944, 0x000007, + 0x004020, 0x003AE5, 0x000040, 0x0028E5, + 0x000042, 0x48000A, 0x004904, 0x39F886, + 0x002C65, 0x000042, 0x40000A, 0x0000D5, + 0x454104, 0x000007, 0x000655, 0x054504, + 0x368286, 0x0001D5, 0x054504, 0x368086, + 0x002B65, 0x000042, 0x003AE5, 0x50004A, + 0x40000A, 0x45C3D4, 0x000007, 0x454504, + 0x000007, 0x0000CD, 0x444944, 0x000007, + 0x454504, 0x000007, 0x00014D, 0x554944, + 0x000007, 0x045144, 0x367986, 0x002C65, + 0x000042, 0x48000A, 0x4CD104, 0x000007, + 0x04C144, 0x368386, 0x000007, 0x160007, + 0x002CE5, 0x040042, 0x40000A, 0x004020, + 0x000040, 0x002965, 0x000042, 0x40000A, + 0x004104, 0x36F086, 0x000007, 0x002402, + 0x383206, 0x005C02, 0x0025E5, 0x000042, + 0x40000A, 0x004274, 0x002AE5, 0x000042, + 0x40000A, 0x004274, 0x500112, 0x0029E5, + 0x000042, 0x40000A, 0x004234, 0x454104, + 0x000007, 0x004020, 0x000040, 0x003EE5, + 0x000020, 0x000040, 0x002DE5, 0x400152, + 0x50000A, 0x045144, 0x37DA86, 0x0000C5, + 0x003EE5, 0x004020, 0x000040, 0x002BE5, + 0x000042, 0x40000A, 0x404254, 0x000007, + 0x002AE5, 0x004020, 0x000040, 0x500132, + 0x040134, 0x005674, 0x0029E5, 0x020042, + 0x42000A, 0x000042, 0x50000A, 0x05417C, + 0x0028E5, 0x000042, 0x48000A, 0x0000C5, + 0x4CC144, 0x38A086, 0x0026E5, 0x0027E5, + 0x020042, 0x40004A, 0x50000A, 0x00423C, + 0x00567C, 0x0028E5, 0x004820, 0x000040, + 0x281D12, 0x282512, 0x001F72, 0x002965, + 0x000042, 0x40000A, 0x004104, 0x393A86, + 0x0E0007, 0x160007, 0x1E0007, 0x003EE5, + 0x000042, 0x40000A, 0x004104, 0x397886, + 0x002D65, 0x000042, 0x28340A, 0x003465, + 0x020042, 0x42004A, 0x004020, 0x4A004A, + 0x50004A, 0x05D2F4, 0x54D104, 0x00735C, + 0x39E186, 0x000007, 0x000606, 0x080007, + 0x0C0007, 0x080007, 0x0A0007, 0x0001E5, + 0x020045, 0x004020, 0x000060, 0x000365, + 0x000040, 0x002E65, 0x001A20, 0x0A1A60, + 0x000040, 0x003465, 0x020042, 0x42004A, + 0x004020, 0x4A004A, 0x000606, 0x50004A, + 0x0017FD, 0x018042, 0x08000A, 0x000904, + 0x225A86, 0x000007, 0x00107D, 0x018042, + 0x0011FD, 0x33804A, 0x19804A, 0x20000A, + 0x000095, 0x2A1144, 0x01A144, 0x3B9086, + 0x00040D, 0x00B184, 0x3B9186, 0x0018FD, + 0x018042, 0x0010FD, 0x09804A, 0x38000A, + 0x000095, 0x010924, 0x003A64, 0x3B8186, + 0x000007, 0x003904, 0x3B9286, 0x000007, + 0x3B9A06, 0x00000D, 0x00008D, 0x000820, + 0x00387D, 0x018040, 0x700002, 0x00117D, + 0x018042, 0x00197D, 0x29804A, 0x30000A, + 0x380002, 0x003124, 0x000424, 0x000424, + 0x002A24, 0x280502, 0x00068D, 0x000810, + 0x28143A, 0x00750D, 0x00B124, 0x002264, + 0x3D0386, 0x284402, 0x000810, 0x280C3A, + 0x0B800D, 0x000820, 0x0002FD, 0x018040, + 0x200007, 0x00758D, 0x00B124, 0x100102, + 0x012144, 0x3E4986, 0x001810, 0x10003A, + 0x00387D, 0x018042, 0x08000A, 0x000904, + 0x3E4886, 0x030000, 0x3E4A06, 0x0000BD, + 0x00008D, 0x023164, 0x000A64, 0x280D02, + 0x0B808D, 0x000820, 0x0002FD, 0x018040, + 0x200007, 0x00387D, 0x018042, 0x08000A, + 0x000904, 0x3E3286, 0x030000, 0x0002FD, + 0x018042, 0x08000A, 0x000904, 0x3D8286, + 0x000007, 0x002810, 0x28043A, 0x00750D, + 0x030924, 0x002264, 0x280D02, 0x02316C, + 0x28450A, 0x0B810D, 0x000820, 0x0002FD, + 0x018040, 0x200007, 0x00008D, 0x000A24, + 0x3E4A06, 0x100102, 0x001810, 0x10003A, + 0x0000BD, 0x003810, 0x30043A, 0x00187D, + 0x018042, 0x0018FD, 0x09804A, 0x20000A, + 0x0000AD, 0x028924, 0x07212C, 0x001010, + 0x300583, 0x300D8B, 0x3014BB, 0x301C83, + 0x002083, 0x00137D, 0x038042, 0x33844A, + 0x33ACCB, 0x33B4CB, 0x33BCCB, 0x33C4CB, + 0x33CCCB, 0x33D4CB, 0x305C8B, 0x006083, + 0x001E0D, 0x0005FD, 0x018042, 0x20000A, + 0x020924, 0x00068D, 0x00A96C, 0x00009D, + 0x0002FD, 0x018042, 0x08000A, 0x000904, + 0x3F6A86, 0x000007, 0x280502, 0x280D0A, + 0x284402, 0x001810, 0x28143A, 0x0C008D, + 0x000820, 0x0002FD, 0x018040, 0x220007, + 0x003904, 0x225886, 0x001E0D, 0x00057D, + 0x018042, 0x20000A, 0x020924, 0x0000A5, + 0x0002FD, 0x018042, 0x08000A, 0x000904, + 0x402A86, 0x000007, 0x280502, 0x280C02, + 0x002010, 0x28143A, 0x0C010D, 0x000820, + 0x0002FD, 0x018040, 0x225A06, 0x220007, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000 +}; + +#endif //_HWMCODE_ + + diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/Config.in linux/drivers/sound/Config.in --- v2.4.0-test1/linux/drivers/sound/Config.in Thu May 11 15:30:07 2000 +++ linux/drivers/sound/Config.in Tue Jun 20 07:52:36 2000 @@ -3,9 +3,6 @@ # 18 Apr 1998, Michael Elizabeth Chastain, # More hacking for modularisation. # -# See drivers/sound/README.CONFIG for more information. - - # Prompt user for primary drivers. @@ -27,7 +24,7 @@ dep_tristate ' SGI Visual Workstation Sound' CONFIG_SOUND_VWSND $CONFIG_SOUND fi -dep_tristate ' Trident 4DWave DX/NX or SiS 7018 PCI Audio Core' CONFIG_SOUND_TRIDENT $CONFIG_SOUND +dep_tristate ' Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core' CONFIG_SOUND_TRIDENT $CONFIG_SOUND dep_tristate ' Support for Turtle Beach MultiSound Classic, Tahiti, Monterey' CONFIG_SOUND_MSNDCLAS $CONFIG_SOUND if [ "$CONFIG_SOUND_MSNDCLAS" = "y" -o "$CONFIG_SOUND_MSNDCLAS" = "m" ]; then @@ -79,7 +76,7 @@ int 'MSND buffer size (kB)' CONFIG_MSND_FIFOSIZE 128 fi -tristate ' VIA 82C686 Audio Codec' CONFIG_SOUND_VIA82CXXX +dep_tristate ' VIA 82C686 Audio Codec' CONFIG_SOUND_VIA82CXXX $CONFIG_PCI dep_tristate ' OSS sound modules' CONFIG_SOUND_OSS $CONFIG_SOUND @@ -149,6 +146,7 @@ dep_tristate ' Yamaha FM synthesizer (YM3812/OPL-3) support' CONFIG_SOUND_YM3812 $CONFIG_SOUND_OSS dep_tristate ' Yamaha OPL3-SA1 audio controller' CONFIG_SOUND_OPL3SA1 $CONFIG_SOUND_OSS dep_tristate ' Yamaha OPL3-SA2, SA3, and SAx based PnP cards' CONFIG_SOUND_OPL3SA2 $CONFIG_SOUND_OSS + dep_tristate ' Yamaha PCI legacy mode support' CONFIG_SOUND_YMPCI $CONFIG_SOUND_OSS $CONFIG_PCI dep_tristate ' 6850 UART support' CONFIG_SOUND_UART6850 $CONFIG_SOUND_OSS dep_tristate ' Gallant Audio Cards (SC-6000 and SC-6600 based)' CONFIG_SOUND_AEDSP16 $CONFIG_SOUND_OSS @@ -181,3 +179,4 @@ fi +dep_tristate ' TV card (bt848) mixer support' CONFIG_SOUND_TVMIXER $CONFIG_SOUND $CONFIG_I2C diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/Hwmcode.h linux/drivers/sound/Hwmcode.h --- v2.4.0-test1/linux/drivers/sound/Hwmcode.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/Hwmcode.h Tue Jun 20 07:52:36 2000 @@ -0,0 +1,804 @@ +//============================================================================= +// Copyright (c) 1997 Yamaha Corporation. All Rights Reserved. +// +// Title: +// hwmcode.c +// Desc: +// micro-code for CTRL & DSP +// HISTORY: +// April 03, 1997: 1st try by M. Mukojima +//============================================================================= +#define YDSXG_DSPLENGTH 0x0080 +#define YDSXG_CTRLLENGTH 0x3000 + + +static unsigned long int gdwDSPCode[YDSXG_DSPLENGTH >> 2] = { + 0x00000081, 0x000001a4, 0x0000000a, 0x0000002f, + 0x00080253, 0x01800317, 0x0000407b, 0x0000843f, + 0x0001483c, 0x0001943c, 0x0005d83c, 0x00001c3c, + 0x0000c07b, 0x00050c3f, 0x0121503c, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000 +}; + + +// -------------------------------------------- +// DS-1E Controller InstructionRAM Code +// 1999/06/21 +// Buf441 slot is Enabled. +// -------------------------------------------- +// 04/09?@creat +// 04/12 stop nise fix +// 06/21?@WorkingOff timming +static unsigned long gdwCtrl1eCode[YDSXG_CTRLLENGTH >> 2] = { + 0x000007, 0x240007, 0x0C0007, 0x1C0007, + 0x060007, 0x700002, 0x000020, 0x030040, + 0x007104, 0x004286, 0x030040, 0x000F0D, + 0x000810, 0x20043A, 0x000282, 0x00020D, + 0x000810, 0x20043A, 0x001282, 0x200E82, + 0x00800D, 0x000810, 0x20043A, 0x001A82, + 0x03460D, 0x000810, 0x10043A, 0x02EC0D, + 0x000810, 0x18043A, 0x00010D, 0x020015, + 0x0000FD, 0x000020, 0x038860, 0x039060, + 0x038060, 0x038040, 0x038040, 0x038040, + 0x018040, 0x000A7D, 0x038040, 0x038040, + 0x018040, 0x200402, 0x000882, 0x08001A, + 0x000904, 0x017186, 0x000007, 0x260007, + 0x400007, 0x000007, 0x03258D, 0x000810, + 0x18043A, 0x260007, 0x284402, 0x00087D, + 0x018042, 0x00160A, 0x05A206, 0x000007, + 0x440007, 0x00230D, 0x000810, 0x08043A, + 0x22FA06, 0x000007, 0x0007FD, 0x018042, + 0x08000A, 0x000904, 0x02AB86, 0x000195, + 0x090D04, 0x000007, 0x000820, 0x0000F5, + 0x000B7D, 0x01F060, 0x0000FD, 0x033A06, + 0x018040, 0x000A7D, 0x038042, 0x13804A, + 0x18000A, 0x001820, 0x059060, 0x058860, + 0x018040, 0x0000FD, 0x018042, 0x70000A, + 0x000115, 0x071144, 0x033B86, 0x030000, + 0x007020, 0x036206, 0x018040, 0x00360D, + 0x000810, 0x08043A, 0x232206, 0x000007, + 0x02EC0D, 0x000810, 0x18043A, 0x019A06, + 0x000007, 0x240007, 0x000F8D, 0x000810, + 0x00163A, 0x002402, 0x005C02, 0x0028FD, + 0x000020, 0x018040, 0x08000D, 0x000815, + 0x510984, 0x000007, 0x00004D, 0x000E5D, + 0x000E02, 0x00430D, 0x000810, 0x08043A, + 0x2E1206, 0x000007, 0x00008D, 0x000924, + 0x000F02, 0x00470D, 0x000810, 0x08043A, + 0x2E1206, 0x000007, 0x480480, 0x001210, + 0x28043A, 0x00778D, 0x000810, 0x280C3A, + 0x00068D, 0x000810, 0x28143A, 0x284402, + 0x03258D, 0x000810, 0x18043A, 0x07FF8D, + 0x000820, 0x0002FD, 0x018040, 0x260007, + 0x200007, 0x0002FD, 0x018042, 0x08000A, + 0x000904, 0x051286, 0x000007, 0x240007, + 0x02EC0D, 0x000810, 0x18043A, 0x00387D, + 0x018042, 0x08000A, 0x001015, 0x010984, + 0x019B86, 0x000007, 0x01B206, 0x000007, + 0x0008FD, 0x018042, 0x18000A, 0x001904, + 0x22B886, 0x280007, 0x001810, 0x28043A, + 0x280C02, 0x00000D, 0x000810, 0x28143A, + 0x08808D, 0x000820, 0x0002FD, 0x018040, + 0x200007, 0x00020D, 0x189904, 0x000007, + 0x00402D, 0x0000BD, 0x0002FD, 0x018042, + 0x08000A, 0x000904, 0x065A86, 0x000007, + 0x000100, 0x000A20, 0x00047D, 0x018040, + 0x018042, 0x20000A, 0x003015, 0x012144, + 0x036186, 0x000007, 0x002104, 0x036186, + 0x000007, 0x000F8D, 0x000810, 0x280C3A, + 0x023944, 0x07C986, 0x000007, 0x001810, + 0x28043A, 0x08810D, 0x000820, 0x0002FD, + 0x018040, 0x200007, 0x002810, 0x78003A, + 0x00788D, 0x000810, 0x08043A, 0x2A1206, + 0x000007, 0x00400D, 0x001015, 0x189904, + 0x292904, 0x393904, 0x000007, 0x070206, + 0x000007, 0x0004F5, 0x00007D, 0x000020, + 0x00008D, 0x010860, 0x018040, 0x00047D, + 0x038042, 0x21804A, 0x18000A, 0x021944, + 0x229086, 0x000007, 0x004075, 0x71F104, + 0x000007, 0x010042, 0x28000A, 0x002904, + 0x225886, 0x000007, 0x003C0D, 0x30A904, + 0x000007, 0x00077D, 0x018042, 0x08000A, + 0x000904, 0x08DA86, 0x00057D, 0x002820, + 0x03B060, 0x08F206, 0x018040, 0x003020, + 0x03A860, 0x018040, 0x0002FD, 0x018042, + 0x08000A, 0x000904, 0x08FA86, 0x000007, + 0x00057D, 0x018042, 0x28040A, 0x000E8D, + 0x000810, 0x280C3A, 0x00000D, 0x000810, + 0x28143A, 0x09000D, 0x000820, 0x0002FD, + 0x018040, 0x200007, 0x003DFD, 0x000020, + 0x018040, 0x00107D, 0x009D8D, 0x000810, + 0x08043A, 0x2A1206, 0x000007, 0x000815, + 0x08001A, 0x010984, 0x0A5186, 0x00137D, + 0x200500, 0x280F20, 0x338F60, 0x3B8F60, + 0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60, + 0x038A60, 0x018040, 0x00107D, 0x018042, + 0x08000A, 0x000215, 0x010984, 0x3A8186, + 0x000007, 0x007FBD, 0x383DC4, 0x000007, + 0x001A7D, 0x001375, 0x018042, 0x09004A, + 0x10000A, 0x0B8D04, 0x139504, 0x000007, + 0x000820, 0x019060, 0x001104, 0x225886, + 0x010040, 0x0017FD, 0x018042, 0x08000A, + 0x000904, 0x225A86, 0x000007, 0x00197D, + 0x038042, 0x09804A, 0x10000A, 0x000924, + 0x001664, 0x0011FD, 0x038042, 0x2B804A, + 0x19804A, 0x00008D, 0x218944, 0x000007, + 0x002244, 0x0C1986, 0x000007, 0x001A64, + 0x002A24, 0x00197D, 0x080102, 0x100122, + 0x000820, 0x039060, 0x018040, 0x003DFD, + 0x00008D, 0x000820, 0x018040, 0x001375, + 0x001A7D, 0x010042, 0x09804A, 0x10000A, + 0x00021D, 0x0189E4, 0x2992E4, 0x309144, + 0x000007, 0x00060D, 0x000A15, 0x000C1D, + 0x001025, 0x00A9E4, 0x012BE4, 0x000464, + 0x01B3E4, 0x0232E4, 0x000464, 0x000464, + 0x000464, 0x000464, 0x00040D, 0x08B1C4, + 0x000007, 0x000820, 0x000BF5, 0x030040, + 0x00197D, 0x038042, 0x09804A, 0x000A24, + 0x08000A, 0x080E64, 0x000007, 0x100122, + 0x000820, 0x031060, 0x010040, 0x0064AC, + 0x00027D, 0x000020, 0x018040, 0x00107D, + 0x018042, 0x0011FD, 0x3B804A, 0x09804A, + 0x20000A, 0x000095, 0x1A1144, 0x00A144, + 0x0E5886, 0x00040D, 0x00B984, 0x0E5986, + 0x0018FD, 0x018042, 0x0010FD, 0x09804A, + 0x28000A, 0x000095, 0x010924, 0x002A64, + 0x0E4986, 0x000007, 0x002904, 0x0E5A86, + 0x000007, 0x0E6206, 0x080002, 0x00008D, + 0x00387D, 0x000820, 0x018040, 0x00127D, + 0x018042, 0x10000A, 0x003904, 0x0F0986, + 0x00080D, 0x7FFFB5, 0x00B984, 0x0ED986, + 0x000025, 0x0FB206, 0x00002D, 0x000015, + 0x00082D, 0x02E00D, 0x000820, 0x0FFA06, + 0x00000D, 0x7F8035, 0x00B984, 0x0FA986, + 0x400025, 0x00008D, 0x110944, 0x000007, + 0x00018D, 0x109504, 0x000007, 0x009164, + 0x000424, 0x000424, 0x000424, 0x100102, + 0x280002, 0x02DF0D, 0x000820, 0x0FFA06, + 0x00018D, 0x00042D, 0x00008D, 0x109504, + 0x000007, 0x00020D, 0x109184, 0x000007, + 0x02DF8D, 0x000820, 0x00008D, 0x0038FD, + 0x018040, 0x003BFD, 0x001020, 0x03A860, + 0x000815, 0x313184, 0x212184, 0x000007, + 0x03B060, 0x03A060, 0x018040, 0x0022FD, + 0x000095, 0x010924, 0x000424, 0x000424, + 0x001264, 0x100102, 0x000820, 0x039060, + 0x018040, 0x001924, 0x010F0D, 0x00397D, + 0x000820, 0x058040, 0x038042, 0x09844A, + 0x000606, 0x08040A, 0x000424, 0x000424, + 0x00117D, 0x018042, 0x08000A, 0x000A24, + 0x280502, 0x280C02, 0x09800D, 0x000820, + 0x0002FD, 0x018040, 0x200007, 0x0022FD, + 0x018042, 0x08000A, 0x000095, 0x280DC4, + 0x011924, 0x00197D, 0x018042, 0x0011FD, + 0x09804A, 0x10000A, 0x0000B5, 0x113144, + 0x0A8D04, 0x000007, 0x080A44, 0x129504, + 0x000007, 0x0023FD, 0x001020, 0x038040, + 0x101244, 0x000007, 0x000820, 0x039060, + 0x018040, 0x0002FD, 0x018042, 0x08000A, + 0x000904, 0x123286, 0x000007, 0x003BFD, + 0x000100, 0x000A10, 0x0B807A, 0x13804A, + 0x090984, 0x000007, 0x000095, 0x013D04, + 0x12B886, 0x10000A, 0x100002, 0x090984, + 0x000007, 0x038042, 0x11804A, 0x090D04, + 0x000007, 0x10000A, 0x090D84, 0x000007, + 0x00257D, 0x000820, 0x018040, 0x00010D, + 0x000810, 0x28143A, 0x00127D, 0x018042, + 0x20000A, 0x00197D, 0x018042, 0x00117D, + 0x31804A, 0x10000A, 0x003124, 0x013B8D, + 0x00397D, 0x000820, 0x058040, 0x038042, + 0x09844A, 0x000606, 0x08040A, 0x300102, + 0x003124, 0x000424, 0x000424, 0x001224, + 0x280502, 0x001A4C, 0x143986, 0x700002, + 0x00002D, 0x030000, 0x00387D, 0x018042, + 0x10000A, 0x146206, 0x002124, 0x0000AD, + 0x100002, 0x00010D, 0x000924, 0x006B24, + 0x014A0D, 0x00397D, 0x000820, 0x058040, + 0x038042, 0x09844A, 0x000606, 0x08040A, + 0x003264, 0x00008D, 0x000A24, 0x001020, + 0x00227D, 0x018040, 0x014F8D, 0x000810, + 0x08043A, 0x2B5A06, 0x000007, 0x002820, + 0x00207D, 0x018040, 0x00117D, 0x038042, + 0x13804A, 0x33800A, 0x00387D, 0x018042, + 0x08000A, 0x000904, 0x177286, 0x000007, + 0x00008D, 0x030964, 0x015B0D, 0x00397D, + 0x000820, 0x058040, 0x038042, 0x09844A, + 0x000606, 0x08040A, 0x380102, 0x000424, + 0x000424, 0x001224, 0x0002FD, 0x018042, + 0x08000A, 0x000904, 0x15DA86, 0x000007, + 0x280502, 0x001A4C, 0x177186, 0x000007, + 0x032164, 0x00632C, 0x003DFD, 0x018042, + 0x08000A, 0x000095, 0x090904, 0x000007, + 0x000820, 0x001A4C, 0x169986, 0x018040, + 0x030000, 0x16B206, 0x002124, 0x00010D, + 0x000924, 0x006B24, 0x016F0D, 0x00397D, + 0x000820, 0x058040, 0x038042, 0x09844A, + 0x000606, 0x08040A, 0x003A64, 0x000095, + 0x001224, 0x0002FD, 0x018042, 0x08000A, + 0x000904, 0x171286, 0x000007, 0x01760D, + 0x000810, 0x08043A, 0x2B5A06, 0x000007, + 0x160A06, 0x000007, 0x007020, 0x08010A, + 0x10012A, 0x0020FD, 0x038860, 0x039060, + 0x018040, 0x00227D, 0x018042, 0x003DFD, + 0x08000A, 0x31844A, 0x000904, 0x181086, + 0x18008B, 0x00008D, 0x189904, 0x00312C, + 0x18E206, 0x000007, 0x00324C, 0x186B86, + 0x000007, 0x001904, 0x186886, 0x000007, + 0x000095, 0x199144, 0x00222C, 0x003124, + 0x00636C, 0x000E3D, 0x001375, 0x000BFD, + 0x010042, 0x09804A, 0x10000A, 0x038AEC, + 0x0393EC, 0x00224C, 0x18E186, 0x000007, + 0x00008D, 0x189904, 0x00226C, 0x00322C, + 0x30050A, 0x301DAB, 0x002083, 0x0018FD, + 0x018042, 0x08000A, 0x018924, 0x300502, + 0x001083, 0x001875, 0x010042, 0x10000A, + 0x00008D, 0x010924, 0x001375, 0x330542, + 0x330CCB, 0x332CCB, 0x3334CB, 0x333CCB, + 0x3344CB, 0x334CCB, 0x3354CB, 0x305C8B, + 0x006083, 0x0002F5, 0x010042, 0x08000A, + 0x000904, 0x19B286, 0x000007, 0x001E2D, + 0x0005FD, 0x018042, 0x08000A, 0x028924, + 0x280502, 0x00060D, 0x000810, 0x280C3A, + 0x00008D, 0x000810, 0x28143A, 0x0A808D, + 0x000820, 0x0002F5, 0x010040, 0x220007, + 0x001275, 0x030042, 0x21004A, 0x00008D, + 0x1A0944, 0x000007, 0x01AB8D, 0x000810, + 0x08043A, 0x2CAA06, 0x000007, 0x0001F5, + 0x030042, 0x0D004A, 0x10000A, 0x089144, + 0x000007, 0x000820, 0x010040, 0x0025F5, + 0x0A3144, 0x000007, 0x000820, 0x032860, + 0x030040, 0x00217D, 0x038042, 0x0B804A, + 0x10000A, 0x000820, 0x031060, 0x030040, + 0x00008D, 0x000124, 0x00012C, 0x000E64, + 0x001A64, 0x00636C, 0x08010A, 0x10012A, + 0x000820, 0x031060, 0x030040, 0x0020FD, + 0x018042, 0x08000A, 0x00227D, 0x018042, + 0x10000A, 0x000820, 0x031060, 0x030040, + 0x00197D, 0x018042, 0x08000A, 0x0022FD, + 0x038042, 0x10000A, 0x000820, 0x031060, + 0x030040, 0x090D04, 0x000007, 0x000820, + 0x030040, 0x038042, 0x0B804A, 0x10000A, + 0x000820, 0x031060, 0x030040, 0x038042, + 0x13804A, 0x19804A, 0x110D04, 0x198D04, + 0x000007, 0x08000A, 0x001020, 0x031860, + 0x030860, 0x030040, 0x00008D, 0x0B0944, + 0x000007, 0x000820, 0x010040, 0x0005F5, + 0x030042, 0x08000A, 0x000820, 0x010040, + 0x0000F5, 0x010042, 0x08000A, 0x000904, + 0x1D9886, 0x001E75, 0x030042, 0x01044A, + 0x000C0A, 0x1DAA06, 0x000007, 0x000402, + 0x000C02, 0x00177D, 0x001AF5, 0x018042, + 0x03144A, 0x031C4A, 0x03244A, 0x032C4A, + 0x03344A, 0x033C4A, 0x03444A, 0x004C0A, + 0x00043D, 0x0013F5, 0x001AFD, 0x030042, + 0x0B004A, 0x1B804A, 0x13804A, 0x20000A, + 0x089144, 0x19A144, 0x0389E4, 0x0399EC, + 0x005502, 0x005D0A, 0x030042, 0x0B004A, + 0x1B804A, 0x13804A, 0x20000A, 0x089144, + 0x19A144, 0x0389E4, 0x0399EC, 0x006502, + 0x006D0A, 0x030042, 0x0B004A, 0x19004A, + 0x2B804A, 0x13804A, 0x21804A, 0x30000A, + 0x089144, 0x19A144, 0x2AB144, 0x0389E4, + 0x0399EC, 0x007502, 0x007D0A, 0x03A9E4, + 0x000702, 0x00107D, 0x000415, 0x018042, + 0x08000A, 0x0109E4, 0x000F02, 0x002AF5, + 0x0019FD, 0x010042, 0x09804A, 0x10000A, + 0x000934, 0x001674, 0x0029F5, 0x010042, + 0x10000A, 0x00917C, 0x002075, 0x010042, + 0x08000A, 0x000904, 0x200A86, 0x0026F5, + 0x0027F5, 0x030042, 0x09004A, 0x10000A, + 0x000A3C, 0x00167C, 0x001A75, 0x000BFD, + 0x010042, 0x51804A, 0x48000A, 0x160007, + 0x001075, 0x010042, 0x282C0A, 0x281D12, + 0x282512, 0x001F32, 0x1E0007, 0x0E0007, + 0x001975, 0x010042, 0x002DF5, 0x0D004A, + 0x10000A, 0x009144, 0x20EA86, 0x010042, + 0x28340A, 0x000E5D, 0x00008D, 0x000375, + 0x000820, 0x010040, 0x05D2F4, 0x54D104, + 0x00735C, 0x218B86, 0x000007, 0x0C0007, + 0x080007, 0x0A0007, 0x02178D, 0x000810, + 0x08043A, 0x34B206, 0x000007, 0x219206, + 0x000007, 0x080007, 0x002275, 0x010042, + 0x20000A, 0x002104, 0x225886, 0x001E2D, + 0x0002F5, 0x010042, 0x08000A, 0x000904, + 0x21CA86, 0x000007, 0x002010, 0x30043A, + 0x00057D, 0x0180C3, 0x08000A, 0x028924, + 0x280502, 0x280C02, 0x0A810D, 0x000820, + 0x0002F5, 0x010040, 0x220007, 0x0004FD, + 0x018042, 0x70000A, 0x030000, 0x007020, + 0x07FA06, 0x018040, 0x022B8D, 0x000810, + 0x08043A, 0x2CAA06, 0x000007, 0x0002FD, + 0x018042, 0x08000A, 0x000904, 0x22C286, + 0x000007, 0x020206, 0x000007, 0x000875, + 0x0009FD, 0x00010D, 0x234206, 0x000295, + 0x000B75, 0x00097D, 0x00000D, 0x000515, + 0x010042, 0x18000A, 0x001904, 0x2A0086, + 0x0006F5, 0x001020, 0x010040, 0x0004F5, + 0x000820, 0x010040, 0x000775, 0x010042, + 0x09804A, 0x10000A, 0x001124, 0x000904, + 0x23F286, 0x000815, 0x080102, 0x101204, + 0x241206, 0x000575, 0x081204, 0x000007, + 0x100102, 0x000575, 0x000425, 0x021124, + 0x100102, 0x000820, 0x031060, 0x010040, + 0x001924, 0x2A0086, 0x00008D, 0x000464, + 0x009D04, 0x291086, 0x180102, 0x000575, + 0x010042, 0x28040A, 0x00018D, 0x000924, + 0x280D02, 0x00000D, 0x000924, 0x281502, + 0x10000D, 0x000820, 0x0002F5, 0x010040, + 0x200007, 0x001175, 0x0002FD, 0x018042, + 0x08000A, 0x000904, 0x24FA86, 0x000007, + 0x000100, 0x080B20, 0x130B60, 0x1B0B60, + 0x030A60, 0x010040, 0x050042, 0x3D004A, + 0x35004A, 0x2D004A, 0x20000A, 0x0006F5, + 0x010042, 0x28140A, 0x0004F5, 0x010042, + 0x08000A, 0x000315, 0x010D04, 0x260286, + 0x004015, 0x000095, 0x010D04, 0x25F086, + 0x100022, 0x10002A, 0x261A06, 0x000007, + 0x333104, 0x2AA904, 0x000007, 0x032124, + 0x280502, 0x284402, 0x001124, 0x400102, + 0x000424, 0x000424, 0x003224, 0x00292C, + 0x00636C, 0x277386, 0x000007, 0x02B164, + 0x000464, 0x000464, 0x00008D, 0x000A64, + 0x280D02, 0x10008D, 0x000820, 0x0002F5, + 0x010040, 0x220007, 0x00008D, 0x38B904, + 0x000007, 0x03296C, 0x30010A, 0x0002F5, + 0x010042, 0x08000A, 0x000904, 0x270286, + 0x000007, 0x00212C, 0x28050A, 0x00316C, + 0x00046C, 0x00046C, 0x28450A, 0x001124, + 0x006B64, 0x100102, 0x00008D, 0x01096C, + 0x280D0A, 0x10010D, 0x000820, 0x0002F5, + 0x010040, 0x220007, 0x004124, 0x000424, + 0x000424, 0x003224, 0x300102, 0x032944, + 0x27FA86, 0x000007, 0x300002, 0x0004F5, + 0x010042, 0x08000A, 0x000315, 0x010D04, + 0x284086, 0x003124, 0x000464, 0x300102, + 0x0002F5, 0x010042, 0x08000A, 0x000904, + 0x284A86, 0x000007, 0x284402, 0x003124, + 0x300502, 0x003924, 0x300583, 0x000883, + 0x0005F5, 0x010042, 0x28040A, 0x00008D, + 0x008124, 0x280D02, 0x00008D, 0x008124, + 0x281502, 0x10018D, 0x000820, 0x0002F5, + 0x010040, 0x220007, 0x001025, 0x000575, + 0x030042, 0x09004A, 0x10000A, 0x0A0904, + 0x121104, 0x000007, 0x001020, 0x050860, + 0x050040, 0x0006FD, 0x018042, 0x09004A, + 0x10000A, 0x0000A5, 0x0A0904, 0x121104, + 0x000007, 0x000820, 0x019060, 0x010040, + 0x0002F5, 0x010042, 0x08000A, 0x000904, + 0x29CA86, 0x000007, 0x244206, 0x000007, + 0x000606, 0x000007, 0x0002F5, 0x010042, + 0x08000A, 0x000904, 0x2A1A86, 0x000007, + 0x000100, 0x080B20, 0x138B60, 0x1B8B60, + 0x238B60, 0x2B8B60, 0x338B60, 0x3B8B60, + 0x438B60, 0x4B8B60, 0x538B60, 0x5B8B60, + 0x638B60, 0x6B8B60, 0x738B60, 0x7B8B60, + 0x038F60, 0x0B8F60, 0x138F60, 0x1B8F60, + 0x238F60, 0x2B8F60, 0x338F60, 0x3B8F60, + 0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60, + 0x638F60, 0x6B8F60, 0x738F60, 0x7B8F60, + 0x038A60, 0x000606, 0x018040, 0x00008D, + 0x000A64, 0x280D02, 0x000A24, 0x00027D, + 0x018042, 0x10000A, 0x001224, 0x0003FD, + 0x018042, 0x08000A, 0x000904, 0x2C0A86, + 0x000007, 0x00018D, 0x000A24, 0x000464, + 0x000464, 0x080102, 0x000924, 0x000424, + 0x000424, 0x100102, 0x02000D, 0x009144, + 0x2C6186, 0x000007, 0x0001FD, 0x018042, + 0x08000A, 0x000A44, 0x2C4386, 0x018042, + 0x0A000D, 0x000820, 0x0002FD, 0x018040, + 0x200007, 0x00027D, 0x001020, 0x000606, + 0x018040, 0x0002F5, 0x010042, 0x08000A, + 0x000904, 0x2CB286, 0x000007, 0x00037D, + 0x018042, 0x08000A, 0x000904, 0x2CE286, + 0x000007, 0x000075, 0x002E7D, 0x010042, + 0x0B804A, 0x000020, 0x000904, 0x000686, + 0x010040, 0x31844A, 0x30048B, 0x000883, + 0x00008D, 0x000810, 0x28143A, 0x00008D, + 0x000810, 0x280C3A, 0x000675, 0x010042, + 0x08000A, 0x003815, 0x010924, 0x280502, + 0x0B000D, 0x000820, 0x0002F5, 0x010040, + 0x000606, 0x220007, 0x000464, 0x000464, + 0x000606, 0x000007, 0x000134, 0x007F8D, + 0x00093C, 0x281D12, 0x282512, 0x001F32, + 0x0E0007, 0x00010D, 0x00037D, 0x000820, + 0x018040, 0x05D2F4, 0x000007, 0x080007, + 0x00037D, 0x018042, 0x08000A, 0x000904, + 0x2E8A86, 0x000007, 0x000606, 0x000007, + 0x000007, 0x000012, 0x100007, 0x320007, + 0x600007, 0x460007, 0x100080, 0x48001A, + 0x004904, 0x2EF186, 0x000007, 0x001210, + 0x58003A, 0x000145, 0x5C5D04, 0x000007, + 0x000080, 0x48001A, 0x004904, 0x2F4186, + 0x000007, 0x001210, 0x50003A, 0x005904, + 0x2F9886, 0x000045, 0x0000C5, 0x7FFFF5, + 0x7FFF7D, 0x07D524, 0x004224, 0x500102, + 0x200502, 0x000082, 0x40001A, 0x004104, + 0x2FC986, 0x000007, 0x003865, 0x40001A, + 0x004020, 0x00104D, 0x04C184, 0x31AB86, + 0x000040, 0x040007, 0x000165, 0x000145, + 0x004020, 0x000040, 0x000765, 0x080080, + 0x40001A, 0x004104, 0x305986, 0x000007, + 0x001210, 0x40003A, 0x004104, 0x30B286, + 0x00004D, 0x0000CD, 0x004810, 0x20043A, + 0x000882, 0x40001A, 0x004104, 0x30C186, + 0x000007, 0x004820, 0x005904, 0x319886, + 0x000040, 0x0007E5, 0x200480, 0x2816A0, + 0x3216E0, 0x3A16E0, 0x4216E0, 0x021260, + 0x000040, 0x000032, 0x400075, 0x00007D, + 0x07D574, 0x200512, 0x000082, 0x40001A, + 0x004104, 0x317186, 0x000007, 0x038A06, + 0x640007, 0x0000E5, 0x000020, 0x000040, + 0x000A65, 0x000020, 0x020040, 0x020040, + 0x000040, 0x000165, 0x000042, 0x70000A, + 0x007104, 0x323286, 0x000007, 0x060007, + 0x019A06, 0x640007, 0x050000, 0x007020, + 0x000040, 0x038A06, 0x640007, 0x000007, + 0x00306D, 0x028860, 0x029060, 0x08000A, + 0x028860, 0x008040, 0x100012, 0x00100D, + 0x009184, 0x32D186, 0x000E0D, 0x009184, + 0x33E186, 0x000007, 0x300007, 0x001020, + 0x003B6D, 0x008040, 0x000080, 0x08001A, + 0x000904, 0x32F186, 0x000007, 0x001220, + 0x000DED, 0x008040, 0x008042, 0x10000A, + 0x40000D, 0x109544, 0x000007, 0x001020, + 0x000DED, 0x008040, 0x008042, 0x20040A, + 0x000082, 0x08001A, 0x000904, 0x338186, + 0x000007, 0x003B6D, 0x008042, 0x08000A, + 0x000E15, 0x010984, 0x342B86, 0x600007, + 0x08001A, 0x000C15, 0x010984, 0x341386, + 0x000020, 0x1A0007, 0x0002ED, 0x008040, + 0x620007, 0x00306D, 0x028042, 0x0A804A, + 0x000820, 0x0A804A, 0x000606, 0x10804A, + 0x000007, 0x282512, 0x001F32, 0x05D2F4, + 0x54D104, 0x00735C, 0x000786, 0x000007, + 0x0C0007, 0x0A0007, 0x1C0007, 0x003465, + 0x020040, 0x004820, 0x025060, 0x40000A, + 0x024060, 0x000040, 0x454944, 0x000007, + 0x004020, 0x003AE5, 0x000040, 0x0028E5, + 0x000042, 0x48000A, 0x004904, 0x39F886, + 0x002C65, 0x000042, 0x40000A, 0x0000D5, + 0x454104, 0x000007, 0x000655, 0x054504, + 0x368286, 0x0001D5, 0x054504, 0x368086, + 0x002B65, 0x000042, 0x003AE5, 0x50004A, + 0x40000A, 0x45C3D4, 0x000007, 0x454504, + 0x000007, 0x0000CD, 0x444944, 0x000007, + 0x454504, 0x000007, 0x00014D, 0x554944, + 0x000007, 0x045144, 0x367986, 0x002C65, + 0x000042, 0x48000A, 0x4CD104, 0x000007, + 0x04C144, 0x368386, 0x000007, 0x160007, + 0x002CE5, 0x040042, 0x40000A, 0x004020, + 0x000040, 0x002965, 0x000042, 0x40000A, + 0x004104, 0x36F086, 0x000007, 0x002402, + 0x383206, 0x005C02, 0x0025E5, 0x000042, + 0x40000A, 0x004274, 0x002AE5, 0x000042, + 0x40000A, 0x004274, 0x500112, 0x0029E5, + 0x000042, 0x40000A, 0x004234, 0x454104, + 0x000007, 0x004020, 0x000040, 0x003EE5, + 0x000020, 0x000040, 0x002DE5, 0x400152, + 0x50000A, 0x045144, 0x37DA86, 0x0000C5, + 0x003EE5, 0x004020, 0x000040, 0x002BE5, + 0x000042, 0x40000A, 0x404254, 0x000007, + 0x002AE5, 0x004020, 0x000040, 0x500132, + 0x040134, 0x005674, 0x0029E5, 0x020042, + 0x42000A, 0x000042, 0x50000A, 0x05417C, + 0x0028E5, 0x000042, 0x48000A, 0x0000C5, + 0x4CC144, 0x38A086, 0x0026E5, 0x0027E5, + 0x020042, 0x40004A, 0x50000A, 0x00423C, + 0x00567C, 0x0028E5, 0x004820, 0x000040, + 0x281D12, 0x282512, 0x001F72, 0x002965, + 0x000042, 0x40000A, 0x004104, 0x393A86, + 0x0E0007, 0x160007, 0x1E0007, 0x003EE5, + 0x000042, 0x40000A, 0x004104, 0x397886, + 0x002D65, 0x000042, 0x28340A, 0x003465, + 0x020042, 0x42004A, 0x004020, 0x4A004A, + 0x50004A, 0x05D2F4, 0x54D104, 0x00735C, + 0x39E186, 0x000007, 0x000606, 0x080007, + 0x0C0007, 0x080007, 0x0A0007, 0x0001E5, + 0x020045, 0x004020, 0x000060, 0x000365, + 0x000040, 0x002E65, 0x001A20, 0x0A1A60, + 0x000040, 0x003465, 0x020042, 0x42004A, + 0x004020, 0x4A004A, 0x000606, 0x50004A, + 0x0017FD, 0x018042, 0x08000A, 0x000904, + 0x225A86, 0x000007, 0x00107D, 0x018042, + 0x0011FD, 0x33804A, 0x19804A, 0x20000A, + 0x000095, 0x2A1144, 0x01A144, 0x3B9086, + 0x00040D, 0x00B184, 0x3B9186, 0x0018FD, + 0x018042, 0x0010FD, 0x09804A, 0x38000A, + 0x000095, 0x010924, 0x003A64, 0x3B8186, + 0x000007, 0x003904, 0x3B9286, 0x000007, + 0x3B9A06, 0x00000D, 0x00008D, 0x000820, + 0x00387D, 0x018040, 0x700002, 0x00117D, + 0x018042, 0x00197D, 0x29804A, 0x30000A, + 0x380002, 0x003124, 0x000424, 0x000424, + 0x002A24, 0x280502, 0x00068D, 0x000810, + 0x28143A, 0x00750D, 0x00B124, 0x002264, + 0x3D0386, 0x284402, 0x000810, 0x280C3A, + 0x0B800D, 0x000820, 0x0002FD, 0x018040, + 0x200007, 0x00758D, 0x00B124, 0x100102, + 0x012144, 0x3E4986, 0x001810, 0x10003A, + 0x00387D, 0x018042, 0x08000A, 0x000904, + 0x3E4886, 0x030000, 0x3E4A06, 0x0000BD, + 0x00008D, 0x023164, 0x000A64, 0x280D02, + 0x0B808D, 0x000820, 0x0002FD, 0x018040, + 0x200007, 0x00387D, 0x018042, 0x08000A, + 0x000904, 0x3E3286, 0x030000, 0x0002FD, + 0x018042, 0x08000A, 0x000904, 0x3D8286, + 0x000007, 0x002810, 0x28043A, 0x00750D, + 0x030924, 0x002264, 0x280D02, 0x02316C, + 0x28450A, 0x0B810D, 0x000820, 0x0002FD, + 0x018040, 0x200007, 0x00008D, 0x000A24, + 0x3E4A06, 0x100102, 0x001810, 0x10003A, + 0x0000BD, 0x003810, 0x30043A, 0x00187D, + 0x018042, 0x0018FD, 0x09804A, 0x20000A, + 0x0000AD, 0x028924, 0x07212C, 0x001010, + 0x300583, 0x300D8B, 0x3014BB, 0x301C83, + 0x002083, 0x00137D, 0x038042, 0x33844A, + 0x33ACCB, 0x33B4CB, 0x33BCCB, 0x33C4CB, + 0x33CCCB, 0x33D4CB, 0x305C8B, 0x006083, + 0x001E0D, 0x0005FD, 0x018042, 0x20000A, + 0x020924, 0x00068D, 0x00A96C, 0x00009D, + 0x0002FD, 0x018042, 0x08000A, 0x000904, + 0x3F6A86, 0x000007, 0x280502, 0x280D0A, + 0x284402, 0x001810, 0x28143A, 0x0C008D, + 0x000820, 0x0002FD, 0x018040, 0x220007, + 0x003904, 0x225886, 0x001E0D, 0x00057D, + 0x018042, 0x20000A, 0x020924, 0x0000A5, + 0x0002FD, 0x018042, 0x08000A, 0x000904, + 0x402A86, 0x000007, 0x280502, 0x280C02, + 0x002010, 0x28143A, 0x0C010D, 0x000820, + 0x0002FD, 0x018040, 0x225A06, 0x220007, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000 +}; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/Makefile linux/drivers/sound/Makefile --- v2.4.0-test1/linux/drivers/sound/Makefile Thu May 11 15:30:07 2000 +++ linux/drivers/sound/Makefile Tue Jun 20 07:52:36 2000 @@ -67,6 +67,7 @@ obj-$(CONFIG_SOUND_AWE32_SYNTH) += awe_wave.o obj-$(CONFIG_SOUND_VIA82CXXX) += via82cxxx_audio.o ac97_codec.o +obj-$(CONFIG_SOUND_YMPCI) += ymf_sb.o sb_lib.o uart401.o obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o obj-$(CONFIG_SOUND_VWSND) += vwsnd.o diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/ac97_codec.c linux/drivers/sound/ac97_codec.c --- v2.4.0-test1/linux/drivers/sound/ac97_codec.c Tue May 23 15:31:35 2000 +++ linux/drivers/sound/ac97_codec.c Tue Jun 20 07:52:36 2000 @@ -21,7 +21,7 @@ * * History * v0.4 Mar 15 2000 Ollie Lho - * dual codec support verified with 4 channel output + * dual codecs support verified with 4 channels output * v0.3 Feb 22 2000 Ollie Lho * bug fix for record mask setting * v0.2 Feb 10 2000 Ollie Lho @@ -332,9 +332,10 @@ /* else, write the first set in the mask as the output */ /* clear out current set value first (AC97 supports only 1 input!) */ - val = (1 << ac97_rm2oss[codec->codec_read(codec, AC97_RECORD_SELECT)&0x07]); - if (mask != val) mask &= ~val; - + val = (1 << ac97_rm2oss[codec->codec_read(codec, AC97_RECORD_SELECT) & 0x07]); + if (mask != val) + mask &= ~val; + val = ffs(mask); val = ac97_oss_rm[val-1]; val |= val << 8; /* set both channels */ @@ -423,7 +424,7 @@ switch (_IOC_NR(cmd)) { case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ if (!codec->recmask_io) return -EINVAL; - if(!val) return 0; + if (!val) return 0; if (!(val &= codec->record_sources)) return -EINVAL; codec->recmask_io(codec, 0, val); @@ -449,6 +450,7 @@ { int len = 0, cap, extid, val, id1, id2; struct ac97_codec *codec; + int is_ac97_20 = 0; if ((codec = data) == NULL) return -ENODEV; @@ -462,6 +464,7 @@ extid &= ~((1<<2)|(1<<4)|(1<<5)|(1<<10)|(1<<11)|(1<<12)|(1<<13)); len += sprintf (page+len, "AC97 Version : %s\n", extid ? "2.0 or later" : "1.0"); + if (extid) is_ac97_20 = 1; cap = codec->codec_read(codec, AC97_RESET); len += sprintf (page+len, "Capabilities :%s%s%s%s%s%s\n", @@ -500,6 +503,7 @@ val & 0x0100 ? "MIC2" : "MIC1", val & 0x0080 ? "on" : "off"); + extid = codec->codec_read(codec, AC97_EXTENDED_ID); cap = extid; len += sprintf (page+len, "Ext Capabilities :%s%s%s%s%s%s%s\n", cap & 0x0001 ? " -var rate PCM audio-" : "", @@ -509,10 +513,37 @@ cap & 0x0080 ? " -PCM surround DAC-" : "", cap & 0x0100 ? " -PCM LFE DAC-" : "", cap & 0x0200 ? " -slot/DAC mappings-" : ""); + if (is_ac97_20) { + len += sprintf (page+len, "Front DAC rate : %d\n", + codec->codec_read(codec, AC97_PCM_FRONT_DAC_RATE)); + } return len; } +/** + * ac97_probe_codec - Initialize and setup AC97-compatible codec + * @codec: (in/out) Kernel info for a single AC97 codec + * + * Reset the AC97 codec, then initialize the mixer and + * the rest of the @codec structure. + * + * The codec_read and codec_write fields of @codec are + * required to be setup and working when this function + * is called. All other fields are set by this function. + * + * codec_wait field of @codec can optionally be provided + * when calling this function. If codec_wait is not %NULL, + * this function will call codec_wait any time it is + * necessary to wait for the audio chip to reach the + * codec-ready state. If codec_wait is %NULL, then + * the default behavior is to call schedule_timeout. + * Currently codec_wait is used to wait for AC97 codec + * reset to complete. + * + * Returns 1 (true) on success, or 0 (false) on failure. + */ + int ac97_probe_codec(struct ac97_codec *codec) { u16 id1, id2; @@ -520,8 +551,19 @@ int i; /* probing AC97 codec, AC97 2.0 says that bit 15 of register 0x00 (reset) should - be read zero. Probing of AC97 in this way is not reliable, it is not even SAFE !! */ + * be read zero. + * + * FIXME: is the following comment outdated? -jgarzik + * Probing of AC97 in this way is not reliable, it is not even SAFE !! + */ codec->codec_write(codec, AC97_RESET, 0L); + + /* also according to spec, we wait for codec-ready state */ + if (codec->codec_wait) + codec->codec_wait(codec); + else + schedule_timeout(5); + if ((audio = codec->codec_read(codec, AC97_RESET)) & 0x8000) { printk(KERN_ERR "ac97_codec: %s ac97 codec not present\n", codec->id ? "Secondary" : "Primary"); @@ -546,8 +588,8 @@ } if (codec->name == NULL) codec->name = "Unknown"; - printk(KERN_INFO "ac97_codec: AC97 %s codec, vendor id1: 0x%04x, " - "id2: 0x%04x (%s)\n", audio ? "Audio" : (modem ? "Modem" : ""), + printk(KERN_INFO "ac97_codec: AC97%s codec, id: 0x%04x:0x%04x (%s)\n", + audio ? " audio" : (modem ? " modem" : ""), id1, id2, codec->name); return ac97_init_mixer(codec); @@ -595,11 +637,6 @@ } return 1; -} - -static int ac97_init_modem(struct ac97_codec *codec) -{ - return 0; } static int sigmatel_init(struct ac97_codec * codec) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/awe_wave.c linux/drivers/sound/awe_wave.c --- v2.4.0-test1/linux/drivers/sound/awe_wave.c Mon Mar 27 08:08:28 2000 +++ linux/drivers/sound/awe_wave.c Mon Jun 19 13:42:41 2000 @@ -3252,7 +3252,7 @@ int removed = 0; prev = NULL; - for (p = sf->infos; p; prev = p, p = next) { + for (p = sf->infos; p; p = next) { next = p->next; if (p->type == V_ST_NORMAL && p->bank == bank && p->instr == instr) { @@ -3266,8 +3266,11 @@ sf->num_info--; removed++; kfree(p); - } + } else + prev = p; } + if (removed) + rebuild_preset_list(); return removed; } @@ -3318,7 +3321,7 @@ } break; case AWE_WR_REPLACE: - /* replace mode - remoe the instrument if it already exists */ + /* replace mode - remove the instrument if it already exists */ remove_info(sf, hdr.bank, hdr.instr); break; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/cmpci.c linux/drivers/sound/cmpci.c --- v2.4.0-test1/linux/drivers/sound/cmpci.c Tue May 23 15:31:35 2000 +++ linux/drivers/sound/cmpci.c Tue Jun 20 07:52:36 2000 @@ -1161,7 +1161,6 @@ return -ENODEV; VALIDATE_STATE(s); file->private_data = s; - MOD_INC_USE_COUNT; return 0; } @@ -1170,7 +1169,6 @@ struct cm_state *s = (struct cm_state *)file->private_data; VALIDATE_STATE(s); - MOD_DEC_USE_COUNT; return 0; } @@ -1180,6 +1178,7 @@ } static /*const*/ struct file_operations cm_mixer_fops = { + owner: THIS_MODULE, llseek: cm_llseek, ioctl: cm_ioctl_mixdev, open: cm_open_mixdev, @@ -1765,7 +1764,6 @@ set_fmt(s, fmtm, fmts); s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); up(&s->open_sem); - MOD_INC_USE_COUNT; return 0; } @@ -1788,11 +1786,11 @@ s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); up(&s->open_sem); wake_up(&s->open_wait); - MOD_DEC_USE_COUNT; return 0; } static /*const*/ struct file_operations cm_audio_fops = { + owner: THIS_MODULE, llseek: cm_llseek, read: cm_read, write: cm_write, @@ -2012,7 +2010,6 @@ spin_unlock_irqrestore(&s->lock, flags); s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE); up(&s->open_sem); - MOD_INC_USE_COUNT; return 0; } @@ -2062,11 +2059,11 @@ spin_unlock_irqrestore(&s->lock, flags); up(&s->open_sem); wake_up(&s->open_wait); - MOD_DEC_USE_COUNT; return 0; } static /*const*/ struct file_operations cm_midi_fops = { + owner: THIS_MODULE, llseek: cm_llseek, read: cm_midi_read, write: cm_midi_write, @@ -2207,7 +2204,6 @@ outb(1, s->iosynth+3); /* enable OPL3 */ s->open_mode |= FMODE_DMFM; up(&s->open_sem); - MOD_INC_USE_COUNT; return 0; } @@ -2227,11 +2223,11 @@ } up(&s->open_sem); wake_up(&s->open_wait); - MOD_DEC_USE_COUNT; return 0; } static /*const*/ struct file_operations cm_dmfm_fops = { + owner: THIS_MODULE, llseek: cm_llseek, ioctl: cm_dmfm_ioctl, open: cm_dmfm_open, @@ -2321,6 +2317,8 @@ (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A, pcidev)) || (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B, pcidev)) || (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738, pcidev)))) { + if (pci_enable_device(pcidev)) + continue; if (pcidev->irq == 0) continue; if (!(s = kmalloc(sizeof(struct cm_state), GFP_KERNEL))) { @@ -2345,7 +2343,7 @@ init_MUTEX(&s->open_sem); spin_lock_init(&s->lock); s->magic = CM_MAGIC; - s->iobase = pcidev->resource[0].start; + s->iobase = pci_resource_start(pcidev, 0); s->iosynth = 0x388; s->iomidi = 0x330; spin_lock_init(&s->lock); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/cs4232.c linux/drivers/sound/cs4232.c --- v2.4.0-test1/linux/drivers/sound/cs4232.c Tue Mar 7 14:32:26 2000 +++ linux/drivers/sound/cs4232.c Mon Jun 19 13:42:41 2000 @@ -346,6 +346,11 @@ if(synthio != -1) printk(KERN_WARNING "cs4232: wavefront support not enabled in this driver.\n"); #endif + if(io==-1||irq==-1||dma==-1) + { + printk(KERN_ERR "cs4232: Must set io, irq and dma.\n"); + return -ENODEV; + } cfg.io_base = io; cfg.irq = irq; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/dmasound/dmasound_awacs.c linux/drivers/sound/dmasound/dmasound_awacs.c --- v2.4.0-test1/linux/drivers/sound/dmasound/dmasound_awacs.c Tue May 23 15:31:35 2000 +++ linux/drivers/sound/dmasound/dmasound_awacs.c Tue Jun 20 07:52:36 2000 @@ -1184,7 +1184,7 @@ } static struct timer_list beep_timer = { - NULL, NULL, 0, 0, awacs_nosound + function: awacs_nosound }; static void awacs_mksound(unsigned int hz, unsigned int ticks) @@ -1703,14 +1703,14 @@ case SOUND_MIXER_READ_RECLEV: data = awacs_get_volume(awacs_reg[0], 4); return IOCTL_OUT(arg, data); - case MIXER_WRITE(SOUND_MASK_MONITOR): + case MIXER_WRITE(SOUND_MIXER_MONITOR): IOCTL_IN(arg, data); awacs_reg[1] &= ~MASK_LOOPTHRU; if ((data & 0xff) >= 50) awacs_reg[1] |= MASK_LOOPTHRU; awacs_write(MASK_ADDR1 | awacs_reg[1]); /* fall through */ - case MIXER_READ(SOUND_MASK_MONITOR): + case MIXER_READ(SOUND_MIXER_MONITOR): data = (awacs_reg[1] & MASK_LOOPTHRU)? 100: 0; return IOCTL_OUT(arg, data); } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/dmasound/dmasound_core.c linux/drivers/sound/dmasound/dmasound_core.c --- v2.4.0-test1/linux/drivers/sound/dmasound/dmasound_core.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/dmasound/dmasound_core.c Tue Jun 20 07:52:36 2000 @@ -494,7 +494,6 @@ static int mixer_open(struct inode *inode, struct file *file) { - MOD_INC_USE_COUNT; dmasound.mach.open(); mixer.busy = 1; return 0; @@ -504,7 +503,6 @@ { mixer.busy = 0; dmasound.mach.release(); - MOD_DEC_USE_COUNT; return 0; } static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, @@ -533,6 +531,7 @@ static struct file_operations mixer_fops = { + owner: THIS_MODULE, llseek: sound_lseek, ioctl: mixer_ioctl, open: mixer_open, @@ -843,11 +842,9 @@ { int rc; - MOD_INC_USE_COUNT; dmasound.mach.open(); if ((rc = write_sq_open(file)) || (rc = read_sq_open(file))) { dmasound.mach.release(); - MOD_DEC_USE_COUNT; return rc; } @@ -917,7 +914,6 @@ write_sq_release_buffers(); read_sq_release_buffers(); dmasound.mach.release(); - MOD_DEC_USE_COUNT; /* There is probably a DOS atack here. They change the mode flag. */ /* XXX add check here */ @@ -1029,6 +1025,7 @@ static struct file_operations sq_fops = { + owner: THIS_MODULE, llseek: sound_lseek, write: sq_write, ioctl: sq_ioctl, @@ -1088,7 +1085,6 @@ if (state.busy) return -EBUSY; - MOD_INC_USE_COUNT; dmasound.mach.open(); state.ptr = 0; state.busy = 1; @@ -1147,7 +1143,6 @@ { state.busy = 0; dmasound.mach.release(); - MOD_DEC_USE_COUNT; return 0; } @@ -1165,8 +1160,8 @@ return n; } -static struct file_operations state_fops = -{ +static struct file_operations state_fops = { + owner: THIS_MODULE, llseek: sound_lseek, read: state_read, open: state_open, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/emu10k1/audio.c linux/drivers/sound/emu10k1/audio.c --- v2.4.0-test1/linux/drivers/sound/emu10k1/audio.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/audio.c Tue Jun 20 07:52:36 2000 @@ -969,12 +969,9 @@ if (entry == &emu10k1_devs) return -ENODEV; - MOD_INC_USE_COUNT; - if ((wave_dev = (struct emu10k1_wavedevice *) kmalloc(sizeof(struct emu10k1_wavedevice), GFP_KERNEL)) == NULL) { ERROR(); - MOD_DEC_USE_COUNT; return -EINVAL; } @@ -988,7 +985,6 @@ if ((woinst = (struct woinst *) kmalloc(sizeof(struct woinst), GFP_KERNEL)) == NULL) { ERROR(); - MOD_DEC_USE_COUNT; return -ENODEV; } @@ -1055,7 +1051,6 @@ if ((wiinst = (struct wiinst *) kmalloc(sizeof(struct wiinst), GFP_KERNEL)) == NULL) { ERROR(); - MOD_DEC_USE_COUNT; return -ENODEV; } @@ -1176,7 +1171,6 @@ kfree(wave_dev); wake_up_interruptible(&card->open_wait); - MOD_DEC_USE_COUNT; return 0; } @@ -1430,6 +1424,7 @@ } struct file_operations emu10k1_audio_fops = { + owner:THIS_MODULE, llseek:emu10k1_audio_llseek, read:emu10k1_audio_read, write:emu10k1_audio_write, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/emu10k1/main.c linux/drivers/sound/emu10k1/main.c --- v2.4.0-test1/linux/drivers/sound/emu10k1/main.c Tue May 23 15:31:35 2000 +++ linux/drivers/sound/emu10k1/main.c Tue Jun 20 07:52:36 2000 @@ -622,7 +622,7 @@ pci_set_master(pci_dev); - card->iobase = pci_dev->resource[0].start; + card->iobase = pci_resource_start(pci_dev, 0); if (request_region(card->iobase, EMU10K1_EXTENT, card_names[pci_id->driver_data]) == NULL) { printk(KERN_ERR "emu10k1: IO space in use\n"); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/emu10k1/midi.c linux/drivers/sound/emu10k1/midi.c --- v2.4.0-test1/linux/drivers/sound/emu10k1/midi.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/midi.c Tue Jun 20 07:52:36 2000 @@ -98,14 +98,11 @@ if (entry == &emu10k1_devs) return -ENODEV; - MOD_INC_USE_COUNT; - /* Wait for device to become free */ down(&card->open_sem); while (card->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) { if (file->f_flags & O_NONBLOCK) { up(&card->open_sem); - MOD_DEC_USE_COUNT; return -EBUSY; } @@ -113,7 +110,6 @@ interruptible_sleep_on(&card->open_wait); if (signal_pending(current)) { - MOD_DEC_USE_COUNT; return -ERESTARTSYS; } @@ -121,7 +117,6 @@ } if ((midi_dev = (struct emu10k1_mididevice *) kmalloc(sizeof(*midi_dev), GFP_KERNEL)) == NULL) { - MOD_DEC_USE_COUNT; return -EINVAL; } @@ -145,14 +140,12 @@ != CTSTATUS_SUCCESS) { ERROR(); kfree(midi_dev); - MOD_DEC_USE_COUNT; return -ENODEV; } /* Add two buffers to receive sysex buffer */ if (midiin_add_buffer(midi_dev, &midihdr1) != CTSTATUS_SUCCESS) { kfree(midi_dev); - MOD_DEC_USE_COUNT; return -ENODEV; } @@ -161,7 +154,6 @@ kfree(midihdr1->data); kfree(midihdr1); kfree(midi_dev); - MOD_DEC_USE_COUNT; return -ENODEV; } } @@ -175,7 +167,6 @@ != CTSTATUS_SUCCESS) { ERROR(); kfree(midi_dev); - MOD_DEC_USE_COUNT; return -ENODEV; } } @@ -237,8 +228,6 @@ up(&card->open_sem); wake_up_interruptible(&card->open_wait); - MOD_DEC_USE_COUNT; - return 0; } @@ -438,6 +427,7 @@ /* MIDI file operations */ struct file_operations emu10k1_midi_fops = { + owner:THIS_MODULE, read:emu10k1_midi_read, write:emu10k1_midi_write, poll:emu10k1_midi_poll, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/emu10k1/mixer.c linux/drivers/sound/emu10k1/mixer.c --- v2.4.0-test1/linux/drivers/sound/emu10k1/mixer.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/mixer.c Tue Jun 20 07:52:36 2000 @@ -803,8 +803,6 @@ if (entry == &emu10k1_devs) return -ENODEV; - MOD_INC_USE_COUNT; - file->private_data = card; return 0; } @@ -812,11 +810,11 @@ static int emu10k1_mixer_release(struct inode *inode, struct file *file) { DPF(3, "emu10k1_mixer_release()\n"); - MOD_DEC_USE_COUNT; return 0; } struct file_operations emu10k1_mixer_fops = { + owner:THIS_MODULE, llseek:emu10k1_mixer_llseek, ioctl:emu10k1_mixer_ioctl, open:emu10k1_mixer_open, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c --- v2.4.0-test1/linux/drivers/sound/es1370.c Mon Jun 19 16:32:00 2000 +++ linux/drivers/sound/es1370.c Tue Jun 20 07:52:36 2000 @@ -1030,7 +1030,6 @@ } VALIDATE_STATE(s); file->private_data = s; - MOD_INC_USE_COUNT; return 0; } @@ -1039,7 +1038,6 @@ struct es1370_state *s = (struct es1370_state *)file->private_data; VALIDATE_STATE(s); - MOD_DEC_USE_COUNT; return 0; } @@ -1049,6 +1047,7 @@ } static /*const*/ struct file_operations es1370_mixer_fops = { + owner: THIS_MODULE, llseek: es1370_llseek, ioctl: es1370_ioctl_mixdev, open: es1370_open_mixdev, @@ -1710,7 +1709,6 @@ spin_unlock_irqrestore(&s->lock, flags); s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); up(&s->open_sem); - MOD_INC_USE_COUNT; return 0; } @@ -1734,11 +1732,11 @@ s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); wake_up(&s->open_wait); up(&s->open_sem); - MOD_DEC_USE_COUNT; return 0; } static /*const*/ struct file_operations es1370_audio_fops = { + owner: THIS_MODULE, llseek: es1370_llseek, read: es1370_read, write: es1370_write, @@ -1975,7 +1973,7 @@ return 0; case SNDCTL_DSP_GETOSPACE: - if (!(s->ctrl & CTRL_DAC2_EN) && (val = prog_dmabuf_dac1(s)) != 0) + if (!(s->ctrl & CTRL_DAC1_EN) && (val = prog_dmabuf_dac1(s)) != 0) return val; spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); @@ -2116,7 +2114,6 @@ spin_unlock_irqrestore(&s->lock, flags); s->open_mode |= FMODE_DAC; up(&s->open_sem); - MOD_INC_USE_COUNT; return 0; } @@ -2132,11 +2129,11 @@ s->open_mode &= ~FMODE_DAC; wake_up(&s->open_wait); up(&s->open_sem); - MOD_DEC_USE_COUNT; return 0; } static /*const*/ struct file_operations es1370_dac_fops = { + owner: THIS_MODULE, llseek: es1370_llseek, write: es1370_write_dac, poll: es1370_poll_dac, @@ -2357,7 +2354,6 @@ spin_unlock_irqrestore(&s->lock, flags); s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE); up(&s->open_sem); - MOD_INC_USE_COUNT; return 0; } @@ -2403,11 +2399,11 @@ spin_unlock_irqrestore(&s->lock, flags); wake_up(&s->open_wait); up(&s->open_sem); - MOD_DEC_USE_COUNT; return 0; } static /*const*/ struct file_operations es1370_midi_fops = { + owner: THIS_MODULE, llseek: es1370_llseek, read: es1370_midi_read, write: es1370_midi_write, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c --- v2.4.0-test1/linux/drivers/sound/es1371.c Mon Jun 19 16:32:00 2000 +++ linux/drivers/sound/es1371.c Tue Jun 20 07:52:36 2000 @@ -168,6 +168,7 @@ #define CT5880REV_CT5880_C 0x02 #define ES1371REV_ES1371_B 0x09 #define EV1938REV_EV1938_A 0x00 +#define ES1371REV_ES1373_8 0x08 #define ES1371_MAGIC ((PCI_VENDOR_ID_ENSONIQ<<16)|PCI_DEVICE_ID_ENSONIQ_ES1371) @@ -1216,7 +1217,6 @@ } VALIDATE_STATE(s); file->private_data = s; - MOD_INC_USE_COUNT; return 0; } @@ -1225,7 +1225,6 @@ struct es1371_state *s = (struct es1371_state *)file->private_data; VALIDATE_STATE(s); - MOD_DEC_USE_COUNT; return 0; } @@ -1238,6 +1237,7 @@ } static /*const*/ struct file_operations es1371_mixer_fops = { + owner: THIS_MODULE, llseek: es1371_llseek, ioctl: es1371_ioctl_mixdev, open: es1371_open_mixdev, @@ -1895,7 +1895,6 @@ spin_unlock_irqrestore(&s->lock, flags); s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); up(&s->open_sem); - MOD_INC_USE_COUNT; return 0; } @@ -1918,11 +1917,11 @@ s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); up(&s->open_sem); wake_up(&s->open_wait); - MOD_DEC_USE_COUNT; return 0; } static /*const*/ struct file_operations es1371_audio_fops = { + owner: THIS_MODULE, llseek: es1371_llseek, read: es1371_read, write: es1371_write, @@ -2150,7 +2149,7 @@ return 0; case SNDCTL_DSP_GETOSPACE: - if (!(s->ctrl & CTRL_DAC2_EN) && (val = prog_dmabuf_dac1(s)) != 0) + if (!(s->ctrl & CTRL_DAC1_EN) && (val = prog_dmabuf_dac1(s)) != 0) return val; spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); @@ -2290,7 +2289,6 @@ spin_unlock_irqrestore(&s->lock, flags); s->open_mode |= FMODE_DAC; up(&s->open_sem); - MOD_INC_USE_COUNT; return 0; } @@ -2306,11 +2304,11 @@ s->open_mode &= ~FMODE_DAC; up(&s->open_sem); wake_up(&s->open_wait); - MOD_DEC_USE_COUNT; return 0; } static /*const*/ struct file_operations es1371_dac_fops = { + owner: THIS_MODULE, llseek: es1371_llseek, write: es1371_write_dac, poll: es1371_poll_dac, @@ -2531,7 +2529,6 @@ spin_unlock_irqrestore(&s->lock, flags); s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE); up(&s->open_sem); - MOD_INC_USE_COUNT; return 0; } @@ -2576,11 +2573,11 @@ spin_unlock_irqrestore(&s->lock, flags); up(&s->open_sem); wake_up(&s->open_wait); - MOD_DEC_USE_COUNT; return 0; } static /*const*/ struct file_operations es1371_midi_fops = { + owner: THIS_MODULE, llseek: es1371_llseek, read: es1371_midi_read, write: es1371_midi_write, @@ -2778,7 +2775,8 @@ /* if we are a 5880 turn on the AC97 */ if (s->vendor == PCI_VENDOR_ID_ENSONIQ && ((s->device == PCI_DEVICE_ID_ENSONIQ_CT5880 && s->rev == CT5880REV_CT5880_C) || - (s->device == PCI_DEVICE_ID_ENSONIQ_ES1371 && s->rev == ES1371REV_CT5880_A))) { + (s->device == PCI_DEVICE_ID_ENSONIQ_ES1371 && s->rev == ES1371REV_CT5880_A) || + (s->device == PCI_DEVICE_ID_ENSONIQ_ES1371 && s->rev == ES1371REV_ES1373_8))) { cssr |= CSTAT_5880_AC97_RST; outl(cssr, s->io+ES1371_REG_STATUS); /* need to delay around 20ms(bleech) to give diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c --- v2.4.0-test1/linux/drivers/sound/esssolo1.c Mon Jun 19 16:32:00 2000 +++ linux/drivers/sound/esssolo1.c Tue Jun 20 07:52:36 2000 @@ -909,7 +909,6 @@ } VALIDATE_STATE(s); file->private_data = s; - MOD_INC_USE_COUNT; return 0; } @@ -918,7 +917,6 @@ struct solo1_state *s = (struct solo1_state *)file->private_data; VALIDATE_STATE(s); - MOD_DEC_USE_COUNT; return 0; } @@ -928,6 +926,7 @@ } static /*const*/ struct file_operations solo1_mixer_fops = { + owner: THIS_MODULE, llseek: solo1_llseek, ioctl: solo1_ioctl_mixdev, open: solo1_open_mixdev, @@ -1526,7 +1525,6 @@ s->open_mode &= ~(FMODE_READ | FMODE_WRITE); wake_up(&s->open_wait); up(&s->open_sem); - MOD_DEC_USE_COUNT; return 0; } @@ -1572,12 +1570,12 @@ s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0; s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); up(&s->open_sem); - MOD_INC_USE_COUNT; prog_codec(s); return 0; } static /*const*/ struct file_operations solo1_audio_fops = { + owner: THIS_MODULE, llseek: solo1_llseek, read: solo1_read, write: solo1_write, @@ -1869,7 +1867,6 @@ spin_unlock_irqrestore(&s->lock, flags); s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE); up(&s->open_sem); - MOD_INC_USE_COUNT; return 0; } @@ -1915,11 +1912,11 @@ spin_unlock_irqrestore(&s->lock, flags); wake_up(&s->open_wait); up(&s->open_sem); - MOD_DEC_USE_COUNT; return 0; } static /*const*/ struct file_operations solo1_midi_fops = { + owner: THIS_MODULE, llseek: solo1_llseek, read: solo1_midi_read, write: solo1_midi_write, @@ -2075,7 +2072,6 @@ outb(1, s->sbbase+3); /* enable OPL3 */ s->open_mode |= FMODE_DMFM; up(&s->open_sem); - MOD_INC_USE_COUNT; return 0; } @@ -2096,11 +2092,11 @@ release_region(s->sbbase, FMSYNTH_EXTENT); wake_up(&s->open_wait); up(&s->open_sem); - MOD_DEC_USE_COUNT; return 0; } static /*const*/ struct file_operations solo1_dmfm_fops = { + owner: THIS_MODULE, llseek: solo1_llseek, ioctl: solo1_dmfm_ioctl, open: solo1_dmfm_open, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/i810_audio.c linux/drivers/sound/i810_audio.c --- v2.4.0-test1/linux/drivers/sound/i810_audio.c Thu May 11 15:30:08 2000 +++ linux/drivers/sound/i810_audio.c Tue Jun 20 07:52:36 2000 @@ -46,6 +46,18 @@ * There is no midi support, no synth support. Use timidity. To get * esd working you need to use esd -r 48000 as it won't probe 48KHz * by default. mpg123 can't handle 48Khz only audio so use xmms. + * + * Fix The Sound On Dell + * + * Not everyone uses 48KHz. We know of no way to detect this reliably + * and certainly not to get the right data. If your i810 audio sounds + * stupid you may need to investigate other speeds. According to Analog + * they tend to use a 14.318MHz clock which gives you a base rate of + * 41194Hz. + * + * This is available via the 'ftsodell=1' option. + * + * If you need to force a specific rate set the clocking= option */ #include @@ -74,10 +86,17 @@ #ifndef PCI_DEVICE_ID_INTEL_82901 #define PCI_DEVICE_ID_INTEL_82901 0x2425 #endif +#ifndef PCI_DEVICE_ID_INTEL_ICH2 +#define PCI_DEVICE_ID_INTEL_ICH2 0x2445 +#endif #ifndef PCI_DEVICE_ID_INTEL_440MX #define PCI_DEVICE_ID_INTEL_440MX 0x7195 #endif +static int ftsodell=0; +static int clocking=48000; + + #define ADC_RUNNING 1 #define DAC_RUNNING 2 @@ -180,13 +199,15 @@ enum { ICH82801AA = 0, ICH82901AB, - INTEL440MX + INTEL440MX, + INTELICH2, }; static char * card_names[] = { "Intel ICH 82801AA", "Intel ICH 82901AB", - "Intel 440MX" + "Intel 440MX", + "Intel ICH2" }; static struct pci_device_id i810_pci_tbl [] __initdata = { @@ -196,6 +217,8 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, ICH82901AB}, {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_440MX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTEL440MX}, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH2}, {0,} }; @@ -295,7 +318,6 @@ static struct i810_card *devs = NULL; static int i810_open_mixdev(struct inode *inode, struct file *file); -static int i810_release_mixdev(struct inode *inode, struct file *file); static int i810_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); static loff_t i810_llseek(struct file *file, loff_t offset, int origin); @@ -363,12 +385,27 @@ struct ac97_codec *codec=state->card->ac97_codec[0]; if(!(state->card->ac97_features&0x0001)) - return 48000; + { + dmabuf->rate = clocking; + return clocking; + } if (rate > 48000) rate = 48000; - if (rate < 4000) - rate = 4000; + if (rate < 8000) + rate = 8000; + + /* + * Adjust for misclocked crap + */ + + rate = ( rate * clocking)/48000; + + /* Analog codecs can go lower via magic registers but others + might not */ + + if(rate < 8000) + rate = 8000; /* Power down the DAC */ dacp=i810_ac97_get(codec, AC97_POWER_CONTROL); @@ -378,10 +415,10 @@ i810_ac97_set(codec, AC97_PCM_FRONT_DAC_RATE, rate); rp=i810_ac97_get(codec, AC97_PCM_FRONT_DAC_RATE); - printk("DAC rate set to %d Returned %d\n", - rate, (int)rp); +// printk("DAC rate set to %d Returned %d\n", +// rate, (int)rp); - rate=rp; + rate=(rp * 48000) / clocking; /* Power it back up */ i810_ac97_set(codec, AC97_POWER_CONTROL, dacp); @@ -402,25 +439,41 @@ struct ac97_codec *codec=state->card->ac97_codec[0]; if(!(state->card->ac97_features&0x0001)) - return 48000; + { + dmabuf->rate = clocking; + return clocking; + } if (rate > 48000) rate = 48000; - if (rate < 4000) - rate = 4000; + if (rate < 8000) + rate = 8000; + + /* + * Adjust for misclocked crap + */ + + rate = ( rate * clocking)/48000; + + /* Analog codecs can go lower via magic registers but others + might not */ + + if(rate < 8000) + rate = 8000; + /* Power down the ADC */ dacp=i810_ac97_get(codec, AC97_POWER_CONTROL); i810_ac97_set(codec, AC97_POWER_CONTROL, dacp|0x0100); /* Load the rate and read the effective rate */ - i810_ac97_set(codec, AC97_PCM_LR_ADC_RATE, rate); - rp=i810_ac97_get(codec, AC97_PCM_LR_ADC_RATE); + i810_ac97_set(codec, AC97_PCM_LR_DAC_RATE, rate); + rp=i810_ac97_get(codec, AC97_PCM_LR_DAC_RATE); - printk("ADC rate set to %d Returned %d\n", - rate, (int)rp); +// printk("ADC rate set to %d Returned %d\n", +// rate, (int)rp); - rate=rp; + rate = (rp * 48000) / clocking; /* Power it back up */ i810_ac97_set(codec, AC97_POWER_CONTROL, dacp); @@ -1547,7 +1600,6 @@ state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); up(&state->open_sem); - MOD_INC_USE_COUNT; return 0; } @@ -1582,11 +1634,11 @@ /* we're covered by the open_sem */ up(&state->open_sem); - MOD_DEC_USE_COUNT; return 0; } static /*const*/ struct file_operations i810_audio_fops = { + owner: THIS_MODULE, llseek: i810_llseek, read: i810_read, write: i810_write, @@ -1640,13 +1692,6 @@ match: file->private_data = card->ac97_codec[i]; - MOD_INC_USE_COUNT; - return 0; -} - -static int i810_release_mixdev(struct inode *inode, struct file *file) -{ - MOD_DEC_USE_COUNT; return 0; } @@ -1659,10 +1704,10 @@ } static /*const*/ struct file_operations i810_mixer_fops = { + owner: THIS_MODULE, llseek: i810_llseek, ioctl: i810_ioctl_mixdev, open: i810_open_mixdev, - release: i810_release_mixdev, }; /* AC97 codec initialisation. */ @@ -1828,8 +1873,11 @@ kfree(card); } + MODULE_AUTHOR(""); MODULE_DESCRIPTION("Intel 810 audio support"); +MODULE_PARM(ftsodell, "i"); +MODULE_PARM(clocking, "i"); #define I810_MODULE_NAME "intel810_audio" @@ -1845,6 +1893,9 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; + if(ftsodell==1) + clocking=41194; + printk(KERN_INFO "Intel 810 + AC97 Audio, version " DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/maestro.c linux/drivers/sound/maestro.c --- v2.4.0-test1/linux/drivers/sound/maestro.c Fri May 12 14:18:55 2000 +++ linux/drivers/sound/maestro.c Tue Jun 20 07:52:36 2000 @@ -236,6 +236,7 @@ #include #include #include +#include #include static int maestro_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *d); @@ -2081,7 +2082,6 @@ return -ENODEV; file->private_data = card; - MOD_INC_USE_COUNT; return 0; } @@ -2091,7 +2091,6 @@ VALIDATE_CARD(card); - MOD_DEC_USE_COUNT; return 0; } @@ -2105,6 +2104,7 @@ } static /*const*/ struct file_operations ess_mixer_fops = { + owner: THIS_MODULE, llseek: ess_llseek, ioctl: ess_ioctl_mixdev, open: ess_open_mixdev, @@ -2976,7 +2976,6 @@ s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); up(&s->open_sem); - MOD_INC_USE_COUNT; return 0; } @@ -3007,11 +3006,11 @@ } up(&s->open_sem); wake_up(&s->open_wait); - MOD_DEC_USE_COUNT; return 0; } static struct file_operations ess_audio_fops = { + owner: THIS_MODULE, llseek: ess_llseek, read: ess_read, write: ess_write, @@ -3447,11 +3446,7 @@ return 1; } -#ifdef MODULE -int init_module(void) -#else -int SILLY_MAKE_INIT(init_maestro(void)) -#endif +int __init init_maestro(void) { struct pci_dev *pcidev = NULL; int foundone = 0; @@ -3558,8 +3553,6 @@ nuke_maestros(); } -#else /* MODULE */ -__initcall(init_maestro); #endif /* --------------------------------------------------------------------- */ @@ -3718,3 +3711,5 @@ out: return 0; } + +module_init(init_maestro); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/msnd.c linux/drivers/sound/msnd.c --- v2.4.0-test1/linux/drivers/sound/msnd.c Fri Jan 21 18:19:17 2000 +++ linux/drivers/sound/msnd.c Mon Jun 19 13:42:41 2000 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/nm256_audio.c linux/drivers/sound/nm256_audio.c --- v2.4.0-test1/linux/drivers/sound/nm256_audio.c Tue Mar 7 14:32:26 2000 +++ linux/drivers/sound/nm256_audio.c Mon Jun 19 13:42:41 2000 @@ -18,6 +18,7 @@ #include #include #include +#include #include "sound_config.h" #include "soundmodule.h" #include "nm256.h" diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/pas2_mixer.c linux/drivers/sound/pas2_mixer.c --- v2.4.0-test1/linux/drivers/sound/pas2_mixer.c Tue Mar 7 14:32:26 2000 +++ linux/drivers/sound/pas2_mixer.c Mon Jun 19 13:42:41 2000 @@ -69,7 +69,7 @@ if (pas_model == 4) { - outw(data | (data << 8), (ioaddr ^ translate_code) - 1); + outw(data | (data << 8), (ioaddr + translate_code) - 1); outb((0x80), 0); } else pas_write(data, ioaddr); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c --- v2.4.0-test1/linux/drivers/sound/sb_card.c Tue May 23 15:31:35 2000 +++ linux/drivers/sound/sb_card.c Mon Jun 19 13:42:41 2000 @@ -42,6 +42,9 @@ * * 06-05-2000 added another card. Daniel M. Newman * + * 25-05-2000 Added Creative SB AWE64 Gold (CTL00B2). + * Pål-Kristian Engstad + * */ #include @@ -265,6 +268,11 @@ 0,0,0,0, 0,1,1,-1}, {"Sound Blaster 16", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0028), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster 16", ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0029), ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0,0,0,0, @@ -341,6 +349,11 @@ 0,1,1,-1}, {"Sound Blaster AWE 64 Gold", ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x009E), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster AWE 64 Gold", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00B2), ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044), 0,0,0,0, 0,1,1,-1}, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/skeleton.c linux/drivers/sound/skeleton.c --- v2.4.0-test1/linux/drivers/sound/skeleton.c Thu Jan 14 22:59:47 1999 +++ linux/drivers/sound/skeleton.c Mon Jun 19 13:42:41 2000 @@ -78,9 +78,9 @@ * For the example we will only initialise the MSS */ - iobase = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; - mssbase = pcidev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK; - mpubase = pcidev->base_address[2] & PCI_BASE_ADDRESS_IO_MASK; + iobase = pci_resource_start(pcidev, 0); + mssbase = pci_resource_start(pcidev, 1); + mpubase = pci_resource_start(pcidev, 2); /* * Reset the board @@ -160,6 +160,8 @@ while((pcidev = pci_find_device(PCI_VENDOR_MYIDENT, PCI_DEVICE_ID_MYIDENT_MYCARD1, pcidev))!=NULL) { + if (pci_enable_device(pcidev)) + continue; count+=mycard_install(pcidev); if(count) return 0; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c --- v2.4.0-test1/linux/drivers/sound/sonicvibes.c Mon Jun 19 16:32:00 2000 +++ linux/drivers/sound/sonicvibes.c Tue Jun 20 07:52:36 2000 @@ -1240,7 +1240,6 @@ } VALIDATE_STATE(s); file->private_data = s; - MOD_INC_USE_COUNT; return 0; } @@ -1249,7 +1248,6 @@ struct sv_state *s = (struct sv_state *)file->private_data; VALIDATE_STATE(s); - MOD_DEC_USE_COUNT; return 0; } @@ -1259,6 +1257,7 @@ } static /*const*/ struct file_operations sv_mixer_fops = { + owner: THIS_MODULE, llseek: sv_llseek, ioctl: sv_ioctl_mixdev, open: sv_open_mixdev, @@ -1900,7 +1899,6 @@ set_fmt(s, fmtm, fmts); s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); up(&s->open_sem); - MOD_INC_USE_COUNT; return 0; } @@ -1923,11 +1921,11 @@ s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); wake_up(&s->open_wait); up(&s->open_sem); - MOD_DEC_USE_COUNT; return 0; } static /*const*/ struct file_operations sv_audio_fops = { + owner: THIS_MODULE, llseek: sv_llseek, read: sv_read, write: sv_write, @@ -2157,7 +2155,6 @@ spin_unlock_irqrestore(&s->lock, flags); s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE); up(&s->open_sem); - MOD_INC_USE_COUNT; return 0; } @@ -2203,11 +2200,11 @@ spin_unlock_irqrestore(&s->lock, flags); wake_up(&s->open_wait); up(&s->open_sem); - MOD_DEC_USE_COUNT; return 0; } static /*const*/ struct file_operations sv_midi_fops = { + owner: THIS_MODULE, llseek: sv_llseek, read: sv_midi_read, write: sv_midi_write, @@ -2357,7 +2354,6 @@ outb(1, s->iosynth+3); /* enable OPL3 */ s->open_mode |= FMODE_DMFM; up(&s->open_sem); - MOD_INC_USE_COUNT; return 0; } @@ -2377,11 +2373,11 @@ } wake_up(&s->open_wait); up(&s->open_sem); - MOD_DEC_USE_COUNT; return 0; } static /*const*/ struct file_operations sv_dmfm_fops = { + owner: THIS_MODULE, llseek: sv_llseek, ioctl: sv_dmfm_ioctl, open: sv_dmfm_open, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/sound_core.c linux/drivers/sound/sound_core.c --- v2.4.0-test1/linux/drivers/sound/sound_core.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/sound_core.c Wed Jun 21 22:31:02 2000 @@ -175,9 +175,9 @@ sprintf (name_buf, "%s", name); else sprintf (name_buf, "%s%d", name, (r - low) / SOUND_STEP); - s->de = devfs_register (devfs_handle, name_buf, 0, + s->de = devfs_register (devfs_handle, name_buf, DEVFS_FL_NONE, SOUND_MAJOR, s->unit_minor, - S_IFCHR | mode, 0, 0, fops, NULL); + S_IFCHR | mode, fops, NULL); return r; } @@ -456,6 +456,7 @@ static struct file_operations soundcore_fops= { + owner: THIS_MODULE, open: soundcore_open, }; @@ -508,12 +509,25 @@ s = __look_for_unit(chain, unit); } if (s) { - file->f_op=s->unit_fops; + /* + * We rely upon the fact that we can't be unloaded while the + * subdriver is there, so if ->open() is successful we can + * safely drop the reference counter and if it is not we can + * revert to old ->f_op. Ugly, indeed, but that's the cost of + * switching ->f_op in the first place. + */ + int err = 0; + struct file_operations *old_fops = file->f_op; + file->f_op = fops_get(s->unit_fops); spin_unlock(&sound_loader_lock); if(file->f_op->open) - return file->f_op->open(inode,file); - else - return 0; + err = file->f_op->open(inode,file); + if (err) { + fops_put(file->f_op); + file->f_op = fops_get(old_fops); + } + fops_put(old_fops); + return err; } spin_unlock(&sound_loader_lock); return -ENODEV; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c --- v2.4.0-test1/linux/drivers/sound/soundcard.c Thu May 11 15:30:08 2000 +++ linux/drivers/sound/soundcard.c Wed Jun 21 22:31:02 2000 @@ -495,8 +495,8 @@ return 0; } -struct file_operations oss_sound_fops = -{ +struct file_operations oss_sound_fops = { + owner: THIS_MODULE, llseek: sound_lseek, read: sound_read, write: sound_write, @@ -565,9 +565,9 @@ for (j = 0; j < num || j == 0; j++) { soundcard_make_name (name_buf, dev_list[i].name, j); if (do_register) - devfs_register (NULL, name_buf, 0, DEVFS_FL_NONE, + devfs_register (NULL, name_buf, DEVFS_FL_NONE, SOUND_MAJOR, dev_list[i].minor+ (j* 0x10), - S_IFCHR | dev_list[i].mode, 0, 0, + S_IFCHR | dev_list[i].mode, &oss_sound_fops, NULL); else { devfs_handle_t de; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/trident.c linux/drivers/sound/trident.c --- v2.4.0-test1/linux/drivers/sound/trident.c Tue May 23 15:31:35 2000 +++ linux/drivers/sound/trident.c Tue Jun 20 07:52:36 2000 @@ -1,6 +1,6 @@ /* * - * Trident 4D-Wave/SiS 7018 OSS driver for Linux 2.2.x + * Trident 4D-Wave/SiS 7018/ALi 5451 OSS driver for Linux 2.2.x * * Driver: Alan Cox * @@ -12,6 +12,7 @@ * Hacked up by: * Aaron Holtzman * Ollie Lho SiS 7018 Audio Core Support + * Ching Ling Lee ALi 5451 Audio Core Support * * * This program is free software; you can redistribute it and/or modify @@ -29,10 +30,14 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * History - * v0.14.3 May 20 2000 Aaron Holtzman - * Fix kfree'd memory access in release - * Fix race in open while looking for a free virtual channel slot - * remove open_wait wq (which appears to be unused) + * v0.14.5 May 23 2000 Ollie Lho + * Misc bug fix from the Net + * v0.14.4 May 20 2000 Aaron Holtzman + * Fix kfree'd memory access in release + * Fix race in open while looking for a free virtual channel slot + * remove open_wait wq (which appears to be unused) + * v0.14.3 May 10 2000 Ollie Lho + * fixed a small bug in trident_update_ptr, xmms 1.0.1 no longer uses 100% CPU * v0.14.2 Mar 29 2000 Ching Ling Lee * Add clear to silence advance in trident_update_ptr * fix invalid data of the end of the sound @@ -109,13 +114,13 @@ #include "trident.h" -#define DRIVER_VERSION "0.14" +#define DRIVER_VERSION "0.14.5" /* magic numbers to protect our data structures */ #define TRIDENT_CARD_MAGIC 0x5072696E /* "Prin" */ #define TRIDENT_STATE_MAGIC 0x63657373 /* "cess" */ -#define TRIDENT_DMA_MASK 0x3fffffff /* DMA buffer mask for pci_alloc_consist */ +#define TRIDENT_DMA_MASK 0x3fffffff /* DMA buffer mask for pci_alloc_consist */ #define NR_HW_CH 32 @@ -151,7 +156,7 @@ "ALi Audio Accelerator" }; -static struct pci_device_id trident_pci_tbl [] __initdata = { +static struct pci_device_id trident_pci_tbl [] __devinitdata = { {PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TRIDENT_4D_DX}, {PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX, @@ -314,7 +319,6 @@ static u16 trident_ac97_get(struct ac97_codec *codec, u8 reg); static int trident_open_mixdev(struct inode *inode, struct file *file); -static int trident_release_mixdev(struct inode *inode, struct file *file); static int trident_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); static loff_t trident_llseek(struct file *file, loff_t offset, int origin); @@ -438,16 +442,14 @@ #endif } -static u32 trident_get_interrupt_mask (struct trident_card * card, - unsigned int b) +static u32 trident_get_interrupt_mask (struct trident_card * card, unsigned int channel) { - struct trident_pcm_bank *bank = &card->banks[b]; + struct trident_pcm_bank *bank = &card->banks[channel]; u32 addr = bank->addresses->aint; return inl(TRID_REG(card, addr)); } -static int trident_check_channel_interrupt(struct trident_card * card, - unsigned int channel) +static int trident_check_channel_interrupt(struct trident_card * card, unsigned int channel) { unsigned int mask = 1 << (channel & 0x1f); u32 reg = trident_get_interrupt_mask (card, channel >> 5); @@ -460,8 +462,7 @@ return (reg & mask) ? TRUE : FALSE; } -static void trident_ack_channel_interrupt(struct trident_card * card, - unsigned int channel) +static void trident_ack_channel_interrupt(struct trident_card * card, unsigned int channel) { unsigned int mask = 1 << (channel & 0x1f); struct trident_pcm_bank *bank = &card->banks[channel >> 5]; @@ -537,8 +538,7 @@ } -static void trident_free_pcm_channel(struct trident_card *card, - unsigned int channel) +static void trident_free_pcm_channel(struct trident_card *card, int channel) { int bank; @@ -551,7 +551,7 @@ card->banks[bank].bitmap &= ~(1 << (channel)); } -static void ali_free_pcm_channel(struct trident_card *card, unsigned int channel) +static void ali_free_pcm_channel(struct trident_card *card, int channel) { int bank; @@ -574,18 +574,16 @@ if (channel > 63) return FALSE; - /* select hardware channel to write */ + /* select hardware channel to write */ outb(channel, TRID_REG(card, T4D_LFO_GC_CIR)); /* Output the channel registers, but don't write register three to an ALI chip. */ - for (i = 0; i < CHANNEL_REGS; i++) { if (i == 3 && card->pci_id == PCI_DEVICE_ID_ALI_5451) continue; outl(data[i], TRID_REG(card, CHANNEL_START + 4*i)); } - return TRUE; } @@ -1141,7 +1139,7 @@ dmabuf->hwptr = hwptr; dmabuf->total_bytes += diff; - /* error handling and process wake up for DAC */ + /* error handling and process wake up for ADC */ if (dmabuf->enable == ADC_RUNNING) { if (dmabuf->mapped) { dmabuf->count -= diff; @@ -1171,7 +1169,10 @@ //there is invalid data in the end of half buffer if ((clear_cnt = half_dmasize - swptr) < 0) clear_cnt += half_dmasize; - memset (dmabuf->rawbuf + swptr, silence, clear_cnt); //clear the invalid data + //clear the invalid data + memset (dmabuf->rawbuf + swptr, + silence, clear_cnt); + dmabuf->endcleared = 1; } } else if (dmabuf->count < (signed) dmabuf->fragsize) { @@ -1181,12 +1182,15 @@ memset (dmabuf->rawbuf + swptr, silence, clear_cnt); dmabuf->endcleared = 1; } - } - /* since dma machine only interrupts at ESO and ESO/2, we sure have at - least half of dma buffer free, so wake up the process unconditionally */ - wake_up(&dmabuf->wait); + } + /* trident_update_ptr is called by interrupt handler or by process via + ioctl/poll, we only wake up the waiting process when we have more + than 1/2 buffer of data to process (always true for interrupt handler) */ + if (dmabuf->count > (signed)dmabuf->dmasize/2) + wake_up(&dmabuf->wait); } } + /* error handling and process wake up for DAC */ if (dmabuf->enable == DAC_RUNNING) { if (dmabuf->mapped) { @@ -1203,9 +1207,11 @@ __stop_dac(state); dmabuf->error++; } - /* since dma machine only interrupts at ESO and ESO/2, we sure have at - least half of dma buffer free, so wake up the process unconditionally */ - wake_up(&dmabuf->wait); + /* trident_update_ptr is called by interrupt handler or by process via + ioctl/poll, we only wake up the waiting process when we have more + than 1/2 buffer free (always true for interrupt handler) */ + if (dmabuf->count < (signed)dmabuf->dmasize/2) + wake_up(&dmabuf->wait); } } dmabuf->update_flag &= ~ALI_ADDRESS_INT_UPDATE; @@ -1336,7 +1342,8 @@ ret = 0; if (state->card->pci_id == PCI_DEVICE_ID_ALI_5451) - outl ( inl (TRID_REG (state->card, ALI_GLOBAL_CONTROL)) | ALI_PCM_IN_ENABLE, TRID_REG (state->card, ALI_GLOBAL_CONTROL)); + outl(inl(TRID_REG (state->card, ALI_GLOBAL_CONTROL)) | ALI_PCM_IN_ENABLE, + TRID_REG (state->card, ALI_GLOBAL_CONTROL)); while (count > 0) { spin_lock_irqsave(&state->card->lock, flags); @@ -1439,7 +1446,8 @@ if (state->card->pci_id == PCI_DEVICE_ID_ALI_5451) if (dmabuf->channel->num == ALI_PCM_IN_CHANNEL) - outl ( inl (TRID_REG (state->card, ALI_GLOBAL_CONTROL)) & ALI_PCM_IN_DISABLE, TRID_REG (state->card, ALI_GLOBAL_CONTROL)); + outl ( inl (TRID_REG (state->card, ALI_GLOBAL_CONTROL)) & + ALI_PCM_IN_DISABLE, TRID_REG (state->card, ALI_GLOBAL_CONTROL)); while (count > 0) { spin_lock_irqsave(&state->card->lock, flags); @@ -1912,8 +1920,9 @@ if (card->states[i] == NULL) { state = card->states[i] = (struct trident_state *) kmalloc(sizeof(struct trident_state), GFP_KERNEL); - if (state == NULL) + if (state == NULL) { return -ENOMEM; + } memset(state, 0, sizeof(struct trident_state)); dmabuf = &state->dmabuf; goto found_virt; @@ -1923,9 +1932,9 @@ card = card->next; } /* no more virtual channel avaiable */ - if (!state) + if (!state) { return -ENODEV; - + } found_virt: /* found a free virtual channel, allocate hardware channels */ if(file->f_mode & FMODE_READ) @@ -1946,7 +1955,6 @@ init_waitqueue_head(&dmabuf->wait); file->private_data = state; - /* set default sample format. According to OSS Programmer's Guide /dev/dsp should be default to unsigned 8-bits, mono, with sample rate 8kHz and /dev/dspW will accept 16-bits sample */ @@ -1991,11 +1999,10 @@ up(&card->open_sem); #ifdef DEBUG - printk(KERN_ERR "trident: open virtual channel %d, hard channel %d\n", - state->virt, - dmabuf->channel->num); + printk(KERN_ERR "trident: open virtual channel %d, hard channel %d\n", + state->virt, dmabuf->channel->num); #endif - MOD_INC_USE_COUNT; + return 0; } @@ -2020,7 +2027,6 @@ dealloc_dmabuf(state); state->card->free_pcm_channel(state->card, dmabuf->channel->num); } - if (file->f_mode & FMODE_READ) { stop_adc(state); dealloc_dmabuf(state); @@ -2033,11 +2039,11 @@ /* we're covered by the open_sem */ up(&card->open_sem); - MOD_DEC_USE_COUNT; return 0; } static /*const*/ struct file_operations trident_audio_fops = { + owner: THIS_MODULE, llseek: trident_llseek, read: trident_read, write: trident_write, @@ -2261,19 +2267,13 @@ card->ac97_codec[i]->dev_mixer == minor) goto match; - if (!card) + if (!card) { return -ENODEV; - + } match: file->private_data = card->ac97_codec[i]; - MOD_INC_USE_COUNT; - return 0; -} -static int trident_release_mixdev(struct inode *inode, struct file *file) -{ - MOD_DEC_USE_COUNT; return 0; } @@ -2286,10 +2286,10 @@ } static /*const*/ struct file_operations trident_mixer_fops = { + owner: THIS_MODULE, llseek: trident_llseek, ioctl: trident_ioctl_mixdev, open: trident_open_mixdev, - release: trident_release_mixdev, }; /* AC97 codec initialisation. */ @@ -2385,7 +2385,7 @@ } pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision); - iobase = pci_resource_start (pci_dev, 0); + iobase = pci_resource_start(pci_dev, 0); if (check_region(iobase, 256)) { printk(KERN_ERR "trident: can't allocate I/O space at 0x%4.4lx\n", iobase); @@ -2393,7 +2393,7 @@ } if (pci_enable_device(pci_dev)) - return -ENODEV; + return -ENODEV; if ((card = kmalloc(sizeof(struct trident_card), GFP_KERNEL)) == NULL) { printk(KERN_ERR "trident: out of memory\n"); @@ -2421,20 +2421,19 @@ printk(KERN_INFO "trident: %s found at IO 0x%04lx, IRQ %d\n", card_names[pci_id->driver_data], card->iobase, card->irq); - if(card->pci_id == PCI_DEVICE_ID_ALI_5451) - { + if(card->pci_id == PCI_DEVICE_ID_ALI_5451) { card->alloc_pcm_channel = ali_alloc_pcm_channel; card->alloc_rec_pcm_channel = ali_alloc_rec_pcm_channel; card->free_pcm_channel = ali_free_pcm_channel; card->address_interrupt = ali_address_interrupt; } - else - { + else { card->alloc_pcm_channel = trident_alloc_pcm_channel; card->alloc_rec_pcm_channel = trident_alloc_pcm_channel; card->free_pcm_channel = trident_free_pcm_channel; card->address_interrupt = trident_address_interrupt; } + /* claim our iospace and irq */ request_region(card->iobase, 256, card_names[pci_id->driver_data]); if (request_irq(card->irq, &trident_interrupt, SA_SHIRQ, @@ -2462,12 +2461,12 @@ } outl(0x00, TRID_REG(card, T4D_MUSICVOL_WAVEVOL)); - if (card->pci_id == PCI_DEVICE_ID_ALI_5451) - { + if (card->pci_id == PCI_DEVICE_ID_ALI_5451) { /* edited by HMSEO for GT sound */ #ifdef CONFIG_ALPHA_NAUTILUS - ac97_data = trident_ac97_get (card->ac97_codec[0], AC97_POWER_CONTROL); - trident_ac97_set (card->ac97_codec[0], AC97_POWER_CONTROL, ac97_data | ALI_EAPD_POWER_DOWN); + u16 ac97_data = trident_ac97_get (card->ac97_codec[0], AC97_POWER_CONTROL); + trident_ac97_set (card->ac97_codec[0], AC97_POWER_CONTROL, + ac97_data | ALI_EAPD_POWER_DOWN); #endif /* edited by HMSEO for GT sound*/ } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/via82cxxx_audio.c linux/drivers/sound/via82cxxx_audio.c --- v2.4.0-test1/linux/drivers/sound/via82cxxx_audio.c Tue May 23 15:31:35 2000 +++ linux/drivers/sound/via82cxxx_audio.c Tue Jun 20 07:52:36 2000 @@ -6,12 +6,16 @@ * See the "COPYING" file distributed with this software for more info. * * For a list of known bugs (errata) and documentation, - * see via82cxxx.txt in linux/Documentation/sound. + * see via-audio.pdf in linux/Documentation/DocBook. + * If this documentation does not exist, run "make pdfdocs". + * If "make pdfdocs" fails, obtain the documentation from + * the driver's Website at + * http://gtf.org/garzik/drivers/via82cxxx/ * */ -#define VIA_VERSION "1.1.6" +#define VIA_VERSION "1.1.8" #include @@ -304,7 +308,7 @@ static struct pci_device_id via_pci_tbl[] __initdata = { - { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, PCI_ANY_ID, PCI_ANY_ID, }, { 0, } }; MODULE_DEVICE_TABLE(pci,via_pci_tbl); @@ -325,12 +329,40 @@ * */ +/** + * via_chan_stop - Terminate DMA on specified PCM channel + * @iobase: PCI base address for SGD channel registers + * + * Terminate scatter-gather DMA operation for given + * channel (derived from @iobase), if DMA is active. + * + * Note that @iobase is not the PCI base address, + * but the PCI base address plus an offset to + * one of three PCM channels supported by the chip. + * + */ + static inline void via_chan_stop (int iobase) { if (inb (iobase + VIA_PCM_STATUS) & VIA_SGD_ACTIVE) outb (VIA_SGD_TERMINATE, iobase + VIA_PCM_CONTROL); } + +/** + * via_chan_status_clear - Clear status flags on specified DMA channel + * @iobase: PCI base address for SGD channel registers + * + * Clear any pending status flags for the given + * DMA channel (derived from @iobase), if any + * flags are asserted. + * + * Note that @iobase is not the PCI base address, + * but the PCI base address plus an offset to + * one of three PCM channels supported by the chip. + * + */ + static inline void via_chan_status_clear (int iobase) { u8 tmp = inb (iobase + VIA_PCM_STATUS); @@ -339,12 +371,33 @@ outb (tmp, iobase + VIA_PCM_STATUS); } + +/** + * sg_begin - Begin recording or playback on a PCM channel + * @chan: Channel for which DMA operation shall begin + * + * Start scatter-gather DMA for the given channel. + * + */ + static inline void sg_begin (struct via_channel *chan) { outb (VIA_SGD_START, chan->iobase + VIA_PCM_CONTROL); } +/** + * via_chan_bufs_in_use - Number of buffers waiting to be consumed + * @chan: Channel for which DMA buffers will be counted + * + * Count the number of buffers waiting to be consumed. For a + * playback operation, this is the number of buffers which have + * yet to be sent to the DAC. For a recording operation, this + * is the number of buffers waiting to be consumed by software + * calling read() system call. + * + */ + static inline int via_chan_bufs_in_use (struct via_channel *chan) { return atomic_read(&chan->next_buf) - @@ -352,12 +405,31 @@ } +/** + * via_chan_full - Check for no-free-buffers condition + * @chan: Channel for which DMA full condition will be checked + * + * Count the number of buffers waiting to be consumed, and return + * true (non-zero) if no buffers are available to be filled on the + * given DMA channel. + * + */ + static inline int via_chan_full (struct via_channel *chan) { return (via_chan_bufs_in_use (chan) == VIA_DMA_BUFFERS); } +/** + * via_chan_empty - Check for no-buffers-in-use condition + * @chan: Channel for which DMA empty condition will be checked + * + * Count the number of buffers waiting to be consumed, and return + * true (non-zero) if no buffers are currently in use. + * + */ + static inline int via_chan_empty (struct via_channel *chan) { return (atomic_read(&chan->next_buf) == @@ -372,6 +444,15 @@ * */ + +/** + * via_stop_everything - Stop all audio operations + * @card: Private info for specified board + * + * Stops all DMA operations and interrupts, and clear + * any pending status bits resulting from those operations. + */ + static void via_stop_everything (struct via_info *card) { DPRINTK ("ENTER\n"); @@ -402,6 +483,24 @@ } +/** + * via_set_rate - Set PCM rate for given channel + * @card: Private info for specified board + * @rate: Desired PCM sample rate, in Khz + * @inhale_deeply: Boolean. If non-zero (true), the recording sample rate + * is set. If zero (false), the playback sample rate + * is set. + * + * Sets the PCM sample rate for a channel. + * + * Values for @rate are clamped to a range of 4000 Khz through 48000 Khz, + * due to hardware constraints. + * + * FIXME: @inhale_deeply argument is ignored, and %AC97_PCM_FRONT_DAC_RATE + * is the only rate which is really set. This needs to be fixed when + * recording support is added. + */ + static int via_set_rate (struct via_info *card, unsigned rate, int inhale_deeply) { @@ -423,12 +522,32 @@ } +/** + * via_set_adc_rate - Set PCM rate for recording channel + * @card: Private info for specified board + * @rate: Desired PCM sample rate, in Khz + * + * Sets the PCM sample rate for a recording channel. + * + * FIXME: @inhale_deeply argument to via_set_rate is ignored, and %AC97_PCM_FRONT_DAC_RATE + * is the only rate which is really set. Thus, this function will + * not work until via_set_rate is fixed. + */ + static inline int via_set_adc_rate (struct via_info *card, int rate) { return via_set_rate (card, rate, 1); } +/** + * via_set_dac_rate - Set PCM rate for playback channel + * @card: Private info for specified board + * @rate: Desired PCM sample rate, in Khz + * + * Sets the PCM sample rate for a playback channel. + */ + static inline int via_set_dac_rate (struct via_info *card, int rate) { return via_set_rate (card, rate, 0); @@ -442,6 +561,27 @@ * */ +/** + * via_chan_init - Initialize PCM channel + * @card: Private audio chip info + * @chan: Channel to be initialized + * @chan_ofs: Offset from PCI address, which determines the + * set of SGD registers to use. + * + * Performs all the preparations necessary to begin + * using a PCM channel. + * + * Currently the preparations include allocating the + * scatter-gather DMA table and buffers, setting the + * PCM channel to a known state, and passing the + * address of the DMA table to the hardware. + * + * Note that special care is taken when passing the + * DMA table address to hardware, because it was found + * during driver development that the hardware did not + * always "take" the address. + */ + static int via_chan_init (struct via_info *card, struct via_channel *chan, long chan_ofs) { @@ -533,6 +673,20 @@ } +/** + * via_chan_free - Release a PCM channel + * @card: Private audio chip info + * @chan: Channel to be released + * + * Performs all the functions necessary to clean up + * an initialized channel. + * + * Currently these functions include disabled any + * active DMA operations, setting the PCM channel + * back to a known state, and releasing any allocated + * sound buffers. + */ + static void via_chan_free (struct via_info *card, struct via_channel *chan) { int i; @@ -575,6 +729,22 @@ } +/** + * via_chan_pcm_fmt - Update PCM channel settings + * @card: Private audio chip info + * @chan: Channel to be updated + * @reset: Boolean. If non-zero, channel will be reset + * to 8-bit mono mode. + * + * Stores the settings of the current PCM format, + * 8-bit or 16-bit, and mono/stereo, into the + * hardware settings for the specified channel. + * If @reset is non-zero, the channel is reset + * to 8-bit mono mode. Otherwise, the channel + * is set to the values stored in the channel + * information struct @chan. + */ + static void via_chan_pcm_fmt (struct via_info *card, struct via_channel *chan, int reset) { @@ -603,6 +773,14 @@ } +/** + * via_chan_clear - Stop DMA channel operation, and reset pointers + * @chan: Channel to be cleared + * + * Call via_chan_stop to halt DMA operations, and then resets + * all software pointers which track DMA operation. + */ + static void via_chan_clear (struct via_channel *chan) { via_chan_stop (chan->iobase); @@ -612,6 +790,21 @@ } +/** + * via_chan_set_speed - Set PCM sample rate for given channel + * @card: Private info for specified board + * @chan: Channel whose sample rate will be adjusted + * @val: New sample rate, in Khz + * + * Helper function for the %SNDCTL_DSP_SPEED ioctl. OSS semantics + * demand that all audio operations halt (if they are not already + * halted) when the %SNDCTL_DSP_SPEED is given. + * + * This function halts all audio operations for the given channel + * @chan, and then calls via_set_rate to set the audio hardware + * to the new rate. + */ + static int via_chan_set_speed (struct via_info *card, struct via_channel *chan, int val) { @@ -626,6 +819,21 @@ } +/** + * via_chan_set_fmt - Set PCM sample size for given channel + * @card: Private info for specified board + * @chan: Channel whose sample size will be adjusted + * @val: New sample size, use the %AFMT_xxx constants + * + * Helper function for the %SNDCTL_DSP_SETFMT ioctl. OSS semantics + * demand that all audio operations halt (if they are not already + * halted) when the %SNDCTL_DSP_SETFMT is given. + * + * This function halts all audio operations for the given channel + * @chan, and then calls via_chan_pcm_fmt to set the audio hardware + * to the new sample size, either 8-bit or 16-bit. + */ + static int via_chan_set_fmt (struct via_info *card, struct via_channel *chan, int val) { @@ -656,6 +864,21 @@ } +/** + * via_chan_set_stereo - Enable or disable stereo for a DMA channel + * @card: Private info for specified board + * @chan: Channel whose stereo setting will be adjusted + * @val: New sample size, use the %AFMT_xxx constants + * + * Helper function for the %SNDCTL_DSP_CHANNELS and %SNDCTL_DSP_STEREO ioctls. OSS semantics + * demand that all audio operations halt (if they are not already + * halted) when %SNDCTL_DSP_CHANNELS or SNDCTL_DSP_STEREO is given. + * + * This function halts all audio operations for the given channel + * @chan, and then calls via_chan_pcm_fmt to set the audio hardware + * to enable or disable stereo. + */ + static int via_chan_set_stereo (struct via_info *card, struct via_channel *chan, int val) { @@ -690,6 +913,14 @@ #if 0 +/** + * via_chan_dump_bufs - Display DMA table contents + * @chan: Channel whose DMA table will be displayed + * + * Debugging function which displays the contents of the + * scatter-gather DMA table for the given channel @chan. + */ + static void via_chan_dump_bufs (struct via_channel *chan) { int i; @@ -715,6 +946,15 @@ * */ +/** + * via_ac97_wait_idle - Wait until AC97 codec is not busy + * @card: Private info for specified board + * + * Sleep until the AC97 codec is no longer busy. + * Returns the final value read from the SGD + * register being polled. + */ + static u8 via_ac97_wait_idle (struct via_info *card) { u8 tmp8; @@ -740,6 +980,21 @@ } +/** + * via_ac97_read_reg - Read AC97 standard register + * @codec: Pointer to generic AC97 codec info + * @reg: Index of AC97 register to be read + * + * Read the value of a single AC97 codec register, + * as defined by the Intel AC97 specification. + * + * Defines the standard AC97 read-register operation + * required by the kernel's ac97_codec interface. + * + * Returns the 16-bit value stored in the specified + * register. + */ + static u16 via_ac97_read_reg (struct ac97_codec *codec, u8 reg) { u32 data; @@ -788,6 +1043,19 @@ } +/** + * via_ac97_write_reg - Write AC97 standard register + * @codec: Pointer to generic AC97 codec info + * @reg: Index of AC97 register to be written + * @value: Value to be written to AC97 register + * + * Write the value of a single AC97 codec register, + * as defined by the Intel AC97 specification. + * + * Defines the standard AC97 write-register operation + * required by the kernel's ac97_codec interface. + */ + static void via_ac97_write_reg (struct ac97_codec *codec, u8 reg, u16 value) { u32 data; @@ -829,8 +1097,6 @@ DPRINTK ("ENTER\n"); - MOD_INC_USE_COUNT; - pci_for_each_dev(pdev) { drvr = pci_dev_driver (pdev); if (drvr == &via_driver) { @@ -843,7 +1109,6 @@ } DPRINTK ("EXIT, returning -ENODEV\n"); - MOD_DEC_USE_COUNT; return -ENODEV; match: @@ -853,18 +1118,6 @@ return 0; } - -static int via_mixer_release (struct inode *inode, struct file *file) -{ - DPRINTK ("ENTER\n"); - - MOD_DEC_USE_COUNT; - - DPRINTK ("EXIT, returning 0\n"); - return 0; -} - - static int via_mixer_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { @@ -889,8 +1142,8 @@ static struct file_operations via_mixer_fops = { + owner: THIS_MODULE, open: via_mixer_open, - release: via_mixer_release, llseek: via_llseek, ioctl: via_mixer_ioctl, }; @@ -971,9 +1224,11 @@ VIA_CR41_VRA | VIA_CR41_AC97_RESET); udelay (100); +#if 0 /* this breaks on K7M */ /* disable legacy stuff */ pci_write_config_byte (pdev, 0x42, 0x00); udelay(10); +#endif /* route FM trap to IRQ, disable FM trap */ pci_write_config_byte (pdev, 0x48, 0x05); @@ -1097,50 +1352,36 @@ struct via_info *card = dev_id; struct via_channel *chan; u8 status; - int unhandled = 1; - static long intcount = 0; - assert (irq == card->pdev->irq); - - intcount++; - status = inb (card->baseaddr + 0x00); if (status) { assert (card->open_mode & FMODE_WRITE); chan = &card->ch_out; - unhandled = 0; if (status & VIA_SGD_FLAG) { assert ((status & VIA_SGD_EOL) == 0); outb (VIA_SGD_FLAG, chan->iobase + 0x00); - DPRINTK("FLAG intr, status=0x%02X, intcount=%ld\n", - status, intcount); + DPRINTK("FLAG intr, status=0x%02X\n", status); via_interrupt_write (chan); } if (status & VIA_SGD_EOL) { assert ((status & VIA_SGD_FLAG) == 0); outb (VIA_SGD_EOL, chan->iobase + 0x00); - DPRINTK("EOL intr, status=0x%02X, intcount=%ld\n", - status, intcount); + DPRINTK("EOL intr, status=0x%02X\n", status); via_interrupt_write (chan); } if (status & VIA_SGD_STOPPED) { outb (VIA_SGD_STOPPED, chan->iobase + 0x00); - DPRINTK("STOPPED intr, status=0x%02X, intcount=%ld\n", - status, intcount); + DPRINTK("STOPPED intr, status=0x%02X\n", status); } #if 0 via_chan_dump_bufs (&card->ch_out); #endif } - - if (unhandled) - printk (KERN_WARNING PFX "unhandled interrupt, st=%02x, st32=%08x\n", - status, inl (card->baseaddr + 0x84)); } @@ -1229,6 +1470,7 @@ */ static struct file_operations via_dsp_fops = { + owner: THIS_MODULE, open: via_dsp_open, release: via_dsp_release, read: via_dsp_read, @@ -1860,8 +2102,6 @@ DPRINTK ("ENTER, minor=%d, file->f_mode=0x%x\n", minor, file->f_mode); - MOD_INC_USE_COUNT; - if (file->f_mode & FMODE_READ) /* no input ATM */ goto err_out; @@ -1951,7 +2191,6 @@ card->open_mode &= ~file->f_mode; spin_unlock_irqrestore (&card->lock, flags); err_out: - MOD_DEC_USE_COUNT; DPRINTK("ERROR EXIT, returning %d\n", rc); return rc; } @@ -1981,7 +2220,6 @@ spin_unlock_irqrestore (&card->lock, flags); wake_up (&card->open_wait); - MOD_DEC_USE_COUNT; DPRINTK("EXIT, returning 0\n"); return 0; @@ -2331,6 +2569,7 @@ via_interrupt_cleanup (card); via_card_cleanup_proc (card); via_dsp_cleanup (card); + via_ac97_cleanup (card); release_region (pci_resource_start (pdev, 0), pci_resource_len (pdev, 0)); @@ -2360,12 +2599,9 @@ int rc; DPRINTK ("ENTER\n"); - - MOD_INC_USE_COUNT; rc = via_init_proc (); if (rc) { - MOD_DEC_USE_COUNT; DPRINTK ("EXIT, returning %d\n", rc); return rc; } @@ -2375,12 +2611,9 @@ if (rc == 0) pci_unregister_driver (&via_driver); via_cleanup_proc (); - MOD_DEC_USE_COUNT; DPRINTK ("EXIT, returning -ENODEV\n"); return -ENODEV; } - - MOD_DEC_USE_COUNT; DPRINTK ("EXIT, returning 0\n"); return 0; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/wavfront.c linux/drivers/sound/wavfront.c --- v2.4.0-test1/linux/drivers/sound/wavfront.c Fri Mar 10 16:40:44 2000 +++ linux/drivers/sound/wavfront.c Tue Jun 20 07:52:36 2000 @@ -1953,7 +1953,6 @@ { /* XXX fix me */ dev.opened = file->f_flags; - MOD_INC_USE_COUNT; return 0; } @@ -1962,7 +1961,6 @@ { dev.opened = 0; dev.debug = 0; - MOD_DEC_USE_COUNT; return 0; } @@ -1996,6 +1994,7 @@ } static /*const*/ struct file_operations wavefront_fops = { + owner: THIS_MODULE, llseek: wavefront_llseek, ioctl: wavefront_ioctl, open: wavefront_open, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/ymf_sb.c linux/drivers/sound/ymf_sb.c --- v2.4.0-test1/linux/drivers/sound/ymf_sb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/ymf_sb.c Tue Jun 20 07:52:36 2000 @@ -0,0 +1,867 @@ +/* + Legacy audio driver for YMF724, 740, 744, 754 series. + Copyright 2000 Daisuke Nagano + + Based on the VIA 82Cxxx driver by Jeff Garzik + And ported to 2.3.x by Jeff Garzik too :) My it is a small world. + + Distribued under the GNU PUBLIC LICENSE (GPL) Version 2. + See the "COPYING" file distributed with kernel source tree for more info. + + ------------------------------------------------------------------------- + + It only supports SBPro compatible function of YMF7xx series s.t. + * 22.05kHz, 8-bit and stereo sample + * OPL3-compatible FM synthesizer + * MPU-401 compatible "external" MIDI interface + + ------------------------------------------------------------------------- + + Revision history + + Tue May 14 19:00:00 2000 0.0.1 + * initial release + + Tue May 16 19:29:29 2000 0.0.2 + + * add a little delays for reset devices. + * fixed addressing bug. + + Sun May 21 15:14:37 2000 0.0.3 + + * Add 'master_vol' module parameter to change 'PCM out Vol' of AC'97. + * remove native UART401 support. External MIDI port should be supported + by sb_midi driver. + * add support for SPDIF OUT. Module parameter 'spdif_out' is now available. + + Wed May 31 00:13:57 2000 0.0.4 + + * remove entries in Hwmcode.h. Now YMF744 / YMF754 sets instructions + in 724hwmcode.h. + * fixed wrong legacy_io setting on YMF744/YMF754 . + + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "sound_config.h" +#include "soundmodule.h" +#include "sb.h" + +#include "724hwmcode.h" + +#undef YMF_DEBUG +#define SUPPORT_UART401_MIDI 1 + +/* ---------------------------------------------------------------------- */ + +#ifndef SOUND_LOCK +#define SOUND_LOCK do {} while (0) +#define SOUND_LOCK_END do {} while (0) +#endif + +#ifndef PCI_VENDOR_ID_YAMAHA +#define PCI_VENDOR_ID_YAMAHA 0x1073 +#endif +#ifndef PCI_DEVICE_ID_YMF724 +#define PCI_DEVICE_ID_YMF724 0x0004 +#endif +#ifndef PCI_DEVICE_ID_YMF740 +#define PCI_DEVICE_ID_YMF740 0x000A +#endif +#ifndef PCI_DEVICE_ID_YMF740C +#define PCI_DEVICE_ID_YMF740C 0x000C +#endif +#ifndef PCI_DEVICE_ID_YMF724F +#define PCI_DEVICE_ID_YMF724F 0x000D +#endif +#ifndef PCI_DEVICE_ID_YMF744 +#define PCI_DEVICE_ID_YMF744 0x0010 +#endif +#ifndef PCI_DEVICE_ID_YMF754 +#define PCI_DEVICE_ID_YMF754 0x0012 +#endif + +/* ---------------------------------------------------------------------- */ + +#define YMFSB_RESET_DELAY 5 + +#define YMFSB_REGSIZE 0x8000 + +#define YMFSB_AC97TIMEOUT 2000 + +#define YMFSB_WORKBITTIMEOUT 250000 + +#define YMFSB_DSPLENGTH 0x0080 +#define YMFSB_CTRLLENGTH 0x3000 + +#define YMFSB_PCIR_VENDORID 0x00 +#define YMFSB_PCIR_DEVICEID 0x02 +#define YMFSB_PCIR_CMD 0x04 +#define YMFSB_PCIR_REVISIONID 0x08 +#define YMFSB_PCIR_BASEADDR 0x10 +#define YMFSB_PCIR_IRQ 0x3c + +#define YMFSB_PCIR_LEGCTRL 0x40 +#define YMFSB_PCIR_ELEGCTRL 0x42 +#define YMFSB_PCIR_DSXGCTRL 0x48 +#define YMFSB_PCIR_OPLADR 0x60 +#define YMFSB_PCIR_SBADR 0x62 +#define YMFSB_PCIR_MPUADR 0x64 + +#define YMFSB_INTFLAG 0x0004 +#define YMFSB_ACTIVITY 0x0006 +#define YMFSB_GLOBALCTRL 0x0008 +#define YMFSB_ZVCTRL 0x000A +#define YMFSB_TIMERCTRL 0x0010 +#define YMFSB_TIMERCOUNT 0x0012 +#define YMFSB_SPDIFOUTCTRL 0x0018 +#define YMFSB_SPDIFOUTSTATUS 0x001C +#define YMFSB_EEPROMCTRL 0x0020 +#define YMFSB_SPDIFINCTRL 0x0034 +#define YMFSB_SPDIFINSTATUS 0x0038 +#define YMFSB_DSPPROGRAMDL 0x0048 +#define YMFSB_DLCNTRL 0x004C +#define YMFSB_GPIOININTFLAG 0x0050 +#define YMFSB_GPIOININTENABLE 0x0052 +#define YMFSB_GPIOINSTATUS 0x0054 +#define YMFSB_GPIOOUTCTRL 0x0056 +#define YMFSB_GPIOFUNCENABLE 0x0058 +#define YMFSB_GPIOTYPECONFIG 0x005A +#define YMFSB_AC97CMDDATA 0x0060 +#define YMFSB_AC97CMDADR 0x0062 +#define YMFSB_PRISTATUSDATA 0x0064 +#define YMFSB_PRISTATUSADR 0x0066 +#define YMFSB_SECSTATUSDATA 0x0068 +#define YMFSB_SECSTATUSADR 0x006A +#define YMFSB_SECCONFIG 0x0070 +#define YMFSB_LEGACYOUTVOL 0x0080 +#define YMFSB_LEGACYOUTVOLL 0x0080 +#define YMFSB_LEGACYOUTVOLR 0x0082 +#define YMFSB_NATIVEDACOUTVOL 0x0084 +#define YMFSB_NATIVEDACOUTVOLL 0x0084 +#define YMFSB_NATIVEDACOUTVOLR 0x0086 +#define YMFSB_SPDIFOUTVOL 0x0088 +#define YMFSB_SPDIFOUTVOLL 0x0088 +#define YMFSB_SPDIFOUTVOLR 0x008A +#define YMFSB_AC3OUTVOL 0x008C +#define YMFSB_AC3OUTVOLL 0x008C +#define YMFSB_AC3OUTVOLR 0x008E +#define YMFSB_PRIADCOUTVOL 0x0090 +#define YMFSB_PRIADCOUTVOLL 0x0090 +#define YMFSB_PRIADCOUTVOLR 0x0092 +#define YMFSB_LEGACYLOOPVOL 0x0094 +#define YMFSB_LEGACYLOOPVOLL 0x0094 +#define YMFSB_LEGACYLOOPVOLR 0x0096 +#define YMFSB_NATIVEDACLOOPVOL 0x0098 +#define YMFSB_NATIVEDACLOOPVOLL 0x0098 +#define YMFSB_NATIVEDACLOOPVOLR 0x009A +#define YMFSB_SPDIFLOOPVOL 0x009C +#define YMFSB_SPDIFLOOPVOLL 0x009E +#define YMFSB_SPDIFLOOPVOLR 0x009E +#define YMFSB_AC3LOOPVOL 0x00A0 +#define YMFSB_AC3LOOPVOLL 0x00A0 +#define YMFSB_AC3LOOPVOLR 0x00A2 +#define YMFSB_PRIADCLOOPVOL 0x00A4 +#define YMFSB_PRIADCLOOPVOLL 0x00A4 +#define YMFSB_PRIADCLOOPVOLR 0x00A6 +#define YMFSB_NATIVEADCINVOL 0x00A8 +#define YMFSB_NATIVEADCINVOLL 0x00A8 +#define YMFSB_NATIVEADCINVOLR 0x00AA +#define YMFSB_NATIVEDACINVOL 0x00AC +#define YMFSB_NATIVEDACINVOLL 0x00AC +#define YMFSB_NATIVEDACINVOLR 0x00AE +#define YMFSB_BUF441OUTVOL 0x00B0 +#define YMFSB_BUF441OUTVOLL 0x00B0 +#define YMFSB_BUF441OUTVOLR 0x00B2 +#define YMFSB_BUF441LOOPVOL 0x00B4 +#define YMFSB_BUF441LOOPVOLL 0x00B4 +#define YMFSB_BUF441LOOPVOLR 0x00B6 +#define YMFSB_SPDIFOUTVOL2 0x00B8 +#define YMFSB_SPDIFOUTVOL2L 0x00B8 +#define YMFSB_SPDIFOUTVOL2R 0x00BA +#define YMFSB_SPDIFLOOPVOL2 0x00BC +#define YMFSB_SPDIFLOOPVOL2L 0x00BC +#define YMFSB_SPDIFLOOPVOL2R 0x00BE +#define YMFSB_ADCSLOTSR 0x00C0 +#define YMFSB_RECSLOTSR 0x00C4 +#define YMFSB_ADCFORMAT 0x00C8 +#define YMFSB_RECFORMAT 0x00CC +#define YMFSB_P44SLOTSR 0x00D0 +#define YMFSB_STATUS 0x0100 +#define YMFSB_CTRLSELECT 0x0104 +#define YMFSB_MODE 0x0108 +#define YMFSB_SAMPLECOUNT 0x010C +#define YMFSB_NUMOFSAMPLES 0x0110 +#define YMFSB_CONFIG 0x0114 +#define YMFSB_PLAYCTRLSIZE 0x0140 +#define YMFSB_RECCTRLSIZE 0x0144 +#define YMFSB_EFFCTRLSIZE 0x0148 +#define YMFSB_WORKSIZE 0x014C +#define YMFSB_MAPOFREC 0x0150 +#define YMFSB_MAPOFEFFECT 0x0154 +#define YMFSB_PLAYCTRLBASE 0x0158 +#define YMFSB_RECCTRLBASE 0x015C +#define YMFSB_EFFCTRLBASE 0x0160 +#define YMFSB_WORKBASE 0x0164 +#define YMFSB_DSPINSTRAM 0x1000 +#define YMFSB_CTRLINSTRAM 0x4000 + + +/* ---------------------------------------------------------------------- */ + +#define MAX_CARDS 4 + +#define PFX "ymf_sb: " + +#define YMFSB_VERSION "0.0.4" +#define YMFSB_CARD_NAME "YMF7xx Legacy Audio driver " YMFSB_VERSION + +#ifdef SUPPORT_UART401_MIDI +#if 0 +# define ymf7xxsb_probe_midi probe_uart401 +# define ymf7xxsb_attach_midi attach_uart401 +# define ymf7xxsb_unload_midi unload_uart401 +#else +# define ymf7xxsb_probe_midi probe_sbmpu +# define ymf7xxsb_attach_midi attach_sbmpu +# define ymf7xxsb_unload_midi unload_sbmpu +#endif +#endif + +/* ---------------------------------------------------------------------- */ + +static struct address_info sb_data[MAX_CARDS]; +static struct address_info opl3_data[MAX_CARDS]; +#ifdef SUPPORT_UART401_MIDI +static struct address_info mpu_data[MAX_CARDS]; +#endif +static unsigned cards = 0; +static unsigned short *ymfbase[MAX_CARDS]; + +/* ---------------------------------------------------------------------- */ + +#ifdef MODULE +#ifdef SUPPORT_UART401_MIDI +static int mpu_io = 0; +#endif +static int synth_io = 0; +static int io = 0; +static int dma = 0; +static int master_vol = -1; +static int spdif_out = 0; +#ifdef SUPPORT_UART401_MIDI +MODULE_PARM(mpu_io, "i"); +#endif +MODULE_PARM(synth_io, "i"); +MODULE_PARM(io,"i"); +MODULE_PARM(dma,"i"); +MODULE_PARM(master_vol,"i"); +MODULE_PARM(spdif_out,"i"); +#else +#ifdef SUPPORT_UART401_MIDI +static int mpu_io = 0x330; +#endif +static int synth_io = 0x388; +static int io = 0x220; +static int dma = 1; +static int master_vol = 80; +static int spdif_out = 0; +#endif + +/* ---------------------------------------------------------------------- */ + +static int readRegWord( int adr ) { + + if (ymfbase[cards]==NULL) return 0; + + return readw(ymfbase[cards]+adr/2); +} + +static void writeRegWord( int adr, int val ) { + + if (ymfbase[cards]==NULL) return; + + writew((unsigned short)(val&0xffff), ymfbase[cards] + adr/2); + + return; +} + +static int readRegDWord( int adr ) { + + if (ymfbase[cards]==NULL) return 0; + + return (readl(ymfbase[cards]+adr/2)); +} + +static void writeRegDWord( int adr, int val ) { + + if (ymfbase[cards]==NULL) return; + + writel((unsigned int)(val&0xffffffff), ymfbase[cards]+adr/2); + + return; +} + +/* ---------------------------------------------------------------------- */ + +static int checkPrimaryBusy( void ) +{ + int timeout=0; + + while ( timeout++ < YMFSB_AC97TIMEOUT ) + { + if ( (readRegWord(YMFSB_PRISTATUSADR) & 0x8000) == 0x0000 ) + return 0; + } + return -1; +} + +static int writeAc97( int adr, unsigned short val ) +{ + + if ( adr > 0x7f || adr < 0x00 ) return -1; + + if ( checkPrimaryBusy() ) return -1; + +#ifdef YMF_DEBUG + printk(KERN_INFO PFX "AC97 0x%0x = 0x%0x\n",adr,val); +#endif + + writeRegWord( YMFSB_AC97CMDADR, 0x0000 | adr ); + writeRegWord( YMFSB_AC97CMDDATA, val ); + + return 0; +} + +static int checkCodec( struct pci_dev *pcidev ) +{ + u8 tmp8; + + pci_read_config_byte(pcidev, YMFSB_PCIR_DSXGCTRL, &tmp8); + if ( tmp8 & 0x03 ) { + pci_write_config_byte(pcidev, YMFSB_PCIR_DSXGCTRL, tmp8&0xfc); + mdelay(YMFSB_RESET_DELAY); + pci_write_config_byte(pcidev, YMFSB_PCIR_DSXGCTRL, tmp8|0x03); + mdelay(YMFSB_RESET_DELAY); + pci_write_config_byte(pcidev, YMFSB_PCIR_DSXGCTRL, tmp8&0xfc); + mdelay(YMFSB_RESET_DELAY); + } + + if ( checkPrimaryBusy() ) return -1; + + return 0; +} + +static int setupLegacyIO( struct pci_dev *pcidev ) +{ + int v; + int sbio=0,mpuio=0,oplio=0,dma=0; + + switch(sb_data[cards].io_base) { + case 0x220: + sbio = 0; + break; + case 0x240: + sbio = 1; + break; + case 0x260: + sbio = 2; + break; + case 0x280: + sbio = 3; + break; + default: + return -1; + break; + } +#ifdef YMF_DEBUG + printk(PFX "set SBPro I/O at 0x%x\n",sb_data[cards].io_base); +#endif + +#ifdef SUPPORT_UART401_MIDI + switch(mpu_data[cards].io_base) { + case 0x330: + mpuio = 0; + break; + case 0x300: + mpuio = 1; + break; + case 0x332: + mpuio = 2; + break; + case 0x334: + mpuio = 3; + break; + default: + mpuio = 0; + break; + } +# ifdef YMF_DEBUG + printk(PFX "set MPU401 I/O at 0x%x\n",mpu_data[cards].io_base); +# endif +#endif + + switch(opl3_data[cards].io_base) { + case 0x388: + oplio = 0; + break; + case 0x398: + oplio = 1; + break; + case 0x3a0: + oplio = 2; + break; + case 0x3a8: + oplio = 3; + break; + default: + return -1; + break; + } +#ifdef YMF_DEBUG + printk(PFX "set OPL3 I/O at 0x%x\n",opl3_data[cards].io_base); +#endif + + dma = sb_data[cards].dma; +#ifdef YMF_DEBUG + printk(PFX "set DMA address at 0x%x\n",sb_data[cards].dma); +#endif + + v = 0x0000 | ((dma<<6)&0x03) | 0x003f; + pci_write_config_word(pcidev, YMFSB_PCIR_LEGCTRL, v); +#ifdef YMF_DEBUG + printk(PFX "LEGCTRL: 0x%x\n",v); +#endif + switch( pcidev->device ) { + case PCI_DEVICE_ID_YMF724: + case PCI_DEVICE_ID_YMF740: + case PCI_DEVICE_ID_YMF724F: + case PCI_DEVICE_ID_YMF740C: + v = 0x8800 | ((mpuio<<4)&0x03) | ((sbio<<2)&0x03) | (oplio&0x03); + pci_write_config_word(pcidev, YMFSB_PCIR_ELEGCTRL, v); +#ifdef YMF_DEBUG + printk(PFX "ELEGCTRL: 0x%x\n",v); +#endif + break; + + case PCI_DEVICE_ID_YMF744: + case PCI_DEVICE_ID_YMF754: + v = 0x8800; + pci_write_config_word(pcidev, YMFSB_PCIR_ELEGCTRL, v); +#ifdef YMF_DEBUG + printk(PFX "ELEGCTRL: 0x%x\n",v); +#endif + pci_write_config_word(pcidev, YMFSB_PCIR_OPLADR, opl3_data[cards].io_base); + pci_write_config_word(pcidev, YMFSB_PCIR_SBADR, sb_data[cards]. +io_base); +#ifdef SUPPORT_UART401_MIDI + pci_write_config_word(pcidev, YMFSB_PCIR_MPUADR, mpu_data[cards].io_base); +#endif + break; + + default: + printk(KERN_ERR PFX "Invalid device ID: %d\n",pcidev->device); + return -1; + break; + } + + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static void enableDSP( void ) +{ + writeRegDWord( YMFSB_CONFIG, 0x00000001 ); + return; +} + +static void disableDSP( void ) +{ + int val; + int i; + + val = readRegDWord( YMFSB_CONFIG ); + if ( val ) { + writeRegDWord( YMFSB_CONFIG, 0 ); + } + + i=0; + while( ++i < YMFSB_WORKBITTIMEOUT ) { + val = readRegDWord(YMFSB_STATUS); + if ( (val & 0x00000002) == 0x00000000 ) break; + } + + return; +} + +static int setupInstruction( struct pci_dev *pcidev ) +{ + int i; + int val; + + writeRegDWord( YMFSB_NATIVEDACOUTVOL, 0 ); /* mute dac */ + disableDSP(); + + writeRegDWord( YMFSB_MODE, 0x00010000 ); + + /* DS-XG Software Reset */ + writeRegDWord( YMFSB_MODE, 0x00000000 ); + writeRegDWord( YMFSB_MAPOFREC, 0x00000000 ); + writeRegDWord( YMFSB_MAPOFEFFECT, 0x00000000 ); + writeRegDWord( YMFSB_PLAYCTRLBASE, 0x00000000 ); + writeRegDWord( YMFSB_RECCTRLBASE, 0x00000000 ); + writeRegDWord( YMFSB_EFFCTRLBASE, 0x00000000 ); + + val = readRegWord( YMFSB_GLOBALCTRL ); + writeRegWord( YMFSB_GLOBALCTRL, (val&~0x0007) ); + + /* setup DSP instruction code */ + for ( i=0 ; i>2] ); + } + + switch( pcidev->device ) { + case PCI_DEVICE_ID_YMF724: + case PCI_DEVICE_ID_YMF740: + /* setup Control instruction code */ + for ( i=0 ; i>2] ); + } + break; + + case PCI_DEVICE_ID_YMF724F: + case PCI_DEVICE_ID_YMF740C: + case PCI_DEVICE_ID_YMF744: + case PCI_DEVICE_ID_YMF754: + /* setup Control instruction code */ + for ( i=0 ; i>2] ); + } + break; + + default: + return -1; + } + + enableDSP(); + + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static int __init ymf7xx_init(struct pci_dev *pcidev) +{ + unsigned short v; + + /* Read hardware information */ +#ifdef YMF_DEBUG + unsigned int dv; + pci_read_config_word(pcidev, YMFSB_PCIR_VENDORID, &v); + printk(KERN_INFO PFX "Vendor ID = 0x%x\n",v); + pci_read_config_word(pcidev, YMFSB_PCIR_DEVICEID, &v); + printk(KERN_INFO PFX "Device ID = 0x%x\n",v); + pci_read_config_word(pcidev, YMFSB_PCIR_REVISIONID, &v); + printk(KERN_INFO PFX "Revision ID = 0x%x\n",v&0xff); + pci_read_config_dword(pcidev, YMFSB_PCIR_BASEADDR, &dv); + printk(KERN_INFO PFX "Base address = 0x%x\n",dv); + pci_read_config_word(pcidev, YMFSB_PCIR_IRQ, &v); + printk(KERN_INFO PFX "IRQ line = 0x%x\n",v&0xff); +#endif + + /* enables memory space access / bus mastering */ + pci_read_config_word(pcidev, YMFSB_PCIR_CMD, &v); + pci_write_config_word(pcidev, YMFSB_PCIR_CMD, v|0x06); + + /* check codec */ +#ifdef YMF_DEBUG + printk(KERN_INFO PFX "check codec...\n"); +#endif + if (checkCodec(pcidev)) return -1; + + /* setup legacy I/O */ +#ifdef YMF_DEBUG + printk(KERN_INFO PFX "setup legacy I/O...\n"); +#endif + if (setupLegacyIO(pcidev)) return -1; + + /* setup instruction code */ +#ifdef YMF_DEBUG + printk(KERN_INFO PFX "setup instructions...\n"); +#endif + if (setupInstruction(pcidev)) return -1; + + /* AC'97 setup */ +#ifdef YMF_DEBUG + printk(KERN_INFO PFX "setup AC'97...\n"); +#endif + if ( writeAc97(AC97_RESET ,0x0000) ) /* Reset */ + return -1; + if ( writeAc97(AC97_MASTER_VOL_STEREO,0x0000) ) /* Master Volume */ + return -1; + + v = 31*(100-master_vol)/100; + v = (v<<8 | v)&0x7fff; + if ( writeAc97(AC97_PCMOUT_VOL ,v ) ) /* PCM out Volume */ + return -1; + +#ifdef YMF_DEBUG + printk(KERN_INFO PFX "setup Legacy Volume...\n"); +#endif + /* Legacy Audio Output Volume L & R ch */ + writeRegDWord( YMFSB_LEGACYOUTVOL, 0x3fff3fff ); + +#ifdef YMF_DEBUG + printk(KERN_INFO PFX "setup SPDIF output control...\n"); +#endif + /* SPDIF Output control */ + v = spdif_out != 0 ? 0x0001 : 0x0000; + writeRegWord( YMFSB_SPDIFOUTCTRL, v ); + /* no copyright protection, + sample-rate converted, + re-recorded software comercially available (the 1st generation), + original */ + writeRegWord( YMFSB_SPDIFOUTSTATUS, 0x9a04 ); + + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static void __init ymf7xxsb_attach_sb(struct address_info *hw_config) +{ + if(!sb_dsp_init(hw_config)) + hw_config->slots[0] = -1; +} + +static int __init ymf7xxsb_probe_sb(struct address_info *hw_config) +{ + if (check_region(hw_config->io_base, 16)) + { + printk(KERN_DEBUG PFX "SBPro port 0x%x is already in use\n", + hw_config->io_base); + return 0; + } + return sb_dsp_detect(hw_config, SB_PCI_YAMAHA, 0, NULL); +} + + +static void ymf7xxsb_unload_sb(struct address_info *hw_config, int unload_mpu) +{ + if(hw_config->slots[0]!=-1) + sb_dsp_unload(hw_config, unload_mpu); +} + +/* ---------------------------------------------------------------------- */ + +enum chip_types { + CH_YMF724 = 0, + CH_YMF724F, + CH_YMF740, + CH_YMF740C, + CH_YMF744, + CH_YMF754, +}; + +/* directly indexed by chip_types enum above */ +/* note we keep this a struct to ease adding + * other per-board or per-chip info here */ +struct { + const char *devicename; +} devicetable[] __initdata = +{ + { "YMF724A-E" }, + { "YMF724F" }, + { "YMF740A-B" }, + { "YMF740C" }, + { "YMF744" }, + { "YMF754" }, +}; + +static struct pci_device_id ymf7xxsb_pci_tbl[] __initdata = { + { PCI_VENDOR_ID_YAMAHA, PCI_DEVICE_ID_YMF724, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_YMF724 }, + { PCI_VENDOR_ID_YAMAHA, PCI_DEVICE_ID_YMF724F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_YMF724F }, + { PCI_VENDOR_ID_YAMAHA, PCI_DEVICE_ID_YMF740, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_YMF740 }, + { PCI_VENDOR_ID_YAMAHA, PCI_DEVICE_ID_YMF740C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_YMF740C }, + { PCI_VENDOR_ID_YAMAHA, PCI_DEVICE_ID_YMF744, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_YMF744 }, + { PCI_VENDOR_ID_YAMAHA, PCI_DEVICE_ID_YMF754, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_YMF754 }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, ymf7xxsb_pci_tbl); + +static int __init ymf7xxsb_init_one (struct pci_dev *pcidev, const struct pci_device_id *ent) +{ + + const char *devicename; + unsigned long iobase; + + if (cards == MAX_CARDS) { + printk (KERN_DEBUG PFX "maximum number of cards reached\n"); + return -ENODEV; + } + + if ( pcidev->irq == 0 ) return -ENODEV; + iobase = pci_resource_start (pcidev, 0); + if ( iobase == 0x00000000 ) return -ENODEV; + + devicename = devicetable[ent->driver_data].devicename; + + /* remap memory mapped I/O onto kernel virtual memory */ + if ( (ymfbase[cards] = ioremap_nocache(iobase, YMFSB_REGSIZE)) == 0 ) + { + printk(KERN_ERR PFX "ioremap (0x%lx) returns zero\n", iobase); + return -ENODEV; + } + printk(KERN_INFO PFX "found %s at 0x%lx\n", devicename, iobase); +#ifdef YMF_DEBUG + printk(KERN_INFO PFX "remappling to 0x%p\n", ymfbase[cards]); +#endif + + memset (&sb_data[cards], 0, sizeof (struct address_info)); + memset (&opl3_data[cards], 0, sizeof (struct address_info)); +#ifdef SUPPORT_UART401_MIDI + memset (&mpu_data[cards], 0, sizeof (struct address_info)); +#endif + + sb_data[cards].name = YMFSB_CARD_NAME; + opl3_data[cards].name = YMFSB_CARD_NAME; +#ifdef SUPPORT_UART401_MIDI + mpu_data[cards].name = YMFSB_CARD_NAME; +#endif + + sb_data[cards].card_subtype = MDL_YMPCI; + + if ( io == 0 ) io = 0x220; + sb_data[cards].io_base = io; + sb_data[cards].irq = pcidev->irq; + sb_data[cards].dma = dma; + + if ( synth_io == 0 ) synth_io = 0x388; + opl3_data[cards].io_base = synth_io; + opl3_data[cards].irq = -1; + +#ifdef SUPPORT_UART401_MIDI + if ( mpu_io == 0 ) mpu_io = 0x330; + mpu_data[cards].io_base = mpu_io; + mpu_data[cards].irq = -1; +#endif + + if ( ymf7xx_init(pcidev) ) { + printk (KERN_ERR PFX + "Cannot initialize %s, aborting\n", + devicename); + return -ENODEV; + } + + /* register legacy SoundBlaster Pro */ + if (!ymf7xxsb_probe_sb(&sb_data[cards])) { + printk (KERN_ERR PFX + "SB probe at 0x%X failed, aborting\n", + io); + return -ENODEV; + } + ymf7xxsb_attach_sb (&sb_data[cards]); + +#ifdef SUPPORT_UART401_MIDI + /* register legacy MIDI */ + if ( mpu_io > 0 && 0) + { + if (!ymf7xxsb_probe_midi (&mpu_data[cards])) { + printk (KERN_ERR PFX + "MIDI probe @ 0x%X failed, aborting\n", + mpu_io); + ymf7xxsb_unload_sb (&sb_data[cards], 0); + return -ENODEV; + } + ymf7xxsb_attach_midi (&mpu_data[cards]); + } +#endif + + /* register legacy OPL3 */ + + cards++; + return 0; +} + +static struct pci_driver ymf7xxsb_driver = { + name: "ymf7xxsb", + id_table: ymf7xxsb_pci_tbl, + probe: ymf7xxsb_init_one, +}; + +static int __init init_ymf7xxsb_module(void) +{ + int i; + + /* + * Binds us to the sound subsystem + */ + SOUND_LOCK; + + if ( master_vol < 0 ) master_vol = 50; + if ( master_vol > 100 ) master_vol = 100; + + for (i=0 ; im_hook = 0; j->ex.bits.hookstate = 1; - if (j->async_queue) - kill_fasync(j->async_queue, SIGIO, POLL_IN); // Send apps notice of change + kill_fasync(&j->async_queue, SIGIO, POLL_IN); // Send apps notice of change } goto timer_end; } @@ -536,8 +535,7 @@ j->proc_load = j->ssr.high << 8 | j->ssr.low; if (!j->m_hook) { j->m_hook = j->ex.bits.hookstate = 1; - if (j->async_queue) - kill_fasync(j->async_queue, SIGIO, POLL_IN); // Send apps notice of change + kill_fasync(&j->async_queue, SIGIO, POLL_IN); // Send apps notice of change } } else { if (j->dsp.low == 0x21 && @@ -552,8 +550,7 @@ if (j->m_hook) { j->m_hook = 0; j->ex.bits.hookstate = 1; - if (j->async_queue) - kill_fasync(j->async_queue, SIGIO, POLL_IN); // Send apps notice of change + kill_fasync(&j->async_queue, SIGIO, POLL_IN); // Send apps notice of change } } } @@ -642,8 +639,7 @@ } if (j->ex.bytes) { wake_up_interruptible(&j->poll_q); // Wake any blocked selects - if (j->async_queue) - kill_fasync(j->async_queue, SIGIO, POLL_IN); // Send apps notice of change + kill_fasync(&j->async_queue, SIGIO, POLL_IN); // Send apps notice of change } } else { break; @@ -917,8 +913,7 @@ j->r_hook = fOffHook; if (j->port != PORT_POTS) { j->ex.bits.hookstate = 1; - if (j->async_queue) - kill_fasync(j->async_queue, SIGIO, POLL_IN); // Send apps notice of change + kill_fasync(&j->async_queue, SIGIO, POLL_IN); // Send apps notice of change } } @@ -1045,8 +1040,6 @@ if (file_p->f_mode & FMODE_WRITE) j->writers++; - MOD_INC_USE_COUNT; - if (ixjdebug > 0) // printk(KERN_INFO "Opening board %d\n", NUM(inode->i_rdev)); printk(KERN_INFO "Opening board %d\n", p->board); @@ -1196,7 +1189,6 @@ j->rec_frame_size = j->play_frame_size = 0; ixj_fasync(-1, file_p, 0); // remove from list of async notification - MOD_DEC_USE_COUNT; return 0; } @@ -1471,8 +1463,7 @@ wake_up_interruptible(&j->poll_q); // Wake any blocked selects - if (j->async_queue) - kill_fasync(j->async_queue, SIGIO, POLL_IN); // Send apps notice of frame + kill_fasync(&j->async_queue, SIGIO, POLL_IN); // Send apps notice of frame } } @@ -1557,8 +1548,7 @@ wake_up_interruptible(&j->poll_q); // Wake any blocked selects - if (j->async_queue) - kill_fasync(j->async_queue, SIGIO, POLL_IN); // Send apps notice of empty buffer + kill_fasync(&j->async_queue, SIGIO, POLL_IN); // Send apps notice of empty buffer #ifdef PERFMON_STATS ++j->frameswritten; #endif @@ -3949,6 +3939,7 @@ struct file_operations ixj_fops = { + owner: THIS_MODULE, read: ixj_enhanced_read, write: ixj_enhanced_write, poll: ixj_poll, @@ -4615,10 +4606,12 @@ pci = pci_find_device(0x15E2, 0x0500, pci); if (!pci) break; + if (pci_enable_device(pci)) + break; { - ixj[cnt].DSPbase = pci->resource[0].start; + ixj[cnt].DSPbase = pci_resource_start(pci, 0); ixj[cnt].XILINXbase = ixj[cnt].DSPbase + 0x10; - ixj[cnt].serial = PCIEE_GetSerialNumber(pci->resource[2].start); + ixj[cnt].serial = (PCIEE_GetSerialNumber)pci_resource_start(pci, 2); result = check_region(ixj[cnt].DSPbase, 16); if (result) { diff -u --recursive --new-file v2.4.0-test1/linux/drivers/telephony/phonedev.c linux/drivers/telephony/phonedev.c --- v2.4.0-test1/linux/drivers/telephony/phonedev.c Tue Apr 11 15:09:19 2000 +++ linux/drivers/telephony/phonedev.c Tue Jun 20 07:57:28 2000 @@ -49,6 +49,7 @@ unsigned int minor = MINOR(inode->i_rdev); int err = 0; struct phone_device *p; + struct file_operations *old_fops; if (minor >= PHONE_NUM_DEVICES) return -ENODEV; @@ -69,12 +70,15 @@ goto end; } } - if (p->open) { + old_fops = file->f_op; + file->f_op = fops_get(p->f_op); + if (p->open) err = p->open(p, file); /* Tell the device it is open */ - if (err) - goto end; + if (err) { + fops_put(file->f_op); + file->f_op = fops_get(old_fops); } - file->f_op = p->f_op; + fops_put(old_fops); end: up(&phone_lock); return err; @@ -129,6 +133,7 @@ static struct file_operations phone_fops = { + owner: THIS_MODULE, open: phone_open, }; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/Config.in linux/drivers/usb/Config.in --- v2.4.0-test1/linux/drivers/usb/Config.in Tue May 23 15:31:35 2000 +++ linux/drivers/usb/Config.in Fri Jun 23 20:52:23 2000 @@ -10,6 +10,11 @@ comment 'Miscellaneous USB options' bool ' Preliminary USB device filesystem' CONFIG_USB_DEVICEFS + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' Enforce USB bandwidth allocation (EXPERIMENTAL)' CONFIG_USB_BANDWIDTH + else + define_bool CONFIG_USB_BANDWIDTH n + fi comment 'USB Controllers' if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then @@ -55,6 +60,7 @@ dep_tristate ' USB ADMtek Pegasus-based device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET dep_tristate ' USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV + dep_tristate ' Microtek X6USB scanner support (EXPERIMENTAL)' CONFIG_USB_MICROTEK $CONFIG_SCSI fi comment 'USB HID' @@ -64,7 +70,10 @@ dep_tristate ' USB HIDBP Mouse support' CONFIG_USB_MOUSE $CONFIG_USB fi dep_tristate ' Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB - dep_tristate ' Logitech WingMan Force joystick support' CONFIG_USB_WMFORCE $CONFIG_USB + dep_tristate ' I-Force joysticks/wheels' CONFIG_INPUT_IFORCE_USB $CONFIG_USB + if [ "$CONFIG_INPUT_IFORCE_USB" != "n" ]; then + define_tristate CONFIG_INPUT_IFORCE $CONFIG_INPUT_IFORCE_USB + fi dep_tristate ' Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_USB dep_tristate ' Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_USB if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/Makefile linux/drivers/usb/Makefile --- v2.4.0-test1/linux/drivers/usb/Makefile Tue Apr 11 15:09:19 2000 +++ linux/drivers/usb/Makefile Wed Jun 21 08:22:21 2000 @@ -61,7 +61,7 @@ obj-$(CONFIG_USB_HID) += hid.o input.o obj-$(CONFIG_USB_KBD) += usbkbd.o input.o obj-$(CONFIG_USB_WACOM) += wacom.o input.o -obj-$(CONFIG_USB_WMFORCE) += wmforce.o input.o +obj-$(CONFIG_INPUT_IFORCE) += iforce.o input.o obj-$(CONFIG_INPUT_KEYBDEV) += keybdev.o input.o obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o input.o obj-$(CONFIG_INPUT_JOYDEV) += joydev.o input.o @@ -82,6 +82,7 @@ obj-$(CONFIG_USB_PEGASUS) += pegasus.o obj-$(CONFIG_USB_RIO500) += rio500.o obj-$(CONFIG_USB_DSBR) += dsbr100.o +obj-$(CONFIG_USB_MICROTEK) += microtek.o # Extract lists of the multi-part drivers. # The 'int-*' lists are the intermediate files used to build the multi's. diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/acm.c linux/drivers/usb/acm.c --- v2.4.0-test1/linux/drivers/usb/acm.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/usb/acm.c Mon Jun 19 13:42:41 2000 @@ -329,6 +329,7 @@ if (!ACM_READY(acm)) return -EINVAL; if (acm->writeurb.status == -EINPROGRESS) return 0; + if (!count) return 0; count = (count > acm->writesize) ? acm->writesize : count; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/audio.c linux/drivers/usb/audio.c --- v2.4.0-test1/linux/drivers/usb/audio.c Mon Jun 19 16:32:00 2000 +++ linux/drivers/usb/audio.c Mon Jun 19 13:42:41 2000 @@ -1788,7 +1788,7 @@ dev->devnum, ms->iface, ms->ch[i].slctunitid & 0xff); continue; } - for (j = i; j < ms->numch; i++) { + for (j = i; j < ms->numch; j++) { if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff) continue; mask |= 1 << j; @@ -1821,7 +1821,7 @@ } /* first generate smask */ smask = bmask = 0; - for (j = i; j < ms->numch; i++) { + for (j = i; j < ms->numch; j++) { if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff) continue; smask |= 1 << ms->ch[j].osschannel; @@ -1835,7 +1835,7 @@ continue; if (j > 1) srcmask &= ~bmask; - for (j = i; j < ms->numch; i++) { + for (j = i; j < ms->numch; j++) { if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff) continue; if (!(srcmask & (1 << ms->ch[j].osschannel))) @@ -1937,7 +1937,6 @@ file->private_data = ms; s->count++; - MOD_INC_USE_COUNT; up(&open_sem); return 0; } @@ -1949,7 +1948,6 @@ down(&open_sem); release(s); - MOD_DEC_USE_COUNT; return 0; } @@ -2045,6 +2043,7 @@ } static /*const*/ struct file_operations usb_mixer_fops = { + owner: THIS_MODULE, llseek: usb_audio_llseek, ioctl: usb_audio_ioctl_mixdev, open: usb_audio_open_mixdev, @@ -2609,7 +2608,6 @@ file->private_data = as; as->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); s->count++; - MOD_INC_USE_COUNT; up(&open_sem); return 0; } @@ -2645,11 +2643,11 @@ as->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); release(s); wake_up(&open_wait); - MOD_DEC_USE_COUNT; return 0; } static /*const*/ struct file_operations usb_audio_fops = { + owner: THIS_MODULE, llseek: usb_audio_llseek, read: usb_audio_read, write: usb_audio_write, @@ -3193,6 +3191,16 @@ state->termtype = 0; } +static struct mixerchannel *slctsrc_findunit(struct consmixstate *state, __u8 unitid) +{ + unsigned int i; + + for (i = 0; i < state->nrmixch; i++) + if (state->mixch[i].unitid == unitid) + return &state->mixch[i]; + return NULL; +} + static void usb_audio_selectorunit(struct consmixstate *state, unsigned char *selector) { unsigned int chnum, i, mixch; @@ -3206,7 +3214,9 @@ usb_audio_recurseunit(state, selector[5]); if (state->nrmixch != mixch) { mch = &state->mixch[state->nrmixch-1]; - mch->slctunitid = selector[5] | (1 << 8); + mch->slctunitid = selector[3] | (1 << 8); + } else if ((mch = slctsrc_findunit(state, selector[5]))) { + mch->slctunitid = selector[3] | (1 << 8); } else { printk(KERN_INFO "usbaudio: selector unit %u: ignoring channel 1\n", selector[3]); } @@ -3223,7 +3233,9 @@ } if (state->nrmixch != mixch) { mch = &state->mixch[state->nrmixch-1]; - mch->slctunitid = selector[5] | ((i + 1) << 8); + mch->slctunitid = selector[3] | ((i + 1) << 8); + } else if ((mch = slctsrc_findunit(state, selector[5+i]))) { + mch->slctunitid = selector[3] | ((i + 1) << 8); } else { printk(KERN_INFO "usbaudio: selector unit %u: ignoring channel %u\n", selector[3], i+1); } @@ -3604,8 +3616,10 @@ #endif if (config->interface[ifnum].altsetting[0].bInterfaceClass != USB_CLASS_AUDIO || config->interface[ifnum].altsetting[0].bInterfaceSubClass != 1) { +#if 0 printk(KERN_DEBUG "usbaudio: vendor id 0x%04x, product id 0x%04x contains no AudioControl interface\n", dev->descriptor.idVendor, dev->descriptor.idProduct); +#endif return NULL; } /* diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/dabusb.c linux/drivers/usb/dabusb.c --- v2.4.0-test1/linux/drivers/usb/dabusb.c Fri Mar 10 16:40:44 2000 +++ linux/drivers/usb/dabusb.c Mon Jun 19 13:42:41 2000 @@ -573,10 +573,9 @@ int devnum = MINOR (inode->i_rdev); pdabusb_t s; - if (devnum < DABUSB_MINOR || devnum > (DABUSB_MINOR + NRDABUSB)) + if (devnum < DABUSB_MINOR || devnum >= (DABUSB_MINOR + NRDABUSB)) return -EIO; - MOD_INC_USE_COUNT; s = &dabusb[devnum - DABUSB_MINOR]; dbg("dabusb_open"); @@ -586,20 +585,17 @@ up (&s->mutex); if (file->f_flags & O_NONBLOCK) { - MOD_DEC_USE_COUNT; return -EBUSY; } schedule_timeout (HZ / 2); if (signal_pending (current)) { - MOD_DEC_USE_COUNT; return -EAGAIN; } down (&s->mutex); } if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) { err("set_interface failed"); - MOD_DEC_USE_COUNT; return -EINVAL; } s->opened = 1; @@ -629,7 +625,6 @@ else wake_up (&s->remove_ok); - MOD_DEC_USE_COUNT; s->opened = 0; return 0; } @@ -692,6 +687,7 @@ static struct file_operations dabusb_fops = { + owner: THIS_MODULE, llseek: dabusb_llseek, read: dabusb_read, ioctl: dabusb_ioctl, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/dabusb.h linux/drivers/usb/dabusb.h --- v2.4.0-test1/linux/drivers/usb/dabusb.h Fri Mar 10 16:40:44 2000 +++ linux/drivers/usb/dabusb.h Mon Jun 19 13:42:41 2000 @@ -49,7 +49,7 @@ #define _DABUSB_IF 2 -#define _DABUSB_ISOPIPE 0x89 +#define _DABUSB_ISOPIPE 0x09 #define _ISOPIPESIZE 16384 #define _BULK_DATA_LEN 64 diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/dc2xx.c linux/drivers/usb/dc2xx.c --- v2.4.0-test1/linux/drivers/usb/dc2xx.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/usb/dc2xx.c Mon Jun 19 13:42:41 2000 @@ -82,8 +82,8 @@ /* table of cameras that work through this driver */ static const struct camera { - short idVendor; - short idProduct; + unsigned short idVendor; + unsigned short idProduct; /* plus hooks for camera-specific info if needed */ } cameras [] = { /* These have the same application level protocol */ @@ -98,7 +98,7 @@ { 0x040a, 0x0110 }, // Kodak DC-260 { 0x040a, 0x0111 }, // Kodak DC-265 { 0x040a, 0x0112 }, // Kodak DC-290 -// { 0x03f0, 0xffff }, // HP PhotoSmart C500 + { 0xf003, 0x6002 }, // HP PhotoSmart C500 /* Other USB devices may well work here too, so long as they * just stick to half duplex bulk packet exchanges. That @@ -284,9 +284,6 @@ } dbg ("open"); - - /* Keep driver from being unloaded while it's in use */ - MOD_INC_USE_COUNT; camera->isActive = 0; file->private_data = camera; @@ -306,8 +303,6 @@ kfree (camera); } - MOD_DEC_USE_COUNT; - dbg ("close"); return 0; @@ -319,6 +314,7 @@ */ static /* const */ struct file_operations usb_camera_fops = { /* Uses GCC initializer extension; simpler to maintain */ + owner: THIS_MODULE, read: camera_read, write: camera_write, open: camera_open, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/devio.c linux/drivers/usb/devio.c --- v2.4.0-test1/linux/drivers/usb/devio.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/usb/devio.c Fri Jun 23 21:00:50 2000 @@ -187,26 +187,60 @@ ssize_t ret = 0; unsigned len; loff_t pos; + int i; pos = *ppos; down_read(&ps->devsem); - if (!ps->dev) + if (!ps->dev) { ret = -ENODEV; - else if (pos < 0) + goto err; + } else if (pos < 0) { ret = -EINVAL; - else if (pos < sizeof(struct usb_device_descriptor)) { + goto err; + } + + if (pos < sizeof(struct usb_device_descriptor)) { len = sizeof(struct usb_device_descriptor) - pos; if (len > nbytes) len = nbytes; - if (copy_to_user(buf, ((char *)&ps->dev->descriptor) + pos, len)) + if (copy_to_user(buf, ((char *)&ps->dev->descriptor) + pos, len)) { ret = -EFAULT; - else { + goto err; + } + + *ppos += len; + buf += len; + nbytes -= len; + ret += len; + } + + pos = sizeof(struct usb_device_descriptor); + for (i = 0; nbytes && i < ps->dev->descriptor.bNumConfigurations; i++) { + struct usb_config_descriptor *config = + (struct usb_config_descriptor *)ps->dev->rawdescriptors[i]; + unsigned int length = le16_to_cpu(config->wTotalLength); + + if (*ppos < pos + length) { + len = length - (*ppos - pos); + if (len > nbytes) + len = nbytes; + + if (copy_to_user(buf, + ps->dev->rawdescriptors[i] + (*ppos - pos), len)) { + ret = -EFAULT; + goto err; + } + *ppos += len; buf += len; nbytes -= len; ret += len; } + + pos += length; } + +err: up_read(&ps->devsem); return ret; } @@ -376,12 +410,9 @@ } struct usb_driver usbdevfs_driver = { - "usbdevfs", - driver_probe, - driver_disconnect, - LIST_HEAD_INIT(usbdevfs_driver.driver_list), - NULL, - 0 + name: "usbdevfs", + probe: driver_probe, + disconnect: driver_disconnect, }; static int claimintf(struct dev_state *ps, unsigned int intf) @@ -481,6 +512,28 @@ return -ENOENT; } +extern struct list_head usb_driver_list; + +static int finddriver(struct usb_driver **driver, char *name) +{ + struct list_head *tmp; + + tmp = usb_driver_list.next; + while (tmp != &usb_driver_list) { + struct usb_driver *d = list_entry(tmp, struct usb_driver, + driver_list); + + if (!strcmp(d->name, name)) { + *driver = d; + return 0; + } + + tmp = tmp->next; + } + + return -EINVAL; +} + /* * file operations */ @@ -662,16 +715,77 @@ return 0; } +static int proc_getdriver(struct dev_state *ps, void *arg) +{ + struct usbdevfs_getdriver gd; + struct usb_interface *interface; + int ret; + + copy_from_user_ret(&gd, arg, sizeof(gd), -EFAULT); + if ((ret = findintfif(ps->dev, gd.interface)) < 0) + return ret; + interface = usb_ifnum_to_if(ps->dev, gd.interface); + if (!interface) + return -EINVAL; + if (!interface->driver) + return -ENODATA; + strcpy(gd.driver, interface->driver->name); + copy_to_user_ret(arg, &gd, sizeof(gd), -EFAULT); + return 0; +} + +static int proc_connectinfo(struct dev_state *ps, void *arg) +{ + struct usbdevfs_connectinfo ci; + + ci.devnum = ps->dev->devnum; + ci.slow = ps->dev->slow; + copy_to_user_ret(arg, &ci, sizeof(ci), -EFAULT); + return 0; +} + +static int proc_resetdevice(struct dev_state *ps) +{ + int i, ret; + + ret = usb_reset_device(ps->dev); + if (ret < 0) + return ret; + + for (i = 0; i < ps->dev->actconfig->bNumInterfaces; i++) { + struct usb_interface *intf = &ps->dev->actconfig->interface[i]; + + /* Don't simulate interfaces we've claimed */ + if (test_bit(i, &ps->ifclaimed)) + continue; + + if (intf->driver) { + down(&intf->driver->serialize); + intf->driver->disconnect(ps->dev, intf->private_data); + intf->driver->probe(ps->dev, i); + up(&intf->driver->serialize); + } + } + + return 0; +} + static int proc_setintf(struct dev_state *ps, void *arg) { struct usbdevfs_setinterface setintf; + struct usb_interface *interface; int ret; copy_from_user_ret(&setintf, arg, sizeof(setintf), -EFAULT); if ((ret = findintfif(ps->dev, setintf.interface)) < 0) return ret; - if ((ret = checkintf(ps, ret))) - return ret; + interface = usb_ifnum_to_if(ps->dev, setintf.interface); + if (!interface) + return -EINVAL; + if (interface->driver) { + if ((ret = checkintf(ps, ret))) + return ret; + } if (usb_set_interface(ps->dev, setintf.interface, setintf.altsetting)) return -EINVAL; return 0; @@ -913,6 +1027,65 @@ return releaseintf(ps, intf); } +static int proc_ioctl (struct dev_state *ps, void *arg) +{ + struct usbdevfs_ioctl ctrl; + int size; + void *buf = 0; + int retval = 0; + + /* get input parameters and alloc buffer */ + copy_from_user_ret (&ctrl, (void *) arg, sizeof (ctrl), -EFAULT); + if ((size = _IOC_SIZE (ctrl.ioctl_code)) > 0) { + if ((buf = kmalloc (size, GFP_KERNEL)) == 0) + return -ENOMEM; + if ((_IOC_DIR (ctrl.ioctl_code) & _IOC_WRITE) != 0 + && copy_from_user (buf, ctrl.data, size) != 0) { + kfree (buf); + return -EFAULT; + } else + memset (arg, 0, size); + } + + /* ioctl to device */ + if (ctrl.ifno < 0) { + switch (ctrl.ioctl_code) { + /* access/release token for issuing control messages + * ask a particular driver to bind/unbind, ... etc + */ + } + retval = -ENOSYS; + + /* ioctl to the driver which has claimed a given interface */ + } else { + struct usb_interface *ifp = 0; + if (!ps->dev) + retval = -ENODEV; + else if (ctrl.ifno >= ps->dev->actconfig->bNumInterfaces) + retval = -EINVAL; + else { + if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno))) + retval = -EINVAL; + else if (ifp->driver == 0 || ifp->driver->ioctl == 0) + retval = -ENOSYS; + } + if (retval == 0) + /* ifno might usefully be passed ... */ + retval = ifp->driver->ioctl (ps->dev, ctrl.ioctl_code, buf); + /* size = min (size, retval)? */ + } + + /* cleanup and return */ + if (retval >= 0 + && (_IOC_DIR (ctrl.ioctl_code) & _IOC_READ) != 0 + && size > 0 + && copy_to_user (ctrl.data, buf, size) != 0) + retval = -EFAULT; + if (buf != 0) + kfree (buf); + return retval; +} + static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct dev_state *ps = (struct dev_state *)file->private_data; @@ -944,6 +1117,18 @@ inode->i_mtime = CURRENT_TIME; break; + case USBDEVFS_RESET: + ret = proc_resetdevice(ps); + break; + + case USBDEVFS_GETDRIVER: + ret = proc_getdriver(ps, (void *)arg); + break; + + case USBDEVFS_CONNECTINFO: + ret = proc_connectinfo(ps, (void *)arg); + break; + case USBDEVFS_SETINTERFACE: ret = proc_setintf(ps, (void *)arg); break; @@ -982,6 +1167,9 @@ ret = proc_releaseinterface(ps, (void *)arg); break; + case USBDEVFS_IOCTL: + ret = proc_ioctl(ps, (void *) arg); + break; } up_read(&ps->devsem); if (ret >= 0) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/dsbr100.c linux/drivers/usb/dsbr100.c --- v2.4.0-test1/linux/drivers/usb/dsbr100.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/usb/dsbr100.c Mon Jun 19 13:42:41 2000 @@ -33,6 +33,9 @@ History: + Version 0.23: + Markus: Sign extension bug fixed by declaring transfer_buffer unsigned + Version 0.22: Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns, thanks to Mike Cox for pointing the problem out. @@ -74,7 +77,7 @@ typedef struct { struct urb readurb,writeurb; struct usb_device *dev; - char transfer_buffer[TB_LEN]; + unsigned char transfer_buffer[TB_LEN]; int curfreq; int stereo; int ifnum; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/evdev.c linux/drivers/usb/evdev.c --- v2.4.0-test1/linux/drivers/usb/evdev.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/usb/evdev.c Fri Jun 23 21:01:29 2000 @@ -1,7 +1,7 @@ /* - * evdev.c Version 0.1 + * $Id: evdev.c,v 1.10 2000/06/23 09:23:00 vojtech Exp $ * - * Copyright (c) 1999 Vojtech Pavlik + * Copyright (c) 1999-2000 Vojtech Pavlik * * Event char devices, giving access to raw input device events. * @@ -39,7 +39,7 @@ #include struct evdev { - int used; + int exist; int open; int minor; struct input_handle handle; @@ -72,8 +72,7 @@ list->buffer[list->head].value = value; list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1); - if (list->fasync) - kill_fasync(list->fasync, SIGIO, POLL_IN); + kill_fasync(&list->fasync, SIGIO, POLL_IN); list = list->next; } @@ -100,18 +99,18 @@ listptr = &((*listptr)->next); *listptr = (*listptr)->next; - if (!--list->evdev->open) - input_close_device(&list->evdev->handle); - - if (!--list->evdev->used) { - input_unregister_minor(list->evdev->devfs); - evdev_table[list->evdev->minor] = NULL; - kfree(list->evdev); + if (!--list->evdev->open) { + if (list->evdev->exist) { + input_close_device(&list->evdev->handle); + } else { + input_unregister_minor(list->evdev->devfs); + evdev_table[list->evdev->minor] = NULL; + kfree(list->evdev); + } } kfree(list); - MOD_DEC_USE_COUNT; return 0; } @@ -123,12 +122,8 @@ if (i > EVDEV_MINORS || !evdev_table[i]) return -ENODEV; - MOD_INC_USE_COUNT; - - if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL))) { - MOD_DEC_USE_COUNT; + if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL))) return -ENOMEM; - } memset(list, 0, sizeof(struct evdev_list)); list->evdev = evdev_table[i]; @@ -137,10 +132,9 @@ file->private_data = list; - list->evdev->used++; - if (!list->evdev->open++) - input_open_device(&list->evdev->handle); + if (list->evdev->exist) + input_open_device(&list->evdev->handle); return 0; } @@ -207,14 +201,20 @@ struct evdev_list *list = file->private_data; struct evdev *evdev = list->evdev; struct input_dev *dev = evdev->handle.dev; + int retval; switch (cmd) { case EVIOCGVERSION: - return put_user(EV_VERSION, (__u32 *) arg); + return put_user(EV_VERSION, (int *) arg); + case EVIOCGID: - return copy_to_user(&dev->id, (void *) arg, - sizeof(struct input_id)) ? -EFAULT : 0; + if ((retval = put_user(dev->idbus, ((short *) arg) + 0))) return retval; + if ((retval = put_user(dev->idvendor, ((short *) arg) + 1))) return retval; + if ((retval = put_user(dev->idproduct, ((short *) arg) + 2))) return retval; + if ((retval = put_user(dev->idversion, ((short *) arg) + 3))) return retval; + return 0; + default: if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ) @@ -222,8 +222,8 @@ if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) { - long *bits = NULL; - int len = 0; + long *bits; + int len; switch (_IOC_NR(cmd) & EV_MAX) { case 0: bits = dev->evbit; len = EV_MAX; break; @@ -235,20 +235,40 @@ default: return -EINVAL; } len = NBITS(len) * sizeof(long); - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - return copy_to_user((void *) arg, bits, len) ? -EFAULT : len; + if (len > _IOC_SIZE(cmd)) { + printk(KERN_WARNING "evdev.c: Truncating bitfield length from %d to %d\n", + len, _IOC_SIZE(cmd)); + len = _IOC_SIZE(cmd); + } + return copy_to_user((char *) arg, bits, len) ? -EFAULT : len; } if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) { - int len = strlen(dev->name) + 1; + int len; + if (!dev->name) return 0; + len = strlen(dev->name) + 1; if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); return copy_to_user((char *) arg, dev->name, len) ? -EFAULT : len; } + + if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { + + int t = _IOC_NR(cmd) & ABS_MAX; + + if ((retval = put_user(dev->abs[t], ((int *) arg) + 0))) return retval; + if ((retval = put_user(dev->absmin[t], ((int *) arg) + 1))) return retval; + if ((retval = put_user(dev->absmax[t], ((int *) arg) + 2))) return retval; + if ((retval = put_user(dev->absfuzz[t], ((int *) arg) + 3))) return retval; + if ((retval = put_user(dev->absflat[t], ((int *) arg) + 4))) return retval; + + return 0; + } } return -EINVAL; } static struct file_operations evdev_fops = { + owner: THIS_MODULE, read: evdev_read, write: evdev_write, poll: evdev_poll, @@ -282,11 +302,11 @@ evdev->handle.handler = handler; evdev->handle.private = evdev; - evdev->used = 1; + evdev->exist = 1; evdev->devfs = input_register_minor("event%d", minor, EVDEV_MINOR_BASE); - printk("event%d: Event device for input%d\n", minor, dev->number); + printk(KERN_INFO "event%d: Event device for input%d\n", minor, dev->number); return &evdev->handle; } @@ -295,10 +315,11 @@ { struct evdev *evdev = handle->private; - if (evdev->open) - input_close_device(handle); + evdev->exist = 0; - if (!--evdev->used) { + if (evdev->open) { + input_close_device(handle); + } else { input_unregister_minor(evdev->devfs); evdev_table[evdev->minor] = NULL; kfree(evdev); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/hid-debug.h linux/drivers/usb/hid-debug.h --- v2.4.0-test1/linux/drivers/usb/hid-debug.h Mon Mar 27 08:08:28 2000 +++ linux/drivers/usb/hid-debug.h Mon Jun 19 13:42:41 2000 @@ -1,5 +1,5 @@ /* - * driver/usb/hid-debug.h + * $Id: hid-debug.h,v 1.2 2000/05/29 10:54:53 vojtech Exp $ * * (c) 1999 Andreas Gal * (c) 2000 Vojtech Pavlik diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/hid.c linux/drivers/usb/hid.c --- v2.4.0-test1/linux/drivers/usb/hid.c Thu May 11 15:30:08 2000 +++ linux/drivers/usb/hid.c Mon Jun 19 13:42:41 2000 @@ -1,5 +1,5 @@ /* - * hid.c Version 0.8 + * $Id: hid.c,v 1.6 2000/05/29 09:01:52 vojtech Exp $ * * Copyright (c) 1999 Andreas Gal * Copyright (c) 2000 Vojtech Pavlik @@ -80,6 +80,9 @@ __s32 y; } hid_hat_to_axis[] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}, { 0, 0}}; +static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", "Joystick", + "Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"}; + /* * Register a new report for a device. */ @@ -1259,6 +1262,27 @@ return 0; } +static int hid_open(struct input_dev *dev) +{ + struct hid_device *hid = dev->private; + + if (hid->open++) + return 0; + + if (usb_submit_urb(&hid->urb)) + return -EIO; + + return 0; +} + +static void hid_close(struct input_dev *dev) +{ + struct hid_device *hid = dev->private; + + if (!--hid->open) + usb_unlink_urb(&hid->urb); +} + /* * Configure the input layer interface * Read all reports and initalize the absoulte field values. @@ -1272,6 +1296,8 @@ hid->input.private = hid; hid->input.event = hid_event; + hid->input.open = hid_open; + hid->input.close = hid_close; for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) { @@ -1313,7 +1339,7 @@ { 0, 0 } }; -static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum) +static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum, char *name) { struct usb_interface_descriptor *interface = dev->actconfig->interface[ifnum].altsetting + 0; struct hid_descriptor *hdesc; @@ -1380,11 +1406,6 @@ FILL_INT_URB(&hid->urb, dev, pipe, hid->buffer, maxp > 32 ? 32 : maxp, hid_irq, hid, endpoint->bInterval); - if (usb_submit_urb(&hid->urb)) { - dbg("submitting interrupt URB failed"); - continue; - } - break; } @@ -1405,6 +1426,20 @@ hid->dr.index = hid->ifnum; hid->dr.length = 1; + hid->input.name = hid->name; + hid->input.idbus = BUS_USB; + hid->input.idvendor = dev->descriptor.idVendor; + hid->input.idproduct = dev->descriptor.idProduct; + hid->input.idversion = dev->descriptor.bcdDevice; + + if (strlen(name)) + strcpy(hid->name, name); + else + sprintf(hid->name, "USB HID %s %04x:%04x", + ((hid->application >= 0x00010000) && (hid->application <= 0x00010008)) ? + hid_types[hid->application & 0xffff] : "Device", + hid->input.idvendor, hid->input.idproduct); + FILL_CONTROL_URB(&hid->urbout, dev, usb_sndctrlpipe(dev, 0), (void*) &hid->dr, hid->bufout, 1, hid_ctrl, hid); @@ -1416,13 +1451,27 @@ static void* hid_probe(struct usb_device *dev, unsigned int ifnum) { - char *hid_name[] = {"Device", "Pointer", "Mouse", "Device", "Joystick", - "Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"}; struct hid_device *hid; + char name[128]; + char *buf; dbg("HID probe called for ifnum %d", ifnum); - if (!(hid = usb_hid_configure(dev, ifnum))) + name[0] = 0; + + if (!(buf = kmalloc(63, GFP_KERNEL))) + return NULL; + + if (dev->descriptor.iManufacturer && + usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0) + strcat(name, buf); + if (dev->descriptor.iProduct && + usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0) + sprintf(name, "%s %s", name, buf); + + kfree(buf); + + if (!(hid = usb_hid_configure(dev, ifnum, name))) return NULL; hid_dump_device(hid); @@ -1430,10 +1479,18 @@ hid_init_input(hid); input_register_device(&hid->input); - printk(KERN_INFO "input%d: USB HID v%x.%02x %s\n", - hid->input.number, hid->version >> 8, hid->version & 0xff, + printk(KERN_INFO "input%d: USB HID v%x.%02x %s", + hid->input.number, + hid->version >> 8, hid->version & 0xff, ((hid->application >= 0x00010000) && (hid->application <= 0x00010008)) ? - hid_name[hid->application & 0xffff] : "device"); + hid_types[hid->application & 0xffff] : "Device"); + + if (strlen(name)) + printk(" [%s]", name); + else + printk(" [%04x:%04x]", hid->input.idvendor, hid->input.idproduct); + + printk(" on usb%d:%d.%d\n", dev->bus->busnum, dev->devnum, ifnum); return hid; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/hid.h linux/drivers/usb/hid.h --- v2.4.0-test1/linux/drivers/usb/hid.h Mon Mar 27 08:08:28 2000 +++ linux/drivers/usb/hid.h Mon Jun 19 13:42:41 2000 @@ -2,7 +2,7 @@ #define __HID_H /* - * drivers/usb/hid.h Version 0.8 + * $Id: hid.h,v 1.4 2000/05/29 09:01:52 vojtech Exp $ * * Copyright (c) 1999 Andreas Gal * Copyright (c) 2000 Vojtech Pavlik @@ -292,7 +292,9 @@ struct urb urb; /* USB URB structure */ struct urb urbout; /* Output URB */ struct input_dev input; /* input device structure */ + int open; /* is the device open by input? */ int quirks; /* Various nasty tricks the device can pull on us */ + char name[128]; /* Device name */ }; #define HID_GLOBAL_STACK_SIZE 4 diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/hub.c linux/drivers/usb/hub.c --- v2.4.0-test1/linux/drivers/usb/hub.c Tue May 23 15:31:35 2000 +++ linux/drivers/usb/hub.c Mon Jun 19 13:42:41 2000 @@ -18,7 +18,9 @@ #undef DEBUG #endif #include +#include +#include #include #include @@ -26,6 +28,7 @@ /* Wakes up khubd */ static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED; +static DECLARE_MUTEX(usb_address0_sem); static LIST_HEAD(hub_event_list); /* List of hubs needing servicing */ static LIST_HEAD(hub_list); /* List containing all of the hubs (for cleanup) */ @@ -116,26 +119,29 @@ static int usb_hub_configure(struct usb_hub *hub) { struct usb_device *dev = hub->dev; - unsigned char buffer[4], *bitmap; + unsigned char buffer[HUB_DESCRIPTOR_MAX_SIZE], *bitmap; struct usb_hub_descriptor *descriptor; struct usb_descriptor_header *header; struct usb_hub_status *hubsts; - int i; - - /* Get the length first */ - if (usb_get_hub_descriptor(dev, buffer, 4) < 0) - return -1; + int i, ret; + /* Request the entire hub descriptor. */ header = (struct usb_descriptor_header *)buffer; - bitmap = kmalloc(header->bLength, GFP_KERNEL); - if (!bitmap) + ret = usb_get_hub_descriptor(dev, buffer, sizeof(buffer)); + /* is large enough for a hub with 127 ports; + * the hub can/will return fewer bytes here. */ + if (ret < 0) { + err("Unable to get hub descriptor (err = %d)", ret); return -1; + } - if (usb_get_hub_descriptor(dev, bitmap, header->bLength) < 0) { - kfree(bitmap); + bitmap = kmalloc(header->bLength, GFP_KERNEL); + if (!bitmap) { + err("Unable to kmalloc %d bytes for bitmap", header->bLength); return -1; } + memcpy (bitmap, buffer, header->bLength); descriptor = (struct usb_hub_descriptor *)bitmap; hub->nports = dev->maxchild = descriptor->bNbrPorts; @@ -182,8 +188,11 @@ kfree(bitmap); - if (usb_get_hub_status(dev, buffer) < 0) + ret = usb_get_hub_status(dev, buffer); + if (ret < 0) { + err("Unable to get hub status (err = %d)", ret); return -1; + } hubsts = (struct usb_hub_status *)buffer; dbg("local power source is %s", @@ -225,12 +234,16 @@ endpoint = &interface->endpoint[0]; /* Output endpoint? Curiousier and curiousier.. */ - if (!(endpoint->bEndpointAddress & USB_DIR_IN)) + if (!(endpoint->bEndpointAddress & USB_DIR_IN)) { + err("Device is hub class, but has output endpoint?"); return NULL; + } /* If it's not an interrupt endpoint, we'd better punt! */ - if ((endpoint->bmAttributes & 3) != 3) + if ((endpoint->bmAttributes & 3) != 3) { + err("Device is hub class, but has endpoint other than interrupt?"); return NULL; + } /* We found a hub */ info("USB hub found"); @@ -321,17 +334,49 @@ kfree(hub); } +static int hub_ioctl (struct usb_device *hub, unsigned int code, void *user_data) +{ + /* assert ifno == 0 (part of hub spec) */ + switch (code) { + case USBDEVFS_HUB_PORTINFO: { + struct usbdevfs_hub_portinfo *info = user_data; + unsigned long flags; + int i; + + spin_lock_irqsave (&hub_event_lock, flags); + if (hub->devnum <= 0) + info->nports = 0; + else { + info->nports = hub->maxchild; + for (i = 0; i < info->nports; i++) { + if (hub->children [i] == NULL) + info->port [i] = 0; + else + info->port [i] = hub->children [i]->devnum; + } + } + spin_unlock_irqrestore (&hub_event_lock, flags); + + return info->nports + 1; + } + + default: + return -ENOSYS; + } +} + static void usb_hub_port_connect_change(struct usb_device *hub, int port) { struct usb_device *usb; struct usb_port_status portsts; unsigned short portstatus, portchange; - int tries; + int ret, tries; wait_ms(100); - /* Check status */ - if (usb_get_port_status(hub, port + 1, &portsts)<0) { - err("get_port_status failed"); + + ret = usb_get_port_status(hub, port + 1, &portsts); + if (ret < 0) { + err("get_port_status(%d) failed (err = %d)", port + 1, ret); return; } @@ -351,21 +396,22 @@ if (!(portstatus & USB_PORT_STAT_CONNECTION)) return; } - wait_ms(400); + wait_ms(400); - /* Reset the port */ + down(&usb_address0_sem); #define MAX_TRIES 5 - - for(tries=0;tries= MAX_TRIES) { err("Cannot enable port %i after %i retries, disabling port.", port+1, MAX_TRIES); err("Maybe the USB cable is bad?"); - return; + goto out; } usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_RESET); /* Allocate a new device struct for it */ - usb = usb_alloc_dev(hub, hub->bus); if (!usb) { err("couldn't allocate usb_device"); - return; + goto out; } usb->slow = (portstatus & USB_PORT_STAT_LOW_SPEED) ? 1 : 0; @@ -405,12 +450,25 @@ usb_connect(usb); /* Run it through the hoops (find a driver, etc) */ - if (usb_new_device(usb)) { - usb_disconnect(&hub->children[port]); - /* Woops, disable the port */ - dbg("hub: disabling port %d", port + 1); - usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE); + ret = usb_new_device(usb); + if (ret) { + /* Try resetting the device. Windows does this and it */ + /* gets some devices working correctly */ + usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET); + + ret = usb_new_device(usb); + if (ret) { + usb_disconnect(&hub->children[port]); + + /* Woops, disable the port */ + dbg("hub: disabling port %d", port + 1); + usb_clear_port_feature(hub, port + 1, + USB_PORT_FEAT_ENABLE); + } } + +out: + up(&usb_address0_sem); } static void usb_hub_events(void) @@ -521,10 +579,6 @@ static int usb_hub_thread(void *__hub) { -/* - MOD_INC_USE_COUNT; -*/ - khubd_running = 1; lock_kernel(); @@ -545,10 +599,6 @@ interruptible_sleep_on(&khubd_wait); } while (!signal_pending(current)); -/* - MOD_DEC_USE_COUNT; -*/ - dbg("usb_hub_thread exiting"); khubd_running = 0; @@ -556,10 +606,10 @@ } static struct usb_driver hub_driver = { - "hub", - hub_probe, - hub_disconnect, - { NULL, NULL } + name: "hub", + probe: hub_probe, + ioctl: hub_ioctl, + disconnect: hub_disconnect }; /* @@ -569,8 +619,10 @@ { int pid; - if (usb_register(&hub_driver) < 0) + if (usb_register(&hub_driver) < 0) { + err("Unable to register USB hub driver"); return -1; + } pid = kernel_thread(usb_hub_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); @@ -615,28 +667,130 @@ usb_deregister(&hub_driver); } /* usb_hub_cleanup() */ +/* + * WARNING - If a driver calls usb_reset_device, you should simulate a + * disconnect() and probe() for other interfaces you doesn't claim. This + * is left up to the driver writer right now. This insures other drivers + * have a chance to re-setup their interface. + * + * Take a look at proc_resetdevice in devio.c for some sample code to + * do this. + */ int usb_reset_device(struct usb_device *dev) { struct usb_device *parent = dev->parent; - int i; + struct usb_device_descriptor descriptor; + int i, ret, port = -1; if (!parent) { err("attempting to reset root hub!"); return -EINVAL; } - for (i = 0; i < parent->maxchild; i++) { + for (i = 0; i < parent->maxchild; i++) if (parent->children[i] == dev) { - usb_set_port_feature(parent, i + 1, - USB_PORT_FEAT_RESET); + port = i; + break; + } + + if (port < 0) + return -ENOENT; - usb_disconnect(&dev); - usb_hub_port_connect_change(parent, i); + down(&usb_address0_sem); - return 0; + /* Send a reset to the device */ + usb_set_port_feature(parent, port + 1, USB_PORT_FEAT_RESET); + + wait_ms(200); + + usb_clear_port_feature(parent, port + 1, USB_PORT_FEAT_C_RESET); + + /* Reprogram the Address */ + ret = usb_set_address(dev); + if (ret < 0) { + err("USB device not accepting new address (error=%d)", ret); + clear_bit(dev->devnum, &dev->bus->devmap.devicemap); + dev->devnum = -1; + up(&usb_address0_sem); + return ret; + } + + wait_ms(10); /* Let the SET_ADDRESS settle */ + + up(&usb_address0_sem); + + /* + * Now we fetch the configuration descriptors for the device and + * see if anything has changed. If it has, we dump the current + * parsed descriptors and reparse from scratch. Then we leave + * the device alone for the caller to finish setting up. + * + * If nothing changed, we reprogram the configuration and then + * the alternate settings. + */ + ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &descriptor, + sizeof(descriptor)); + if (ret < 0) + return ret; + + le16_to_cpus(&descriptor.bcdUSB); + le16_to_cpus(&descriptor.idVendor); + le16_to_cpus(&descriptor.idProduct); + le16_to_cpus(&descriptor.bcdDevice); + + if (memcmp(&dev->descriptor, &descriptor, sizeof(descriptor))) { + usb_destroy_configuration(dev); + + ret = usb_get_device_descriptor(dev); + if (ret < sizeof(dev->descriptor)) { + if (ret < 0) + err("unable to get device descriptor (error=%d)", ret); + else + err("USB device descriptor short read (expected %i, got %i)", sizeof(dev->descriptor), ret); + + clear_bit(dev->devnum, &dev->bus->devmap.devicemap); + dev->devnum = -1; + return -EIO; + } + + ret = usb_get_configuration(dev); + if (ret < 0) { + err("unable to get configuration (error=%d)", ret); + clear_bit(dev->devnum, &dev->bus->devmap.devicemap); + dev->devnum = -1; + return 1; + } + + dev->actconfig = dev->config; + usb_set_maxpacket(dev); + + return 1; + } else { + ret = usb_set_configuration(dev, + dev->actconfig->bConfigurationValue); + if (ret < 0) { + err("failed to set active configuration (error=%d)", + ret); + return ret; + } + + for (i = 0; i < dev->actconfig->bNumInterfaces; i++) { + struct usb_interface *intf = + &dev->actconfig->interface[i]; + struct usb_interface_descriptor *as = + &intf->altsetting[intf->act_altsetting]; + + ret = usb_set_interface(dev, as->bInterfaceNumber, + as->bAlternateSetting); + if (ret < 0) { + err("failed to set active alternate setting for interface %d (error=%d)", i, ret); + return ret; + } } + + return 0; } - return -ENOENT; + return 0; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/hub.h linux/drivers/usb/hub.h --- v2.4.0-test1/linux/drivers/usb/hub.h Sun Mar 19 18:35:30 2000 +++ linux/drivers/usb/hub.h Mon Jun 19 13:42:41 2000 @@ -72,6 +72,8 @@ #define HUB_CHANGE_LOCAL_POWER 0x0001 #define HUB_CHANGE_OVERCURRENT 0x0002 +#define HUB_DESCRIPTOR_MAX_SIZE 39 /* enough for 127 ports on a hub */ + /* Hub descriptor */ struct usb_hub_descriptor { __u8 bLength; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/iforce.c linux/drivers/usb/iforce.c --- v2.4.0-test1/linux/drivers/usb/iforce.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/iforce.c Wed Jun 21 08:22:21 2000 @@ -0,0 +1,335 @@ +/* + * $Id: iforce.c,v 1.7 2000/06/04 14:03:36 vojtech Exp $ + * + * Copyright (c) 2000 Vojtech Pavlik + * + * USB/RS232 I-Force joysticks and wheels. + * + * Sponsored by SuSE + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); + +#define USB_VENDOR_ID_LOGITECH 0x046d +#define USB_DEVICE_ID_LOGITECH_WMFORCE 0xc281 + +#define IFORCE_MAX_LENGTH 16 + +#if defined(CONFIG_INPUT_IFORCE_232) || defined(CONFIG_INPUT_IFORCE_232_MODULE) +#define IFORCE_232 +#endif +#if defined(CONFIG_INPUT_IFORCE_USB) || defined(CONFIG_INPUT_IFORCE_USB_MODULE) +#define IFORCE_USB +#endif + +struct iforce { + signed char data[IFORCE_MAX_LENGTH]; + struct input_dev dev; + struct urb irq; + int open; + int idx, pkt, len, id; + unsigned char csum; +}; + +static struct { + __s32 x; + __s32 y; +} iforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; + +static char *iforce_name = "I-Force joystick/wheel"; + +static void iforce_process_packet(struct input_dev *dev, unsigned char id, int idx, unsigned char *data) +{ + switch (id) { + + case 1: /* joystick position data */ + case 3: /* wheel position data */ + + if (id == 1) { + input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0])); + input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2])); + input_report_abs(dev, ABS_THROTTLE, 255 - data[4]); + } else { + input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0])); + input_report_abs(dev, ABS_GAS, 255 - data[2]); + input_report_abs(dev, ABS_BRAKE, 255 - data[3]); + } + + input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x); + input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y); + + input_report_key(dev, BTN_TRIGGER, data[5] & 0x01); + input_report_key(dev, BTN_TOP, data[5] & 0x02); + input_report_key(dev, BTN_THUMB, data[5] & 0x04); + input_report_key(dev, BTN_TOP2, data[5] & 0x08); + input_report_key(dev, BTN_BASE, data[5] & 0x10); + input_report_key(dev, BTN_BASE2, data[5] & 0x20); + input_report_key(dev, BTN_BASE3, data[5] & 0x40); + input_report_key(dev, BTN_BASE4, data[5] & 0x80); + input_report_key(dev, BTN_BASE5, data[6] & 0x01); + input_report_key(dev, BTN_A, data[6] & 0x02); + input_report_key(dev, BTN_B, data[6] & 0x04); + input_report_key(dev, BTN_C, data[6] & 0x08); + break; + + case 2: /* force feedback effect status */ + break; + } +} + + +static int iforce_open(struct input_dev *dev) +{ + struct iforce *iforce = dev->private; + + if (dev->idbus == BUS_USB && !iforce->open++) + if (usb_submit_urb(&iforce->irq)) + return -EIO; + + return 0; +} + +static void iforce_close(struct input_dev *dev) +{ + struct iforce *iforce = dev->private; + + if (dev->idbus == BUS_USB && !--iforce->open) + usb_unlink_urb(&iforce->irq); +} + +static void iforce_input_setup(struct iforce *iforce) +{ + int i; + + iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + iforce->dev.keybit[LONG(BTN_JOYSTICK)] |= BIT(BTN_TRIGGER) | BIT(BTN_TOP) | BIT(BTN_THUMB) | BIT(BTN_TOP2) | + BIT(BTN_BASE) | BIT(BTN_BASE2) | BIT(BTN_BASE3) | BIT(BTN_BASE4) | BIT(BTN_BASE5); + iforce->dev.keybit[LONG(BTN_GAMEPAD)] |= BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C); + iforce->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y) + | BIT(ABS_WHEEL) | BIT(ABS_GAS) | BIT(ABS_BRAKE); + + for (i = ABS_X; i <= ABS_Y; i++) { + iforce->dev.absmax[i] = 1920; + iforce->dev.absmin[i] = -1920; + iforce->dev.absflat[i] = 128; + iforce->dev.absfuzz[i] = 16; + } + + for (i = ABS_THROTTLE; i <= ABS_RUDDER; i++) { + iforce->dev.absmax[i] = 255; + iforce->dev.absmin[i] = 0; + } + + for (i = ABS_HAT0X; i <= ABS_HAT0Y; i++) { + iforce->dev.absmax[i] = 1; + iforce->dev.absmin[i] = -1; + } + + iforce->dev.private = iforce; + iforce->dev.open = iforce_open; + iforce->dev.close = iforce_close; + + input_register_device(&iforce->dev); +} + +#ifdef IFORCE_USB + +static void iforce_usb_irq(struct urb *urb) +{ + struct iforce *iforce = urb->context; + if (urb->status) return; + iforce_process_packet(&iforce->dev, iforce->data[0], 8, iforce->data + 1); +} + +static void *iforce_usb_probe(struct usb_device *dev, unsigned int ifnum) +{ + struct usb_endpoint_descriptor *endpoint; + struct iforce *iforce; + + if (dev->descriptor.idVendor != USB_VENDOR_ID_LOGITECH || + dev->descriptor.idProduct != USB_DEVICE_ID_LOGITECH_WMFORCE) + return NULL; + + endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0; + + if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return NULL; + memset(iforce, 0, sizeof(struct iforce)); + + iforce->dev.name = iforce_name; + iforce->dev.idbus = BUS_USB; + iforce->dev.idvendor = dev->descriptor.idVendor; + iforce->dev.idproduct = dev->descriptor.idProduct; + iforce->dev.idversion = dev->descriptor.bcdDevice; + + FILL_INT_URB(&iforce->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress), + iforce->data, 8, iforce_usb_irq, iforce, endpoint->bInterval); + + iforce_input_setup(iforce); + + printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n", + iforce->dev.number, iforce_name, dev->bus->busnum, dev->devnum, ifnum); + + return iforce; +} + +static void iforce_usb_disconnect(struct usb_device *dev, void *ptr) +{ + struct iforce *iforce = ptr; + usb_unlink_urb(&iforce->irq); + input_unregister_device(&iforce->dev); + kfree(iforce); +} + +static struct usb_driver iforce_usb_driver = { + name: "iforce", + probe: iforce_usb_probe, + disconnect: iforce_usb_disconnect, +}; + +#endif + +#ifdef IFORCE_232 + +static void iforce_serio_irq(struct serio *serio, unsigned char data, unsigned int flags) +{ + struct iforce* iforce = serio->private; + + if (!iforce->pkt) { + if (data != 0x2b) { + return; + } + iforce->pkt = 1; + return; + } + + if (!iforce->id) { + if (data > 3) { + iforce->pkt = 0; + return; + } + iforce->id = data; + return; + } + + if (!iforce->len) { + if (data > IFORCE_MAX_LENGTH) { + iforce->pkt = 0; + iforce->id = 0; + return; + } + iforce->len = data; + return; + } + + if (iforce->idx < iforce->len) { + iforce->csum += iforce->data[iforce->idx++] = data; + return; + } + + if (iforce->idx == iforce->len) { + iforce_process_packet(&iforce->dev, iforce->id, iforce->idx, iforce->data); + iforce->pkt = 0; + iforce->id = 0; + iforce->len = 0; + iforce->idx = 0; + iforce->csum = 0; + } +} + +static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev) +{ + struct iforce *iforce; + + if (serio->type != (SERIO_RS232 | SERIO_IFORCE)) + return; + + if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return; + memset(iforce, 0, sizeof(struct iforce)); + + iforce->dev.name = iforce_name; + iforce->dev.idbus = BUS_RS232; + iforce->dev.idvendor = SERIO_IFORCE; + iforce->dev.idproduct = 0x0001; + iforce->dev.idversion = 0x0100; + + serio->private = iforce; + + if (serio_open(serio, dev)) { + kfree(iforce); + return; + } + + iforce_input_setup(iforce); + + printk(KERN_INFO "input%d: %s on serio%d\n", + iforce->dev.number, iforce_name, serio->number); +} + +static void iforce_serio_disconnect(struct serio *serio) +{ + struct iforce* iforce = serio->private; + input_unregister_device(&iforce->dev); + serio_close(serio); + kfree(iforce); +} + +static struct serio_dev iforce_serio_dev = { + interrupt: iforce_serio_irq, + connect: iforce_serio_connect, + disconnect: iforce_serio_disconnect, +}; + +#endif + +static int __init iforce_init(void) +{ +#ifdef IFORCE_USB + usb_register(&iforce_usb_driver); +#endif +#ifdef IFORCE_232 + serio_register_device(&iforce_serio_dev); +#endif + return 0; +} + +static void __exit iforce_exit(void) +{ +#ifdef IFORCE_USB + usb_deregister(&iforce_usb_driver); +#endif +#ifdef IFORCE_232 + serio_unregister_device(&iforce_serio_dev); +#endif +} + +module_init(iforce_init); +module_exit(iforce_exit); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/input.c linux/drivers/usb/input.c --- v2.4.0-test1/linux/drivers/usb/input.c Tue May 23 15:31:35 2000 +++ linux/drivers/usb/input.c Wed Jun 21 22:31:02 2000 @@ -1,7 +1,7 @@ /* - * input.c Version 0.1 + * $Id: input.c,v 1.7 2000/05/28 17:31:36 vojtech Exp $ * - * Copyright (c) 1999 Vojtech Pavlik + * Copyright (c) 1999-2000 Vojtech Pavlik * * The input layer module itself * @@ -91,11 +91,27 @@ case EV_ABS: - if (code > ABS_MAX || !test_bit(code, dev->absbit) || (value == dev->abs[code])) + if (code > ABS_MAX || !test_bit(code, dev->absbit)) return; - dev->abs[code] = value; + if (dev->absfuzz[code]) { + if ((value > dev->abs[code] - (dev->absfuzz[code] >> 1)) && + (value < dev->abs[code] + (dev->absfuzz[code] >> 1))) + return; + + if ((value > dev->abs[code] - dev->absfuzz[code]) && + (value < dev->abs[code] + dev->absfuzz[code])) + value = (dev->abs[code] * 3 + value) >> 2; + + if ((value > dev->abs[code] - (dev->absfuzz[code] << 1)) && + (value < dev->abs[code] + (dev->absfuzz[code] << 1))) + value = (dev->abs[code] + value) >> 1; + } + + if (dev->abs[code] == value) + return; + dev->abs[code] = value; break; case EV_REL: @@ -344,16 +360,25 @@ static int input_open_file(struct inode *inode, struct file *file) { struct input_handler *handler = input_table[MINOR(inode->i_rdev) >> 5]; + struct file_operations *old_fops; + int err; if (!handler || !handler->fops || !handler->fops->open) return -ENODEV; - file->f_op = handler->fops; - - return handler->fops->open(inode, file); + old_fops = file->f_op; + file->f_op = fops_get(handler->fops); + err = handler->fops->open(inode, file); + if (err) { + fops_put(file->f_op); + file->f_op = fops_get(old_fops); + } + fops_put(old_fops); + return err; } static struct file_operations input_fops = { + owner: THIS_MODULE, open: input_open_file, }; @@ -361,8 +386,8 @@ { char devfs_name[16]; sprintf(devfs_name, name, minor); - return devfs_register(input_devfs_handle, devfs_name, 0, DEVFS_FL_DEFAULT, INPUT_MAJOR, minor + minor_base, - S_IFCHR | S_IRUGO | S_IWUSR, 0, 0, &input_fops, NULL); + return devfs_register(input_devfs_handle, devfs_name, DEVFS_FL_DEFAULT, INPUT_MAJOR, minor + minor_base, + S_IFCHR | S_IRUGO | S_IWUSR, &input_fops, NULL); } void input_unregister_minor(devfs_handle_t handle) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/joydev.c linux/drivers/usb/joydev.c --- v2.4.0-test1/linux/drivers/usb/joydev.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/usb/joydev.c Fri Jun 23 21:01:29 2000 @@ -1,7 +1,7 @@ /* - * joydev.c Version 0.1 + * $Id: joydev.c,v 1.11 2000/06/23 09:23:00 vojtech Exp $ * - * Copyright (c) 1999 Vojtech Pavlik + * Copyright (c) 1999-2000 Vojtech Pavlik * Copyright (c) 1999 Colin Van Dyke * * Joystick device driver for the input driver suite. @@ -50,10 +50,9 @@ #define JOYDEV_BUFFER_SIZE 64 struct joydev { - int used; + int exist; int open; int minor; - char name[32]; struct input_handle handle; wait_queue_head_t wait; devfs_handle_t devfs; @@ -67,6 +66,7 @@ __u16 keypam[KEY_MAX - BTN_MISC]; __u8 absmap[ABS_MAX]; __u8 abspam[ABS_MAX]; + __s16 abs[ABS_MAX]; }; struct joydev_list { @@ -122,7 +122,9 @@ case EV_ABS: event.type = JS_EVENT_AXIS; event.number = joydev->absmap[code]; - event.value = joydev_correct(value, &joydev->corr[event.number]); + event.value = joydev_correct(value, joydev->corr + event.number); + if (event.value == joydev->abs[event.number]) return; + joydev->abs[event.number] = event.value; break; default: @@ -139,8 +141,7 @@ if (list->tail == (list->head = (list->head + 1) & (JOYDEV_BUFFER_SIZE - 1))) list->startup = 0; - if (list->fasync) - kill_fasync(list->fasync, SIGIO, POLL_IN); + kill_fasync(&list->fasync, SIGIO, POLL_IN); list = list->next; } @@ -167,18 +168,18 @@ listptr = &((*listptr)->next); *listptr = (*listptr)->next; - if (!--list->joydev->open) - input_close_device(&list->joydev->handle); - - if (!--list->joydev->used) { - input_unregister_minor(list->joydev->devfs); - joydev_table[list->joydev->minor] = NULL; - kfree(list->joydev); + if (!--list->joydev->open) { + if (list->joydev->exist) { + input_close_device(&list->joydev->handle); + } else { + input_unregister_minor(list->joydev->devfs); + joydev_table[list->joydev->minor] = NULL; + kfree(list->joydev); + } } kfree(list); - MOD_DEC_USE_COUNT; return 0; } @@ -190,12 +191,8 @@ if (i > JOYDEV_MINORS || !joydev_table[i]) return -ENODEV; - MOD_INC_USE_COUNT; - - if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL))) { - MOD_DEC_USE_COUNT; + if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL))) return -ENOMEM; - } memset(list, 0, sizeof(struct joydev_list)); list->joydev = joydev_table[i]; @@ -204,10 +201,9 @@ file->private_data = list; - list->joydev->used++; - if (!list->joydev->open++) - input_open_device(&list->joydev->handle); + if (list->joydev->exist) + input_open_device(&list->joydev->handle); return 0; } @@ -234,8 +230,8 @@ data.buttons = ((joydev->nkey > 0 && test_bit(joydev->keypam[0], input->key)) ? 1 : 0) | ((joydev->nkey > 1 && test_bit(joydev->keypam[1], input->key)) ? 2 : 0); - data.x = ((joydev_correct(input->abs[ABS_X], &joydev->corr[0]) / 256) + 128) >> joydev->glue.JS_CORR.x; - data.y = ((joydev_correct(input->abs[ABS_Y], &joydev->corr[1]) / 256) + 128) >> joydev->glue.JS_CORR.y; + data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x; + data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y; if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE))) return -EFAULT; @@ -280,13 +276,12 @@ if (list->startup < joydev->nkey) { event.type = JS_EVENT_BUTTON | JS_EVENT_INIT; - event.value = !!test_bit(joydev->keypam[list->startup], input->key); event.number = list->startup; + event.value = !!test_bit(joydev->keypam[event.number], input->key); } else { event.type = JS_EVENT_AXIS | JS_EVENT_INIT; - event.value = joydev_correct(input->abs[joydev->abspam[list->startup - joydev->nkey]], - &joydev->corr[list->startup - joydev->nkey]); event.number = list->startup - joydev->nkey; + event.value = joydev->abs[event.number]; } if (copy_to_user(buf + retval, &event, sizeof(struct js_event))) @@ -322,6 +317,8 @@ { struct joydev_list *list = file->private_data; struct joydev *joydev = list->joydev; + struct input_dev *dev = joydev->handle.dev; + switch (cmd) { @@ -360,9 +357,11 @@ sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0; default: if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) { - int len = strlen(joydev->name) + 1; + int len; + if (!dev->name) return 0; + len = strlen(dev->name) + 1; if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - if (copy_to_user((char *) arg, joydev->name, len)) return -EFAULT; + if (copy_to_user((char *) arg, dev->name, len)) return -EFAULT; return len; } } @@ -370,6 +369,7 @@ } static struct file_operations joydev_fops = { + owner: THIS_MODULE, read: joydev_read, write: joydev_write, poll: joydev_poll, @@ -401,8 +401,6 @@ init_waitqueue_head(&joydev->wait); - sprintf(joydev->name, "joydev%d", joydev->minor); - joydev->minor = minor; joydev_table[minor] = joydev; @@ -410,7 +408,7 @@ joydev->handle.handler = handler; joydev->handle.private = joydev; - joydev->used = 1; + joydev->exist = 1; for (i = 0; i < ABS_MAX; i++) if (test_bit(i, dev->absbit)) { @@ -445,11 +443,13 @@ joydev->corr[i].coef[1] = (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j]; joydev->corr[i].coef[2] = (1 << 29) / ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]); joydev->corr[i].coef[3] = (1 << 29) / ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]); + + joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i); } joydev->devfs = input_register_minor("js%d", minor, JOYDEV_MINOR_BASE); - printk("js%d: Joystick device for input%d\n", minor, dev->number); + printk(KERN_INFO "js%d: Joystick device for input%d\n", minor, dev->number); return &joydev->handle; } @@ -458,10 +458,11 @@ { struct joydev *joydev = handle->private; - if (joydev->open) - input_close_device(handle); + joydev->exist = 0; - if (!--joydev->used) { + if (joydev->open) { + input_close_device(handle); + } else { input_unregister_minor(joydev->devfs); joydev_table[joydev->minor] = NULL; kfree(joydev); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/keybdev.c linux/drivers/usb/keybdev.c --- v2.4.0-test1/linux/drivers/usb/keybdev.c Thu May 11 15:30:08 2000 +++ linux/drivers/usb/keybdev.c Mon Jun 19 13:42:41 2000 @@ -1,7 +1,7 @@ /* - * keybdev.c Version 0.1 + * $Id: keybdev.c,v 1.3 2000/05/28 17:31:36 vojtech Exp $ * - * Copyright (c) 1999 Vojtech Pavlik + * Copyright (c) 1999-2000 Vojtech Pavlik * * Input driver to keyboard driver binding. * @@ -162,14 +162,14 @@ input_open_device(handle); - printk("keybdev.c: Adding keyboard: input%d\n", dev->number); + printk(KERN_INFO "keybdev.c: Adding keyboard: input%d\n", dev->number); return handle; } static void keybdev_disconnect(struct input_handle *handle) { - printk("keybdev.c: Removing keyboard: input%d\n", handle->dev->number); + printk(KERN_INFO "keybdev.c: Removing keyboard: input%d\n", handle->dev->number); input_close_device(handle); kfree(handle); } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/mdc800.c linux/drivers/usb/mdc800.c --- v2.4.0-test1/linux/drivers/usb/mdc800.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/usb/mdc800.c Mon Jun 19 13:42:41 2000 @@ -539,17 +539,13 @@ { int retval=0; - MOD_INC_USE_COUNT; - if (mdc800->state == NOT_CONNECTED) { - MOD_DEC_USE_COUNT; return -EBUSY; } if (mdc800->open) { - MOD_DEC_USE_COUNT; return -EBUSY; } @@ -568,7 +564,6 @@ if (usb_submit_urb (mdc800->irq_urb)) { err ("request USB irq fails (submit_retval=%i urb_status=%i).",retval, mdc800->irq_urb->status); - MOD_DEC_USE_COUNT; return -EIO; } @@ -599,8 +594,6 @@ retval=-EIO; } - MOD_DEC_USE_COUNT; - return retval; } @@ -833,6 +826,7 @@ /* File Operations of this drivers */ static struct file_operations mdc800_device_ops = { + owner: THIS_MODULE, read: mdc800_device_read, write: mdc800_device_write, open: mdc800_device_open, diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/microtek.c linux/drivers/usb/microtek.c --- v2.4.0-test1/linux/drivers/usb/microtek.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/microtek.c Mon Jun 19 13:42:41 2000 @@ -0,0 +1,1051 @@ +/* Driver for Microtek Scanmaker X6 USB scanner, and possibly others. + * + * (C) Copyright 2000 John Fremlin + * (C) Copyright 2000 Oliver Neukum + * + * Parts shamelessly stolen from usb-storage and copyright by their + * authors. Thanks to Matt Dharm for giving us permission! + * + * This driver implements a SCSI host controller driver and a USB + * device driver. To avoid confusion, all the USB related stuff is + * prefixed by mts_usb_ and all the SCSI stuff by mts_scsi_. + * + * Microtek (www.microtek.com) did not release the specifications for + * their USB protocol to us, so we had to reverse engineer them. We + * don't know for which models they are valid. + * + * The X6 USB has three bulk endpoints, one output (0x1) down which + * commands and outgoing data are sent, and two input: 0x82 from which + * normal data is read from the scanner (in packets of maximum 32 + * bytes) and from which the status byte is read, and 0x83 from which + * the results of a scan (or preview) are read in up to 64 * 1024 byte + * chunks by the Windows driver. We don't know how much it is possible + * to read at a time from 0x83. + * + * It seems possible to read (with URB transfers) everything from 0x82 + * in one go, without bothering to read in 32 byte chunks. + * + * There seems to be an optimisation of a further READ implicit if + * you simply read from 0x83. + * + * Guessed protocol: + * + * Send raw SCSI command to EP 0x1 + * + * If there is data to receive: + * If the command was READ datatype=image: + * Read a lot of data from EP 0x83 + * Else: + * Read data from EP 0x82 + * Else: + * If there is data to transmit: + * Write it to EP 0x1 + * + * Read status byte from EP 0x82 + * + * References: + * + * The SCSI command set for the scanner is available from + * ftp://ftp.microtek.com/microtek/devpack/ + * + * Microtek NV sent us a more up to date version of the document. If + * you want it, just send mail. + * + * Status: + * + * This driver does not work properly yet. + * Untested with multiple scanners. + * Untested on SMP. + * Untested on UHCI. + * + * History: + * + * 20000417 starting history + * 20000417 fixed load oops + * 20000417 fixed unload oops + * 20000419 fixed READ IMAGE detection + * 20000424 started conversion to use URBs + * 20000502 handled short transfers as errors + * 20000513 rename and organisation of functions (john) + * 20000513 added IDs for all products supported by Windows driver (john) + * 20000514 Rewrote mts_scsi_queuecommand to use URBs (john) + * 20000514 Version 0.0.8j + * 20000514 Fix reporting of non-existant devices to SCSI layer (john) + * 20000514 Added MTS_DEBUG_INT (john) + * 20000514 Changed "usb-microtek" to "microtek" for consistency (john) + * 20000514 Stupid bug fixes (john) + * 20000514 Version 0.0.9j + * 20000515 Put transfer context and URB in mts_desc (john) + * 20000515 Added prelim turn off debugging support (john) + * 20000515 Version 0.0.10j + * 20000515 Fixed up URB allocation (clear URB on alloc) (john) + * 20000515 Version 0.0.11j + * 20000516 Removed unnecessary spinlock in mts_transfer_context (john) + * 20000516 Removed unnecessary up on instance lock in mts_remove_nolock (john) + * 20000516 Implemented (badly) scsi_abort (john) + * 20000516 Version 0.0.12j + * 20000517 Hopefully removed mts_remove_nolock quasideadlock (john) + * 20000517 Added mts_debug_dump to print ll USB info (john) + * 20000518 Tweaks and documentation updates (john) + * 20000518 Version 0.0.13j + * 20000518 Cleaned up abort handling (john) + * 20000523 Removed scsi_command and various scsi_..._resets (john) + * 20000523 Added unlink URB on scsi_abort, now OHCI supports it (john) + * 20000523 Fixed last tiresome compile warning (john) + * 20000523 Version 0.0.14j (though version 0.1 has come out?) + * 20000602 Added primitive reset + * 20000602 Version 0.2.0 + * 20000603 various cosmetic changes + * 20000603 Version 0.2.1 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "../scsi/scsi.h" +#include "../scsi/hosts.h" +#include "../scsi/sd.h" + +#include "microtek.h" + +/* Constants */ + +#define MTS_ABORT_TIMEOUT HZ /*jiffies*/ + + +/* Should we do debugging? */ + +#define MTS_DO_DEBUG + + +/* USB layer driver interface */ + +static void *mts_usb_probe(struct usb_device *dev, unsigned int interface); +static void mts_usb_disconnect(struct usb_device *dev, void *ptr); + +static struct usb_driver mts_usb_driver = { + "microtek", + mts_usb_probe, + mts_usb_disconnect, + { NULL, NULL } /* we need no fops. let gcc fill it */ +}; + + +/* Internal driver stuff */ + +#define MTS_VERSION "0.2.1" +#define MTS_NAME "microtek usb (rev " MTS_VERSION "): " + +#define MTS_WARNING(x...) \ + printk( KERN_WARNING MTS_NAME ## x ) +#define MTS_ERROR(x...) \ + printk( KERN_ERR MTS_NAME ## x ) +#define MTS_INT_ERROR(x...) \ + MTS_ERROR( ## x ) +#define MTS_MESSAGE(x...) \ + printk( KERN_INFO MTS_NAME ## x ) + +#if defined MTS_DO_DEBUG + +#define MTS_DEBUG(x...) \ + printk( KERN_DEBUG MTS_NAME ## x ) + +#define MTS_DEBUG_GOT_HERE() \ + MTS_DEBUG("got to %s:%d (%s)\n", __FILE__, (int)__LINE__, __PRETTY_FUNCTION__ ) +#define MTS_DEBUG_INT() \ + do { MTS_DEBUG_GOT_HERE(); \ + MTS_DEBUG("transfer = %x context = %x\n",(int)transfer,(int)context ); \ + MTS_DEBUG("status = %x data-length = %x sent = %x\n",(int)transfer->status,(int)context->data_length, (int)transfer->actual_length ); \ + mts_debug_dump(context->instance);\ + } while(0) +#else + +#define MTS_NUL_STATEMENT do { } while(0) + +#define MTS_DEBUG(x...) MTS_NUL_STATEMENT +#define MTS_DEBUG_GOT_HERE() MTS_NUL_STATEMENT +#define MTS_DEBUG_INT() MTS_NUL_STATEMENT + +#endif + + + +#define MTS_INT_INIT()\ + do {\ + context = (struct mts_transfer_context*)transfer->context; \ + if (atomic_read(&context->do_abort)) {\ + mts_transfer_cleanup(transfer);\ + return;\ + }\ + MTS_DEBUG_INT();\ + } while (0) + +static inline void mts_debug_dump(struct mts_desc* desc) { + MTS_DEBUG("desc at 0x%x: halted = %x%x, toggle = %x%x\n", + (int)desc,(int)desc->usb_dev->halted[1],(int)desc->usb_dev->halted[0], + (int)desc->usb_dev->toggle[1],(int)desc->usb_dev->toggle[0] + ); + MTS_DEBUG("ep_out=%x ep_response=%x ep_image=%x\n", + usb_sndbulkpipe(desc->usb_dev,desc->ep_out), + usb_rcvbulkpipe(desc->usb_dev,desc->ep_response), + usb_rcvbulkpipe(desc->usb_dev,desc->ep_image) + ); +} + + +static inline void mts_show_command(Scsi_Cmnd *srb) +{ + char *what = NULL; + + switch (srb->cmnd[0]) { + case TEST_UNIT_READY: what = "TEST_UNIT_READY"; break; + case REZERO_UNIT: what = "REZERO_UNIT"; break; + case REQUEST_SENSE: what = "REQUEST_SENSE"; break; + case FORMAT_UNIT: what = "FORMAT_UNIT"; break; + case READ_BLOCK_LIMITS: what = "READ_BLOCK_LIMITS"; break; + case REASSIGN_BLOCKS: what = "REASSIGN_BLOCKS"; break; + case READ_6: what = "READ_6"; break; + case WRITE_6: what = "WRITE_6"; break; + case SEEK_6: what = "SEEK_6"; break; + case READ_REVERSE: what = "READ_REVERSE"; break; + case WRITE_FILEMARKS: what = "WRITE_FILEMARKS"; break; + case SPACE: what = "SPACE"; break; + case INQUIRY: what = "INQUIRY"; break; + case RECOVER_BUFFERED_DATA: what = "RECOVER_BUFFERED_DATA"; break; + case MODE_SELECT: what = "MODE_SELECT"; break; + case RESERVE: what = "RESERVE"; break; + case RELEASE: what = "RELEASE"; break; + case COPY: what = "COPY"; break; + case ERASE: what = "ERASE"; break; + case MODE_SENSE: what = "MODE_SENSE"; break; + case START_STOP: what = "START_STOP"; break; + case RECEIVE_DIAGNOSTIC: what = "RECEIVE_DIAGNOSTIC"; break; + case SEND_DIAGNOSTIC: what = "SEND_DIAGNOSTIC"; break; + case ALLOW_MEDIUM_REMOVAL: what = "ALLOW_MEDIUM_REMOVAL"; break; + case SET_WINDOW: what = "SET_WINDOW"; break; + case READ_CAPACITY: what = "READ_CAPACITY"; break; + case READ_10: what = "READ_10"; break; + case WRITE_10: what = "WRITE_10"; break; + case SEEK_10: what = "SEEK_10"; break; + case WRITE_VERIFY: what = "WRITE_VERIFY"; break; + case VERIFY: what = "VERIFY"; break; + case SEARCH_HIGH: what = "SEARCH_HIGH"; break; + case SEARCH_EQUAL: what = "SEARCH_EQUAL"; break; + case SEARCH_LOW: what = "SEARCH_LOW"; break; + case SET_LIMITS: what = "SET_LIMITS"; break; + case READ_POSITION: what = "READ_POSITION"; break; + case SYNCHRONIZE_CACHE: what = "SYNCHRONIZE_CACHE"; break; + case LOCK_UNLOCK_CACHE: what = "LOCK_UNLOCK_CACHE"; break; + case READ_DEFECT_DATA: what = "READ_DEFECT_DATA"; break; + case MEDIUM_SCAN: what = "MEDIUM_SCAN"; break; + case COMPARE: what = "COMPARE"; break; + case COPY_VERIFY: what = "COPY_VERIFY"; break; + case WRITE_BUFFER: what = "WRITE_BUFFER"; break; + case READ_BUFFER: what = "READ_BUFFER"; break; + case UPDATE_BLOCK: what = "UPDATE_BLOCK"; break; + case READ_LONG: what = "READ_LONG"; break; + case WRITE_LONG: what = "WRITE_LONG"; break; + case CHANGE_DEFINITION: what = "CHANGE_DEFINITION"; break; + case WRITE_SAME: what = "WRITE_SAME"; break; + case READ_TOC: what = "READ_TOC"; break; + case LOG_SELECT: what = "LOG_SELECT"; break; + case LOG_SENSE: what = "LOG_SENSE"; break; + case MODE_SELECT_10: what = "MODE_SELECT_10"; break; + case MODE_SENSE_10: what = "MODE_SENSE_10"; break; + case MOVE_MEDIUM: what = "MOVE_MEDIUM"; break; + case READ_12: what = "READ_12"; break; + case WRITE_12: what = "WRITE_12"; break; + case WRITE_VERIFY_12: what = "WRITE_VERIFY_12"; break; + case SEARCH_HIGH_12: what = "SEARCH_HIGH_12"; break; + case SEARCH_EQUAL_12: what = "SEARCH_EQUAL_12"; break; + case SEARCH_LOW_12: what = "SEARCH_LOW_12"; break; + case READ_ELEMENT_STATUS: what = "READ_ELEMENT_STATUS"; break; + case SEND_VOLUME_TAG: what = "SEND_VOLUME_TAG"; break; + case WRITE_LONG_2: what = "WRITE_LONG_2"; break; + default: + MTS_DEBUG("can't decode command\n"); + goto out; + break; + } + MTS_DEBUG( "Command %s (%d bytes)\n", what, srb->cmd_len); + + out: + MTS_DEBUG( " %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + srb->cmnd[0], srb->cmnd[1], srb->cmnd[2], srb->cmnd[3], srb->cmnd[4], srb->cmnd[5], + srb->cmnd[6], srb->cmnd[7], srb->cmnd[8], srb->cmnd[9]); +} + +static inline int mts_is_aborting(struct mts_desc* desc) { + return (atomic_read(&desc->context.do_abort)); +} + +static inline void mts_request_abort(struct mts_desc* desc) { + MTS_DEBUG_GOT_HERE(); + mts_debug_dump(desc); + atomic_set(&desc->context.do_abort,1); +} + +static inline void mts_urb_abort(struct mts_desc* desc) { + MTS_DEBUG_GOT_HERE(); + mts_debug_dump(desc); + if ( desc->urb.status == USB_ST_URB_PENDING ) { + usb_unlink_urb( &desc->urb ); + } +} + +static inline void mts_wait_abort(struct mts_desc* desc) +{ + mts_request_abort(desc); + + while( !atomic_read(&desc->lock.count) ) { +/* Is there a function to check if the semaphore is locked? */ + schedule_timeout( MTS_ABORT_TIMEOUT ); + MTS_DEBUG_GOT_HERE(); + mts_urb_abort(desc); + } + +} + + +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 ); + + mts_wait_abort(to_remove); + + down( &to_remove->lock ); + + 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_module(MODULE_SCSI_HA, &(to_remove->ctempl)); + + 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) +/* interrupt context (!) */ +{ + struct mts_desc* desc = (struct mts_desc*)(srb->host->hostdata[0]); + + MTS_DEBUG_GOT_HERE(); + + mts_request_abort(desc); + mts_urb_abort(desc); + + return SCSI_ABORT_PENDING; +} + +static int mts_scsi_host_reset (Scsi_Cmnd *srb) +{ + struct mts_desc* desc = (struct mts_desc*)(srb->host->hostdata[0]); + + MTS_DEBUG_GOT_HERE(); + mts_debug_dump(desc); + + usb_reset_device(desc->usb_dev); + 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)); + 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 ); + +static void mts_transfer_cleanup( struct urb *transfer ); + + +inline static +void mts_int_submit_urb (struct urb* transfer, + int pipe, + void* data, + unsigned length, + mts_usb_urb_callback callback ) +/* Interrupt context! */ + +/* Holding transfer->context->lock! */ +{ + int res; + struct mts_transfer_context* context; + + MTS_INT_INIT(); + + FILL_BULK_URB(transfer, + context->instance->usb_dev, + pipe, + data, + length, + callback, + context + ); + +/* transfer->transfer_flags = USB_DISABLE_SPD;*/ + transfer->transfer_flags = USB_ASYNC_UNLINK; + transfer->status = 0; + transfer->timeout = 100; + + res = usb_submit_urb( transfer ); + if ( res ) { + MTS_INT_ERROR( "could not submit URB! Error was %d\n",(int)res ); + context->srb->result = DID_ERROR << 16; + context->state = mts_con_error; + mts_transfer_cleanup(transfer); + } + return; +} + + +static void mts_transfer_cleanup( struct urb *transfer ) +/* Interrupt context! */ +{ + struct mts_transfer_context* context = (struct mts_transfer_context*)transfer->context; + + up( &context->instance->lock ); + if ( context->final_callback ) + context->final_callback(context->srb); + +} + +static void mts_transfer_done( struct urb *transfer ) +{ + struct mts_transfer_context* context; + + MTS_INT_INIT(); + + context->srb->result &= MTS_MAX_CHUNK_MASK; + context->srb->result |= (unsigned)context->status<<1; + + mts_transfer_cleanup(transfer); + + return; +} + + +static void mts_get_status( struct urb *transfer ) +/* Interrupt context! */ +{ + struct mts_transfer_context* context; + + MTS_INT_INIT(); + + context->state = mts_con_status; + + mts_int_submit_urb(transfer, + usb_rcvbulkpipe(context->instance->usb_dev, + context->instance->ep_response), + &context->status, + 1, + mts_transfer_done ); + + + return; +} + +static void mts_data_done( struct urb* transfer ) +/* Interrupt context! */ +{ + struct mts_transfer_context* context; + + MTS_INT_INIT(); + + if ( context->data_length != transfer->actual_length ) { + context->srb->resid = context->data_length - transfer->actual_length; + } else if ( transfer->status ) { + context->srb->result = DID_ERROR<<16; + } + + mts_get_status(transfer); + + return; +} + + +static void mts_command_done( struct urb *transfer ) +/* Interrupt context! */ +{ + struct mts_transfer_context* context; + + MTS_INT_INIT(); + + if ( transfer->status ) { + context->srb->result = DID_ERROR<<16; + mts_transfer_cleanup(transfer); + + return; + } + + if ( context->data ) { + context->state = mts_con_data; + mts_int_submit_urb(transfer, + context->data_pipe, + context->data, + context->data_length, + mts_data_done); + } else mts_get_status(transfer); + + return; +} + + + + static const u8 mts_read_image_sig[] = { 0x28, 00, 00, 00 }; + static const u8 mts_read_image_sig_len = 4; + static const unsigned char mts_direction[256/8] = { + 0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77, + 0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + +#define MTS_DIRECTION_IS_IN(x) ((mts_direction[x>>3] >> (x & 7)) & 1) + +static void +mts_build_transfer_context( Scsi_Cmnd *srb, struct mts_desc* desc ) +{ + + int pipe; + + + MTS_DEBUG_GOT_HERE(); + + desc->context.instance = desc; + desc->context.srb = srb; + desc->context.state = mts_con_command; + atomic_set(&desc->context.do_abort,0); + + if ( !srb->bufflen ){ + desc->context.data = 0; + desc->context.data_length = 0; + return; + } else { + desc->context.data = srb->buffer; + desc->context.data_length = srb->bufflen; + } + + /* can't rely on srb->sc_data_direction */ + + /* Brutally ripped from usb-storage */ + + if ( !memcmp( srb->cmnd, mts_read_image_sig, mts_read_image_sig_len ) +) { pipe = usb_rcvbulkpipe(desc->usb_dev,desc->ep_image); + MTS_DEBUG( "transfering from desc->ep_image == %d\n", + (int)desc->ep_image ); + } else if ( MTS_DIRECTION_IS_IN(srb->cmnd[0]) ) { + pipe = usb_rcvbulkpipe(desc->usb_dev,desc->ep_response); + MTS_DEBUG( "transfering from desc->ep_response == %d\n", + (int)desc->ep_response); + } else { + MTS_DEBUG("transfering to desc->ep_out == %d\n", + (int)desc->ep_out); + pipe = usb_sndbulkpipe(desc->usb_dev,desc->ep_out); + } + desc->context.data_pipe = pipe; +} + + +static +int mts_scsi_queuecommand( Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback ) +{ + struct mts_desc* desc = (struct mts_desc*)(srb->host->hostdata[0]); + int err = 0; + int res; + + MTS_DEBUG_GOT_HERE(); + mts_show_command(srb); + mts_debug_dump(desc); + + if ( srb->device->lun || srb->device->id || srb->device->channel ) { + + MTS_DEBUG("Command to LUN=%d ID=%d CHANNEL=%d from SCSI layer\n",(int)srb->device->lun,(int)srb->device->id, (int)srb->device->channel ); + + MTS_DEBUG("this device doesn't exist\n"); + + srb->result = DID_BAD_TARGET << 16; + + if(callback) + callback(srb); + + goto out; + } + + down(&desc->lock); + + MTS_DEBUG_GOT_HERE(); + mts_show_command(srb); + + + FILL_BULK_URB(&desc->urb, + desc->usb_dev, + usb_sndbulkpipe(desc->usb_dev,desc->ep_out), + srb->cmnd, + srb->cmd_len, + mts_command_done, + &desc->context + ); + + + mts_build_transfer_context( srb, desc ); + desc->context.final_callback = callback; + desc->urb.timeout = 100; + desc->urb.transfer_flags = USB_ASYNC_UNLINK; + +/* desc->urb.transfer_flags = USB_DISABLE_SPD;*/ + + res=usb_submit_urb(&desc->urb); + + if(res){ + MTS_ERROR("error %d submitting URB\n",(int)res); + srb->result = DID_ERROR << 16; + + if(callback) + callback(srb); + + goto out; + } + + MTS_DEBUG_GOT_HERE(); + + 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: "microtek", + detect: mts_scsi_detect, + release: mts_scsi_release, + command: 0, + queuecommand: mts_scsi_queuecommand, + + eh_abort_handler: mts_scsi_abort, + eh_device_reset_handler:0, + eh_bus_reset_handler: 0, + eh_host_reset_handler: mts_scsi_host_reset, + + can_queue: 1, + this_id: -1, + cmd_per_lun: 1, + present: 0, + unchecked_isa_dma: FALSE, + use_clustering: FALSE, + use_new_eh_code: TRUE, + emulated: TRUE +}; + + +/* USB layer driver interface implementation */ + +static void mts_usb_disconnect (struct usb_device *dev, void *ptr) +{ + struct mts_desc* to_remove = (struct mts_desc*)ptr; + + MTS_DEBUG_GOT_HERE(); + + /* leave the list - lock it */ + down(&mts_list_semaphore); + + mts_remove_nolock(to_remove); + + up(&mts_list_semaphore); +} + +struct vendor_product +{ + u16 idVendor; + u16 idProduct; + char* name; + enum + { + mts_sup_unknown=0, + mts_sup_alpha, + mts_sup_full + } + support_status; +} ; + + +/* These are taken from the msmUSB.inf file on the Windows driver CD */ +const static struct vendor_product mts_supported_products[] = +{ + { + 0x4ce, 0x300,"Phantom 336CX",mts_sup_unknown + }, + { + 0x5da, 0x94,"Phantom 336CX",mts_sup_unknown + }, + { + 0x5da, 0x99,"Scanmaker X6",mts_sup_alpha + }, + { + 0x5da, 0x9a,"Phantom C6",mts_sup_unknown + }, + { + 0x5da, 0xa0,"Phantom 336CX",mts_sup_unknown + }, + { + 0x5da, 0xa3,"ScanMaker V6USL",mts_sup_unknown + }, + { + 0x5da, 0x80a3,"ScanMaker V6USL",mts_sup_unknown + }, + { + 0x5da, 0x80ac,"Scanmaker V6UL",mts_sup_unknown + } +} +; +const static struct vendor_product* mts_last_product = &mts_supported_products[ sizeof(mts_supported_products) / sizeof(struct vendor_product) ]; + /* Must never be derefed, points to one after last entry */ + + +static void * mts_usb_probe (struct usb_device *dev, unsigned int interface) +{ + int i; + int result; + int ep_out = -1; + int ep_in_set[3]; /* this will break if we have more than three endpoints + which is why we check */ + int *ep_in_current = ep_in_set; + + struct mts_desc * new_desc; + struct vendor_product const* p; + + /* the altsettting 0 on the interface we're probing */ + struct usb_interface_descriptor *altsetting; + + MTS_DEBUG_GOT_HERE(); + MTS_DEBUG( "usb-device descriptor at %x\n", (int)dev ); + + MTS_DEBUG( "product id = 0x%x, vendor id = 0x%x\n", + (int)dev->descriptor.idProduct, + (int)dev->descriptor.idVendor ); + + MTS_DEBUG_GOT_HERE(); + + /* checking IDs */ + for( p = mts_supported_products; p != mts_last_product; p++ ) + if ( dev->descriptor.idVendor == p->idVendor && + dev->descriptor.idProduct == p->idProduct ) + goto is_supported; + else + MTS_DEBUG( "doesn't appear to be model %s\n", p->name ); + + MTS_DEBUG( "returning NULL: unsupported\n" ); + + return NULL; + + is_supported: + + MTS_DEBUG_GOT_HERE(); + + MTS_DEBUG( "found model %s\n", p->name ); + if ( p->support_status != mts_sup_full ) + MTS_MESSAGE( "model %s is not known to be fully supported, reports welcome!\n", + p->name ); + + /* the altsettting 0 on the interface we're probing */ + altsetting = + &(dev->actconfig->interface[interface].altsetting[0]); + + + /* Check if the config is sane */ + + if ( altsetting->bNumEndpoints != MTS_EP_TOTAL ) { + MTS_WARNING( "expecting %d got %d endpoints! Bailing out.\n", + (int)MTS_EP_TOTAL, (int)altsetting->bNumEndpoints ); + return NULL; + } + + for( i = 0; i < altsetting->bNumEndpoints; i++ ) { + if ((altsetting->endpoint[i].bmAttributes & + USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) { + + MTS_WARNING( "can only deal with bulk endpoints; endpoint %d is not bulk.\n", + (int)altsetting->endpoint[i].bEndpointAddress ); + } else { + if (altsetting->endpoint[i].bEndpointAddress & + USB_DIR_IN) + *ep_in_current++ + = altsetting->endpoint[i].bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK; + else { + if ( ep_out != -1 ) { + MTS_WARNING( "can only deal with one output endpoints. Bailing out." ); + return NULL; + } + + ep_out = altsetting->endpoint[i].bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK; + } + } + + } + + + if ( ep_out == -1 ) { + MTS_WARNING( "couldn't find an output bulk endpoint. Bailing out.\n" ); + return NULL; + } + + + /* I don't understand the following fully (it's from usb-storage) -- John */ + + /* set the interface -- STALL is an acceptable response here */ + result = usb_set_interface(dev, altsetting->bInterfaceNumber, 0); + + MTS_DEBUG("usb_set_interface returned %d.\n",result); + switch( result ) + { + case 0: /* no error */ + break; + + case -EPIPE: + usb_clear_halt(dev, usb_sndctrlpipe(dev, 0)); + MTS_DEBUG( "clearing clearing stall on control interface\n" ); + break; + + default: + MTS_DEBUG( "unknown error %d from usb_set_interface\n", + (int)result ); + return NULL; + } + + + /* 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 NULL; + } + + /* As done by usb_alloc_urb */ + memset( new_desc, 0, sizeof(*new_desc) ); + spin_lock_init(&new_desc->urb.lock); + + + /* initialising that descriptor */ + new_desc->usb_dev = dev; + new_desc->interface = interface; + + 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 ); + + if ( new_desc->ep_response != MTS_EP_RESPONSE ) + MTS_WARNING( "will this work? Response EP is not usually %d\n", + (int)new_desc->ep_response ); + + if ( new_desc->ep_image != MTS_EP_IMAGE ) + MTS_WARNING( "will this work? Image data EP is not usually %d\n", + (int)new_desc->ep_image ); + + + /* 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_module(MODULE_SCSI_HA, &(new_desc->ctempl)); + /* Will get hit back in microtek_detect by this func */ + if ( result ) + { + MTS_ERROR( "error %d from scsi_register_module! Help!\n", + (int)result ); + + /* FIXME: need more cleanup? */ + kfree( new_desc ); + return NULL; + } + 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"); + + return (void *)new_desc; +} + + + +/* get us noticed by the rest of the kernel */ + +int __init microtek_drv_init(void) +{ + int result; + + MTS_DEBUG_GOT_HERE(); + init_MUTEX(&mts_list_semaphore); + + if ((result = usb_register(&mts_usb_driver)) < 0) { + MTS_DEBUG("usb_register returned %d\n", result ); + return -1; + } else { + MTS_DEBUG("driver registered.\n"); + } + + return 0; +} + +void __exit microtek_drv_exit(void) +{ + struct mts_desc* next; + + MTS_DEBUG_GOT_HERE(); + + 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); +module_exit(microtek_drv_exit); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/microtek.h linux/drivers/usb/microtek.h --- v2.4.0-test1/linux/drivers/usb/microtek.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/microtek.h Mon Jun 19 13:42:41 2000 @@ -0,0 +1,73 @@ + /* + * Driver for Microtek Scanmaker X6 USB scanner and possibly others. + * + * (C) Copyright 2000 John Fremlin + * (C) Copyright 2000 Oliver Neukum + * + * See microtek.c for history + * + */ + +typedef void (*mts_scsi_cmnd_callback)(Scsi_Cmnd *); +typedef void (*mts_usb_urb_callback) (struct urb *); + + +struct mts_transfer_context +{ + struct mts_desc* instance; + mts_scsi_cmnd_callback final_callback; + Scsi_Cmnd *srb; + + void* data; + unsigned data_length; + int data_pipe; + + enum { + mts_con_none, + mts_con_command, + mts_con_data, + mts_con_status, + mts_con_error, + mts_con_done + } + state; + + atomic_t do_abort; /* when != 0 URB completion routines will + return straightaway */ + + u8 status; /* status returned from ep_response after command completion */ +}; + + +struct mts_desc { + struct mts_desc *next; + struct mts_desc *prev; + + struct usb_device *usb_dev; + + int interface; + + /* Endpoint addresses */ + u8 ep_out; + u8 ep_response; + u8 ep_image; + + struct Scsi_Host * host; + Scsi_Host_Template ctempl; + int host_number; + + struct semaphore lock; + + struct urb urb; + struct mts_transfer_context context; +}; + + +#define MTS_EP_OUT 0x1 +#define MTS_EP_RESPONSE 0x2 +#define MTS_EP_IMAGE 0x3 +#define MTS_EP_TOTAL 0x3 + +#define MTS_MAX_CHUNK_MASK ~0x3fu +/*maximum amount the scanner will transmit at once */ + diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/mousedev.c linux/drivers/usb/mousedev.c --- v2.4.0-test1/linux/drivers/usb/mousedev.c Thu May 11 15:30:08 2000 +++ linux/drivers/usb/mousedev.c Fri Jun 23 21:01:29 2000 @@ -1,7 +1,7 @@ /* - * mousedev.c Version 0.1 + * $Id: mousedev.c,v 1.10 2000/06/23 09:23:00 vojtech Exp $ * - * Copyright (c) 1999 Vojtech Pavlik + * Copyright (c) 1999-2000 Vojtech Pavlik * * Input driver to PS/2 or ImPS/2 device driver module. * @@ -47,7 +47,7 @@ #endif struct mousedev { - int used; + int exist; int open; int minor; wait_queue_head_t wait; @@ -138,8 +138,7 @@ list->ready = 1; - if (list->fasync) - kill_fasync(list->fasync, SIGIO, POLL_IN); + kill_fasync(&list->fasync, SIGIO, POLL_IN); list = list->next; } @@ -173,25 +172,32 @@ struct input_handle *handle = mousedev_handler.handle; while (handle) { struct mousedev *mousedev = handle->private; - if (!mousedev->open) - input_close_device(handle); + if (!mousedev->open) { + if (mousedev->exist) { + input_close_device(&mousedev->handle); + } else { + input_unregister_minor(mousedev->devfs); + mousedev_table[mousedev->minor] = NULL; + kfree(mousedev); + } + } handle = handle->hnext; } } else { - if (!mousedev_mix.open) - input_close_device(&list->mousedev->handle); + if (!mousedev_mix.open) { + if (list->mousedev->exist) { + input_close_device(&list->mousedev->handle); + } else { + input_unregister_minor(list->mousedev->devfs); + mousedev_table[list->mousedev->minor] = NULL; + kfree(list->mousedev); + } + } } } - if (!--list->mousedev->used) { - input_unregister_minor(list->mousedev->devfs); - mousedev_table[list->mousedev->minor] = NULL; - kfree(list->mousedev); - } - kfree(list); - MOD_DEC_USE_COUNT; return 0; } @@ -203,12 +209,8 @@ if (i > MOUSEDEV_MINORS || !mousedev_table[i]) return -ENODEV; - MOD_INC_USE_COUNT; - - if (!(list = kmalloc(sizeof(struct mousedev_list), GFP_KERNEL))) { - MOD_DEC_USE_COUNT; + if (!(list = kmalloc(sizeof(struct mousedev_list), GFP_KERNEL))) return -ENOMEM; - } memset(list, 0, sizeof(struct mousedev_list)); list->mousedev = mousedev_table[i]; @@ -216,20 +218,20 @@ mousedev_table[i]->list = list; file->private_data = list; - list->mousedev->used++; - if (!list->mousedev->open++) { if (list->mousedev->minor == MOUSEDEV_MIX) { struct input_handle *handle = mousedev_handler.handle; while (handle) { struct mousedev *mousedev = handle->private; if (!mousedev->open) - input_open_device(handle); + if (mousedev->exist) + input_open_device(handle); handle = handle->hnext; } } else { - if (!mousedev_mix.open) - input_open_device(&list->mousedev->handle); + if (!mousedev_mix.open) + if (list->mousedev->exist) + input_open_device(&list->mousedev->handle); } } @@ -311,8 +313,7 @@ list->buffer = list->bufsiz; } - if (list->fasync) - kill_fasync(list->fasync, SIGIO, POLL_IN); + kill_fasync(&list->fasync, SIGIO, POLL_IN); wake_up_interruptible(&list->mousedev->wait); @@ -376,6 +377,7 @@ } struct file_operations mousedev_fops = { + owner: THIS_MODULE, read: mousedev_read, write: mousedev_write, poll: mousedev_poll, @@ -408,7 +410,7 @@ memset(mousedev, 0, sizeof(struct mousedev)); init_waitqueue_head(&mousedev->wait); - mousedev->used = 1; + mousedev->exist = 1; mousedev->minor = minor; mousedev_table[minor] = mousedev; @@ -421,7 +423,7 @@ if (mousedev_mix.open) input_open_device(&mousedev->handle); - printk("mouse%d: PS/2 mouse device for input%d\n", minor, dev->number); + printk(KERN_INFO "mouse%d: PS/2 mouse device for input%d\n", minor, dev->number); return &mousedev->handle; } @@ -430,10 +432,13 @@ { struct mousedev *mousedev = handle->private; - if (mousedev->open || mousedev_mix.open) - input_close_device(handle); + mousedev->exist = 0; - if (!--mousedev->used) { + if (mousedev->open) { + input_close_device(handle); + } else { + if (mousedev_mix.open) + input_close_device(handle); input_unregister_minor(mousedev->devfs); mousedev_table[mousedev->minor] = NULL; kfree(mousedev); @@ -455,11 +460,11 @@ memset(&mousedev_mix, 0, sizeof(struct mousedev)); init_waitqueue_head(&mousedev_mix.wait); mousedev_table[MOUSEDEV_MIX] = &mousedev_mix; - mousedev_mix.used = 1; + mousedev_mix.exist = 1; mousedev_mix.minor = MOUSEDEV_MIX; mousedev_mix.devfs = input_register_minor("mice", MOUSEDEV_MIX, MOUSEDEV_MINOR_BASE); - printk("mice: PS/2 mouse device common for all mice\n"); + printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n"); return 0; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/ov511.c linux/drivers/usb/ov511.c --- v2.4.0-test1/linux/drivers/usb/ov511.c Mon Jun 19 16:32:00 2000 +++ linux/drivers/usb/ov511.c Mon Jun 19 13:42:42 2000 @@ -2,8 +2,8 @@ * OmniVision OV511 Camera-to-USB Bridge Driver * * Copyright (c) 1999-2000 Mark W. McClelland - * Many improvements by Bret Wallach - * Color fixes by by Orion Sky Lawlor, olawlor@acm.org, 2/26/2000 + * Many improvements by Bret Wallach + * Color fixes by by Orion Sky Lawlor (2/26/2000) * Snapshot code by Kevin Moore * OV7620 fixes by Charl P. Botha * Changes by Claudio Matsuoka @@ -30,7 +30,7 @@ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -static const char version[] = "1.15"; +static const char version[] = "1.17"; #define __NO_VERSION__ @@ -55,6 +55,8 @@ #include "ov511.h" +#undef OV511_GBR422 /* Experimental -- sets the 7610 to GBR422 */ + #define OV511_I2C_RETRIES 3 /* Video Size 640 x 480 x 3 bytes for RGB */ @@ -64,8 +66,8 @@ #define DEFAULT_WIDTH 640 #define DEFAULT_HEIGHT 480 -#define GET_SEGSIZE(p) ((p) == VIDEO_PALETTE_RGB24 ? 384 : 256) -#define GET_DEPTH(p) ((p) == VIDEO_PALETTE_RGB24 ? 24 : 8) +#define GET_SEGSIZE(p) ((p) == VIDEO_PALETTE_GREY ? 256 : 384) +#define GET_DEPTH(p) ((p) == VIDEO_PALETTE_GREY ? 8 : 24) /* PARAMETER VARIABLES: */ static int autoadjust = 1; /* CCD dynamically changes exposure, etc... */ @@ -280,6 +282,7 @@ /* IMPORTANT: This output MUST be kept under PAGE_SIZE * or we need to get more sophisticated. */ + out += sprintf (out, "driver_version : %s\n", version); out += sprintf (out, "custom_id : %d\n", ov511->customid); out += sprintf (out, "model : %s\n", ov511->desc ? clist[ov511->desc].description : "unknown"); @@ -300,10 +303,6 @@ ov511->frame[i].depth); out += sprintf (out, " size : %d %d\n", ov511->frame[i].width, ov511->frame[i].height); -#if 0 - out += sprintf (out, " hdr_size : %d %d\n", - ov511->frame[i].hdrwidth, ov511->frame[i].hdrheight); -#endif out += sprintf (out, " format : "); for (j = 0; plist[j].num >= 0; j++) { if (plist[j].num == ov511->frame[i].format) { @@ -317,10 +316,6 @@ ov511->frame[i].segsize); out += sprintf (out, " data_buffer : 0x%p\n", ov511->frame[i].data); -#if 0 - out += sprintf (out, " bytesread : %ld\n", - ov511->frame[i].bytes_read); -#endif } out += sprintf (out, "snap_enabled : %s\n", YES_NO (ov511->snap_enabled)); out += sprintf (out, "bridge : %s\n", @@ -846,28 +841,20 @@ return 0; } -/* FIXME: add 400x300, 176x144, 160x140 */ +/* FIXME: 176x144, 160x140 */ +/* LNCNT values fixed by Lawrence Glaister */ static struct mode_list mlist[] = { - { 640, 480, VIDEO_PALETTE_GREY, 0x4f, 0x3d, 0x00, 0x00, - 0x4f, 0x3d, 0x00, 0x00, 0x04, 0x03, 0x24, 0x04, 0x9e }, - { 640, 480, VIDEO_PALETTE_RGB24,0x4f, 0x3d, 0x00, 0x00, - 0x4f, 0x3d, 0x00, 0x00, 0x06, 0x03, 0x24, 0x04, 0x9e }, - { 320, 240, VIDEO_PALETTE_GREY, 0x27, 0x1f, 0x00, 0x00, - 0x27, 0x1f, 0x00, 0x00, 0x01, 0x03, 0x04, 0x24, 0x1e }, - { 320, 240, VIDEO_PALETTE_RGB24,0x27, 0x1f, 0x00, 0x00, - 0x27, 0x1f, 0x00, 0x00, 0x01, 0x03, 0x04, 0x24, 0x1e }, - { 352, 288, VIDEO_PALETTE_GREY, 0x2b, 0x25, 0x00, 0x00, - 0x2b, 0x25, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e }, - { 352, 288, VIDEO_PALETTE_RGB24,0x2b, 0x25, 0x00, 0x00, - 0x2b, 0x25, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e }, - { 384, 288, VIDEO_PALETTE_GREY, 0x2f, 0x25, 0x00, 0x00, - 0x2f, 0x25, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e }, - { 384, 288, VIDEO_PALETTE_RGB24,0x2f, 0x25, 0x00, 0x00, - 0x2f, 0x25, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e }, - { 448, 336, VIDEO_PALETTE_GREY, 0x37, 0x29, 0x00, 0x00, - 0x37, 0x29, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e }, - { 448, 336, VIDEO_PALETTE_RGB24,0x37, 0x29, 0x00, 0x00, - 0x37, 0x29, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e }, + /* W H C PXCNT LNCNT PXDIV LNDIV M420 COMA COMC COML */ + { 640, 480, 0, 0x4f, 0x3b, 0x00, 0x00, 0x03, 0x24, 0x04, 0x9e }, + { 640, 480, 1, 0x4f, 0x3b, 0x00, 0x00, 0x03, 0x24, 0x04, 0x9e }, + { 320, 240, 0, 0x27, 0x1d, 0x00, 0x00, 0x03, 0x04, 0x24, 0x1e }, + { 320, 240, 1, 0x27, 0x1d, 0x00, 0x00, 0x03, 0x04, 0x24, 0x1e }, + { 352, 288, 0, 0x2b, 0x25, 0x00, 0x00, 0x03, 0x04, 0x04, 0x1e }, + { 352, 288, 1, 0x2b, 0x25, 0x00, 0x00, 0x03, 0x04, 0x04, 0x1e }, + { 384, 288, 0, 0x2f, 0x25, 0x00, 0x00, 0x03, 0x04, 0x04, 0x1e }, + { 384, 288, 1, 0x2f, 0x25, 0x00, 0x00, 0x03, 0x04, 0x04, 0x1e }, + { 448, 336, 0, 0x37, 0x29, 0x00, 0x00, 0x03, 0x04, 0x04, 0x1e }, + { 448, 336, 1 ,0x37, 0x29, 0x00, 0x00, 0x03, 0x04, 0x04, 0x1e }, { 0, 0 } }; @@ -875,11 +862,9 @@ ov511_mode_init_regs(struct usb_ov511 *ov511, int width, int height, int mode, int sub_flag) { - int rc = 0; - struct usb_device *dev = ov511->dev; - int hwsbase = 0; - int hwebase = 0; int i; + struct usb_device *dev = ov511->dev; + int hwsbase = 0, hwebase = 0; PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d", width, height, mode, sub_flag); @@ -930,87 +915,55 @@ break; } -#if 0 - /* FIXME: subwindow support is currently broken! - */ - if (width == 640 && height == 480) { - if (sub_flag) { - /* horizontal window start */ - ov511_i2c_write(dev, 0x17, hwsbase+(ov511->subx>>2)); - /* horizontal window end */ - ov511_i2c_write(dev, 0x18, - hwebase+((ov511->subx+ov511->subw)>>2)); - /* vertical window start */ - ov511_i2c_write(dev, 0x19, 0x5+(ov511->suby>>1)); - /* vertical window end */ - ov511_i2c_write(dev, 0x1a, - 0x5+((ov511->suby+ov511->subh)>>1)); - ov511_reg_write(dev, 0x12, (ov511->subw>>3)-1); - ov511_reg_write(dev, 0x13, (ov511->subh>>3)-1); - /* clock rate control */ - ov511_i2c_write(dev, 0x11, 0x01); - - /* Snapshot additions */ - ov511_reg_write(dev, 0x1a, (ov511->subw>>3)-1); - ov511_reg_write(dev, 0x1b, (ov511->subh>>3)-1); - ov511_reg_write(dev, 0x1c, 0x00); - ov511_reg_write(dev, 0x1d, 0x00); - } else { - ov511_i2c_write(dev, 0x17, hwsbase); - ov511_i2c_write(dev, 0x18, hwebase + (640>>2)); - ov511_i2c_write(dev, 0x19, 0x5); - ov511_i2c_write(dev, 0x1a, 5 + (480>>1)); - ov511_reg_write(dev, 0x12, 0x4f); - ov511_reg_write(dev, 0x13, 0x3d); - - /* Snapshot additions */ - ov511_reg_write(dev, 0x1a, 0x4f); - ov511_reg_write(dev, 0x1b, 0x3d); - ov511_reg_write(dev, 0x1c, 0x00); - ov511_reg_write(dev, 0x1d, 0x00); - - if (mode == VIDEO_PALETTE_GREY) { - ov511_i2c_write(dev, 0x11, 4); /* check */ - } else { - ov511_i2c_write(dev, 0x11, 6); /* check */ - } - } - - ov511_reg_write(dev, 0x14, 0x00); /* Pixel divisor */ - ov511_reg_write(dev, 0x15, 0x00); /* Line divisor */ - - /* FIXME?? Shouldn't below be true only for YUV420? */ - ov511_reg_write(dev, 0x18, 0x03); /* YUV420/422, YFIR */ + if (sub_flag) { + ov511_i2c_write(dev, 0x17, hwsbase+(ov511->subx>>2)); + ov511_i2c_write(dev, 0x18, hwebase+((ov511->subx+ov511->subw)>>2)); + ov511_i2c_write(dev, 0x19, 0x5+(ov511->suby>>1)); + ov511_i2c_write(dev, 0x1a, 0x5+((ov511->suby+ov511->subh)>>1)); + } else { + ov511_i2c_write(dev, 0x17, hwsbase); + ov511_i2c_write(dev, 0x18, hwebase + (640>>2)); + ov511_i2c_write(dev, 0x19, 0x5); + ov511_i2c_write(dev, 0x1a, 5 + (480>>1)); + } - ov511_i2c_write(dev, 0x12, 0x24); /* Common A */ - ov511_i2c_write(dev, 0x14, 0x04); /* Common C */ + for (i = 0; mlist[i].width; i++) { + int lncnt, pxcnt, clock; - /* 7620 doesn't have register 0x35, so play it safe */ - if (ov511->sensor != SEN_OV7620) - ov511_i2c_write(dev, 0x35, 0x9e); -#endif + if (width != mlist[i].width || height != mlist[i].height) + continue; - for (i = 0; mlist[i].width; i++) { - if (width != mlist[i].width || - height != mlist[i].height || - mode != mlist[i].mode) + if (!mlist[i].color && mode != VIDEO_PALETTE_GREY) continue; - ov511_reg_write(dev, 0x12, mlist[i].pxcnt); - ov511_reg_write(dev, 0x13, mlist[i].lncnt); + /* Here I'm assuming that snapshot size == image size. + * I hope that's always true. --claudio + */ + pxcnt = sub_flag ? (ov511->subw >> 3) - 1 : mlist[i].pxcnt; + lncnt = sub_flag ? (ov511->subh >> 3) - 1 : mlist[i].lncnt; + + ov511_reg_write(dev, 0x12, pxcnt); + ov511_reg_write(dev, 0x13, lncnt); ov511_reg_write(dev, 0x14, mlist[i].pxdv); ov511_reg_write(dev, 0x15, mlist[i].lndv); ov511_reg_write(dev, 0x18, mlist[i].m420); /* Snapshot additions */ - ov511_reg_write(dev, 0x1a, mlist[i].s_pxcnt); - ov511_reg_write(dev, 0x1b, mlist[i].s_lncnt); - ov511_reg_write(dev, 0x1c, mlist[i].s_pxdv); - ov511_reg_write(dev, 0x1d, mlist[i].s_lndv); - - ov511_i2c_write(dev, 0x11, mlist[i].clock); /* check */ + ov511_reg_write(dev, 0x1a, pxcnt); + ov511_reg_write(dev, 0x1b, lncnt); + ov511_reg_write(dev, 0x1c, mlist[i].pxdv); + ov511_reg_write(dev, 0x1d, mlist[i].lndv); + + /* Calculate and set the clock divisor */ + clock = ((sub_flag ? ov511->subw * ov511->subh : width * height) + * (mlist[i].color ? 3 : 2) / 2) / 66000; + ov511_i2c_write(dev, 0x11, clock); +#ifdef OV511_GBR422 + ov511_i2c_write(dev, 0x12, mlist[i].common_A | 0x08); +#else ov511_i2c_write(dev, 0x12, mlist[i].common_A); +#endif ov511_i2c_write(dev, 0x14, mlist[i].common_C); /* 7620 doesn't have register 0x35, so play it safe */ @@ -1020,20 +973,20 @@ break; } + if (ov511_restart(ov511->dev) < 0) + return -EIO; + if (mlist[i].width == 0) { err("Unknown mode (%d, %d): %d", width, height, mode); - rc = -EINVAL; + return -EINVAL; } - if (ov511_restart(ov511->dev) < 0) - return -EIO; - #ifdef OV511_DEBUG if (debug >= 5) ov511_dump_i2c_regs(dev); #endif - return rc; + return 0; } /********************************************************************** @@ -1115,7 +1068,7 @@ * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199 * 8 9 ... 15 72 73 ... 79 200 201 ... 207 * ... ... ... - * 56 57 ... 63 120 121 127 248 249 ... 255 + * 56 57 ... 63 120 121 ... 127 ... 248 249 ... 255 * * Note that the U and V data in one segment represents a 16 x 16 pixel * area, but the Y data represents a 32 x 8 pixel area. @@ -1132,6 +1085,57 @@ #undef OV511_DUMPPIX +#ifdef OV511_GBR422 +static void +ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0, + int iOutY, int iOutUV, int iHalf, int iWidth) +{ + int k, l, m; + unsigned char *pIn; + unsigned char *pOut, *pOut1; + + pIn = pIn0; + pOut = pOut0 + iOutUV + (force_rgb ? 2 : 0); + + for (k = 0; k < 8; k++) { + pOut1 = pOut; + for (l = 0; l < 8; l++) { + *pOut1 = *(pOut1 + 3) = *(pOut1 + iWidth*3) = + *(pOut1 + iWidth*3 + 3) = *pIn++; + pOut1 += 6; + } + pOut += iWidth*3*2; + } + + pIn = pIn0 + 64; + pOut = pOut0 + iOutUV + (force_rgb ? 0 : 2); + for (k = 0; k < 8; k++) { + pOut1 = pOut; + for (l = 0; l < 8; l++) { + *pOut1 = *(pOut1 + 3) = *(pOut1 + iWidth*3) = + *(pOut1 + iWidth*3 + 3) = *pIn++; + pOut1 += 6; + } + pOut += iWidth*3*2; + } + + pIn = pIn0 + 128; + pOut = pOut0 + iOutY + 1; + for (k = 0; k < 4; k++) { + pOut1 = pOut; + for (l = 0; l < 8; l++) { + for (m = 0; m < 8; m++) { + *pOut1 = *pIn++; + pOut1 += 3; + } + pOut1 += (iWidth - 8) * 3; + } + pOut += 8 * 3; + } +} + +#else + static void ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0, int iOutY, int iOutUV, int iHalf, int iWidth) @@ -1225,6 +1229,7 @@ } #endif } +#endif /* * For 640x480 RAW BW images, data shows up in 1200 256 byte segments. @@ -1252,7 +1257,7 @@ for (m = 0; m < 8; m++) { *pOut1++ = *pIn++; } - pOut1 += iWidth - WDIV; + pOut1 += iWidth - 8; } pOut += 8; } @@ -1350,12 +1355,10 @@ /* Frame end */ if (cdata[8] & 0x80) { -#if 0 struct timeval *ts; ts = (struct timeval *)(frame->data + MAX_FRAME_SIZE); - do_gettimeofday (ts); -#endif + do_gettimeofday (ts); PDEBUG(4, "Frame end, curframe = %d, packnum=%d, hw=%d, vw=%d", ov511->curframe, (int)(cdata[ov511->packet_size - 1]), @@ -1456,9 +1459,9 @@ } /* - * iY counts segment lines - * jY counts segment columns - * iOutY is the offset (in bytes) of the segment upper left corner + * i counts segment lines + * j counts segment columns + * iOut is the offset (in bytes) of the upper left corner */ iY = iSegY / (frame->width / WDIV); jY = iSegY - iY * (frame->width / WDIV); @@ -1467,11 +1470,15 @@ jUV = iSegUV - iUV * (frame->width / WDIV * 2); iOutUV = (iUV*HDIV*2*frame->width + jUV*WDIV/2) * (frame->depth >> 3); - if (frame->format == VIDEO_PALETTE_GREY) + switch (frame->format) { + case VIDEO_PALETTE_GREY: ov511_parse_data_grey (pData, pOut, iOutY, frame->width); - else if (frame->format == VIDEO_PALETTE_RGB24) + break; + case VIDEO_PALETTE_RGB24: ov511_parse_data_rgb24 (pData, pOut, iOutY, iOutUV, iY & 1, frame->width); + break; + } pData = &cdata[iPix]; } @@ -1480,8 +1487,7 @@ if (frame->segment < frame->width * frame->height / 256) { ov511->scratchlen = (ov511->packet_size - 1) - iPix; if (ov511->scratchlen < frame->segsize) - memmove(ov511->scratch, pData, - ov511->scratchlen); + memmove(ov511->scratch, pData, ov511->scratchlen); else ov511->scratchlen = 0; } @@ -1677,25 +1683,23 @@ static int ov511_open(struct video_device *dev, int flags) { - int err = -EBUSY; struct usb_ov511 *ov511 = (struct usb_ov511 *)dev; - int i; + int i, err = 0; + MOD_INC_USE_COUNT; PDEBUG(4, "opening"); - down(&ov511->lock); - if (ov511->user) { - up(&ov511->lock); - return -EBUSY; - } + err = -EBUSY; + if (ov511->user) + goto out; err = -ENOMEM; /* Allocate memory for the frame buffers */ ov511->fbuf = rvmalloc(OV511_NUMFRAMES * MAX_DATA_SIZE); if (!ov511->fbuf) - return err; + goto out; ov511->sub_flag = 0; @@ -1710,7 +1714,7 @@ open_free_ret: while (--i) kfree(ov511->sbuf[i].data); rvfree(ov511->fbuf, 2 * MAX_DATA_SIZE); - return err; + goto out; } PDEBUG(4, "sbuf[%d] @ %p", i, ov511->sbuf[i].data); } @@ -1720,11 +1724,14 @@ goto open_free_ret; ov511->user++; + +out: up(&ov511->lock); - MOD_INC_USE_COUNT; + if (err) + MOD_DEC_USE_COUNT; - return 0; + return err; } static void ov511_close(struct video_device *dev) @@ -1737,8 +1744,6 @@ down(&ov511->lock); ov511->user--; - MOD_DEC_USE_COUNT; - ov511_stop_isoc(ov511); rvfree(ov511->fbuf, OV511_NUMFRAMES * MAX_DATA_SIZE); @@ -1751,6 +1756,9 @@ video_unregister_device(&ov511->vdev); kfree(ov511); } + + MOD_DEC_USE_COUNT; + } static int ov511_init_done(struct video_device *dev) @@ -1887,18 +1895,11 @@ return -EINVAL; if (vc.decimation) return -EINVAL; -#if 0 - vc.x /= 4; - vc.x *= 4; - vc.y /= 2; - vc.y *= 2; - vc.width /= 32; - vc.width *= 32; -#else + vc.x &= ~3L; vc.y &= ~1L; vc.y &= ~31L; -#endif + if (vc.width == 0) vc.width = 32; @@ -1989,6 +1990,7 @@ case VIDIOCMCAPTURE: { struct video_mmap vm; + int ret; if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) return -EFAULT; @@ -2017,8 +2019,12 @@ before changing modes */ interruptible_sleep_on(&ov511->wq); if (signal_pending(current)) return -EINTR; - ov511_mode_init_regs(ov511, vm.width, vm.height, + ret = ov511_mode_init_regs(ov511, vm.width, vm.height, vm.format, ov511->sub_flag); +#if 0 + if (ret < 0) + return ret; +#endif } ov511->frame[vm.frame].width = vm.width; @@ -2290,6 +2296,17 @@ int i, success; int rc; + /* Lawrence Glaister reports: + * + * Register 0x0f in the 7610 has the following effects: + * + * 0x85 (AEC method 1): Best overall, good contrast range + * 0x45 (AEC method 2): Very overexposed + * 0xa5 (spec sheet default): Ok, but the black level is + * shifted resulting in loss of contrast + * 0x05 (old driver setting): very overexposed, too much + * contrast + */ static struct ov511_regvals aRegvalsNorm7610[] = { { OV511_I2C_BUS, 0x10, 0xff }, { OV511_I2C_BUS, 0x16, 0x06 }, @@ -2299,16 +2316,16 @@ { OV511_I2C_BUS, 0x06, 0x00 }, { OV511_I2C_BUS, 0x12, 0x00 }, { OV511_I2C_BUS, 0x38, 0x81 }, - { OV511_I2C_BUS, 0x28, 0x24 }, /* 0c */ + { OV511_I2C_BUS, 0x28, 0x24 }, /* 0c */ { OV511_I2C_BUS, 0x05, 0x00 }, - { OV511_I2C_BUS, 0x0f, 0x05 }, + { OV511_I2C_BUS, 0x0f, 0x85 }, /* lg's setting */ { OV511_I2C_BUS, 0x15, 0x01 }, { OV511_I2C_BUS, 0x20, 0x1c }, { OV511_I2C_BUS, 0x23, 0x2a }, { OV511_I2C_BUS, 0x24, 0x10 }, { OV511_I2C_BUS, 0x25, 0x8a }, { OV511_I2C_BUS, 0x27, 0xc2 }, - { OV511_I2C_BUS, 0x29, 0x03 }, /* 91 */ + { OV511_I2C_BUS, 0x29, 0x03 }, /* 91 */ { OV511_I2C_BUS, 0x2a, 0x04 }, { OV511_I2C_BUS, 0x2c, 0xfe }, { OV511_I2C_BUS, 0x30, 0x71 }, @@ -2331,7 +2348,7 @@ { OV511_I2C_BUS, 0x12, 0x00 }, { OV511_I2C_BUS, 0x28, 0x24 }, { OV511_I2C_BUS, 0x05, 0x00 }, - { OV511_I2C_BUS, 0x0f, 0x05 }, + { OV511_I2C_BUS, 0x0f, 0x85 }, /* lg's setting */ { OV511_I2C_BUS, 0x15, 0x01 }, { OV511_I2C_BUS, 0x23, 0x00 }, { OV511_I2C_BUS, 0x24, 0x10 }, @@ -2530,9 +2547,6 @@ usb_driver_release_interface(&ov511_driver, &dev->actconfig->interface[ov511->iface]); - kfree(ov511); - ov511 = NULL; - return -EBUSY; } @@ -2570,9 +2584,12 @@ if (interface->bInterfaceSubClass != 0x00) return NULL; + /* Since code below may sleep, we use this as a lock */ + MOD_INC_USE_COUNT; + if ((ov511 = kmalloc(sizeof(*ov511), GFP_KERNEL)) == NULL) { err("couldn't kmalloc ov511 struct"); - return NULL; + goto error; } memset(ov511, 0, sizeof(*ov511)); @@ -2610,7 +2627,7 @@ /* Lifeview USB Life TV not supported */ if (clist[i].id == 38) { err("This device is not supported yet."); - return NULL; + goto error; } if (clist[i].id == -1) { @@ -2627,12 +2644,12 @@ if (!ov511_configure(ov511)) { ov511->user = 0; init_MUTEX(&ov511->lock); /* to 1 == available */ - return ov511; } else { err("Failed to configure camera"); goto error; } + MOD_DEC_USE_COUNT; return ov511; error: @@ -2641,6 +2658,7 @@ ov511 = NULL; } + MOD_DEC_USE_COUNT; return NULL; } @@ -2649,7 +2667,7 @@ { struct usb_ov511 *ov511 = (struct usb_ov511 *) ptr; -// video_unregister_device(&ov511->vdev); + MOD_INC_USE_COUNT; /* We don't want people trying to open up the device */ if (!ov511->user) @@ -2692,10 +2710,12 @@ #endif /* Free the memory */ - if (!ov511->user) { + if (ov511 && !ov511->user) { kfree(ov511); ov511 = NULL; } + + MOD_DEC_USE_COUNT; } static struct usb_driver ov511_driver = { diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/ov511.h linux/drivers/usb/ov511.h --- v2.4.0-test1/linux/drivers/usb/ov511.h Tue May 23 15:31:35 2000 +++ linux/drivers/usb/ov511.h Mon Jun 19 13:42:42 2000 @@ -339,16 +339,11 @@ struct mode_list { int width; int height; - int mode; - u8 pxcnt; - u8 lncnt; - u8 pxdv; - u8 lndv; - u8 s_pxcnt; - u8 s_lncnt; - u8 s_pxdv; - u8 s_lndv; - u8 clock; + int color; /* 0=grayscale, 1=color */ + u8 pxcnt; /* pixel counter */ + u8 lncnt; /* line counter */ + u8 pxdv; /* pixel divisor */ + u8 lndv; /* line divisor */ u8 m420; u8 common_A; u8 common_C; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/pegasus.c linux/drivers/usb/pegasus.c --- v2.4.0-test1/linux/drivers/usb/pegasus.c Tue May 23 15:31:35 2000 +++ linux/drivers/usb/pegasus.c Fri Jun 23 20:59:33 2000 @@ -1,11 +1,37 @@ /* ** Pegasus: USB 10/100Mbps/HomePNA (1Mbps) Controller ** -** Copyright (R) 1999,2000 Petko Manolov - Petkan (petkan@spct.net) +** Copyright (c) 1999,2000 Petko Manolov - Petkan (petkan@spct.net) +** ** -** Distribute under GPL version 2 or later. +** ChangeLog: +** .... Most of the time spend reading sources & docs. +** v0.2.x First official release for the Linux kernel. +** v0.3.0 Beutified and structured, some bugs fixed. +** v0.3.x URBifying bulk requests and bugfixing. First relatively +** stable release. Still can touch device's registers only +** from top-halves. +** v0.4.0 Control messages remained unurbified are now URBs. +** Now we can touch the HW at any time. */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 #include #include @@ -16,7 +42,7 @@ #include -static const char *version = __FILE__ ": v0.3.12 2000/05/22 (C) 1999-2000 Petko Manolov (petkan@spct.net)\n"; +static const char *version = __FILE__ ": v0.4.0 2000/06/15 (C) 1999-2000 Petko Manolov (petkan@spct.net)\n"; #define PEGASUS_MTU 1500 @@ -24,17 +50,39 @@ #define SROM_WRITE 0x01 #define SROM_READ 0x02 #define PEGASUS_TX_TIMEOUT (HZ*5) +#define PEGASUS_CTRL_TIMEOUT 1000 #define PEGASUS_RESET 1 #define ALIGN(x) x __attribute__((aligned(L1_CACHE_BYTES))) +enum pegasus_registers { + EthCtrl0 = 0, + EthCtrl1 = 1, + EthCtrl2 = 2, + EthID = 0x10, + EpromOffset = 0x20, + EpromData = 0x21, /* 0x21 low, 0x22 high byte */ + EpromCtrl = 0x23, + PhyAddr = 0x25, + PhyData = 0x26, /* 0x26 low, 0x27 high byte */ + PhyCtrl = 0x28, + UsbStst = 0x2a, + EthTxStat0 = 0x2b, + EthTxStat1 = 0x2c, + EthRxStat = 0x2d, + Gpio0 = 0x7e, + Gpio1 = 0x7f, +}; + + struct pegasus { struct usb_device *usb; struct net_device *net; struct net_device_stats stats; int flags; - spinlock_t pegasus_lock; - struct urb rx_urb, tx_urb, intr_urb; + spinlock_t pegasus_lock, ctrl_lock; + struct urb rx_urb, tx_urb, intr_urb, ctrl_urb; + devrequest dr; unsigned char ALIGN(rx_buff[PEGASUS_MAX_MTU]); unsigned char ALIGN(tx_buff[PEGASUS_MAX_MTU]); unsigned char ALIGN(intr_buff[8]); @@ -64,8 +112,11 @@ {"D-Link DSB-650TX", 0x2001, 0x4001, NULL}, {"D-Link DSB-650TX", 0x2001, 0x4002, NULL}, {"D-Link DSB-650TX(PNA)", 0x2001, 0x4003, NULL}, + {"D-Link DU-E10", 0x07b8, 0xabc1, NULL}, + {"D-Link DU-E100", 0x07b8, 0x4002, NULL}, {"Linksys USB100TX", 0x066b, 0x2203, NULL}, {"Linksys USB100TX", 0x066b, 0x2204, NULL}, + {"Linksys USB Ethernet Adapter", 0x066b, 0x2206, NULL}, {"SMC 202 USB Ethernet", 0x0707, 0x0200, NULL}, {"ADMtek AN986 \"Pegasus\" USB Ethernet (eval board)", 0x07a6, 0x0986, NULL}, {"Accton USB 10/100 Ethernet Adapter", 0x083a, 0x1046, NULL}, @@ -75,23 +126,120 @@ }; -#define pegasus_get_registers(dev, indx, size, data)\ - usb_control_msg(dev, usb_rcvctrlpipe(dev,0), 0xf0, 0xc0, 0, indx, data, size, HZ); -#define pegasus_set_registers(dev, indx, size, data)\ - usb_control_msg(dev, usb_sndctrlpipe(dev,0), 0xf1, 0x40, 0, indx, data, size, HZ); -#define pegasus_set_register(dev, indx, value) \ - { __u8 data = value; \ - usb_control_msg(dev, usb_sndctrlpipe(dev,0), 0xf1, 0x40, data, indx, &data, 1, HZ);} + +static void pegasus_ctrl_end( urb_t *urb ) +{ + if ( urb->status ) + warn("ctrl_urb end status %d", urb->status); +} + + +static int pegasus_ctrl_timeout( urb_t *ctrl_urb ) +{ + int timeout=0; + + while ( ctrl_urb->status == -EINPROGRESS ) { + if ( timeout++ < PEGASUS_CTRL_TIMEOUT ) { + udelay(100); + continue; + } + err("ctrl urb busy %d", ctrl_urb->status); + usb_unlink_urb( ctrl_urb ); + return ctrl_urb->status; + } + return 0; +} + + +static int pegasus_get_registers( struct pegasus *pegasus, __u16 indx, __u16 size, void *data ) +{ + int ret; + + + spin_lock( &pegasus->ctrl_lock ); + pegasus->dr.requesttype = 0xc0; + pegasus->dr.request = 0xf0; + pegasus->dr.value = 0x0; + pegasus->dr.index = indx; + pegasus->dr.length = pegasus->ctrl_urb.transfer_buffer_length = size; + + FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb, + usb_rcvctrlpipe(pegasus->usb,0), (char *)&pegasus->dr, + data, size, pegasus_ctrl_end, pegasus ); + + if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) + err("BAD CTRLs %d", ret); + else + ret = pegasus_ctrl_timeout( &pegasus->ctrl_urb ); + + spin_unlock( &pegasus->ctrl_lock ); + + return ret; +} + + +static int pegasus_set_registers( struct pegasus *pegasus, __u16 indx, __u16 size, void *data ) +{ + int ret; + + + spin_lock( &pegasus->ctrl_lock ); + pegasus->dr.requesttype = 0x40; + pegasus->dr.request = 0xf1; + pegasus->dr.value = 0x0; + pegasus->dr.index = indx; + pegasus->dr.length = pegasus->ctrl_urb.transfer_buffer_length = size; + + FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb, + usb_sndctrlpipe(pegasus->usb,0), (char *)&pegasus->dr, + data, size, pegasus_ctrl_end, pegasus ); + + if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) + err("BAD CTRL %d", ret); + else + ret = pegasus_ctrl_timeout( &pegasus->ctrl_urb ); + + spin_unlock( &pegasus->ctrl_lock ); + + return ret; +} -static int pegasus_read_phy_word(struct usb_device *dev, __u8 index, __u16 *regdata) +static int pegasus_set_register( struct pegasus *pegasus, __u16 indx,__u8 data ) +{ + int ret; + + + spin_lock( &pegasus->ctrl_lock ); + pegasus->dr.requesttype = 0x40; + pegasus->dr.request = 0xf1; + pegasus->dr.value = data; + pegasus->dr.index = indx; + pegasus->dr.length = pegasus->ctrl_urb.transfer_buffer_length = 1; + + FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb, + usb_sndctrlpipe(pegasus->usb,0), (char *)&pegasus->dr, + &data, 1, pegasus_ctrl_end, pegasus ); + + if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) + err("BAD CTRL %d", ret); + else + ret = pegasus_ctrl_timeout( &pegasus->ctrl_urb ); + + spin_unlock( &pegasus->ctrl_lock ); + + return ret; +} + + +static int pegasus_read_phy_word(struct pegasus *pegasus, __u8 index, __u16 *regdata) { int i; __u8 data[4] = { 1, 0, 0, 0x40 + index }; - pegasus_set_registers(dev, 0x25, 4, data); + pegasus_set_registers(pegasus, PhyAddr, 4, data); for (i = 0; i < 100; i++) { - pegasus_get_registers(dev, 0x26, 3, data); + pegasus_get_registers(pegasus, PhyData, 3, data); if (data[2] & 0x80) { *regdata = *(__u16 *)(data); return 0; @@ -104,14 +252,14 @@ } -static int pegasus_write_phy_word(struct usb_device *dev, __u8 index, __u16 regdata) +static int pegasus_write_phy_word(struct pegasus *pegasus, __u8 index, __u16 regdata) { int i; __u8 data[4] = { 1, regdata, regdata >> 8, 0x20 + index }; - pegasus_set_registers(dev, 0x25, 4, data); + pegasus_set_registers(pegasus, PhyAddr, 4, data); for (i = 0; i < 100; i++) { - pegasus_get_registers(dev, 0x28, 1, data); + pegasus_get_registers(pegasus, PhyCtrl, 1, data); if (data[0] & 0x80) return 0; udelay(100); @@ -122,51 +270,51 @@ } -static int pegasus_rw_srom_word(struct usb_device *dev, __u8 index, __u16 *retdata, __u8 direction) +static int pegasus_rw_eprom_word(struct pegasus *pegasus, __u8 index, __u16 *retdata, __u8 direction) { int i; __u8 data[4] = { index, 0, 0, direction }; - pegasus_set_registers(dev, 0x20, 4, data); + pegasus_set_registers(pegasus, EpromOffset, 4, data); for (i = 0; i < 100; i++) { - pegasus_get_registers(dev, 0x23, 1, data); + pegasus_get_registers(pegasus, EpromCtrl, 1, data); if (data[0] & 4) { - pegasus_get_registers(dev, 0x21, 2, data); + pegasus_get_registers(pegasus, EpromData, 2, data); *retdata = *(__u16 *)data; return 0; } } - warn("pegasus_rw_srom_word() failed"); + warn("pegasus_rw_eprom_word() failed"); return 1; } -static int pegasus_get_node_id(struct usb_device *dev, __u8 *id) +static int pegasus_get_node_id(struct pegasus *pegasus, __u8 *id) { int i; for (i = 0; i < 3; i++) - if (pegasus_rw_srom_word(dev,i,(__u16 *)&id[i * 2],SROM_READ)) + if (pegasus_rw_eprom_word(pegasus,i,(__u16 *)&id[i*2],SROM_READ)) return 1; return 0; } -static int pegasus_reset_mac(struct usb_device *dev) +static int pegasus_reset_mac(struct pegasus *pegasus) { __u8 data = 0x8; int i; - pegasus_set_register(dev, 1, data); + pegasus_set_register(pegasus, EthCtrl1, data); for (i = 0; i < 100; i++) { - pegasus_get_registers(dev, 1, 1, &data); + pegasus_get_registers(pegasus, EthCtrl1, 1, &data); if (~data & 0x08) { if (loopback & 1) return 0; if (loopback & 2) - pegasus_write_phy_word(dev, 0, 0x4000); - pegasus_set_register(dev, 0x7e, 0x24); - pegasus_set_register(dev, 0x7e, 0x27); + pegasus_write_phy_word(pegasus, 0, 0x4000); + pegasus_set_register(pegasus, Gpio0, 0x24); + pegasus_set_register(pegasus, Gpio0, 0x27); return 0; } } @@ -180,22 +328,22 @@ __u16 partmedia, temp; __u8 node_id[6]; __u8 data[4]; + struct pegasus *pegasus = dev->priv; - if (pegasus_get_node_id(usb, node_id)) + if (pegasus_get_node_id(pegasus, node_id)) return 1; - pegasus_set_registers(usb, 0x10, 6, node_id); + pegasus_set_registers(pegasus, EthID, 6, node_id); memcpy(dev->dev_addr, node_id, 6); - if (pegasus_read_phy_word(usb, 1, &temp)) + if (pegasus_read_phy_word(pegasus, 1, &temp)) return 2; if ((~temp & 4) && !loopback) { - warn("%s: link NOT established (0x%x), check the cable.", + warn("%s: link NOT established (0x%x) - check the cable.", dev->name, temp); - /* return 3; FIXME */ } - if (pegasus_read_phy_word(usb, 5, &partmedia)) + if (pegasus_read_phy_word(pegasus, 5, &partmedia)) return 4; if ((partmedia & 0x1f) != 1) { @@ -207,7 +355,7 @@ data[1] = (partmedia & 0x100) ? 0x30 : ((partmedia & 0x80) ? 0x10 : 0); data[2] = (loopback & 1) ? 0x09 : 0x01; - pegasus_set_registers(usb, 0, 3, data); + pegasus_set_registers(pegasus, EthCtrl0, 3, data); return 0; } @@ -223,7 +371,7 @@ __u16 pkt_len; if (urb->status) { - info("%s: RX status %d", net->name, urb->status); + dbg("%s: RX status %d", net->name, urb->status); goto goon; } @@ -278,24 +426,26 @@ { struct pegasus *pegasus = urb->context; - spin_lock(&pegasus->pegasus_lock); if (urb->status) info("%s: TX status %d", pegasus->net->name, urb->status); +#if 1 /* Should be fixed */ + if (urb->status == -ETIMEDOUT) + pegasus_reset_mac(pegasus); +#endif netif_wake_queue(pegasus->net); - - spin_unlock(&pegasus->pegasus_lock); } static void pegasus_tx_timeout(struct net_device *net) { struct pegasus *pegasus = net->priv; - warn("%s: Tx timed out. Reseting...", net->name); + usb_unlink_urb(&pegasus->tx_urb); + warn("%s: Tx timed out. Reseting...", net->name); + pegasus_reset_mac( pegasus ); pegasus->stats.tx_errors++; net->trans_start = jiffies; - pegasus->flags |= PEGASUS_RESET; netif_wake_queue(net); } @@ -369,9 +519,14 @@ netif_stop_queue(net); - usb_unlink_urb(&pegasus->rx_urb); - usb_unlink_urb(&pegasus->tx_urb); - usb_unlink_urb(&pegasus->intr_urb); + if ( pegasus->ctrl_urb.status == -EINPROGRESS ) + usb_unlink_urb(&pegasus->ctrl_urb); + if ( pegasus->rx_urb.status == -EINPROGRESS ) + usb_unlink_urb(&pegasus->rx_urb); + if ( pegasus->tx_urb.status == -EINPROGRESS ) + usb_unlink_urb(&pegasus->tx_urb); + if ( pegasus->intr_urb.status == -EINPROGRESS ) + usb_unlink_urb(&pegasus->intr_urb); MOD_DEC_USE_COUNT; @@ -388,12 +543,12 @@ case SIOCDEVPRIVATE: data[0] = 1; case SIOCDEVPRIVATE+1: - pegasus_read_phy_word(pegasus->usb, data[1] & 0x1f, &data[3]); + pegasus_read_phy_word(pegasus, data[1] & 0x1f, &data[3]); return 0; case SIOCDEVPRIVATE+2: if (!capable(CAP_NET_ADMIN)) return -EPERM; - pegasus_write_phy_word(pegasus->usb, data[1] & 0x1f, data[2]); + pegasus_write_phy_word(pegasus, data[1] & 0x1f, data[2]); return 0; default: return -EOPNOTSUPP; @@ -404,19 +559,23 @@ static void pegasus_set_rx_mode(struct net_device *net) { struct pegasus *pegasus = net->priv; + __u8 tmp; netif_stop_queue(net); if (net->flags & IFF_PROMISC) { info("%s: Promiscuous mode enabled", net->name); -/* pegasus_set_register(pegasus->usb, 2, 0x04); FIXME */ + pegasus_get_registers(pegasus, EthCtrl2, 1, &tmp); + pegasus_set_register(pegasus, EthCtrl2, tmp | 4); } else if ((net->mc_count > multicast_filter_limit) || (net->flags & IFF_ALLMULTI)) { - pegasus_set_register(pegasus->usb, 0, 0xfa); - pegasus_set_register(pegasus->usb, 2, 0); + pegasus_set_register(pegasus, EthCtrl0, 0xfa); + pegasus_set_register(pegasus, EthCtrl2, 0); info("%s set allmulti", net->name); } else { info("%s: set Rx mode", net->name); + pegasus_get_registers(pegasus, EthCtrl2, 1, &tmp); + pegasus_set_register(pegasus, EthCtrl2, tmp & ~4); } netif_wake_queue(net); @@ -458,12 +617,6 @@ } memset(pegasus, 0, sizeof(struct pegasus)); - if (pegasus_reset_mac(dev)) { - err("can't reset MAC"); - kfree(pegasus); - return NULL; - } - net = init_etherdev(0, 0); net->priv = pegasus; net->open = pegasus_open; @@ -479,6 +632,7 @@ pegasus->usb = dev; pegasus->net = net; pegasus->pegasus_lock = SPIN_LOCK_UNLOCKED; + pegasus->ctrl_lock = SPIN_LOCK_UNLOCKED; FILL_BULK_URB(&pegasus->rx_urb, dev, usb_rcvbulkpipe(dev, 1), pegasus->rx_buff, PEGASUS_MAX_MTU, pegasus_read_bulk, @@ -489,7 +643,12 @@ FILL_INT_URB(&pegasus->intr_urb, dev, usb_rcvintpipe(dev, 3), pegasus->intr_buff, 8, pegasus_irq, pegasus, 500); - + if (pegasus_reset_mac(pegasus)) { + err("can't reset MAC"); + kfree(pegasus); + return NULL; + } + printk(KERN_INFO "%s: %s\n", net->name, usb_dev_id[dev_indx].name); return pegasus; @@ -509,10 +668,15 @@ dev_close(pegasus->net); unregister_netdev(pegasus->net); - - usb_unlink_urb(&pegasus->rx_urb); - usb_unlink_urb(&pegasus->tx_urb); - usb_unlink_urb(&pegasus->intr_urb); + + if ( pegasus->ctrl_urb.status == -EINPROGRESS ) + usb_unlink_urb(&pegasus->ctrl_urb); + if ( pegasus->rx_urb.status == -EINPROGRESS ) + usb_unlink_urb(&pegasus->rx_urb); + if ( pegasus->tx_urb.status == -EINPROGRESS ) + usb_unlink_urb(&pegasus->tx_urb); + if ( pegasus->intr_urb.status == -EINPROGRESS ) + usb_unlink_urb(&pegasus->intr_urb); kfree(pegasus); } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/printer.c linux/drivers/usb/printer.c --- v2.4.0-test1/linux/drivers/usb/printer.c Tue May 23 15:31:35 2000 +++ linux/drivers/usb/printer.c Mon Jun 19 13:42:42 2000 @@ -1,9 +1,10 @@ /* - * printer.c Version 0.4 + * printer.c Version 0.5 * - * Copyright (c) 1999 Michael Gee - * Copyright (c) 1999 Pavel Machek - * Copyright (c) 2000 Vojtech Pavlik + * Copyright (c) 1999 Michael Gee + * Copyright (c) 1999 Pavel Machek + * Copyright (c) 2000 Vojtech Pavlik + * Copyright (c) 2000 Randy Dunlap * * USB Printer Device Class driver for USB printers and printer cables * @@ -14,6 +15,7 @@ * v0.2 - some more cleanups * v0.3 - cleaner again, waitqueue fixes * v0.4 - fixes in unidirectional mode + * v0.5 - add DEVICE_ID string support */ /* @@ -44,6 +46,18 @@ #include #define USBLP_BUF_SIZE 8192 +#define DEVICE_ID_SIZE 1024 + +#define IOCNR_GET_DEVICE_ID 1 +#define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len) /* get device_id string */ + +/* + * A DEVICE_ID string may include the printer's serial number. + * It should end with a semi-colon (';'). + * An example from an HP 970C DeskJet printer is (this is one long string, + * with the serial number changed): +MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:Hewlett-Packard DeskJet 970C;SERN:US970CSEPROF;VSTATUS:$HB0$NC0,ff,DN,IDLE,CUT,K1,C0,DP,NR,KP000,CP027;VP:0800,FL,B0;VJ: ; + */ /* * USB Printer Requests @@ -67,6 +81,8 @@ int minor; /* minor number of device */ unsigned char used; /* True if open */ unsigned char bidir; /* interface is bidirectional */ + unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */ + /* first 2 bytes are (big-endian) length */ }; static struct usblp *usblp_table[USBLP_MINORS] = { NULL, /* ... */ }; @@ -75,21 +91,22 @@ * Functions for usblp control messages. */ -static int usblp_ctrl_msg(struct usblp *usblp, int request, int dir, int recip, void *buf, int len) +static int usblp_ctrl_msg(struct usblp *usblp, int request, int dir, int recip, int value, void *buf, int len) { int retval = usb_control_msg(usblp->dev, dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0), - request, USB_TYPE_CLASS | dir | recip, 0, usblp->ifnum, buf, len, HZ * 5); - dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d len: %#x result: %d", request, !!dir, recip, len, retval); + request, USB_TYPE_CLASS | dir | recip, value, usblp->ifnum, buf, len, HZ * 5); + dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d len: %#x result: %d", + request, !!dir, recip, value, len, retval); return retval < 0 ? retval : 0; } #define usblp_read_status(usblp, status)\ - usblp_ctrl_msg(usblp, USBLP_REQ_GET_STATUS, USB_DIR_IN, USB_RECIP_INTERFACE, status, 1) -#define usblp_get_id(usblp, id, maxlen)\ - usblp_ctrl_msg(usblp, USBLP_REQ_GET_ID, USB_DIR_IN, USB_RECIP_INTERFACE, id, maxlen) + usblp_ctrl_msg(usblp, USBLP_REQ_GET_STATUS, USB_DIR_IN, USB_RECIP_INTERFACE, 0, status, 1) +#define usblp_get_id(usblp, config, id, maxlen)\ + usblp_ctrl_msg(usblp, USBLP_REQ_GET_ID, USB_DIR_IN, USB_RECIP_INTERFACE, config, id, maxlen) #define usblp_reset(usblp)\ - usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_DIR_OUT, USB_RECIP_OTHER, NULL, 0) + usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_DIR_OUT, USB_RECIP_OTHER, 0, NULL, 0) /* * URB callback. @@ -121,8 +138,7 @@ return -EIO; } - if (status & LP_PERRORP) { - + if (~status & LP_PERRORP) { if (status & LP_POUTPA) { info("usblp%d: out of paper", usblp->minor); return -ENOSPC; @@ -161,10 +177,7 @@ if (usblp->used) return -EBUSY; - MOD_INC_USE_COUNT; - if ((retval = usblp_check_status(usblp))) { - MOD_DEC_USE_COUNT; return retval; } @@ -187,18 +200,17 @@ struct usblp *usblp = file->private_data; usblp->used = 0; - + if (usblp->dev) { if (usblp->bidir) - usb_unlink_urb(&usblp->readurb); - usb_unlink_urb(&usblp->writeurb); - MOD_DEC_USE_COUNT; + usb_unlink_urb(&usblp->readurb); + usb_unlink_urb(&usblp->writeurb); return 0; } usblp_table[usblp->minor] = NULL; + kfree(usblp->device_id_string); kfree(usblp); - MOD_DEC_USE_COUNT; return 0; } @@ -212,6 +224,34 @@ | (usblp->writeurb.status == -EINPROGRESS ? 0 : POLLOUT | POLLWRNORM); } +static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + int length; + struct usblp *usblp = file->private_data; + + if ((_IOC_TYPE(cmd) != 'P') || (_IOC_DIR(cmd) != _IOC_READ)) + return -EINVAL; + + switch (_IOC_NR(cmd)) { + case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */ + length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */ +#if 0 + dbg ("usblp_ioctl GET_DEVICE_ID: actlen=%d, user size=%d, string='%s'", + length, _IOC_SIZE(cmd), &usblp->device_id_string[2]); +#endif + if (length > _IOC_SIZE(cmd)) + length = _IOC_SIZE(cmd); /* truncate */ + if (copy_to_user ((unsigned char *)arg, usblp->device_id_string, (unsigned long) length)) + return -EFAULT; + break; + + default: + return -EINVAL; + } + + return 0; +} + static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct usblp *usblp = file->private_data; @@ -230,7 +270,7 @@ if (signal_pending(current)) return writecount ? writecount : -EINTR; - timeout = interruptible_sleep_on_timeout(&usblp->wait, timeout); + timeout = interruptible_sleep_on_timeout(&usblp->wait, timeout); } } @@ -248,14 +288,14 @@ usblp->writeurb.transfer_buffer_length = 0; } else { if (!(retval = usblp_check_status(usblp))) { - err("usblp%d: error %d writing to printer", - usblp->minor, usblp->writeurb.status); + err("usblp%d: error %d writing to printer (retval=%d)", + usblp->minor, usblp->writeurb.status, retval); return -EIO; } return retval; } - + if (writecount == count) continue; @@ -286,7 +326,7 @@ while (usblp->readurb.status == -EINPROGRESS) { if (signal_pending(current)) return -EINTR; - interruptible_sleep_on(&usblp->wait); + interruptible_sleep_on(&usblp->wait); } } @@ -318,6 +358,7 @@ struct usb_endpoint_descriptor *epread, *epwrite; struct usblp *usblp; int minor, i, alts = -1, bidir = 0; + int length, err; char *buf; for (i = 0; i < dev->actconfig->interface[ifnum].num_altsetting; i++) { @@ -386,6 +427,13 @@ return NULL; } + if (!(usblp->device_id_string = kmalloc(DEVICE_ID_SIZE, GFP_KERNEL))) { + err("out of memory"); + kfree(usblp); + kfree(buf); + return NULL; + } + FILL_BULK_URB(&usblp->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress), buf, 0, usblp_bulk, usblp); @@ -393,6 +441,27 @@ FILL_BULK_URB(&usblp->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress), buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, usblp_bulk, usblp); + /* Get the device_id string if possible. FIXME: Could make this kmalloc(length). */ + err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1); + if (err >= 0) { + length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */ + if (length < DEVICE_ID_SIZE) + usblp->device_id_string[length] = '\0'; + else + usblp->device_id_string[DEVICE_ID_SIZE - 1] = '\0'; + dbg ("usblp%d Device ID string [%d]=%s", + minor, length, &usblp->device_id_string[2]); + } + else { + err ("usblp%d: error = %d reading IEEE-1284 Device ID string", + minor, err); + usblp->device_id_string[0] = usblp->device_id_string[1] = '\0'; + } + +#ifdef DEBUG + usblp_check_status(usblp); +#endif + info("usblp%d: USB %sdirectional printer dev %d if %d alt %d", minor, bidir ? "Bi" : "Uni", dev->devnum, ifnum, alts); @@ -418,16 +487,20 @@ if (usblp->used) return; + kfree(usblp->device_id_string); + usblp_table[usblp->minor] = NULL; kfree(usblp); } static struct file_operations usblp_fops = { + owner: THIS_MODULE, read: usblp_read, write: usblp_write, + poll: usblp_poll, + ioctl: usblp_ioctl, open: usblp_open, release: usblp_release, - poll: usblp_poll, }; static struct usb_driver usblp_driver = { diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/scanner.c linux/drivers/usb/scanner.c --- v2.4.0-test1/linux/drivers/usb/scanner.c Thu May 11 15:30:08 2000 +++ linux/drivers/usb/scanner.c Mon Jun 19 13:42:42 2000 @@ -1,7 +1,7 @@ /* -*- linux-c -*- */ /* - * Driver for USB Scanners (linux-2.3.99-pre6-3) + * Driver for USB Scanners (linux-2.4.0test1-ac7) * * Copyright (C) 1999, 2000 David E. Nelson * @@ -192,6 +192,12 @@ * scanner lookup/ident table. Thanks Randy. * - Documentation updates. * - Added wait queues to read_scanner(). + * + * + * 0.4.3.1 + * + * - Fixed HP S20 ID's...again..sigh. Thanks to Ruud + * Linders . * * * TODO diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/scanner.h linux/drivers/usb/scanner.h --- v2.4.0-test1/linux/drivers/usb/scanner.h Thu May 11 15:30:08 2000 +++ linux/drivers/usb/scanner.h Mon Jun 19 13:42:42 2000 @@ -1,5 +1,5 @@ /* - * Driver for USB Scanners (linux-2.3.99-pre6-3) + * Driver for USB Scanners (linux-2.4.0test1-ac7) * * Copyright (C) 1999, 2000 David E. Nelson * @@ -118,7 +118,7 @@ { 0x03f0, 0x0205 }, /* 3300C */ { 0x03f0, 0x0101 }, /* 4100C */ { 0x03f0, 0x0105 }, /* 4200C */ - { 0x03f0, 0x0202 }, /* PhotoSmart S20 */ + { 0x03f0, 0x0102 }, /* PhotoSmart S20 */ { 0x03f0, 0x0401 }, /* 5200C */ { 0x03f0, 0x0201 }, /* 6200C */ { 0x03f0, 0x0601 }, /* 6300C */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/serial/digi_acceleport.c linux/drivers/usb/serial/digi_acceleport.c --- v2.4.0-test1/linux/drivers/usb/serial/digi_acceleport.c Tue May 23 15:31:35 2000 +++ linux/drivers/usb/serial/digi_acceleport.c Mon Jun 19 13:42:42 2000 @@ -14,24 +14,75 @@ * Peter Berger (pberger@brimson.com) * Al Borchers (borchers@steinerpoint.com) * +* (6/4/2000) pberger and borchers +* -- Replaced separate calls to spin_unlock_irqrestore and +* interruptible_sleep_on_interruptible with a new function +* cond_wait_interruptible_timeout_irqrestore. This eliminates +* the race condition where the wake up could happen after +* the unlock and before the sleep. +* -- Close now waits for output to drain. +* -- Open waits until any close in progress is finished. +* -- All out of band responses are now processed, not just the +* first in a USB packet. +* -- Fixed a bug that prevented the driver from working when the +* first Digi port was not the first USB serial port--the driver +* was mistakenly using the external USB serial port number to +* try to index into its internal ports. +* -- Fixed an SMP bug -- write_bulk_callback is called directly from +* an interrupt, so spin_lock_irqsave/spin_unlock_irqrestore are +* needed for locks outside write_bulk_callback that are also +* acquired by write_bulk_callback to prevent deadlocks. +* -- Fixed support for select() by making digi_chars_in_buffer() +* return 256 when -EINPROGRESS is set, as the line discipline +* code in n_tty.c expects. +* -- Fixed an include file ordering problem that prevented debugging +* messages from working. +* -- Fixed an intermittent timeout problem that caused writes to +* sometimes get stuck on some machines on some kernels. It turns +* out in these circumstances write_chan() (in n_tty.c) was +* asleep waiting for our wakeup call. Even though we call +* wake_up_interruptible() in digi_write_bulk_callback(), there is +* a race condition that could cause the wakeup to fail: if our +* wake_up_interruptible() call occurs between the time that our +* driver write routine finishes and write_chan() sets current->state +* to TASK_INTERRUPTIBLE, the effect of our wakeup setting the state +* to TASK_RUNNING will be lost and write_chan's subsequent call to +* schedule() will never return (unless it catches a signal). +* This race condition occurs because write_bulk_callback() (and thus +* the wakeup) are called asynchonously from an interrupt, rather than +* from the scheduler. We can avoid the race by calling the wakeup +* from the scheduler queue and that's our fix: Now, at the end of +* write_bulk_callback() we queue up a wakeup call on the scheduler +* task queue. We still also invoke the wakeup directly since that +* squeezes a bit more performance out of the driver, and any lost +* race conditions will get cleaned up at the next scheduler run. +* +* NOTE: The problem also goes away if you comment out +* the two code lines in write_chan() where current->state +* is set to TASK_RUNNING just before calling driver.write() and to +* TASK_INTERRUPTIBLE immediately afterwards. This is why the +* problem did not show up with the 2.2 kernels -- they do not +* include that code. +* * (5/16/2000) pberger and borchers -* -- added timeouts to sleeps -* -- handle transition to/from B0 in digi_set_termios +* -- Added timeouts to sleeps, to defend against lost wake ups. +* -- Handle transition to/from B0 baud rate in digi_set_termios. * * (5/13/2000) pberger and borchers -* -- all commands now sent on out of band port, using digi_write_oob -* -- get modem control signals whenever they change, support TIOCMGET/ -* SET/BIS/BIC ioctls +* -- All commands now sent on out of band port, using +* digi_write_oob_command. +* -- Get modem control signals whenever they change, support TIOCMGET/ +* SET/BIS/BIC ioctls. * -- digi_set_termios now supports parity, word size, stop bits, and -* receive enable -* -- cleaned up open and close, use digi_set_termios and digi_write_oob -* to set port parameters -* -- added digi_startup_device to start read chains on all ports -* -- write buffer is only used when count==1, to be sure put_char can -* write a char (unless the buffer is full) +* receive enable. +* -- Cleaned up open and close, use digi_set_termios and +* digi_write_oob_command to set port parameters. +* -- Added digi_startup_device to start read chains on all ports. +* -- Write buffer is only used when count==1, to be sure put_char can +* write a char (unless the buffer is full). * * (5/10/2000) pberger and borchers -* -- Added MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT calls +* -- Added MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT calls on open/close. * -- Fixed problem where the first incoming character is lost on * port opens after the first close on that port. Now we keep * the read_urb chain open until shutdown. @@ -43,7 +94,33 @@ * (5/3/2000) pberger and borchers * -- First alpha version of the driver--many known limitations and bugs. * -* $Id: digi_acceleport.c,v 1.43 2000/05/17 03:21:38 root Exp root $ +* +* Locking and SMP +* +* - Each port, including the out-of-band port, has a lock used to +* serialize all access to the port's private structure. +* - The port lock is also used to serialize all writes and access to +* the port's URB. +* - The port lock is also used for the port write_wait condition +* variable. Holding the port lock will prevent a wake up on the +* port's write_wait; this can be used with cond_wait_... to be sure +* the wake up is not lost in a race when dropping the lock and +* sleeping waiting for the wakeup. +* - digi_write() does not sleep, since it is sometimes called on +* interrupt time. +* - digi_write_bulk_callback() and digi_read_bulk_callback() are +* called directly from interrupts. Hence spin_lock_irqsave() +* and spin_lock_irqrestore() are used in the rest of the code +* for any locks they acquire. +* - digi_write_bulk_callback() gets the port lock before waking up +* processes sleeping on the port write_wait. It also schedules +* wake ups so they happen from the scheduler, because the tty +* system can miss wake ups from interrupts. +* - All sleeps use a timeout of DIGI_RETRY_TIMEOUT before looping to +* recheck the condition they are sleeping on. This is defensive, +* in case a wake up is lost. +* +* $Id: digi_acceleport.c,v 1.56 2000/06/07 22:47:30 root Exp root $ */ #include @@ -60,8 +137,7 @@ #include #include #include -#include -#include "usb-serial.h" +#include #ifdef CONFIG_USB_SERIAL_DEBUG #define DEBUG @@ -69,16 +145,25 @@ #undef DEBUG #endif +#include +#include "usb-serial.h" + /* Defines */ /* port buffer length -- must be <= transfer buffer length - 2 */ /* so we can be sure to send the full buffer in one urb */ -#define DIGI_PORT_BUF_LEN 16 +#define DIGI_PORT_BUF_LEN 8 -/* retry timeout while waiting for urb->status to go to 0 */ +/* retry timeout while sleeping */ #define DIGI_RETRY_TIMEOUT (HZ/10) +/* timeout while waiting for tty output to drain in close */ +/* this delay is used twice in close, so the total delay could */ +/* be twice this value */ +#define DIGI_CLOSE_TIMEOUT (5*HZ) + + /* AccelePort USB Defines */ /* ids */ @@ -173,6 +258,9 @@ #define DIGI_FLUSH_RX 2 #define DIGI_RESUME_TX 4 /* clears xoff condition */ +#define DIGI_TRANSMIT_NOT_IDLE 0 +#define DIGI_TRANSMIT_IDLE 1 + #define DIGI_DISABLE 0 #define DIGI_ENABLE 1 @@ -211,18 +299,29 @@ /* Structures */ typedef struct digi_private { + int dp_port_num; spinlock_t dp_port_lock; int dp_buf_len; unsigned char dp_buf[DIGI_PORT_BUF_LEN]; unsigned int dp_modem_signals; + int dp_transmit_idle; + int dp_in_close; + wait_queue_head_t dp_close_wait; /* wait queue for close */ + struct tq_struct dp_tasks; } digi_private_t; /* Local Function Declarations */ -static int digi_write_oob( unsigned char *buf, int count ); +static void digi_wakeup_write( struct usb_serial_port *port ); +static void digi_wakeup_write_lock( struct usb_serial_port *port ); +static int digi_write_oob_command( unsigned char *buf, int count ); +static int digi_write_inb_command( struct usb_serial_port *port, + unsigned char *buf, int count ) __attribute__((unused)); static int digi_set_modem_signals( struct usb_serial_port *port, unsigned int modem_signals ); +static int digi_transmit_idle( struct usb_serial_port *port, + unsigned long timeout ); static void digi_rx_throttle (struct usb_serial_port *port); static void digi_rx_unthrottle (struct usb_serial_port *port); static void digi_set_termios( struct usb_serial_port *port, @@ -241,22 +340,24 @@ static int digi_startup( struct usb_serial *serial ); static void digi_shutdown( struct usb_serial *serial ); static void digi_read_bulk_callback( struct urb *urb ); -static void digi_read_oob( struct urb *urb ); +static void digi_read_oob_callback( struct urb *urb ); /* Statics */ /* device info needed for the Digi serial converter */ -static __u16 digi_vendor_id = DIGI_VENDOR_ID; -static __u16 digi_product_id = DIGI_ID; +static u16 digi_vendor_id = DIGI_VENDOR_ID; +static u16 digi_product_id = DIGI_ID; /* out of band port */ static int oob_port_num; /* index of out-of-band port */ static struct usb_serial_port *oob_port; /* out-of-band port */ static int device_startup = 0; -/* startup lock -- used to by digi_startup_device */ -spinlock_t startup_lock; +spinlock_t startup_lock; /* used by startup_device */ + +static wait_queue_head_t modem_change_wait; +static wait_queue_head_t transmit_idle_wait; /* Globals */ @@ -292,7 +393,84 @@ /* Functions */ /* -* Digi Write OOB +* Cond Wait Interruptible Timeout Irqrestore +* +* Do spin_unlock_irqrestore and interruptible_sleep_on_timeout +* so that wake ups are not lost if they occur between the unlock +* and the sleep. In other words, spin_lock_irqrestore and +* interruptible_sleep_on_timeout are "atomic" with respect to +* wake ups. This is used to implement condition variables. +*/ + +static long cond_wait_interruptible_timeout_irqrestore( + wait_queue_head_t *q, long timeout, + spinlock_t *lock, unsigned long flags ) +{ + + wait_queue_t wait; + + + init_waitqueue_entry( &wait, current ); + + set_current_state( TASK_INTERRUPTIBLE ); + + add_wait_queue( q, &wait ); + + spin_unlock_irqrestore( lock, flags ); + + timeout = schedule_timeout(timeout); + + set_current_state( TASK_RUNNING ); + + remove_wait_queue( q, &wait ); + + return( timeout ); + +} + + +/* +* Digi Wakeup Write +* +* Wake up port, line discipline, and tty processes sleeping +* on writes. +*/ + +static void digi_wakeup_write_lock( struct usb_serial_port *port ) +{ + + unsigned long flags; + digi_private_t *priv = (digi_private_t *)(port->private); + + + spin_lock_irqsave( &priv->dp_port_lock, flags ); + digi_wakeup_write( port ); + spin_unlock_irqrestore( &priv->dp_port_lock, flags ); + +} + +static void digi_wakeup_write( struct usb_serial_port *port ) +{ + + struct tty_struct *tty = port->tty; + + + /* wake up port processes */ + wake_up_interruptible( &port->write_wait ); + + /* wake up line discipline */ + if( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) + && tty->ldisc.write_wakeup ) + (tty->ldisc.write_wakeup)(tty); + + /* wake up other tty processes */ + wake_up_interruptible( &tty->write_wait ); + +} + + +/* +* Digi Write OOB Command * * Write commands on the out of band port. Commands are 4 * bytes each, multiple commands can be sent at once, and @@ -301,28 +479,29 @@ * a negative error returned by usb_submit_urb. */ -static int digi_write_oob( unsigned char *buf, int count ) +static int digi_write_oob_command( unsigned char *buf, int count ) { int ret = 0; int len; digi_private_t *oob_priv = (digi_private_t *)(oob_port->private); + unsigned long flags = 0; -dbg( "digi_write_oob: TOP: port=%d, count=%d", oob_port->number, count ); +dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_port_num, count ); - spin_lock( &oob_priv->dp_port_lock ); + spin_lock_irqsave( &oob_priv->dp_port_lock, flags ); while( count > 0 ) { while( oob_port->write_urb->status == -EINPROGRESS ) { - spin_unlock( &oob_priv->dp_port_lock ); - interruptible_sleep_on_timeout( &oob_port->write_wait, - DIGI_RETRY_TIMEOUT ); + cond_wait_interruptible_timeout_irqrestore( + &oob_port->write_wait, DIGI_RETRY_TIMEOUT, + &oob_priv->dp_port_lock, flags ); if( signal_pending(current) ) { return( -EINTR ); } - spin_lock( &oob_priv->dp_port_lock ); + spin_lock_irqsave( &oob_priv->dp_port_lock, flags ); } /* len must be a multiple of 4, so commands are not split */ @@ -337,14 +516,106 @@ count -= len; buf += len; } else { - dbg( "digi_write_oob: usb_submit_urb failed, ret=%d", - ret ); + dbg( + "digi_write_oob_command: usb_submit_urb failed, ret=%d", + ret ); + break; + } + + } + + spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags ); + + return( ret ); + +} + + +/* +* Digi Write In Band Command +* +* Write commands on the given port. Commands are 4 +* bytes each, multiple commands can be sent at once, and +* no command will be split across USB packets. Returns 0 +* if successful, or a negative error returned by digi_write. +*/ + +static int digi_write_inb_command( struct usb_serial_port *port, + unsigned char *buf, int count ) +{ + + int ret = 0; + int len; + digi_private_t *priv = (digi_private_t *)(port->private); + unsigned char *data = port->write_urb->transfer_buffer; + unsigned long flags = 0; + + +dbg( "digi_write_inb_command: TOP: port=%d, count=%d", priv->dp_port_num, +count ); + + spin_lock_irqsave( &priv->dp_port_lock, flags ); + + while( count > 0 ) { + + while( port->write_urb->status == -EINPROGRESS ) { + cond_wait_interruptible_timeout_irqrestore( + &port->write_wait, DIGI_RETRY_TIMEOUT, + &priv->dp_port_lock, flags ); + if( signal_pending(current) ) { + return( -EINTR ); + } + spin_lock_irqsave( &priv->dp_port_lock, flags ); + } + + /* len must be a multiple of 4 and small enough to */ + /* guarantee the write will send all data (or none), */ + /* so commands are not split */ + len = MIN( count, port->bulk_out_size-2-priv->dp_buf_len ); + if( len > 4 ) + len &= ~3; + + /* write any buffered data first */ + if( priv->dp_buf_len > 0 ) { + data[0] = DIGI_CMD_SEND_DATA; + data[1] = priv->dp_buf_len; + memcpy( data+2, priv->dp_buf, priv->dp_buf_len ); + memcpy( data+2+priv->dp_buf_len, buf, len ); + port->write_urb->transfer_buffer_length + = priv->dp_buf_len+2+len; + } else { + memcpy( data, buf, len ); + port->write_urb->transfer_buffer_length = len; + } + +#ifdef DEBUG_DATA + { + int i; + + printk( KERN_DEBUG __FILE__ ": digi_write: port=%d, length=%d, data=", + priv->dp_port_num, port->write_urb->transfer_buffer_length ); + for( i=0; iwrite_urb->transfer_buffer_length; ++i ) { + printk( "%.2x ", + ((unsigned char *)port->write_urb->transfer_buffer)[i] ); + } + printk( "\n" ); + } +#endif + + if( (ret=usb_submit_urb(port->write_urb)) == 0 ) { + priv->dp_buf_len = 0; + count -= len; + buf += len; + } else { + dbg( + "digi_write_inb_command: usb_submit_urb failed, ret=%d", + ret ); break; } } - spin_unlock( &oob_priv->dp_port_lock ); + spin_unlock_irqrestore( &priv->dp_port_lock, flags ); return( ret ); @@ -369,35 +640,35 @@ unsigned char *data = oob_port->write_urb->transfer_buffer; digi_private_t *port_priv = (digi_private_t *)(port->private); digi_private_t *oob_priv = (digi_private_t *)(oob_port->private); + unsigned long flags = 0; dbg( "digi_set_modem_signals: TOP: port=%d, modem_signals=0x%x", -port->number, modem_signals ); +port_priv->dp_port_num, modem_signals ); - spin_lock( &oob_priv->dp_port_lock ); - spin_lock( &port_priv->dp_port_lock ); + spin_lock_irqsave( &oob_priv->dp_port_lock, flags ); + spin_lock_irqsave( &port_priv->dp_port_lock, flags ); while( oob_port->write_urb->status == -EINPROGRESS ) { - spin_unlock( &port_priv->dp_port_lock ); - spin_unlock( &oob_priv->dp_port_lock ); - interruptible_sleep_on_timeout( &oob_port->write_wait, - DIGI_RETRY_TIMEOUT ); + spin_unlock_irqrestore( &port_priv->dp_port_lock, flags ); + cond_wait_interruptible_timeout_irqrestore( + &oob_port->write_wait, DIGI_RETRY_TIMEOUT, + &oob_priv->dp_port_lock, flags ); if( signal_pending(current) ) { return( -EINTR ); } - spin_lock( &oob_priv->dp_port_lock ); - spin_lock( &port_priv->dp_port_lock ); + spin_lock_irqsave( &oob_priv->dp_port_lock, flags ); + spin_lock_irqsave( &port_priv->dp_port_lock, flags ); } - /* command is 4 bytes: command, line, argument, pad */ data[0] = DIGI_CMD_SET_DTR_SIGNAL; - data[1] = port->number; + data[1] = port_priv->dp_port_num; data[2] = (modem_signals&TIOCM_DTR) ? DIGI_DTR_ACTIVE : DIGI_DTR_INACTIVE; data[3] = 0; data[4] = DIGI_CMD_SET_RTS_SIGNAL; - data[5] = port->number; + data[5] = port_priv->dp_port_num; data[6] = (modem_signals&TIOCM_RTS) ? DIGI_RTS_ACTIVE : DIGI_RTS_INACTIVE; data[7] = 0; @@ -413,18 +684,77 @@ ret ); } - spin_unlock( &port_priv->dp_port_lock ); - spin_unlock( &oob_priv->dp_port_lock ); + spin_unlock_irqrestore( &port_priv->dp_port_lock, flags ); + spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags ); return( ret ); } +/* +* Digi Transmit Idle +* +* Digi transmit idle waits, up to timeout ticks, for the transmitter +* to go idle. It returns 0 if successful or a negative error. +* +* There are race conditions here if more than one process is calling +* digi_transmit_idle on the same port at the same time. However, this +* is only called from close, and only one process can be in close on a +* port at a time, so its ok. +*/ + +static int digi_transmit_idle( struct usb_serial_port *port, + unsigned long timeout ) +{ + + int ret; + unsigned char buf[2]; + digi_private_t *priv = (digi_private_t *)(port->private); + unsigned long flags = 0; + + + spin_lock_irqsave( &priv->dp_port_lock, flags ); + priv->dp_transmit_idle = 0; + spin_unlock_irqrestore( &priv->dp_port_lock, flags ); + + buf[0] = DIGI_CMD_TRANSMIT_IDLE; + buf[1] = 0; + + if( (ret=digi_write_inb_command( port, buf, 2 )) != 0 ) + return( ret ); + + timeout += jiffies; + + spin_lock_irqsave( &priv->dp_port_lock, flags ); + + while( jiffies < timeout && !priv->dp_transmit_idle ) { + cond_wait_interruptible_timeout_irqrestore( + &transmit_idle_wait, DIGI_RETRY_TIMEOUT, + &priv->dp_port_lock, flags ); + if( signal_pending(current) ) { + return( -EINTR ); + } + spin_lock_irqsave( &priv->dp_port_lock, flags ); + } + + priv->dp_transmit_idle = 0; + spin_unlock_irqrestore( &priv->dp_port_lock, flags ); + + return( 0 ); + +} + + static void digi_rx_throttle( struct usb_serial_port *port ) { -dbg( "digi_rx_throttle: TOP: port=%d", port->number ); +#ifdef DEBUG + digi_private_t *priv = (digi_private_t *)(port->private); +#endif + + +dbg( "digi_rx_throttle: TOP: port=%d", priv->dp_port_num ); /* stop receiving characters. We just turn off the URB request, and let chars pile up in the device. If we're doing hardware @@ -441,7 +771,12 @@ static void digi_rx_unthrottle( struct usb_serial_port *port ) { -dbg( "digi_rx_unthrottle: TOP: port=%d", port->number ); +#ifdef DEBUG + digi_private_t *priv = (digi_private_t *)(port->private); +#endif + + +dbg( "digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num ); /* just restart the receive interrupt URB */ //if (usb_submit_urb(port->interrupt_in_urb)) @@ -454,6 +789,7 @@ struct termios *old_termios ) { + digi_private_t *priv = (digi_private_t *)(port->private); unsigned int iflag = port->tty->termios->c_iflag; unsigned int cflag = port->tty->termios->c_cflag; unsigned int old_iflag = old_termios->c_iflag; @@ -463,7 +799,7 @@ int i = 0; -dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, old_cflag=0x%x", port->number, iflag, old_iflag, cflag, old_cflag ); +dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, old_cflag=0x%x", priv->dp_port_num, iflag, old_iflag, cflag, old_cflag ); /* set baud rate */ if( (cflag&CBAUD) != (old_cflag&CBAUD) ) { @@ -506,7 +842,7 @@ if( arg != -1 ) { buf[i++] = DIGI_CMD_SET_BAUD_RATE; - buf[i++] = port->number; + buf[i++] = priv->dp_port_num; buf[i++] = arg; buf[i++] = 0; } @@ -526,7 +862,7 @@ } buf[i++] = DIGI_CMD_SET_PARITY; - buf[i++] = port->number; + buf[i++] = priv->dp_port_num; buf[i++] = arg; buf[i++] = 0; @@ -550,7 +886,7 @@ if( arg != -1 ) { buf[i++] = DIGI_CMD_SET_WORD_SIZE; - buf[i++] = port->number; + buf[i++] = priv->dp_port_num; buf[i++] = arg; buf[i++] = 0; } @@ -566,7 +902,7 @@ arg = DIGI_STOP_BITS_1; buf[i++] = DIGI_CMD_SET_STOP_BITS; - buf[i++] = port->number; + buf[i++] = priv->dp_port_num; buf[i++] = arg; buf[i++] = 0; @@ -589,7 +925,7 @@ arg &= ~DIGI_INPUT_FLOW_CONTROL_RTS; buf[i++] = DIGI_CMD_SET_INPUT_FLOW_CONTROL; - buf[i++] = port->number; + buf[i++] = priv->dp_port_num; buf[i++] = arg; buf[i++] = 0; @@ -612,7 +948,7 @@ arg &= ~DIGI_OUTPUT_FLOW_CONTROL_CTS; buf[i++] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL; - buf[i++] = port->number; + buf[i++] = priv->dp_port_num; buf[i++] = arg; buf[i++] = 0; @@ -627,13 +963,13 @@ arg = DIGI_DISABLE; buf[i++] = DIGI_CMD_RECEIVE_ENABLE; - buf[i++] = port->number; + buf[i++] = priv->dp_port_num; buf[i++] = arg; buf[i++] = 0; } - if( (ret=digi_write_oob( buf, i )) != 0 ) + if( (ret=digi_write_oob_command( buf, i )) != 0 ) dbg( "digi_set_termios: write oob failed, ret=%d", ret ); } @@ -641,7 +977,14 @@ static void digi_break_ctl( struct usb_serial_port *port, int break_state ) { -dbg( "digi_break_ctl: TOP: port=%d", port->number ); + +#ifdef DEBUG + digi_private_t *priv = (digi_private_t *)(port->private); +#endif + + +dbg( "digi_break_ctl: TOP: port=%d", priv->dp_port_num ); + } @@ -651,16 +994,17 @@ digi_private_t *priv = (digi_private_t *)(port->private); unsigned int val; + unsigned long flags = 0; -dbg( "digi_ioctl: TOP: port=%d, cmd=0x%x", port->number, cmd ); +dbg( "digi_ioctl: TOP: port=%d, cmd=0x%x", priv->dp_port_num, cmd ); switch (cmd) { case TIOCMGET: - spin_lock( &priv->dp_port_lock ); + spin_lock_irqsave( &priv->dp_port_lock, flags ); val = priv->dp_modem_signals; - spin_unlock( &priv->dp_port_lock ); + spin_unlock_irqrestore( &priv->dp_port_lock, flags ); if( copy_to_user((unsigned int *)arg, &val, sizeof(int)) ) return( -EFAULT ); return( 0 ); @@ -670,12 +1014,12 @@ case TIOCMBIC: if( copy_from_user(&val, (unsigned int *)arg, sizeof(int)) ) return( -EFAULT ); - spin_lock( &priv->dp_port_lock ); + spin_lock_irqsave( &priv->dp_port_lock, flags ); if( cmd == TIOCMBIS ) val = priv->dp_modem_signals | val; else if( cmd == TIOCMBIC ) val = priv->dp_modem_signals & ~val; - spin_unlock( &priv->dp_port_lock ); + spin_unlock_irqrestore( &priv->dp_port_lock, flags ); return( digi_set_modem_signals( port, val ) ); case TIOCMIWAIT: @@ -701,15 +1045,17 @@ int ret,data_len,new_len; digi_private_t *priv = (digi_private_t *)(port->private); + unsigned char *data = port->write_urb->transfer_buffer; + unsigned long flags = 0; dbg( "digi_write: TOP: port=%d, count=%d, from_user=%d, in_interrupt=%d", -port->number, count, from_user, in_interrupt() ); +priv->dp_port_num, count, from_user, in_interrupt() ); /* be sure only one write proceeds at a time */ /* there are races on the port private buffer */ /* and races to check write_urb->status */ - spin_lock( &priv->dp_port_lock ); + spin_lock_irqsave( &priv->dp_port_lock, flags ); /* wait for urb status clear to submit another urb */ if( port->write_urb->status == -EINPROGRESS ) { @@ -724,7 +1070,7 @@ new_len = 0; } - spin_unlock( &priv->dp_port_lock ); + spin_unlock_irqrestore( &priv->dp_port_lock, flags ); return( new_len ); @@ -736,43 +1082,41 @@ data_len = new_len + priv->dp_buf_len; if( data_len == 0 ) { - spin_unlock( &priv->dp_port_lock ); + spin_unlock_irqrestore( &priv->dp_port_lock, flags ); return( 0 ); } - *((unsigned char *)(port->write_urb->transfer_buffer)) - = (unsigned char)DIGI_CMD_SEND_DATA; - *((unsigned char *)(port->write_urb->transfer_buffer)+1) - = (unsigned char)data_len; - port->write_urb->transfer_buffer_length = data_len+2; + *data++ = DIGI_CMD_SEND_DATA; + *data++ = data_len; + /* copy in buffered data first */ - memcpy( port->write_urb->transfer_buffer+2, priv->dp_buf, - priv->dp_buf_len ); + memcpy( data, priv->dp_buf, priv->dp_buf_len ); + data += priv->dp_buf_len; /* copy in new data */ if( from_user ) { - copy_from_user( - port->write_urb->transfer_buffer+2+priv->dp_buf_len, - buf, new_len ); + if( copy_from_user( data, buf, new_len ) ) { + spin_unlock_irqrestore( &priv->dp_port_lock, flags ); + return( -EFAULT ); + } } else { - memcpy( port->write_urb->transfer_buffer+2+priv->dp_buf_len, - buf, new_len ); + memcpy( data, buf, new_len ); } #ifdef DEBUG_DATA -{ + { int i; printk( KERN_DEBUG __FILE__ ": digi_write: port=%d, length=%d, data=", - port->number, port->write_urb->transfer_buffer_length ); + priv->dp_port_num, port->write_urb->transfer_buffer_length ); for( i=0; iwrite_urb->transfer_buffer_length; ++i ) { printk( "%.2x ", ((unsigned char *)port->write_urb->transfer_buffer)[i] ); } printk( "\n" ); -} + } #endif if( (ret=usb_submit_urb(port->write_urb)) == 0 ) { @@ -781,13 +1125,11 @@ } else { dbg( "digi_write: usb_submit_urb failed, ret=%d", ret ); - /* no bytes written - should we return the error code or 0? */ - ret = 0; } /* return length of new data written, or error */ dbg( "digi_write: returning %d", ret ); - spin_unlock( &priv->dp_port_lock ); + spin_unlock_irqrestore( &priv->dp_port_lock, flags ); return( ret ); } @@ -798,17 +1140,18 @@ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial = port->serial; - struct tty_struct *tty = port->tty; digi_private_t *priv = (digi_private_t *)(port->private); int ret; -dbg( "digi_write_bulk_callback: TOP: port=%d", port->number ); +dbg( "digi_write_bulk_callback: TOP: port=%d", priv->dp_port_num ); /* handle callback on out-of-band port */ - if( port->number == oob_port_num ) { + if( priv->dp_port_num == oob_port_num ) { dbg( "digi_write_bulk_callback: oob callback" ); + spin_lock( &priv->dp_port_lock ); wake_up_interruptible( &port->write_wait ); + spin_unlock( &priv->dp_port_lock ); return; } @@ -833,17 +1176,17 @@ priv->dp_buf_len ); #ifdef DEBUG_DATA -{ + { int i; printk( KERN_DEBUG __FILE__ ": digi_write_bulk_callback: port=%d, length=%d, data=", - port->number, port->write_urb->transfer_buffer_length ); + priv->dp_port_num, port->write_urb->transfer_buffer_length ); for( i=0; iwrite_urb->transfer_buffer_length; ++i ) { printk( "%.2x ", ((unsigned char *)port->write_urb->transfer_buffer)[i] ); } printk( "\n" ); -} + } #endif if( (ret=usb_submit_urb(port->write_urb)) == 0 ) { @@ -853,19 +1196,17 @@ } } - spin_unlock( &priv->dp_port_lock ); - /* wake up port processes */ - wake_up_interruptible( &port->write_wait ); + /* wake up processes sleeping on writes immediately */ + digi_wakeup_write( port ); - /* wake up line discipline */ - tty = port->tty; - if( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) - && tty->ldisc.write_wakeup ) - (tty->ldisc.write_wakeup)(tty); + spin_unlock( &priv->dp_port_lock ); - /* wake up other tty processes */ - wake_up_interruptible( &tty->write_wait ); + /* also queue up a wakeup at scheduler time, in case we */ + /* lost the race in write_chan(). */ + priv->dp_tasks.routine = (void *)digi_wakeup_write_lock; + priv->dp_tasks.data = (void *)port; + queue_task( &(priv->dp_tasks), &tq_scheduler ); } @@ -875,20 +1216,21 @@ int room; digi_private_t *priv = (digi_private_t *)(port->private); + unsigned long flags = 0; -dbg( "digi_write_room: TOP: port=%d", port->number ); +dbg( "digi_write_room: TOP: port=%d", priv->dp_port_num ); - spin_lock( &priv->dp_port_lock ); + spin_lock_irqsave( &priv->dp_port_lock, flags ); if( port->write_urb->status == -EINPROGRESS ) room = 0; else room = port->bulk_out_size - 2 - priv->dp_buf_len; - spin_unlock( &priv->dp_port_lock ); + spin_unlock_irqrestore( &priv->dp_port_lock, flags ); -dbg( "digi_write_room: port=%d, room=%d", port->number, room ); +dbg( "digi_write_room: port=%d, room=%d", priv->dp_port_num, room ); return( room ); } @@ -900,13 +1242,14 @@ digi_private_t *priv = (digi_private_t *)(port->private); -dbg( "digi_chars_in_buffer: TOP: port=%d", port->number ); +dbg( "digi_chars_in_buffer: TOP: port=%d", priv->dp_port_num ); if( port->write_urb->status == -EINPROGRESS ) { -dbg( "digi_chars_in_buffer: port=%d, chars=%d", port->number, port->bulk_out_size - 2 ); - return( port->bulk_out_size - 2 ); +dbg( "digi_chars_in_buffer: port=%d, chars=%d", priv->dp_port_num, port->bulk_out_size - 2 ); + /* return( port->bulk_out_size - 2 ); */ + return( 256 ); } else { -dbg( "digi_chars_in_buffer: port=%d, chars=%d", port->number, priv->dp_buf_len ); +dbg( "digi_chars_in_buffer: port=%d, chars=%d", priv->dp_port_num, priv->dp_buf_len ); return( priv->dp_buf_len ); } @@ -916,43 +1259,66 @@ static int digi_open( struct usb_serial_port *port, struct file *filp ) { - int i = 0; int ret; unsigned char buf[32]; digi_private_t *priv = (digi_private_t *)(port->private); struct termios not_termios; + unsigned long flags = 0; -dbg( "digi_open: TOP: port %d, active:%d", port->number, port->active ); +dbg( "digi_open: TOP: port %d, active:%d", priv->dp_port_num, port->active ); /* be sure the device is started up */ if( digi_startup_device( port->serial ) != 0 ) return( -ENXIO ); - MOD_INC_USE_COUNT; - /* if port is already open, just return */ /* be sure exactly one open proceeds */ - spin_lock( &priv->dp_port_lock ); - if( port->active++ ) { - spin_unlock( &priv->dp_port_lock ); + spin_lock_irqsave( &priv->dp_port_lock, flags ); + if( port->active >= 1 && !priv->dp_in_close ) { + ++port->active; + spin_unlock_irqrestore( &priv->dp_port_lock, flags ); + MOD_INC_USE_COUNT; return( 0 ); } - spin_unlock( &priv->dp_port_lock ); + + /* don't wait on a close in progress for non-blocking opens */ + if( priv->dp_in_close && (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0 ) { + spin_unlock_irqrestore( &priv->dp_port_lock, flags ); + return( -EAGAIN ); + } + + /* prevent other opens from proceeding, before giving up lock */ + ++port->active; + + /* wait for close to finish */ + while( priv->dp_in_close ) { + cond_wait_interruptible_timeout_irqrestore( + &priv->dp_close_wait, DIGI_RETRY_TIMEOUT, + &priv->dp_port_lock, flags ); + if( signal_pending(current) ) { + --port->active; + return( -EINTR ); + } + spin_lock_irqsave( &priv->dp_port_lock, flags ); + } + + spin_unlock_irqrestore( &priv->dp_port_lock, flags ); + MOD_INC_USE_COUNT; /* read modem signals automatically whenever they change */ - buf[i++] = DIGI_CMD_READ_INPUT_SIGNALS; - buf[i++] = port->number; - buf[i++] = DIGI_ENABLE; - buf[i++] = 0; + buf[0] = DIGI_CMD_READ_INPUT_SIGNALS; + buf[1] = priv->dp_port_num; + buf[2] = DIGI_ENABLE; + buf[3] = 0; /* flush fifos */ - buf[i++] = DIGI_CMD_IFLUSH_FIFO; - buf[i++] = port->number; - buf[i++] = DIGI_FLUSH_TX | DIGI_FLUSH_RX; - buf[i++] = 0; + buf[4] = DIGI_CMD_IFLUSH_FIFO; + buf[5] = priv->dp_port_num; + buf[6] = DIGI_FLUSH_TX | DIGI_FLUSH_RX; + buf[7] = 0; - if( (ret=digi_write_oob( buf, i )) != 0 ) + if( (ret=digi_write_oob_command( buf, 8 )) != 0 ) dbg( "digi_open: write oob failed, ret=%d", ret ); /* set termios settings */ @@ -971,58 +1337,83 @@ static void digi_close( struct usb_serial_port *port, struct file *filp ) { - int i = 0; int ret; unsigned char buf[32]; + struct tty_struct *tty = port->tty; digi_private_t *priv = (digi_private_t *)(port->private); + unsigned long flags = 0; -dbg( "digi_close: TOP: port %d, active:%d", port->number, port->active ); +dbg( "digi_close: TOP: port %d, active:%d", priv->dp_port_num, port->active ); /* do cleanup only after final close on this port */ - spin_lock( &priv->dp_port_lock ); - if( --port->active ) { - spin_unlock( &priv->dp_port_lock ); + spin_lock_irqsave( &priv->dp_port_lock, flags ); + if( port->active > 1 ) { + --port->active; + spin_unlock_irqrestore( &priv->dp_port_lock, flags ); MOD_DEC_USE_COUNT; return; + } else if( port->active <= 0 ) { + spin_unlock_irqrestore( &priv->dp_port_lock, flags ); + return; } - spin_unlock( &priv->dp_port_lock ); - + priv->dp_in_close = 1; + spin_unlock_irqrestore( &priv->dp_port_lock, flags ); + + /* tell line discipline to process only XON/XOFF */ + tty->closing = 1; + + /* wait for output to drain */ + if( (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0 ) { + tty_wait_until_sent( tty, DIGI_CLOSE_TIMEOUT ); + } + + /* flush driver and line discipline buffers */ + if( tty->driver.flush_buffer ) + tty->driver.flush_buffer( tty ); + if( tty->ldisc.flush_buffer ) + tty->ldisc.flush_buffer( tty ); + + /* wait for transmit idle */ + if( (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0 ) { + digi_transmit_idle( port, DIGI_CLOSE_TIMEOUT ); + } + /* drop DTR and RTS */ digi_set_modem_signals( port, 0 ); /* disable input flow control */ - buf[i++] = DIGI_CMD_SET_INPUT_FLOW_CONTROL; - buf[i++] = port->number; - buf[i++] = DIGI_DISABLE; - buf[i++] = 0; + buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL; + buf[1] = priv->dp_port_num; + buf[2] = DIGI_DISABLE; + buf[3] = 0; /* disable output flow control */ - buf[i++] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL; - buf[i++] = port->number; - buf[i++] = DIGI_DISABLE; - buf[i++] = 0; + buf[4] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL; + buf[5] = priv->dp_port_num; + buf[6] = DIGI_DISABLE; + buf[7] = 0; /* disable reading modem signals automatically */ - buf[i++] = DIGI_CMD_READ_INPUT_SIGNALS; - buf[i++] = port->number; - buf[i++] = DIGI_DISABLE; - buf[i++] = 0; + buf[8] = DIGI_CMD_READ_INPUT_SIGNALS; + buf[9] = priv->dp_port_num; + buf[10] = DIGI_DISABLE; + buf[11] = 0; /* flush fifos */ - buf[i++] = DIGI_CMD_IFLUSH_FIFO; - buf[i++] = port->number; - buf[i++] = DIGI_FLUSH_TX | DIGI_FLUSH_RX; - buf[i++] = 0; + buf[12] = DIGI_CMD_IFLUSH_FIFO; + buf[13] = priv->dp_port_num; + buf[14] = DIGI_FLUSH_TX | DIGI_FLUSH_RX; + buf[15] = 0; /* disable receive */ - buf[i++] = DIGI_CMD_RECEIVE_ENABLE; - buf[i++] = port->number; - buf[i++] = DIGI_DISABLE; - buf[i++] = 0; + buf[16] = DIGI_CMD_RECEIVE_ENABLE; + buf[17] = priv->dp_port_num; + buf[18] = DIGI_DISABLE; + buf[19] = 0; - if( (ret=digi_write_oob( buf, i )) != 0 ) + if( (ret=digi_write_oob_command( buf, 20 )) != 0 ) dbg( "digi_close: write oob failed, ret=%d", ret ); /* wait for final commands on oob port to complete */ @@ -1033,12 +1424,21 @@ break; } } - + /* shutdown any outstanding bulk writes */ usb_unlink_urb (port->write_urb); + tty->closing = 0; + + spin_lock_irqsave( &priv->dp_port_lock, flags ); + --port->active; + priv->dp_in_close = 0; + wake_up_interruptible( &priv->dp_close_wait ); + spin_unlock_irqrestore( &priv->dp_port_lock, flags ); + MOD_DEC_USE_COUNT; +dbg( "digi_close: done" ); } @@ -1093,6 +1493,8 @@ dbg( "digi_startup: TOP" ); spin_lock_init( &startup_lock ); + init_waitqueue_head( &modem_change_wait ); + init_waitqueue_head( &transmit_idle_wait ); /* allocate the private data structures for all ports */ /* number of regular ports + 1 for the out-of-band port */ @@ -1108,8 +1510,14 @@ return( 1 ); /* error */ /* initialize private structure */ + priv->dp_port_num = i; priv->dp_buf_len = 0; priv->dp_modem_signals = 0; + priv->dp_transmit_idle = 0; + priv->dp_in_close = 0; + init_waitqueue_head( &priv->dp_close_wait ); + priv->dp_tasks.next = NULL; + priv->dp_tasks.data = NULL; spin_lock_init( &priv->dp_port_lock ); /* initialize write wait queue for this port */ @@ -1157,6 +1565,7 @@ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial = port->serial; struct tty_struct *tty = port->tty; + digi_private_t *priv = (digi_private_t *)(port->private); int opcode = ((unsigned char *)urb->transfer_buffer)[0]; int len = ((unsigned char *)urb->transfer_buffer)[1]; int status = ((unsigned char *)urb->transfer_buffer)[2]; @@ -1164,11 +1573,11 @@ int ret,i; -dbg( "digi_read_bulk_callback: TOP: port=%d", port->number ); +dbg( "digi_read_bulk_callback: TOP: port=%d", priv->dp_port_num ); /* handle oob callback */ - if( port->number == oob_port_num ) { - digi_read_oob( urb ); + if( priv->dp_port_num == oob_port_num ) { + digi_read_oob_callback( urb ); return; } @@ -1181,13 +1590,15 @@ if( urb->status ) { dbg( "digi_read_bulk_callback: nonzero read bulk status: %d", urb->status ); + if( urb->status == -ENOENT ) + return; goto resubmit; } #ifdef DEBUG_DATA if( urb->actual_length ) { printk( KERN_DEBUG __FILE__ ": digi_read_bulk_callback: port=%d, length=%d, data=", - port->number, urb->actual_length ); + priv->dp_port_num, urb->actual_length ); for( i=0; iactual_length; ++i ) { printk( "%.2x ", ((unsigned char *)urb->transfer_buffer)[i] ); } @@ -1196,7 +1607,7 @@ #endif if( urb->actual_length != len + 2 ) - err( KERN_INFO "digi_read_bulk_callback: INCOMPLETE PACKET, port=%d, opcode=%d, len=%d, actual_length=%d, status=%d", port->number, opcode, len, urb->actual_length, status ); + err( KERN_INFO "digi_read_bulk_callback: INCOMPLETE PACKET, port=%d, opcode=%d, len=%d, actual_length=%d, status=%d", priv->dp_port_num, opcode, len, urb->actual_length, status ); /* receive data */ if( opcode == DIGI_CMD_RECEIVE_DATA && urb->actual_length > 3 ) { @@ -1209,67 +1620,89 @@ /* continue read */ resubmit: - if( (ret=usb_submit_urb(urb)) != 0 ) + if( (ret=usb_submit_urb(urb)) != 0 ) { dbg( "digi_read_bulk_callback: failed resubmitting urb, ret=%d", ret ); + } } -static void digi_read_oob( struct urb *urb ) +static void digi_read_oob_callback( struct urb *urb ) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial = port->serial; digi_private_t *priv; - int oob_opcode = ((unsigned char *)urb->transfer_buffer)[0]; - int oob_line = ((unsigned char *)urb->transfer_buffer)[1]; - int oob_status = ((unsigned char *)urb->transfer_buffer)[2]; - int oob_ret = ((unsigned char *)urb->transfer_buffer)[3]; - int ret; + int opcode, line, status, val; + int i,ret; -dbg( "digi_read_oob: opcode=%d, line=%d, status=%d, ret=%d", oob_opcode, oob_line, oob_status, oob_ret ); +dbg( "digi_read_oob_callback: len=%d", urb->actual_length ); if( urb->status ) { - dbg( "digi_read_oob: nonzero read bulk status on oob: %d", + dbg( "digi_read_oob_callback: nonzero read bulk status on oob: %d", urb->status ); + if( urb->status == -ENOENT ) + return; goto resubmit; } - if( oob_opcode == DIGI_CMD_READ_INPUT_SIGNALS && oob_status == 0 ) { + for( i=0; iactual_length-3; ) { - priv = serial->port[oob_line].private; + opcode = ((unsigned char *)urb->transfer_buffer)[i++]; + line = ((unsigned char *)urb->transfer_buffer)[i++]; + status = ((unsigned char *)urb->transfer_buffer)[i++]; + val = ((unsigned char *)urb->transfer_buffer)[i++]; - spin_lock( &priv->dp_port_lock ); +dbg( "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d", opcode, line, status, val ); - /* convert from digi flags to termiox flags */ - if( oob_ret & DIGI_READ_INPUT_SIGNALS_CTS ) - priv->dp_modem_signals |= TIOCM_CTS; - else - priv->dp_modem_signals &= ~TIOCM_CTS; - if( oob_ret & DIGI_READ_INPUT_SIGNALS_DSR ) - priv->dp_modem_signals |= TIOCM_DSR; - else - priv->dp_modem_signals &= ~TIOCM_DSR; - if( oob_ret & DIGI_READ_INPUT_SIGNALS_RI ) - priv->dp_modem_signals |= TIOCM_RI; - else - priv->dp_modem_signals &= ~TIOCM_RI; - if( oob_ret & DIGI_READ_INPUT_SIGNALS_DCD ) - priv->dp_modem_signals |= TIOCM_CD; - else - priv->dp_modem_signals &= ~TIOCM_CD; + if( status != 0 ) + continue; - spin_unlock( &priv->dp_port_lock ); + priv = serial->port[line].private; + + if( opcode == DIGI_CMD_READ_INPUT_SIGNALS ) { + + spin_lock( &priv->dp_port_lock ); + + /* convert from digi flags to termiox flags */ + if( val & DIGI_READ_INPUT_SIGNALS_CTS ) + priv->dp_modem_signals |= TIOCM_CTS; + else + priv->dp_modem_signals &= ~TIOCM_CTS; + if( val & DIGI_READ_INPUT_SIGNALS_DSR ) + priv->dp_modem_signals |= TIOCM_DSR; + else + priv->dp_modem_signals &= ~TIOCM_DSR; + if( val & DIGI_READ_INPUT_SIGNALS_RI ) + priv->dp_modem_signals |= TIOCM_RI; + else + priv->dp_modem_signals &= ~TIOCM_RI; + if( val & DIGI_READ_INPUT_SIGNALS_DCD ) + priv->dp_modem_signals |= TIOCM_CD; + else + priv->dp_modem_signals &= ~TIOCM_CD; + + wake_up_interruptible( &modem_change_wait ); + spin_unlock( &priv->dp_port_lock ); + + } else if( opcode == DIGI_CMD_TRANSMIT_IDLE ) { + + spin_lock( &priv->dp_port_lock ); + priv->dp_transmit_idle = 1; + wake_up_interruptible( &transmit_idle_wait ); + spin_unlock( &priv->dp_port_lock ); + + } } + resubmit: if( (ret=usb_submit_urb(urb)) != 0 ) { - dbg( "digi_read_oob: failed resubmitting oob urb, ret=%d", + dbg( "digi_read_oob_callback: failed resubmitting oob urb, ret=%d", ret ); } } - diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/serial/usbserial.c linux/drivers/usb/serial/usbserial.c --- v2.4.0-test1/linux/drivers/usb/serial/usbserial.c Tue May 23 15:31:35 2000 +++ linux/drivers/usb/serial/usbserial.c Fri Jun 23 21:01:29 2000 @@ -14,6 +14,9 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (06/23/2000) gkh + * Cleaned up debugging statements in a quest to find UHCI timeout bug. + * * (05/22/2000) gkh * Changed the makefile, enabling the big CONFIG_USB_SERIAL_SOMTHING to be * removed from the individual device source files. @@ -358,7 +361,7 @@ int i, j; int good_spot; - dbg("get_free_serial %d", num_ports); + dbg(__FUNCTION__ " %d", num_ports); *minor = 0; for (i = 0; i < SERIAL_TTY_MINORS; ++i) { @@ -373,14 +376,14 @@ continue; if (!(serial = kmalloc(sizeof(struct usb_serial), GFP_KERNEL))) { - err("Out of memory"); + err(__FUNCTION__ " - Out of memory"); return NULL; } memset(serial, 0, sizeof(struct usb_serial)); serial->magic = USB_SERIAL_MAGIC; serial_table[i] = serial; *minor = i; - dbg("minor base = %d", *minor); + dbg(__FUNCTION__ " - minor base = %d", *minor); for (i = *minor+1; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i) serial_table[i] = serial; return serial; @@ -393,7 +396,7 @@ { int i; - dbg("return_serial"); + dbg(__FUNCTION__); if (serial == NULL) return; @@ -418,7 +421,7 @@ // dbg("ezusb_writememory %x, %d", address, length); if (!transfer_buffer) { - err("ezusb_writememory: kmalloc(%d) failed.", length); + err(__FUNCTION__ " - kmalloc(%d) failed.", length); return -ENOMEM; } memcpy (transfer_buffer, data, length); @@ -431,10 +434,10 @@ int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit) { int response; - dbg("ezusb_set_reset: %d", reset_bit); + dbg(__FUNCTION__ " - %d", reset_bit); response = ezusb_writememory (serial, CPUCS_REG, &reset_bit, 1, 0xa0); if (response < 0) { - err("ezusb_set_reset %d failed", reset_bit); + err(__FUNCTION__ "- %d failed", reset_bit); } return response; } @@ -451,7 +454,7 @@ struct usb_serial_port *port; int portNumber; - dbg("serial_open"); + dbg(__FUNCTION__); /* initialize the pointer incase something fails */ tty->driver_data = NULL; @@ -459,7 +462,7 @@ /* get the serial object associated with this tty pointer */ serial = get_serial_by_minor (MINOR(tty->device)); - if (serial_paranoia_check (serial, "serial_open")) { + if (serial_paranoia_check (serial, __FUNCTION__)) { return -ENODEV; } @@ -481,16 +484,16 @@ static void serial_close(struct tty_struct *tty, struct file * filp) { struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; - struct usb_serial *serial = get_usb_serial (port, "serial_close"); + struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); if (!serial) { return; } - dbg("serial_close port %d", port->number); + dbg(__FUNCTION__ " - port %d", port->number); if (!port->active) { - dbg ("port not opened"); + dbg (__FUNCTION__ " - port not opened"); return; } @@ -506,16 +509,16 @@ static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count) { struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; - struct usb_serial *serial = get_usb_serial (port, "serial_write"); + struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); if (!serial) { return -ENODEV; } - dbg("serial_write port %d, %d byte(s)", port->number, count); + dbg(__FUNCTION__ " - port %d, %d byte(s)", port->number, count); if (!port->active) { - dbg ("port not opened"); + dbg (__FUNCTION__ " - port not opened"); return -EINVAL; } @@ -531,16 +534,16 @@ static int serial_write_room (struct tty_struct *tty) { struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; - struct usb_serial *serial = get_usb_serial (port, "serial_write_room"); + struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); if (!serial) { return -ENODEV; } - dbg("serial_write_room port %d", port->number); + dbg(__FUNCTION__ " - port %d", port->number); if (!port->active) { - dbg ("port not open"); + dbg (__FUNCTION__ " - port not open"); return -EINVAL; } @@ -556,14 +559,14 @@ static int serial_chars_in_buffer (struct tty_struct *tty) { struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; - struct usb_serial *serial = get_usb_serial (port, "serial_chars_in_buffer"); + struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); if (!serial) { return -ENODEV; } if (!port->active) { - dbg ("port not open"); + dbg (__FUNCTION__ " - port not open"); return -EINVAL; } @@ -579,16 +582,16 @@ static void serial_throttle (struct tty_struct * tty) { struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; - struct usb_serial *serial = get_usb_serial (port, "serial_throttle"); + struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); if (!serial) { return; } - dbg("serial_throttle port %d", port->number); + dbg(__FUNCTION__ " - port %d", port->number); if (!port->active) { - dbg ("port not open"); + dbg (__FUNCTION__ " - port not open"); return; } @@ -604,16 +607,16 @@ static void serial_unthrottle (struct tty_struct * tty) { struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; - struct usb_serial *serial = get_usb_serial (port, "serial_unthrottle"); + struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); if (!serial) { return; } - dbg("serial_unthrottle port %d", port->number); + dbg(__FUNCTION__ " - port %d", port->number); if (!port->active) { - dbg ("port not open"); + dbg (__FUNCTION__ " - port not open"); return; } @@ -629,16 +632,16 @@ static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; - struct usb_serial *serial = get_usb_serial (port, "serial_ioctl"); + struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); if (!serial) { return -ENODEV; } - dbg("serial_ioctl port %d", port->number); + dbg(__FUNCTION__ " - port %d", port->number); if (!port->active) { - dbg ("port not open"); + dbg (__FUNCTION__ " - port not open"); return -ENODEV; } @@ -654,16 +657,16 @@ static void serial_set_termios (struct tty_struct *tty, struct termios * old) { struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; - struct usb_serial *serial = get_usb_serial (port, "serial_set_termios"); + struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); if (!serial) { return; } - dbg("serial_set_termios port %d", port->number); + dbg(__FUNCTION__ " - port %d", port->number); if (!port->active) { - dbg ("port not open"); + dbg (__FUNCTION__ " - port not open"); return; } @@ -679,16 +682,16 @@ static void serial_break (struct tty_struct *tty, int break_state) { struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; - struct usb_serial *serial = get_usb_serial (port, "serial_break"); + struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); if (!serial) { return; } - dbg("serial_break port %d", port->number); + dbg(__FUNCTION__ " - port %d", port->number); if (!port->active) { - dbg ("port not open"); + dbg (__FUNCTION__ " - port not open"); return; } @@ -708,10 +711,10 @@ { struct usb_serial *serial = port->serial; - dbg("generic_open port %d", port->number); + dbg(__FUNCTION__ " - port %d", port->number); if (port->active) { - dbg ("device already open"); + dbg (__FUNCTION__ " - device already open"); return -EINVAL; } port->active = 1; @@ -720,7 +723,7 @@ if (serial->num_bulk_in) { /*Start reading from the device*/ if (usb_submit_urb(port->read_urb)) - dbg("usb_submit_urb(read bulk) failed"); + dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed"); } return (0); @@ -731,7 +734,7 @@ { struct usb_serial *serial = port->serial; - dbg("generic_close port %d", port->number); + dbg(__FUNCTION__ " - port %d", port->number); /* shutdown any bulk reads that might be going on */ if (serial->num_bulk_out) { @@ -749,22 +752,33 @@ { struct usb_serial *serial = port->serial; - dbg("generic_serial_write port %d", port->number); + dbg(__FUNCTION__ " - port %d", port->number); if (count == 0) { - dbg("write request of 0 bytes"); + dbg(__FUNCTION__ " - write request of 0 bytes"); return (0); } /* only do something if we have a bulk out endpoint */ if (serial->num_bulk_out) { if (port->write_urb->status == -EINPROGRESS) { - dbg ("already writing"); + dbg (__FUNCTION__ " - already writing"); return (0); } count = (count > port->bulk_out_size) ? port->bulk_out_size : count; +#ifdef DEBUG + { + int i; + printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", count); + for (i = 0; i < count; ++i) { + printk ("%.2x ", buf[i]); + } + printk ("\n"); + } +#endif + if (from_user) { copy_from_user(port->write_urb->transfer_buffer, buf, count); } @@ -776,7 +790,7 @@ port->write_urb->transfer_buffer_length = count; if (usb_submit_urb(port->write_urb)) - dbg("usb_submit_urb(write bulk) failed"); + dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed"); return (count); } @@ -791,14 +805,14 @@ struct usb_serial *serial = port->serial; int room; - dbg("generic_write_room port %d", port->number); + dbg(__FUNCTION__ " - port %d", port->number); if (serial->num_bulk_out) { if (port->write_urb->status == -EINPROGRESS) room = 0; else room = port->bulk_out_size; - dbg("generic_write_room returns %d", room); + dbg(__FUNCTION__ " returns %d", room); return (room); } @@ -810,7 +824,7 @@ { struct usb_serial *serial = port->serial; - dbg("generic_chars_in_buffer port %d", port->number); + dbg(__FUNCTION__ " - port %d", port->number); if (serial->num_bulk_out) { if (port->write_urb->status == -EINPROGRESS) { @@ -825,23 +839,25 @@ static void generic_read_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; - struct usb_serial *serial = get_usb_serial (port, "generic_read_bulk_callback"); + struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; int i; + dbg (__FUNCTION__ " - enter"); + if (!serial) { return; } if (urb->status) { - dbg("nonzero read bulk status received: %d", urb->status); + dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status); return; } #ifdef DEBUG if (urb->actual_length) { - printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length); + printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", urb->actual_length); for (i = 0; i < urb->actual_length; ++i) { printk ("%.2x ", data[i]); } @@ -859,8 +875,10 @@ /* Continue trying to always read */ if (usb_submit_urb(urb)) - dbg("failed resubmitting read urb"); + dbg(__FUNCTION__ " - failed resubmitting read urb"); + dbg (__FUNCTION__ " - exit"); + return; } @@ -868,15 +886,17 @@ static void generic_write_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; - struct usb_serial *serial = get_usb_serial (port, "generic_write_bulk_callback"); + struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); struct tty_struct *tty; + dbg (__FUNCTION__ " - enter"); + if (!serial) { return; } if (urb->status) { - dbg("nonzero write bulk status received: %d", urb->status); + dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status); return; } @@ -886,6 +906,8 @@ wake_up_interruptible(&tty->write_wait); + dbg (__FUNCTION__ " - exit"); + return; } @@ -1255,7 +1277,7 @@ serial_tty_driver.init_termios = tty_std_termios; serial_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; if (tty_register_driver (&serial_tty_driver)) { - err("failed to register tty driver"); + err(__FUNCTION__ " - failed to register tty driver"); return -1; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/serial/visor.c linux/drivers/usb/serial/visor.c --- v2.4.0-test1/linux/drivers/usb/serial/visor.c Tue May 23 15:31:35 2000 +++ linux/drivers/usb/serial/visor.c Fri Jun 23 21:01:29 2000 @@ -11,6 +11,9 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (06/23/2000) gkh + * Cleaned up debugging statements in a quest to find UHCI timeout bug. + * * (04/27/2000) Ryan VanderBijl * Fixed memory leak in visor_close * @@ -80,10 +83,10 @@ ******************************************************************************/ static int visor_open (struct usb_serial_port *port, struct file *filp) { - dbg("visor_open port %d", port->number); + dbg(__FUNCTION__ " - port %d", port->number); if (port->active) { - dbg ("device already open"); + dbg (__FUNCTION__ " - device already open"); return -EINVAL; } @@ -91,7 +94,7 @@ /*Start reading from the device*/ if (usb_submit_urb(port->read_urb)) - dbg("usb_submit_urb(read bulk) failed"); + dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed"); return (0); } @@ -102,10 +105,10 @@ struct usb_serial *serial = port->serial; unsigned char *transfer_buffer = kmalloc (0x12, GFP_KERNEL); - dbg("visor_close port %d", port->number); + dbg(__FUNCTION__ " - port %d", port->number); if (!transfer_buffer) { - err("visor_close: kmalloc(%d) failed.", 0x12); + err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12); } else { /* send a shutdown message to the device */ usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_CLOSE_NOTIFICATION, @@ -122,7 +125,7 @@ static void visor_throttle (struct usb_serial_port *port) { - dbg("visor_throttle port %d", port->number); + dbg(__FUNCTION__ " - port %d", port->number); usb_unlink_urb (port->read_urb); @@ -132,10 +135,10 @@ static void visor_unthrottle (struct usb_serial_port *port) { - dbg("visor_unthrottle port %d", port->number); + dbg(__FUNCTION__ " - port %d", port->number); if (usb_unlink_urb (port->read_urb)) - dbg("usb_submit_urb(read bulk) failed"); + dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed"); return; } @@ -148,20 +151,20 @@ unsigned char *transfer_buffer = kmalloc (256, GFP_KERNEL); if (!transfer_buffer) { - err("visor_startup: kmalloc(%d) failed.", 256); + err(__FUNCTION__ " - kmalloc(%d) failed.", 256); return -ENOMEM; } - dbg("visor_startup"); + dbg(__FUNCTION__); - dbg("visor_setup: Set config to 1"); + dbg(__FUNCTION__ " - Set config to 1"); usb_set_configuration (serial->dev, 1); /* send a get connection info request */ response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_GET_CONNECTION_INFORMATION, 0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300); if (response < 0) { - err("visor_startup: error getting connection information"); + err(__FUNCTION__ " - error getting connection information"); } else { struct visor_connection_info *connection_info = (struct visor_connection_info *)transfer_buffer; char *string; @@ -195,7 +198,7 @@ response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_REQUEST_BYTES_AVAILABLE, 0xc2, 0x0000, 0x0005, transfer_buffer, 0x02, 300); if (response < 0) { - err("visor_startup: error getting bytes available request"); + err(__FUNCTION__ " - error getting bytes available request"); } kfree (transfer_buffer); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/usb-core.c linux/drivers/usb/usb-core.c --- v2.4.0-test1/linux/drivers/usb/usb-core.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/usb/usb-core.c Mon Jun 19 13:42:42 2000 @@ -65,7 +65,7 @@ #endif { usb_major_init(); - usbdevfs_init(); + usbdevfs_init(); usb_hub_init(); #ifndef CONFIG_USB_MODULE diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c --- v2.4.0-test1/linux/drivers/usb/usb-ohci.c Tue May 23 15:31:35 2000 +++ linux/drivers/usb/usb-ohci.c Mon Jun 19 13:42:42 2000 @@ -527,12 +527,12 @@ #ifdef DEBUG urb_print (urb, "UNLINK", 1); #endif - - usb_dec_dev_use (urb->dev); - if (usb_pipedevice (urb->pipe) == ohci->rh.devnum) + if (usb_pipedevice (urb->pipe) == ohci->rh.devnum) { + usb_dec_dev_use(urb->dev); return rh_unlink_urb (urb); /* a request to the virtual root hub */ - + } + if (urb->hcpriv) { /* URB active? */ if (urb->status == USB_ST_URB_PENDING && !ohci->disabled) { @@ -548,15 +548,19 @@ urb_priv->ed->state |= ED_URB_DEL; spin_unlock_irqrestore (&usb_ed_lock, flags); if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) { + usb_dec_dev_use (urb->dev); add_wait_queue (&op_wakeup, &wait); current->state = TASK_UNINTERRUPTIBLE; if (!schedule_timeout (HZ / 10)) /* wait until all TDs are deleted */ err("unlink URB timeout!"); remove_wait_queue (&op_wakeup, &wait); urb->status = -ENOENT; - } else + } else { + /* usb_dec_dev_use done in dl_del_list() */ urb->status = -EINPROGRESS; + } } else { + usb_dec_dev_use (urb->dev); urb_rm_priv (urb); if (urb->complete && (urb->transfer_flags & USB_ASYNC_UNLINK)) { urb->complete (urb); @@ -1974,7 +1978,7 @@ return -ENODEV; pci_set_master (dev); - mem_base = dev->resource[0].start; + mem_base = pci_resource_start(dev, 0); mem_base = (unsigned long) ioremap_nocache (mem_base, 4096); if (!mem_base) { diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/usb-storage.c linux/drivers/usb/usb-storage.c --- v2.4.0-test1/linux/drivers/usb/usb-storage.c Tue May 23 15:31:35 2000 +++ linux/drivers/usb/usb-storage.c Fri Jun 23 20:59:33 2000 @@ -1,11 +1,16 @@ /* Driver for USB Mass Storage compliant devices * - * Initial work by: - * (c) 1999 Michael Gee (michael@linuxspecific.com) + * $Id: usb-storage.c,v 1.11 2000/06/20 03:19:31 mdharm Exp $ * * Current development and maintainance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * + * Developed with the assistance of: + * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) + * + * Initial work by: + * (c) 1999 Michael Gee (michael@linuxspecific.com) + * * This driver is based on the 'USB Mass Storage Class' document. This * describes in detail the protocol used to communicate with such * devices. Clearly, the designers had SCSI and ATAPI commands in @@ -22,6 +27,20 @@ * * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more * information about this driver. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, 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 @@ -88,6 +107,7 @@ char *protocol_name; u8 subclass; u8 protocol; + u8 max_lun; /* information about the device -- only good if device is attached */ u8 ifnum; /* interface number */ @@ -536,8 +556,9 @@ /* save the old command */ memcpy(old_cmnd, srb->cmnd, MAX_COMMAND_SIZE); + /* set the command and the LUN */ srb->cmnd[0] = REQUEST_SENSE; - srb->cmnd[1] = 0; + srb->cmnd[1] = old_cmnd[1] & 0xE0; srb->cmnd[2] = 0; srb->cmnd[3] = 0; srb->cmnd[4] = 18; @@ -791,7 +812,7 @@ result, data); /* if we have a successful request, return the result */ - if (!result) + if (result == 1) return data; /* if we get a STALL, clear the stall */ @@ -839,6 +860,9 @@ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); usb_clear_halt(us->pusb_dev, pipe); + } else if (result) { + /* unknown error -- we've got a problem */ + return USB_STOR_TRANSPORT_ERROR; } /* if the command transfered well, then we go to the data stage */ @@ -976,25 +1000,17 @@ srb->cmnd[0] = srb->cmnd[0] | 0x20; break; } /* end switch on cmnd[0] */ + + /* convert MODE_SELECT data here */ + if (old_cmnd == MODE_SELECT) + usb_stor_scsiSense6to10(srb); /* send the command to the transport layer */ invoke_transport(srb, us); - /* Fix the MODE_SENSE data if we translated the command - */ - if (old_cmnd == MODE_SENSE) { - unsigned char *dta = (unsigned char *)us->srb->request_buffer; - - /* FIXME: we need to compress the entire data structure here - */ - dta[0] = dta[1]; /* data len */ - dta[1] = dta[2]; /* med type */ - dta[2] = dta[3]; /* dev-spec prm */ - dta[3] = dta[7]; /* block desc len */ - printk (KERN_DEBUG USB_STORAGE - "new MODE_SENSE_6 data = %.2X %.2X %.2X %.2X\n", - dta[0], dta[1], dta[2], dta[3]); - } + /* Fix the MODE_SENSE data if we translated the command */ + if ((old_cmnd == MODE_SENSE) && (srb->result == GOOD)) + usb_stor_scsiSense10to6(srb); /* Fix-up the return data from an INQUIRY command to show * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us @@ -1084,24 +1100,16 @@ break; } /* end switch on cmnd[0] */ + /* convert MODE_SELECT data here */ + if (old_cmnd == MODE_SELECT) + usb_stor_scsiSense6to10(srb); + /* send the command to the transport layer */ invoke_transport(srb, us); - /* Fix the MODE_SENSE data here if we had to translate the command - */ - if (old_cmnd == MODE_SENSE) { - unsigned char *dta = (unsigned char *)us->srb->request_buffer; - - /* FIXME: we need to compress the entire data structure here - */ - dta[0] = dta[1]; /* data len */ - dta[1] = dta[2]; /* med type */ - dta[2] = dta[3]; /* dev-spec prm */ - dta[3] = dta[7]; /* block desc len */ - printk (KERN_DEBUG USB_STORAGE - "new MODE_SENSE_6 data = %.2X %.2X %.2X %.2X\n", - dta[0], dta[1], dta[2], dta[3]); - } + /* Fix the MODE_SENSE data if we translated the command */ + if ((old_cmnd == MODE_SENSE) && (srb->result == GOOD)) + usb_stor_scsiSense10to6(srb); /* Fix-up the return data from an INQUIRY command to show * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us @@ -1310,9 +1318,8 @@ down(&(us->notify)); /* free the data structure we were using */ - US_DEBUGP("-- freeing private host data structure\n"); + US_DEBUGP("-- freeing URB\n"); kfree(us->current_urb); - kfree(us); (struct us_data*)psh->hostdata[0] = NULL; /* we always have a successful release */ @@ -1536,11 +1543,10 @@ switch (action) { case US_ACT_COMMAND: - /* reject if target != 0 or if single-lun device - * and LUN != 0 + /* reject if target != 0 or if LUN is higher than + * the maximum known LUN */ - if (us->srb->target || - ((us->flags & US_FL_SINGLE_LUN) && us->srb->lun)) { + if (us->srb->target || (us->srb->lun > us->max_lun)) { US_DEBUGP("Bad device number (%d/%d)\n", us->srb->target, us->srb->lun); @@ -1623,32 +1629,37 @@ /* This is the list of devices we recognize, along with their flag data */ static struct us_unusual_dev us_unusual_dev_list[] = { - { 0x03f0, 0x0107, 0x0200, - "HP USB CD-Writer Plus", US_SC_8070, US_PR_CB, 0}, - { 0x04e6, 0x0001, 0x0200, - "Matshita LS-120", US_SC_8020, US_PR_CB, US_FL_SINGLE_LUN}, - { 0x04e6, 0x0002, 0x0100, - "Shuttle eUSCSI Bridge", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, - { 0x04e6, 0x0006, 0x0100, - "Shuttle eUSB MMC Adapter", US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN}, - { 0x057b, 0x0000, 0x0114, - "Y-E Data Flashbuster-U", US_SC_UFI, US_PR_CB, US_FL_SINGLE_LUN}, - { 0x059b, 0x0030, 0x0100, - "Iomega Zip 250", US_SC_SCSI, US_PR_BULK, US_FL_SINGLE_LUN}, - { 0x0693, 0x0002, 0x0100, - "Hagiwara FlashGate SmartMedia", US_SC_SCSI, US_PR_BULK, - US_FL_ALT_LENGTH}, - { 0x0781, 0x0001, 0x0200, - "Sandisk ImageMate (SDDR-01)", US_SC_SCSI, US_PR_CB, - US_FL_SINGLE_LUN | US_FL_START_STOP}, - { 0x0781, 0x0002, 0x0009, - "Sandisk Imagemate (SDDR-31)", US_SC_SCSI, US_PR_BULK, - US_FL_SINGLE_LUN | US_FL_IGNORE_SER}, - { 0x07af, 0x0005, 0x0100, - "Microtech USB-SCSI-HD50", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, - { 0x0000, 0x0000, 0x0, - "", 0, 0, 0} -}; + { 0x03f0, 0x0107, 0x0200, 0x0200, "HP USB CD-Writer Plus", + US_SC_8070, US_PR_CB, 0}, + { 0x04e6, 0x0001, 0x0200, 0x0200, "Matshita LS-120", + US_SC_8020, US_PR_CB, US_FL_SINGLE_LUN}, + { 0x04e6, 0x0002, 0x0100, 0x0100, "Shuttle eUSCSI Bridge", + US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, + { 0x04e6, 0x0006, 0x0100, 0x0100, "Shuttle eUSB MMC Adapter", + US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN}, + { 0x054c, 0x0010, 0x0210, 0x0210, "Sony DSC-S30", + US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP | + US_FL_MODE_XLATE | US_FL_ALT_LENGTH}, + { 0x054c, 0x002d, 0x0100, 0x0100, "Sony Memorystick MSAC-US1", + US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP | + US_FL_MODE_XLATE | US_FL_ALT_LENGTH}, + { 0x057b, 0x0000, 0x0000, 0x0299, "Y-E Data Flashbuster-U", + US_SC_UFI, US_PR_CB, US_FL_SINGLE_LUN}, + { 0x057b, 0x0000, 0x0300, 0x9999, "Y-E Data Flashbuster-U", + US_SC_UFI, US_PR_CBI, US_FL_SINGLE_LUN}, + { 0x0693, 0x0002, 0x0100, 0x0100, "Hagiwara FlashGate SmartMedia", + US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, + { 0x0781, 0x0001, 0x0200, 0x0200, "Sandisk ImageMate (SDDR-01)", + US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP}, + { 0x0781, 0x0002, 0x0009, 0x0009, "Sandisk Imagemate (SDDR-31)", + US_SC_SCSI, US_PR_BULK, US_FL_IGNORE_SER}, + { 0x07af, 0x0005, 0x0100, 0x0100, "Microtech USB-SCSI-HD50", + US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, + { 0x05ab, 0x0031, 0x0100, 0x0100, "In-System USB/IDE Bridge", + US_SC_8070, US_PR_BULK, US_FL_ALT_LENGTH}, + { 0x0693, 0x0005, 0x0100, 0x0100, "Hagiwara Flashgate", + US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, + { 0 }}; /* Search our ususual device list, based on vendor/product combinations * to see if we can support this device. Returns a pointer to a structure @@ -1667,7 +1678,8 @@ while ((ptr->idVendor != 0x0000) && !((ptr->idVendor == idVendor) && (ptr->idProduct == idProduct) && - (ptr->bcdDevice == bcdDevice))) + (ptr->bcdDeviceMin <= bcdDevice) && + (ptr->bcdDeviceMax >= bcdDevice))) ptr++; /* if the search ended because we hit the end record, we failed */ @@ -1968,20 +1980,21 @@ ss->transport_name = "Control/Bulk"; ss->transport = CB_transport; ss->transport_reset = CB_reset; + ss->max_lun = 7; break; case US_PR_CBI: ss->transport_name = "Control/Bulk/Interrupt"; ss->transport = CBI_transport; ss->transport_reset = CB_reset; + ss->max_lun = 7; break; case US_PR_BULK: ss->transport_name = "Bulk"; ss->transport = Bulk_transport; ss->transport_reset = Bulk_reset; - /* FIXME: for testing purposes only */ - Bulk_max_lun(ss); + ss->max_lun = Bulk_max_lun(ss); break; default: @@ -1994,6 +2007,10 @@ } US_DEBUGP("Transport: %s\n", ss->transport_name); + /* fix for single-lun devices */ + if (ss->flags & US_FL_SINGLE_LUN) + ss->max_lun = 0; + switch (ss->subclass) { case US_SC_RBC: ss->protocol_name = "Reduced Block Commands (RBC)"; @@ -2134,6 +2151,576 @@ up(&(ss->dev_semaphore)); } +/************************************************************** + **************************************************************/ + +#define USB_STOR_SCSI_SENSE_HDRSZ 4 +#define USB_STOR_SCSI_SENSE_10_HDRSZ 8 + +struct usb_stor_scsi_sense_hdr +{ + __u8* dataLength; + __u8* mediumType; + __u8* devSpecParms; + __u8* blkDescLength; +}; + +typedef struct usb_stor_scsi_sense_hdr Usb_Stor_Scsi_Sense_Hdr; + +union usb_stor_scsi_sense_hdr_u +{ + Usb_Stor_Scsi_Sense_Hdr hdr; + __u8* array[USB_STOR_SCSI_SENSE_HDRSZ]; +}; + +typedef union usb_stor_scsi_sense_hdr_u Usb_Stor_Scsi_Sense_Hdr_u; + +struct usb_stor_scsi_sense_hdr_10 +{ + __u8* dataLengthMSB; + __u8* dataLengthLSB; + __u8* mediumType; + __u8* devSpecParms; + __u8* reserved1; + __u8* reserved2; + __u8* blkDescLengthMSB; + __u8* blkDescLengthLSB; +}; + +typedef struct usb_stor_scsi_sense_hdr_10 Usb_Stor_Scsi_Sense_Hdr_10; + +union usb_stor_scsi_sense_hdr_10_u +{ + Usb_Stor_Scsi_Sense_Hdr_10 hdr; + __u8* array[USB_STOR_SCSI_SENSE_10_HDRSZ]; +}; + +typedef union usb_stor_scsi_sense_hdr_10_u Usb_Stor_Scsi_Sense_Hdr_10_u; + +void usb_stor_scsiSenseParseBuffer( Scsi_Cmnd* , Usb_Stor_Scsi_Sense_Hdr_u*, + Usb_Stor_Scsi_Sense_Hdr_10_u*, int* ); +void usb_stor_print_Scsi_Cmnd( Scsi_Cmnd* cmd ); + +int +usb_stor_scsiSense10to6( Scsi_Cmnd* the10 ) +{ + __u8 *buffer=0; + int outputBufferSize = 0; + int length=0; + struct scatterlist *sg = 0; + int i=0, j=0, element=0; + Usb_Stor_Scsi_Sense_Hdr_u the6Locations; + Usb_Stor_Scsi_Sense_Hdr_10_u the10Locations; + int sb=0,si=0,db=0,di=0; + int sgLength=0; + +#if 0 + /* Make sure we get a MODE_SENSE_10 command */ + if ( the10->cmnd[0] != MODE_SENSE_10 ) + { + printk( KERN_ERR USB_STORAGE + "Scsi_Cmnd was not a MODE_SENSE_10.\n" ); + return -1; + } + + /* Now start to format the output */ + the10->cmnd[0] = MODE_SENSE; +#endif + US_DEBUGP("-- converting 10 byte sense data to 6 byte\n"); + the10->cmnd[0] = the10->cmnd[0] & 0xBF; + + /* Determine buffer locations */ + usb_stor_scsiSenseParseBuffer( the10, &the6Locations, &the10Locations, + &length ); + + /* Work out minimum buffer to output */ + outputBufferSize = *the10Locations.hdr.dataLengthLSB; + outputBufferSize += USB_STOR_SCSI_SENSE_HDRSZ; + + /* Check to see if we need to truncate the output */ + if ( outputBufferSize > length ) + { + printk( KERN_WARNING USB_STORAGE + "Had to truncate MODE_SENSE_10 buffer into MODE_SENSE.\n" ); + printk( KERN_WARNING USB_STORAGE + "outputBufferSize is %d and length is %d.\n", + outputBufferSize, length ); + } + outputBufferSize = length; + + /* Data length */ + if ( *the10Locations.hdr.dataLengthMSB != 0 ) /* MSB must be zero */ + { + printk( KERN_WARNING USB_STORAGE + "Command will be truncated to fit in SENSE6 buffer.\n" ); + *the6Locations.hdr.dataLength = 0xff; + } + else + { + *the6Locations.hdr.dataLength = *the10Locations.hdr.dataLengthLSB; + } + + /* Medium type and DevSpecific parms */ + *the6Locations.hdr.mediumType = *the10Locations.hdr.mediumType; + *the6Locations.hdr.devSpecParms = *the10Locations.hdr.devSpecParms; + + /* Block descriptor length */ + if ( *the10Locations.hdr.blkDescLengthMSB != 0 ) /* MSB must be zero */ + { + printk( KERN_WARNING USB_STORAGE + "Command will be truncated to fit in SENSE6 buffer.\n" ); + *the6Locations.hdr.blkDescLength = 0xff; + } + else + { + *the6Locations.hdr.blkDescLength = *the10Locations.hdr.blkDescLengthLSB; + } + + if ( the10->use_sg == 0 ) + { + buffer = the10->request_buffer; + /* Copy the rest of the data */ + memmove( &(buffer[USB_STOR_SCSI_SENSE_HDRSZ]), + &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]), + outputBufferSize - USB_STOR_SCSI_SENSE_HDRSZ ); + /* initialise last bytes left in buffer due to smaller header */ + memset( &(buffer[outputBufferSize + -(USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ)]), + 0, + USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ ); + } + else + { + sg = (struct scatterlist *) the10->request_buffer; + /* scan through this scatterlist and figure out starting positions */ + for ( i=0; i < the10->use_sg; i++) + { + sgLength = sg[i].length; + for ( j=0; juse_sg; + } + element++; + } + } + + /* Now we know where to start the copy from */ + element = USB_STOR_SCSI_SENSE_HDRSZ; + while ( element < outputBufferSize + -(USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ) ) + { + /* check limits */ + if ( sb >= the10->use_sg || + si >= sg[sb].length || + db >= the10->use_sg || + di >= sg[db].length ) + { + printk( KERN_ERR USB_STORAGE + "Buffer overrun averted, this shouldn't happen!\n" ); + break; + } + + /* copy one byte */ + sg[db].address[di] = sg[sb].address[si]; + + /* get next destination */ + if ( sg[db].length-1 == di ) + { + db++; + di=0; + } + else + { + di++; + } + + /* get next source */ + if ( sg[sb].length-1 == si ) + { + sb++; + si=0; + } + else + { + si++; + } + + element++; + } + /* zero the remaining bytes */ + while ( element < outputBufferSize ) + { + /* check limits */ + if ( db >= the10->use_sg || + di >= sg[db].length ) + { + printk( KERN_ERR USB_STORAGE + "Buffer overrun averted, this shouldn't happen!\n" ); + break; + } + + sg[db].address[di] = 0; + + /* get next destination */ + if ( sg[db].length-1 == di ) + { + db++; + di=0; + } + else + { + di++; + } + element++; + } + } + + /* All done any everything was fine */ + return 0; +} + +int +usb_stor_scsiSense6to10( Scsi_Cmnd* the6 ) +{ + /* will be used to store part of buffer */ + __u8 tempBuffer[USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ], + *buffer=0; + int outputBufferSize = 0; + int length=0; + struct scatterlist *sg = 0; + int i=0, j=0, element=0; + Usb_Stor_Scsi_Sense_Hdr_u the6Locations; + Usb_Stor_Scsi_Sense_Hdr_10_u the10Locations; + int sb=0,si=0,db=0,di=0; + int lsb=0,lsi=0,ldb=0,ldi=0; + +#if 0 + /* Make sure we get a MODE_SENSE command */ + if ( the6->cmnd[0] != MODE_SENSE ) + { + printk( KERN_ERR USB_STORAGE + "Scsi_Cmnd was not MODE_SENSE.\n" ); + return -1; + } + + /* Now start to format the output */ + the6->cmnd[0] = MODE_SENSE_10; +#endif + US_DEBUGP("-- converting 6 byte sense data to 10 byte\n"); + the6->cmnd[0] = the6->cmnd[0] | 0x40; + + /* Determine buffer locations */ + usb_stor_scsiSenseParseBuffer( the6, &the6Locations, &the10Locations, + &length ); + + /* Work out minimum buffer to output */ + outputBufferSize = *the6Locations.hdr.dataLength; + outputBufferSize += USB_STOR_SCSI_SENSE_10_HDRSZ; + + /* Check to see if we need to trucate the output */ + if ( outputBufferSize > length ) + { + printk( KERN_WARNING USB_STORAGE + "Had to truncate MODE_SENSE into MODE_SENSE_10 buffer.\n" ); + printk( KERN_WARNING USB_STORAGE + "outputBufferSize is %d and length is %d.\n", + outputBufferSize, length ); + } + outputBufferSize = length; + + /* Block descriptor length - save these before overwriting */ + tempBuffer[2] = *the10Locations.hdr.blkDescLengthMSB; + tempBuffer[3] = *the10Locations.hdr.blkDescLengthLSB; + *the10Locations.hdr.blkDescLengthLSB = *the6Locations.hdr.blkDescLength; + *the10Locations.hdr.blkDescLengthMSB = 0; + + /* reserved - save these before overwriting */ + tempBuffer[0] = *the10Locations.hdr.reserved1; + tempBuffer[1] = *the10Locations.hdr.reserved2; + *the10Locations.hdr.reserved1 = *the10Locations.hdr.reserved2 = 0; + + /* Medium type and DevSpecific parms */ + *the10Locations.hdr.devSpecParms = *the6Locations.hdr.devSpecParms; + *the10Locations.hdr.mediumType = *the6Locations.hdr.mediumType; + + /* Data length */ + *the10Locations.hdr.dataLengthLSB = *the6Locations.hdr.dataLength; + *the10Locations.hdr.dataLengthMSB = 0; + + if ( !the6->use_sg ) + { + buffer = the6->request_buffer; + /* Copy the rest of the data */ + memmove( &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]), + &(buffer[USB_STOR_SCSI_SENSE_HDRSZ]), + outputBufferSize-USB_STOR_SCSI_SENSE_10_HDRSZ ); + /* Put the first four bytes (after header) in place */ + memcpy( &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]), + tempBuffer, + USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ ); + } + else + { + sg = (struct scatterlist *) the6->request_buffer; + /* scan through this scatterlist and figure out ending positions */ + for ( i=0; i < the6->use_sg; i++) + { + for ( j=0; juse_sg; + break; + } + element++; + } + } + /* scan through this scatterlist and figure out starting positions */ + element = length-1; + /* destination is the last element */ + db=the6->use_sg-1; + di=sg[db].length-1; + for ( i=the6->use_sg-1; i >= 0; i--) + { + for ( j=sg[i].length-1; j>=0; j-- ) + { + /* get to end of header and find source for copy */ + if ( element == length - 1 + - (USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ) ) + { + sb=i; + si=j; + /* we've found both sets now, exit loops */ + j=-1; + i=-1; + } + element--; + } + } + /* Now we know where to start the copy from */ + element = length-1 + - (USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ); + while ( element >= USB_STOR_SCSI_SENSE_10_HDRSZ ) + { + /* check limits */ + if ( ( sb <= lsb && si < lsi ) || + ( db <= ldb && di < ldi ) ) + { + printk( KERN_ERR USB_STORAGE + "Buffer overrun averted, this shouldn't happen!\n" ); + break; + } + + /* copy one byte */ + sg[db].address[di] = sg[sb].address[si]; + + /* get next destination */ + if ( di == 0 ) + { + db--; + di=sg[db].length-1; + } + else + { + di--; + } + + /* get next source */ + if ( si == 0 ) + { + sb--; + si=sg[sb].length-1; + } + else + { + si--; + } + + element--; + } + /* copy the remaining four bytes */ + while ( element >= USB_STOR_SCSI_SENSE_HDRSZ ) + { + /* check limits */ + if ( db <= ldb && di < ldi ) + { + printk( KERN_ERR USB_STORAGE + "Buffer overrun averted, this shouldn't happen!\n" ); + break; + } + + sg[db].address[di] = tempBuffer[element-USB_STOR_SCSI_SENSE_HDRSZ]; + + /* get next destination */ + if ( di == 0 ) + { + db--; + di=sg[db].length-1; + } + else + { + di--; + } + element--; + } + } + + /* All done and everything was fine */ + return 0; +} + +void +usb_stor_scsiSenseParseBuffer( Scsi_Cmnd* srb, Usb_Stor_Scsi_Sense_Hdr_u* the6, + Usb_Stor_Scsi_Sense_Hdr_10_u* the10, + int* length_p ) + +{ + int i = 0, j=0, element=0; + struct scatterlist *sg = 0; + int length = 0; + __u8* buffer=0; + + /* are we scatter-gathering? */ + if ( srb->use_sg != 0 ) + { + /* loop over all the scatter gather structures and + * get pointer to the data members in the headers + * (also work out the length while we're here) + */ + sg = (struct scatterlist *) srb->request_buffer; + for (i = 0; i < srb->use_sg; i++) + { + length += sg[i].length; + /* We only do the inner loop for the headers */ + if ( element < USB_STOR_SCSI_SENSE_10_HDRSZ ) + { + /* scan through this scatterlist */ + for ( j=0; jarray[element] = &(sg[i].address[j]); + the10->array[element] = &(sg[i].address[j]); + } + else if ( element < USB_STOR_SCSI_SENSE_10_HDRSZ ) + { + /* only the longer headers still cares now */ + the10->array[element] = &(sg[i].address[j]); + } + /* increase element counter */ + element++; + } + } + } + } + else + { + length = srb->request_bufflen; + buffer = srb->request_buffer; + if ( length < USB_STOR_SCSI_SENSE_10_HDRSZ ) + printk( KERN_ERR USB_STORAGE + "Buffer length smaller than header!!" ); + for( i=0; iarray[i] = &(buffer[i]); + the10->array[i] = &(buffer[i]); + } + else + { + the10->array[i] = &(buffer[i]); + } + } + } + + /* Set value of length passed in */ + *length_p = length; +} + +void +usb_stor_print_Scsi_Cmnd( Scsi_Cmnd* cmd ) +{ + int i=0, bufferSize = cmd->request_bufflen; + __u8* buffer = cmd->request_buffer; + struct scatterlist* sg = (struct scatterlist*)cmd->request_buffer; + + printk( KERN_ERR "Dumping information about %p.\n", cmd ); + printk( KERN_ERR "cmd->cmnd[0] value is %d.\n", cmd->cmnd[0] ); + printk( KERN_ERR "(MODE_SENSE is %d and MODE_SENSE_10 is %d)\n", + MODE_SENSE, MODE_SENSE_10 ); + + printk( KERN_ERR "buffer is %p with length %d.\n", buffer, bufferSize ); + for ( i=0; iuse_sg ); + for ( i=0; iuse_sg; i++ ) + { + printk( KERN_ERR "Length of scatterlist %d is %d.\n", i, sg[i].length ); + printk( KERN_ERR "%2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x\n", + sg[i].address[0], + sg[i].address[1], + sg[i].address[2], + sg[i].address[3], + sg[i].address[4], + sg[i].address[5], + sg[i].address[6], + sg[i].address[7], + sg[i].address[8], + sg[i].address[9], + sg[i].address[10], + sg[i].address[11], + sg[i].address[12], + sg[i].address[13], + sg[i].address[14], + sg[i].address[15] ); + } +} + +/************************************************************** + **************************************************************/ /*********************************************************************** * Initialization and registration @@ -2182,6 +2769,11 @@ US_DEBUGP("-- calling scsi_unregister_module()\n"); scsi_unregister_module(MODULE_SCSI_HA, &(us_list->htmplt)); + + /* Now that scsi_unregister_module is done with the host + * template, we can free the us_data structure (the host + * template is inline in this structure). */ + kfree (us_list); /* advance the list pointer */ us_list = next; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/usb-storage.h linux/drivers/usb/usb-storage.h --- v2.4.0-test1/linux/drivers/usb/usb-storage.h Tue May 23 15:31:35 2000 +++ linux/drivers/usb/usb-storage.h Fri Jun 23 20:59:33 2000 @@ -139,7 +139,8 @@ /* we search the list based on these parameters */ __u16 idVendor; __u16 idProduct; - __u16 bcdDevice; + __u16 bcdDeviceMin; + __u16 bcdDeviceMax; /* the list specifies these parameters */ const char* name; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/usb-uhci.c linux/drivers/usb/usb-uhci.c --- v2.4.0-test1/linux/drivers/usb/usb-uhci.c Tue May 23 15:31:35 2000 +++ linux/drivers/usb/usb-uhci.c Mon Jun 19 13:42:42 2000 @@ -12,7 +12,7 @@ * (C) Copyright 1999 Johannes Erdfelt * (C) Copyright 1999 Randy Dunlap * - * $Id: usb-uhci.c,v 1.231 2000/05/13 15:34:17 acher Exp $ + * $Id: usb-uhci.c,v 1.232 2000/06/11 13:18:30 acher Exp $ */ #include @@ -48,7 +48,7 @@ /* This enables an extra UHCI slab for memory debugging */ #define DEBUG_SLAB -#define VERSTR "$Revision: 1.231 $ time " __TIME__ " " __DATE__ +#define VERSTR "$Revision: 1.232 $ time " __TIME__ " " __DATE__ #include #include "usb-uhci.h" @@ -2600,7 +2600,7 @@ s->running = 1; } -_static void __exit uhci_cleanup_dev(uhci_t *s) +_static void uhci_cleanup_dev(uhci_t *s) { struct usb_device *root_hub = s->bus->root_hub; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/usb.c linux/drivers/usb/usb.c --- v2.4.0-test1/linux/drivers/usb/usb.c Thu May 11 15:30:08 2000 +++ linux/drivers/usb/usb.c Mon Jun 19 13:42:42 2000 @@ -6,6 +6,7 @@ * (C) Copyright Andreas Gal 1999 * (C) Copyright Gregory P. Smith 1999 * (C) Copyright Deti Fliegl 1999 (new USB architecture) + * (C) Copyright Randy Dunlap 2000 * * NOTE! This is not actually a driver at all, rather this is * just a collection of helper routines that implement the @@ -31,6 +32,13 @@ #endif #include +static const int usb_bandwidth_option = +#ifdef CONFIG_USB_BANDWIDTH + 1; +#else + 0; +#endif + /* * Prototypes for the device driver probing/loading functions */ @@ -61,6 +69,9 @@ } info("registered new driver %s", new_driver->name); + + init_MUTEX(&new_driver->serialize); + /* Add it to the list of known drivers */ list_add(&new_driver->driver_list, &usb_driver_list); @@ -105,7 +116,9 @@ struct usb_interface *interface = &dev->actconfig->interface[i]; if (interface->driver == driver) { + down(&driver->serialize); driver->disconnect(dev, interface->private_data); + up(&driver->serialize); usb_driver_release_interface(driver, interface); /* * This will go through the list looking for another @@ -142,13 +155,23 @@ } } +struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum) +{ + int i; + + for (i = 0; i < dev->actconfig->bNumInterfaces; i++) + if (dev->actconfig->interface[i].altsetting[0].bInterfaceNumber == ifnum) + return &dev->actconfig->interface[i]; + + return NULL; +} /* - * calc_bus_time: + * usb_calc_bus_time: * * returns (approximate) USB bus time in nanoseconds for a USB transaction. */ -static long calc_bus_time (int low_speed, int input_dir, int isoc, int bytecount) +static long usb_calc_bus_time (int low_speed, int input_dir, int isoc, int bytecount) { unsigned long tmp; @@ -178,16 +201,16 @@ tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; return (((input_dir) ? 7268L : 6265L) + BW_HOST_DELAY + tmp); -} /* end calc_bus_time */ +} /* - * check_bandwidth_alloc(): + * usb_check_bandwidth(): * * old_alloc is from host_controller->bandwidth_allocated in microseconds; * bustime is from calc_bus_time(), but converted to microseconds. * - * returns 0 if successful, - * -1 if bandwidth request fails. + * returns if successful, + * or USB_ST_BANDWIDTH_ERROR if bandwidth request fails. * * FIXME: * This initial implementation does not use Endpoint.bInterval @@ -204,21 +227,67 @@ * However, this first cut at USB bandwidth allocation does not * contain any frame allocation tracking. */ -static int check_bandwidth_alloc (unsigned int old_alloc, long bustime) +int usb_check_bandwidth (struct usb_device *dev, struct urb *urb) { - unsigned int new_alloc; + int new_alloc; + int old_alloc = dev->bus->bandwidth_allocated; + unsigned int pipe = urb->pipe; + long bustime; + + bustime = usb_calc_bus_time (usb_pipeslow(pipe), usb_pipein(pipe), + usb_pipeisoc(pipe), usb_maxpacket(dev, pipe, usb_pipeout(pipe))); + if (usb_pipeisoc(pipe)) + bustime = NS_TO_US(bustime) / urb->number_of_packets; + else + bustime = NS_TO_US(bustime); - new_alloc = old_alloc + bustime; + new_alloc = old_alloc + (int)bustime; /* what new total allocated bus time would be */ - dbg("usb-bandwidth-alloc: was: %u, new: %u, " - "bustime = %ld us, Pipe allowed: %s", - old_alloc, new_alloc, bustime, - (new_alloc <= FRAME_TIME_MAX_USECS_ALLOC) ? - "yes" : "no"); + if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC) + dbg("usb-check-bandwidth %sFAILED: was %u, would be %u, bustime = %ld us", + usb_bandwidth_option ? "" : "would have ", + old_alloc, new_alloc, bustime); + + if (!usb_bandwidth_option) /* don't enforce it */ + return (bustime); + return (new_alloc <= FRAME_TIME_MAX_USECS_ALLOC) ? bustime : USB_ST_BANDWIDTH_ERROR; +} + +void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc) +{ + dev->bus->bandwidth_allocated += bustime; + if (isoc) + dev->bus->bandwidth_isoc_reqs++; + else + dev->bus->bandwidth_int_reqs++; + urb->bandwidth = bustime; + + dbg("bw_alloc increased by %d to %d for %d requesters", + bustime, + dev->bus->bandwidth_allocated, + dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs); +} + +/* + * usb_release_bandwidth(): + * + * called to release a pipe's bandwidth (in microseconds) + */ +void usb_release_bandwidth(struct usb_device *dev, struct urb *urb, int isoc) +{ + dev->bus->bandwidth_allocated -= urb->bandwidth; + if (isoc) + dev->bus->bandwidth_isoc_reqs--; + else + dev->bus->bandwidth_int_reqs--; - return (new_alloc <= FRAME_TIME_MAX_USECS_ALLOC) ? 0 : -1; -} /* end check_bandwidth_alloc */ + dbg("bw_alloc reduced by %d to %d for %d requesters", + urb->bandwidth, + dev->bus->bandwidth_allocated, + dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs); + urb->bandwidth = 0; +} /* * New functions for (de)registering a controller @@ -242,7 +311,7 @@ bus->bandwidth_isoc_reqs = 0; INIT_LIST_HEAD(&bus->bus_list); - INIT_LIST_HEAD(&bus->inodes); + INIT_LIST_HEAD(&bus->inodes); return bus; } @@ -393,7 +462,10 @@ driver_list); tmp = tmp->next; - if (!(private = driver->probe(dev, ifnum))) + down(&driver->serialize); + private = driver->probe(dev, ifnum); + up(&driver->serialize); + if (!private) continue; usb_driver_claim_interface(driver, interface, private); @@ -452,8 +524,8 @@ dev->bus = bus; dev->parent = parent; atomic_set(&dev->refcnt, 1); - INIT_LIST_HEAD(&dev->inodes); - INIT_LIST_HEAD(&dev->filelist); + INIT_LIST_HEAD(&dev->inodes); + INIT_LIST_HEAD(&dev->filelist); dev->bus->op->allocate(dev); @@ -659,21 +731,6 @@ } /* - * usb_release_bandwidth(): - * - * called to release an interrupt pipe's bandwidth (in microseconds) - */ -void usb_release_bandwidth(struct usb_device *dev, int bw_alloc) -{ - dev->bus->bandwidth_allocated -= bw_alloc; - dev->bus->bandwidth_int_reqs--; - dbg("bw_alloc reduced to %d for %d requesters", - dev->bus->bandwidth_allocated, - dev->bus->bandwidth_int_reqs + - dev->bus->bandwidth_isoc_reqs); -} - -/* * usb_get_current_frame_number() * * returns the current frame number for the parent USB bus/controller @@ -684,6 +741,7 @@ return usb_dev->bus->op->get_frame_number (usb_dev); } /*-------------------------------------------------------------------*/ + static int usb_parse_endpoint(struct usb_device *dev, struct usb_endpoint_descriptor *endpoint, unsigned char *buffer, int size) { struct usb_descriptor_header *header; @@ -826,7 +884,7 @@ begin = buffer; numskipped = 0; - /* Skip over at Interface class or vendor descriptors */ + /* Skip over any interface, class or vendor descriptors */ while (size >= sizeof(struct usb_descriptor_header)) { header = (struct usb_descriptor_header *)buffer; @@ -987,6 +1045,13 @@ if (!dev->config) return; + if (dev->rawdescriptors) { + for (i = 0; i < dev->descriptor.bNumConfigurations; i++) + kfree(dev->rawdescriptors[i]); + + kfree(dev->rawdescriptors); + } + for (c = 0; c < dev->descriptor.bNumConfigurations; c++) { struct usb_config_descriptor *cf = &dev->config[c]; @@ -1129,7 +1194,9 @@ struct usb_interface *interface = &dev->actconfig->interface[i]; struct usb_driver *driver = interface->driver; if (driver) { + down(&driver->serialize); driver->disconnect(dev, interface->private_data); + up(&driver->serialize); usb_driver_release_interface(driver, interface); } } @@ -1143,14 +1210,13 @@ } /* remove /proc/bus/usb entry */ - usbdevfs_remove_device(dev); + usbdevfs_remove_device(dev); /* Free up the device itself, including its device number */ if (dev->devnum > 0) clear_bit(dev->devnum, &dev->bus->devmap.devicemap); - + usb_free_dev(dev); - } /* @@ -1266,7 +1332,7 @@ (duration << 8) | report_id, ifnum, NULL, 0, HZ * SET_TIMEOUT); } -static void usb_set_maxpacket(struct usb_device *dev) +void usb_set_maxpacket(struct usb_device *dev) { int i, b; @@ -1337,15 +1403,10 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) { - struct usb_interface *iface = NULL; - int ret, i; + struct usb_interface *iface; + int ret; - for (i=0; iactconfig->bNumInterfaces; i++) { - if (dev->actconfig->interface[i].altsetting->bInterfaceNumber == interface) { - iface = &dev->actconfig->interface[i]; - break; - } - } + iface = usb_ifnum_to_if(dev, interface); if (!iface) { warn("selecting invalid interface %d", interface); return -EINVAL; @@ -1407,11 +1468,10 @@ int usb_get_configuration(struct usb_device *dev) { - int result; - unsigned int cfgno; + int result; + unsigned int cfgno, length; unsigned char buffer[8]; unsigned char *bigbuffer; - unsigned int tmp; struct usb_config_descriptor *desc = (struct usb_config_descriptor *)buffer; @@ -1435,9 +1495,14 @@ memset(dev->config, 0, dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor)); - for (cfgno = 0; cfgno < dev->descriptor.bNumConfigurations; cfgno++) { - + dev->rawdescriptors = (char **)kmalloc(sizeof(char *) * + dev->descriptor.bNumConfigurations, GFP_KERNEL); + if (!dev->rawdescriptors) { + err("out of memory"); + return -1; + } + for (cfgno = 0; cfgno < dev->descriptor.bNumConfigurations; cfgno++) { /* We grab the first 8 bytes so we know how long the whole */ /* configuration is */ result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8); @@ -1445,41 +1510,41 @@ if (result < 0) err("unable to get descriptor"); else - err("config descriptor too short (expected %i, got %i)",8,result); + err("config descriptor too short (expected %i, got %i)", 8, result); goto err; } /* Get the full buffer */ - le16_to_cpus(&desc->wTotalLength); + length = le16_to_cpu(desc->wTotalLength); - bigbuffer = kmalloc(desc->wTotalLength, GFP_KERNEL); + bigbuffer = kmalloc(length, GFP_KERNEL); if (!bigbuffer) { err("unable to allocate memory for configuration descriptors"); - result=-ENOMEM; + result = -ENOMEM; goto err; } - tmp=desc->wTotalLength; + /* Now that we know the length, get the whole thing */ - result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, desc->wTotalLength); + result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, length); if (result < 0) { err("couldn't get all of config descriptors"); kfree(bigbuffer); goto err; } - if (result < tmp) { - err("config descriptor too short (expected %i, got %i)",tmp,result); + if (result < length) { + err("config descriptor too short (expected %i, got %i)", length, result); kfree(bigbuffer); goto err; } - result = usb_parse_configuration(dev, &dev->config[cfgno], bigbuffer); - kfree(bigbuffer); + dev->rawdescriptors[cfgno] = bigbuffer; + + result = usb_parse_configuration(dev, &dev->config[cfgno], bigbuffer); if (result > 0) dbg("descriptor data left"); - else if (result < 0) - { - result=-1; + else if (result < 0) { + result = -1; goto err; } } @@ -1560,8 +1625,7 @@ */ int usb_new_device(struct usb_device *dev) { - int addr, err; - int tmp; + int err; info("USB new device connect, assigned device number %d", dev->devnum); @@ -1572,10 +1636,15 @@ dev->epmaxpacketin [0] = 8; dev->epmaxpacketout[0] = 8; - /* Even though we have assigned an address for the device, we */ - /* haven't told it what it's address is yet */ - addr = dev->devnum; - dev->devnum = 0; + err = usb_set_address(dev); + if (err < 0) { + err("USB device not accepting new address (error=%d)", err); + clear_bit(dev->devnum, &dev->bus->devmap.devicemap); + dev->devnum = -1; + return 1; + } + + wait_ms(10); /* Let the SET_ADDRESS settle */ err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8); if (err < 8) { @@ -1583,34 +1652,19 @@ err("USB device not responding, giving up (error=%d)", err); else err("USB device descriptor short read (expected %i, got %i)",8,err); - clear_bit(addr, &dev->bus->devmap.devicemap); + clear_bit(dev->devnum, &dev->bus->devmap.devicemap); dev->devnum = -1; return 1; } dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0; dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0; - dev->devnum = addr; - - err = usb_set_address(dev); - - if (err < 0) { - err("USB device not accepting new address (error=%d)", err); - clear_bit(dev->devnum, &dev->bus->devmap.devicemap); - dev->devnum = -1; - return 1; - } - - wait_ms(10); /* Let the SET_ADDRESS settle */ - - tmp = sizeof(dev->descriptor); - err = usb_get_device_descriptor(dev); - if (err < tmp) { + if (err < sizeof(dev->descriptor)) { if (err < 0) - err("unable to get device descriptor (error=%d)",err); + err("unable to get device descriptor (error=%d)", err); else - err("USB device descriptor short read (expected %i, got %i)",tmp,err); + err("USB device descriptor short read (expected %i, got %i)", sizeof(dev->descriptor), err); clear_bit(dev->devnum, &dev->bus->devmap.devicemap); dev->devnum = -1; @@ -1646,7 +1700,7 @@ #endif /* now that the basic setup is over, add a /proc/bus/usb entry */ - usbdevfs_add_device(dev); + usbdevfs_add_device(dev); /* find drivers willing to handle this device */ usb_find_drivers(dev); @@ -1658,16 +1712,25 @@ { int minor = MINOR(inode->i_rdev); struct usb_driver *c = usb_minors[minor/16]; + int err = -ENODEV; + struct file_operations *old_fops; - file->f_op = NULL; - - if (c && (file->f_op = c->fops) && file->f_op->open) - return file->f_op->open(inode,file); - else - return -ENODEV; + if (!c || !c->fops) + return err; + old_fops = file->f_op; + file->f_op = fops_get(c->fops); + if (file->f_op->open) + err = file->f_op->open(inode,file); + if (err) { + fops_put(file->f_op); + file->f_op = fops_get(old_fops); + } + fops_put(old_fops); + return err; } static struct file_operations usb_fops = { + owner: THIS_MODULE, open: usb_open, }; @@ -1704,6 +1767,8 @@ * into the kernel, and other device drivers are built as modules, * then these symbols need to be exported for the modules to use. */ +EXPORT_SYMBOL(usb_ifnum_to_if); + EXPORT_SYMBOL(usb_register); EXPORT_SYMBOL(usb_deregister); EXPORT_SYMBOL(usb_alloc_bus); @@ -1724,6 +1789,9 @@ EXPORT_SYMBOL(usb_reset_device); EXPORT_SYMBOL(usb_connect); EXPORT_SYMBOL(usb_disconnect); + +EXPORT_SYMBOL(usb_check_bandwidth); +EXPORT_SYMBOL(usb_claim_bandwidth); EXPORT_SYMBOL(usb_release_bandwidth); EXPORT_SYMBOL(usb_set_address); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/usbkbd.c linux/drivers/usb/usbkbd.c --- v2.4.0-test1/linux/drivers/usb/usbkbd.c Fri Mar 10 16:40:45 2000 +++ linux/drivers/usb/usbkbd.c Mon Jun 19 13:42:42 2000 @@ -1,7 +1,7 @@ /* - * usbkbd.c Version 0.1 + * $Id: usbkbd.c,v 1.11 2000/05/29 09:01:52 vojtech Exp $ * - * Copyright (c) 1999 Vojtech Pavlik + * Copyright (c) 1999-2000 Vojtech Pavlik * * USB HIDBP Keyboard support * @@ -63,6 +63,8 @@ struct urb irq, led; devrequest dr; unsigned char leds; + char name[128]; + int open; }; static void usb_kbd_irq(struct urb *urb) @@ -125,12 +127,34 @@ warn("led urb status %d received", urb->status); } +static int usb_kbd_open(struct input_dev *dev) +{ + struct usb_kbd *kbd = dev->private; + + if (kbd->open++) + return 0; + + if (usb_submit_urb(&kbd->irq)) + return -EIO; + + return 0; +} + +static void usb_kbd_close(struct input_dev *dev) +{ + struct usb_kbd *kbd = dev->private; + + if (!--kbd->open) + usb_unlink_urb(&kbd->irq); +} + static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum) { struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *endpoint; struct usb_kbd *kbd; - int i; + int i, pipe, maxp; + char *buf; if (dev->descriptor.bNumConfigurations != 1) return NULL; interface = dev->config[0].interface[ifnum].altsetting + 0; @@ -144,6 +168,9 @@ if (!(endpoint->bEndpointAddress & 0x80)) return NULL; if ((endpoint->bmAttributes & 3) != 3) return NULL; + pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); + maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); + usb_set_protocol(dev, interface->bInterfaceNumber, 0); usb_set_idle(dev, interface->bInterfaceNumber, 0, 0); @@ -159,14 +186,11 @@ kbd->dev.private = kbd; kbd->dev.event = usb_kbd_event; + kbd->dev.open = usb_kbd_open; + kbd->dev.close = usb_kbd_close; - { - int pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); - int maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); - - FILL_INT_URB(&kbd->irq, dev, pipe, kbd->new, maxp > 8 ? 8 : maxp, - usb_kbd_irq, kbd, endpoint->bInterval); - } + FILL_INT_URB(&kbd->irq, dev, pipe, kbd->new, maxp > 8 ? 8 : maxp, + usb_kbd_irq, kbd, endpoint->bInterval); kbd->dr.requesttype = USB_TYPE_CLASS | USB_RECIP_INTERFACE; kbd->dr.request = USB_REQ_SET_REPORT; @@ -174,18 +198,37 @@ kbd->dr.index = interface->bInterfaceNumber; kbd->dr.length = 1; - FILL_CONTROL_URB(&kbd->led, dev, usb_sndctrlpipe(dev, 0), - (void*) &kbd->dr, &kbd->leds, 1, usb_kbd_led, kbd); - - if (usb_submit_urb(&kbd->irq)) { + kbd->dev.name = kbd->name; + kbd->dev.idbus = BUS_USB; + kbd->dev.idvendor = dev->descriptor.idVendor; + kbd->dev.idproduct = dev->descriptor.idProduct; + kbd->dev.idversion = dev->descriptor.bcdDevice; + + if (!(buf = kmalloc(63, GFP_KERNEL))) { kfree(kbd); return NULL; } - input_register_device(&kbd->dev); + if (dev->descriptor.iManufacturer && + usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0) + strcat(kbd->name, buf); + if (dev->descriptor.iProduct && + usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0) + sprintf(kbd->name, "%s %s", kbd->name, buf); + + if (!strlen(kbd->name)) + sprintf(kbd->name, "USB HIDBP Keyboard %04x:%04x", + kbd->dev.idvendor, kbd->dev.idproduct); + + kfree(buf); - printk(KERN_INFO "input%d: USB HIDBP keyboard\n", kbd->dev.number); + FILL_CONTROL_URB(&kbd->led, dev, usb_sndctrlpipe(dev, 0), + (void*) &kbd->dr, &kbd->leds, 1, usb_kbd_led, kbd); + + input_register_device(&kbd->dev); + printk(KERN_INFO "input%d: %s on on usb%d:%d.%d\n", + kbd->dev.number, kbd->name, dev->bus->busnum, dev->devnum, ifnum); return kbd; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/usbmouse.c linux/drivers/usb/usbmouse.c --- v2.4.0-test1/linux/drivers/usb/usbmouse.c Fri Mar 10 16:40:45 2000 +++ linux/drivers/usb/usbmouse.c Mon Jun 19 13:42:42 2000 @@ -1,7 +1,7 @@ /* - * usbmouse.c Version 0.1 + * $Id: usbmouse.c,v 1.5 2000/05/29 09:01:52 vojtech Exp $ * - * Copyright (c) 1999 Vojtech Pavlik + * Copyright (c) 1999-2000 Vojtech Pavlik * * USB HIDBP Mouse support * @@ -37,12 +37,12 @@ MODULE_AUTHOR("Vojtech Pavlik "); -#define USBMOUSE_EXTRA - struct usb_mouse { signed char data[8]; + char name[128]; struct input_dev dev; struct urb irq; + int open; }; static void usb_mouse_irq(struct urb *urb) @@ -53,16 +53,36 @@ if (urb->status) return; - input_report_key(dev, BTN_LEFT, !!(data[0] & 0x01)); - input_report_key(dev, BTN_RIGHT, !!(data[0] & 0x02)); - input_report_key(dev, BTN_MIDDLE, !!(data[0] & 0x04)); - input_report_rel(dev, REL_X, data[1]); - input_report_rel(dev, REL_Y, data[2]); -#ifdef USBMOUSE_EXTRA - input_report_key(dev, BTN_SIDE, !!(data[0] & 0x08)); - input_report_key(dev, BTN_EXTRA, !!(data[0] & 0x10)); + input_report_key(dev, BTN_LEFT, data[0] & 0x01); + input_report_key(dev, BTN_RIGHT, data[0] & 0x02); + input_report_key(dev, BTN_MIDDLE, data[0] & 0x04); + input_report_key(dev, BTN_SIDE, data[0] & 0x08); + input_report_key(dev, BTN_EXTRA, data[0] & 0x10); + + input_report_rel(dev, REL_X, data[1]); + input_report_rel(dev, REL_Y, data[2]); input_report_rel(dev, REL_WHEEL, data[3]); -#endif +} + +static int usb_mouse_open(struct input_dev *dev) +{ + struct usb_mouse *mouse = dev->private; + + if (mouse->open++) + return 0; + + if (usb_submit_urb(&mouse->irq)) + return -EIO; + + return 0; +} + +static void usb_mouse_close(struct input_dev *dev) +{ + struct usb_mouse *mouse = dev->private; + + if (!--mouse->open) + usb_unlink_urb(&mouse->irq); } static void *usb_mouse_probe(struct usb_device *dev, unsigned int ifnum) @@ -70,6 +90,8 @@ struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *endpoint; struct usb_mouse *mouse; + int pipe, maxp; + char *buf; if (dev->descriptor.bNumConfigurations != 1) return NULL; interface = dev->config[0].interface[ifnum].altsetting + 0; @@ -83,9 +105,9 @@ if (!(endpoint->bEndpointAddress & 0x80)) return NULL; if ((endpoint->bmAttributes & 3) != 3) return NULL; -#ifndef USBMOUSE_EXTRA - usb_set_protocol(dev, interface->bInterfaceNumber, 0); -#endif + pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); + maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); + usb_set_idle(dev, interface->bInterfaceNumber, 0, 0); if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL))) return NULL; @@ -94,27 +116,44 @@ mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); -#ifdef USBMOUSE_EXTRA mouse->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA); mouse->dev.relbit[0] |= BIT(REL_WHEEL); -#endif - { - int pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); - int maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); + mouse->dev.private = mouse; + mouse->dev.open = usb_mouse_open; + mouse->dev.close = usb_mouse_close; + + mouse->dev.name = mouse->name; + mouse->dev.idbus = BUS_USB; + mouse->dev.idvendor = dev->descriptor.idVendor; + mouse->dev.idproduct = dev->descriptor.idProduct; + mouse->dev.idversion = dev->descriptor.bcdDevice; - FILL_INT_URB(&mouse->irq, dev, pipe, mouse->data, maxp > 8 ? 8 : maxp, - usb_mouse_irq, mouse, endpoint->bInterval); - } - - if (usb_submit_urb(&mouse->irq)) { + if (!(buf = kmalloc(63, GFP_KERNEL))) { kfree(mouse); return NULL; } + if (dev->descriptor.iManufacturer && + usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0) + strcat(mouse->name, buf); + if (dev->descriptor.iProduct && + usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0) + sprintf(mouse->name, "%s %s", mouse->name, buf); + + if (!strlen(mouse->name)) + sprintf(mouse->name, "USB HIDBP Mouse %04x:%04x", + mouse->dev.idvendor, mouse->dev.idproduct); + + kfree(buf); + + FILL_INT_URB(&mouse->irq, dev, pipe, mouse->data, maxp > 8 ? 8 : maxp, + usb_mouse_irq, mouse, endpoint->bInterval); + input_register_device(&mouse->dev); - printk(KERN_INFO "input%d: USB HIDBP mouse\n", mouse->dev.number); + printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n", + mouse->dev.number, mouse->name, dev->bus->busnum, dev->devnum, ifnum); return mouse; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/uss720.c linux/drivers/usb/uss720.c --- v2.4.0-test1/linux/drivers/usb/uss720.c Thu May 11 15:30:08 2000 +++ linux/drivers/usb/uss720.c Mon Jun 19 13:42:42 2000 @@ -546,13 +546,13 @@ struct parport *pp; int i; - printk(KERN_DEBUG "uss720: probe: vendor id 0x%x, device id 0x%x\n", - usbdev->descriptor.idVendor, usbdev->descriptor.idProduct); - if ((usbdev->descriptor.idVendor != 0x047e || usbdev->descriptor.idProduct != 0x1001) && (usbdev->descriptor.idVendor != 0x0557 || usbdev->descriptor.idProduct != 0x2001) && (usbdev->descriptor.idVendor != 0x0729 || usbdev->descriptor.idProduct != 0x1284)) return NULL; + + printk(KERN_DEBUG "uss720: probe: vendor id 0x%x, device id 0x%x\n", + usbdev->descriptor.idVendor, usbdev->descriptor.idProduct); /* our known interfaces have 3 alternate settings */ if (usbdev->actconfig->interface[ifnum].num_altsetting != 3) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/wacom.c linux/drivers/usb/wacom.c --- v2.4.0-test1/linux/drivers/usb/wacom.c Tue May 23 15:31:35 2000 +++ linux/drivers/usb/wacom.c Mon Jun 19 13:42:42 2000 @@ -1,5 +1,5 @@ /* - * wacom.c Version 0.5 + * $Id: wacom.c,v 1.9 2000/05/29 09:01:52 vojtech Exp $ * * Copyright (c) 2000 Vojtech Pavlik * Copyright (c) 2000 Andreas Bach Aaen @@ -18,6 +18,9 @@ * relative mode, proximity. * v0.5 (vp) - Big cleanup, nifty features removed, * they belong in userspace + * v1.8 (vp) - Submit URB only when operating, moved to CVS, + * use input_report_key instead of report_btn and + * other cleanups */ /* @@ -116,6 +119,7 @@ struct urb irq; struct wacom_features *features; int tool; + int open; }; static void wacom_graphire_irq(struct urb *urb) @@ -137,18 +141,18 @@ switch ((data[1] >> 5) & 3) { case 0: /* Pen */ - input_report_btn(dev, BTN_TOOL_PEN, data[1] & 0x80); + input_report_key(dev, BTN_TOOL_PEN, data[1] & 0x80); break; case 1: /* Rubber */ - input_report_btn(dev, BTN_TOOL_RUBBER, data[1] & 0x80); + input_report_key(dev, BTN_TOOL_RUBBER, data[1] & 0x80); break; case 2: /* Mouse */ - input_report_btn(dev, BTN_TOOL_MOUSE, data[7] > 24); - input_report_btn(dev, BTN_LEFT, data[1] & 0x01); - input_report_btn(dev, BTN_RIGHT, data[1] & 0x02); - input_report_btn(dev, BTN_MIDDLE, data[1] & 0x04); + input_report_key(dev, BTN_TOOL_MOUSE, data[7] > 24); + input_report_key(dev, BTN_LEFT, data[1] & 0x01); + input_report_key(dev, BTN_RIGHT, data[1] & 0x02); + input_report_key(dev, BTN_MIDDLE, data[1] & 0x04); input_report_abs(dev, ABS_DISTANCE, data[7]); input_report_rel(dev, REL_WHEEL, (signed char) data[6]); return; @@ -156,9 +160,9 @@ input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8)); - input_report_btn(dev, BTN_TOUCH, data[1] & 0x01); - input_report_btn(dev, BTN_STYLUS, data[1] & 0x02); - input_report_btn(dev, BTN_STYLUS2, data[1] & 0x04); + input_report_key(dev, BTN_TOUCH, data[1] & 0x01); + input_report_key(dev, BTN_STYLUS, data[1] & 0x02); + input_report_key(dev, BTN_STYLUS2, data[1] & 0x04); } static void wacom_intuos_irq(struct urb *urb) @@ -177,21 +181,23 @@ switch (((__u32)data[2] << 4) | (data[3] >> 4)) { case 0x012: wacom->tool = BTN_TOOL_PENCIL; break; /* Inking pen */ + case 0x822: case 0x022: wacom->tool = BTN_TOOL_PEN; break; /* Pen */ case 0x032: wacom->tool = BTN_TOOL_BRUSH; break; /* Stroke pen */ case 0x094: wacom->tool = BTN_TOOL_MOUSE; break; /* Mouse 4D */ case 0x096: wacom->tool = BTN_TOOL_LENS; break; /* Lens cursor */ + case 0x82a: case 0x0fa: wacom->tool = BTN_TOOL_RUBBER; break; /* Eraser */ case 0x112: wacom->tool = BTN_TOOL_AIRBRUSH; break; /* Airbrush */ default: wacom->tool = BTN_TOOL_PEN; break; /* Unknown tool */ } - input_report_btn(dev, wacom->tool, 1); + input_report_key(dev, wacom->tool, 1); return; } if ((data[1] | data[2] | data[3] | data[4] | data[5] | data[6] | data[7] | data[8] | data[9]) == 0x80) { /* Exit report */ - input_report_btn(dev, wacom->tool, 0); + input_report_key(dev, wacom->tool, 0); return; } @@ -202,29 +208,50 @@ input_report_abs(dev, ABS_TILT_X, ((data[7] << 1) & 0x7e) | (data[8] >> 7)); input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f); - input_report_btn(dev, BTN_STYLUS, data[1] & 2); - input_report_btn(dev, BTN_STYLUS2, data[1] & 4); - input_report_btn(dev, BTN_TOUCH, t > 10); + input_report_key(dev, BTN_STYLUS, data[1] & 2); + input_report_key(dev, BTN_STYLUS2, data[1] & 4); + input_report_key(dev, BTN_TOUCH, t > 10); } #define WACOM_INTUOS_TOOLS (BIT(BTN_TOOL_BRUSH) | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS)) struct wacom_features wacom_features[] = { - { "Graphire", 0x10, 8, 10206, 7422, 511, 32, wacom_graphire_irq, + { "Wacom Graphire", 0x10, 8, 10206, 7422, 511, 32, wacom_graphire_irq, BIT(EV_REL), 0, BIT(REL_WHEEL), BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE), 0 }, - { "Intuos 4x5", 0x20, 10, 12700, 10360, 1023, 15, wacom_intuos_irq, + { "Wacom Intuos 4x5", 0x20, 10, 12700, 10360, 1023, 15, wacom_intuos_irq, 0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS }, - { "Intuos 6x8", 0x21, 10, 20320, 15040, 1023, 15, wacom_intuos_irq, + { "Wacom Intuos 6x8", 0x21, 10, 20320, 15040, 1023, 15, wacom_intuos_irq, 0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS }, - { "Intuos 9x12", 0x22, 10, 30480, 23060, 1023, 15, wacom_intuos_irq, + { "Wacom Intuos 9x12", 0x22, 10, 30480, 23060, 1023, 15, wacom_intuos_irq, 0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS }, - { "Intuos 12x12", 0x23, 10, 30480, 30480, 1023, 15, wacom_intuos_irq, + { "Wacom Intuos 12x12", 0x23, 10, 30480, 30480, 1023, 15, wacom_intuos_irq, 0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS }, - { "Intuos 12x18", 0x24, 10, 47720, 30480, 1023, 15, wacom_intuos_irq, + { "Wacom Intuos 12x18", 0x24, 10, 47720, 30480, 1023, 15, wacom_intuos_irq, 0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS }, { NULL , 0 } }; +static int wacom_open(struct input_dev *dev) +{ + struct wacom *wacom = dev->private; + + if (wacom->open++) + return 0; + + if (usb_submit_urb(&wacom->irq)) + return -EIO; + + return 0; +} + +static void wacom_close(struct input_dev *dev) +{ + struct wacom *wacom = dev->private; + + if (!--wacom->open) + usb_unlink_urb(&wacom->irq); +} + static void *wacom_probe(struct usb_device *dev, unsigned int ifnum) { struct usb_endpoint_descriptor *endpoint; @@ -256,17 +283,23 @@ wacom->dev.absmax[ABS_TILT_X] = 127; wacom->dev.absmax[ABS_TILT_Y] = 127; + wacom->dev.private = wacom; + wacom->dev.open = wacom_open; + wacom->dev.close = wacom_close; + + wacom->dev.name = wacom->features->name; + wacom->dev.idbus = BUS_USB; + wacom->dev.idvendor = dev->descriptor.idVendor; + wacom->dev.idproduct = dev->descriptor.idProduct; + wacom->dev.idversion = dev->descriptor.bcdDevice; + FILL_INT_URB(&wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress), wacom->data, wacom->features->pktlen, wacom->features->irq, wacom, endpoint->bInterval); - if (usb_submit_urb(&wacom->irq)) { - kfree(wacom); - return NULL; - } - input_register_device(&wacom->dev); - printk(KERN_INFO "input%d: Wacom %s on usb%d\n", wacom->dev.number, wacom->features->name, dev->devnum); + printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n", + wacom->dev.number, wacom->features->name, dev->bus->busnum, dev->devnum, ifnum); return wacom; } diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/wmforce.c linux/drivers/usb/wmforce.c --- v2.4.0-test1/linux/drivers/usb/wmforce.c Fri Mar 10 16:40:45 2000 +++ linux/drivers/usb/wmforce.c Wed Dec 31 16:00:00 1969 @@ -1,165 +0,0 @@ -/* - * wmforce.c Version 0.1 - * - * Copyright (c) 2000 Vojtech Pavlik - * - * USB Logitech WingMan Force joystick support - * - * Sponsored by SuSE - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include - -MODULE_AUTHOR("Vojtech Pavlik "); - -#define USB_VENDOR_ID_LOGITECH 0x046d -#define USB_DEVICE_ID_LOGITECH_WMFORCE 0xc281 - -struct wmforce { - signed char data[8]; - struct input_dev dev; - struct urb irq; -}; - -static struct { - __s32 x; - __s32 y; -} wmforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; - -static void wmforce_irq(struct urb *urb) -{ - struct wmforce *wmforce = urb->context; - unsigned char *data = wmforce->data; - struct input_dev *dev = &wmforce->dev; - - if (urb->status) return; - - if (data[0] != 1) { - if (data[0] != 2) - warn("received unknown report #%d", data[0]); - return; - } - - input_report_abs(dev, ABS_X, (__s16) (((__s16)data[2] << 8) | data[1])); - input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[4] << 8) | data[3])); - input_report_abs(dev, ABS_THROTTLE, data[5]); - input_report_abs(dev, ABS_HAT0X, wmforce_hat_to_axis[data[7] >> 4].x); - input_report_abs(dev, ABS_HAT0Y, wmforce_hat_to_axis[data[7] >> 4].y); - - input_report_key(dev, BTN_TRIGGER, !!(data[6] & 0x01)); - input_report_key(dev, BTN_TOP, !!(data[6] & 0x02)); - input_report_key(dev, BTN_THUMB, !!(data[6] & 0x04)); - input_report_key(dev, BTN_TOP2, !!(data[6] & 0x08)); - input_report_key(dev, BTN_BASE, !!(data[6] & 0x10)); - input_report_key(dev, BTN_BASE2, !!(data[6] & 0x20)); - input_report_key(dev, BTN_BASE3, !!(data[6] & 0x40)); - input_report_key(dev, BTN_BASE4, !!(data[6] & 0x80)); - input_report_key(dev, BTN_BASE5, !!(data[7] & 0x01)); -} - -static void *wmforce_probe(struct usb_device *dev, unsigned int ifnum) -{ - struct usb_endpoint_descriptor *endpoint; - struct wmforce *wmforce; - int i; - - if (dev->descriptor.idVendor != USB_VENDOR_ID_LOGITECH || - dev->descriptor.idProduct != USB_DEVICE_ID_LOGITECH_WMFORCE) - return NULL; - - endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0; - - if (!(wmforce = kmalloc(sizeof(struct wmforce), GFP_KERNEL))) return NULL; - memset(wmforce, 0, sizeof(struct wmforce)); - - wmforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - wmforce->dev.keybit[LONG(BTN_JOYSTICK)] = BIT(BTN_TRIGGER) | BIT(BTN_TOP) | BIT(BTN_THUMB) | BIT(BTN_TOP2) | - BIT(BTN_BASE) | BIT(BTN_BASE2) | BIT(BTN_BASE3) | BIT(BTN_BASE4) | BIT(BTN_BASE5); - wmforce->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y); - - for (i = ABS_X; i <= ABS_Y; i++) { - wmforce->dev.absmax[i] = 1920; - wmforce->dev.absmin[i] = -1920; - wmforce->dev.absfuzz[i] = 0; - wmforce->dev.absflat[i] = 128; - } - - wmforce->dev.absmax[ABS_THROTTLE] = 0; - wmforce->dev.absmin[ABS_THROTTLE] = 255; - wmforce->dev.absfuzz[ABS_THROTTLE] = 0; - wmforce->dev.absflat[ABS_THROTTLE] = 0; - - for (i = ABS_HAT0X; i <= ABS_HAT0Y; i++) { - wmforce->dev.absmax[i] = 1; - wmforce->dev.absmin[i] = -1; - wmforce->dev.absfuzz[i] = 0; - wmforce->dev.absflat[i] = 0; - } - - FILL_INT_URB(&wmforce->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress), - wmforce->data, 8, wmforce_irq, wmforce, endpoint->bInterval); - - if (usb_submit_urb(&wmforce->irq)) { - kfree(wmforce); - return NULL; - } - - input_register_device(&wmforce->dev); - - printk(KERN_INFO "input%d: Logitech WingMan Force USB\n", wmforce->dev.number); - - return wmforce; -} - -static void wmforce_disconnect(struct usb_device *dev, void *ptr) -{ - struct wmforce *wmforce = ptr; - usb_unlink_urb(&wmforce->irq); - input_unregister_device(&wmforce->dev); - kfree(wmforce); -} - -static struct usb_driver wmforce_driver = { - name: "wmforce", - probe: wmforce_probe, - disconnect: wmforce_disconnect, -}; - -static int __init wmforce_init(void) -{ - usb_register(&wmforce_driver); - return 0; -} - -static void __exit wmforce_exit(void) -{ - usb_deregister(&wmforce_driver); -} - -module_init(wmforce_init); -module_exit(wmforce_exit); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/Config.in linux/drivers/video/Config.in --- v2.4.0-test1/linux/drivers/video/Config.in Mon Jun 19 16:32:00 2000 +++ linux/drivers/video/Config.in Fri Jun 23 20:55:46 2000 @@ -120,6 +120,7 @@ tristate ' ATI Mach64 display support (EXPERIMENTAL)' CONFIG_FB_ATY tristate ' ATI Rage 128 display support (EXPERIMENTAL)' CONFIG_FB_ATY128 bool ' 3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX + tristate ' SIS 630/540 display support (EXPERIMENTAL)' CONFIG_FB_SIS fi fi if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then @@ -155,6 +156,9 @@ fi fi fi + if [ "$CONFIG_HD64461" = "y" ]; then + tristate ' HD64461 Frame Buffer support' CONFIG_FB_HIT + fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate ' Virtual Frame Buffer support (ONLY FOR TESTING!)' CONFIG_FB_VIRTUAL fi @@ -236,6 +240,7 @@ "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \ "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ "$CONFIG_FB_P9100" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \ + "$CONFIG_FB_RIVA" = "m" -o \ "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" -o \ "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" ]; then define_tristate CONFIG_FBCON_CFB8 m @@ -251,20 +256,22 @@ "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \ "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \ "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \ - "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \ - "$CONFIG_FB_SIS" = "y" ]; then + "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \ + "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" ]; then define_tristate CONFIG_FBCON_CFB16 y else if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VESA" = "m" -o \ "$CONFIG_FB_VIRTUAL" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \ - "$CONFIG_FB_Q40" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \ + "$CONFIG_FB_Q40" = "m" -o \ "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \ "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \ "$CONFIG_FB_PM2" = "m" -o "$CONFIG_FB_SGIVW" = "m" -o \ - "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" ]; then + "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \ + "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" -o \ + "$CONFIG_FB_SA1100" = "m" ]; then define_tristate CONFIG_FBCON_CFB16 m fi fi @@ -298,8 +305,8 @@ "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ - "$CONFIG_FB_ATY128" = "m" -o \ - "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_SIS" = "m" ]; then + "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \ + "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_SIS" = "m" ]; then define_tristate CONFIG_FBCON_CFB32 m fi fi diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/Makefile linux/drivers/video/Makefile --- v2.4.0-test1/linux/drivers/video/Makefile Mon Jun 19 16:32:00 2000 +++ linux/drivers/video/Makefile Tue Jun 20 14:28:05 2000 @@ -103,7 +103,6 @@ ifeq ($(CONFIG_FB_RIVA),y) SUB_DIRS += riva obj-y += riva/rivafb.o -MOD_SUB_DIRS += riva else ifeq ($(CONFIG_FB_RIVA),m) MOD_SUB_DIRS += riva @@ -115,6 +114,7 @@ obj-$(CONFIG_FB_HGA) += hgafb.o obj-$(CONFIG_FB_SA1100) += sa1100fb.o obj-$(CONFIG_FB_VIRTUAL) += vfb.o +obj-$(CONFIG_FB_HIT) += hitfb.o fbgen.o # Generic Low Level Drivers diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/S3triofb.c linux/drivers/video/S3triofb.c --- v2.4.0-test1/linux/drivers/video/S3triofb.c Thu Aug 26 13:05:40 1999 +++ linux/drivers/video/S3triofb.c Tue Jun 20 14:14:51 2000 @@ -77,8 +77,6 @@ * Interface used by the world */ -static int s3trio_open(struct fb_info *info, int user); -static int s3trio_release(struct fb_info *info, int user); static int s3trio_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info); static int s3trio_get_var(struct fb_var_screeninfo *var, int con, @@ -141,31 +139,15 @@ static struct fb_ops s3trio_ops = { - s3trio_open, s3trio_release, s3trio_get_fix, s3trio_get_var, s3trio_set_var, - s3trio_get_cmap, s3trio_set_cmap, s3trio_pan_display, s3trio_ioctl + owner: THIS_MODULE, + fb_get_fix: s3trio_get_fix, + fb_get_var: s3trio_get_var, + fb_set_var: s3trio_set_var, + fb_get_cmap: s3trio_get_cmap, + fb_set_cmap: s3trio_set_cmap, + fb_pan_display: s3trio_pan_display, + fb_ioctl: s3trio_ioctl, }; - - - /* - * Open/Release the frame buffer device - */ - -static int s3trio_open(struct fb_info *info, int user) -{ - /* - * Nothing, only a usage count for the moment - */ - - MOD_INC_USE_COUNT; - return(0); -} - -static int s3trio_release(struct fb_info *info, int user) -{ - MOD_DEC_USE_COUNT; - return(0); -} - /* * Get the Fixed Part of the Display diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/acornfb.c linux/drivers/video/acornfb.c --- v2.4.0-test1/linux/drivers/video/acornfb.c Fri May 12 14:18:55 2000 +++ linux/drivers/video/acornfb.c Tue Jun 20 14:14:51 2000 @@ -669,20 +669,6 @@ } static int -acornfb_open(struct fb_info *info, int user) -{ - MOD_INC_USE_COUNT; - return 0; -} - -static int -acornfb_release(struct fb_info *info, int user) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -static int acornfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *trans, struct fb_info *info) { @@ -1133,15 +1119,14 @@ } static struct fb_ops acornfb_ops = { - acornfb_open, - acornfb_release, - acornfb_get_fix, - acornfb_get_var, - acornfb_set_var, - acornfb_get_cmap, - acornfb_set_cmap, - acornfb_pan_display, - acornfb_ioctl + owner: THIS_MODULE, + fb_get_fix: acornfb_get_fix, + fb_get_var: acornfb_get_var, + fb_set_var: acornfb_set_var, + fb_get_cmap: acornfb_get_cmap, + fb_set_cmap: acornfb_set_cmap, + fb_pan_display: acornfb_pan_display, + fb_ioctl: acornfb_ioctl, }; static int diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/amifb.c linux/drivers/video/amifb.c --- v2.4.0-test1/linux/drivers/video/amifb.c Tue Apr 11 15:09:21 2000 +++ linux/drivers/video/amifb.c Tue Jun 20 14:14:51 2000 @@ -1102,8 +1102,6 @@ int amifb_setup(char*); -static int amifb_open(struct fb_info *info, int user); -static int amifb_release(struct fb_info *info, int user); static int amifb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info); static int amifb_get_var(struct fb_var_screeninfo *var, int con, @@ -1185,9 +1183,14 @@ static struct fb_ops amifb_ops = { - amifb_open, amifb_release, amifb_get_fix, amifb_get_var, - amifb_set_var, amifb_get_cmap, amifb_set_cmap, - amifb_pan_display, amifb_ioctl + owner: THIS_MODULE, + fb_get_fix: amifb_get_fix, + fb_get_var: amifb_get_var, + fb_set_var: amifb_set_var, + fb_get_cmap: amifb_get_cmap, + fb_set_cmap: amifb_set_cmap, + fb_pan_display: amifb_pan_display, + fb_ioctl: amifb_ioctl, }; int __init amifb_setup(char *options) @@ -1259,27 +1262,6 @@ } return 0; } - - /* - * Open/Release the frame buffer device - */ - -static int amifb_open(struct fb_info *info, int user) -{ - /* - * Nothing, only a usage count for the moment - */ - - MOD_INC_USE_COUNT; - return(0); -} - -static int amifb_release(struct fb_info *info, int user) -{ - MOD_DEC_USE_COUNT; - return(0); -} - /* * Get the Fixed Part of the Display diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/atafb.c linux/drivers/video/atafb.c --- v2.4.0-test1/linux/drivers/video/atafb.c Tue Dec 7 09:32:46 1999 +++ linux/drivers/video/atafb.c Tue Jun 20 14:14:51 2000 @@ -2426,40 +2426,6 @@ 1, fbhw->setcolreg, info); } - - /* - * Open/Release the frame buffer device - */ - -static int atafb_open(struct fb_info *info, int user) -{ - /* - * Nothing, only a usage count for the moment - */ - - MOD_INC_USE_COUNT; - return(0); -} - -static int atafb_release(struct fb_info *info, int user) -{ - MOD_DEC_USE_COUNT; - return(0); -} - - -static int -atafb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) -{ - struct atafb_par par; - if (con == -1) - atafb_get_par(&par); - else - fbhw->decode_var(&fb_display[con].var,&par); - memset(fix, 0, sizeof(struct fb_fix_screeninfo)); - return fbhw->encode_fix(fix, &par); -} - static int atafb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) { @@ -2658,9 +2624,14 @@ } static struct fb_ops atafb_ops = { - atafb_open, atafb_release, atafb_get_fix, atafb_get_var, - atafb_set_var, atafb_get_cmap, atafb_set_cmap, - atafb_pan_display, atafb_ioctl + owner: THIS_MODULE, + fb_get_fix: atafb_get_fix, + fb_get_var: atafb_get_var, + fb_set_var: atafb_set_var, + fb_get_cmap: atafb_get_cmap, + fb_set_cmap: atafb_set_cmap, + fb_pan_display: atafb_pan_display, + fb_ioctl: atafb_ioctl, }; static void diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/aty.h linux/drivers/video/aty.h --- v2.4.0-test1/linux/drivers/video/aty.h Mon Oct 11 15:38:15 1999 +++ linux/drivers/video/aty.h Tue Jun 20 14:14:51 2000 @@ -67,6 +67,8 @@ #define CUR_HORZ_VERT_POSN 0x006C /* Dword offset 0_1B */ #define CUR_HORZ_VERT_OFF 0x0070 /* Dword offset 0_1C */ +#define CONFIG_PANEL_LG 0x0074 /* Dword offset 0_1D */ + #define GP_IO 0x0078 /* Dword offset 0_1E */ #define HW_DEBUG 0x007C /* Dword offset 0_1F */ @@ -82,6 +84,9 @@ #define BUS_CNTL 0x00A0 /* Dword offset 0_28 */ +#define LCD_INDEX 0x00A4 /* Dword offset 0_29 */ +#define LCD_DATA 0x00A8 /* Dword offset 0_2A */ + #define EXT_MEM_CNTL 0x00AC /* Dword offset 0_2B */ #define MEM_CNTL 0x00B0 /* Dword offset 0_2C */ @@ -102,8 +107,9 @@ #define GEN_TEST_CNTL 0x00D0 /* Dword offset 0_34 */ #define CUSTOM_MACRO_CNTL 0x00D4 /* Dword offset 0_35 */ +#define LCD_GEN_CNTL_LG 0x00D4 /* Dword offset 0_35 */ -#define POWER_MANAGEMENT 0x00D8 /* Dword offset 0_36 (LG) */ +#define POWER_MANAGEMENT_LG 0x00D8 /* Dword offset 0_36 (LG) */ #define CONFIG_CNTL 0x00DC /* Dword offset 0_37 (CT, ET, VT) */ #define CONFIG_CHIP_ID 0x00E0 /* Dword offset 0_38 */ @@ -727,7 +733,7 @@ /* mach64CT family / mach64GT (3D RAGE) class */ #define LB_CHIP_ID 0x4c42 /* RAGE LT PRO, AGP */ #define LD_CHIP_ID 0x4c44 /* RAGE LT PRO */ -#define LG_CHIP_ID 0x4c47 /* RAGE LT PRO */ +#define LG_CHIP_ID 0x4c47 /* RAGE LT */ #define LI_CHIP_ID 0x4c49 /* RAGE LT PRO */ #define LP_CHIP_ID 0x4c50 /* RAGE LT PRO */ #define LT_CHIP_ID 0x4c54 /* RAGE LT */ @@ -741,6 +747,7 @@ #define GI_CHIP_ID 0x4749 /* RAGE PRO, BGA, PCI33 only */ #define GP_CHIP_ID 0x4750 /* RAGE PRO, PQFP, PCI33, full 3D */ #define GQ_CHIP_ID 0x4751 /* RAGE PRO, PQFP, PCI33, limited 3D */ +#define LN_CHIP_ID 0x4c4d /* RAGE Mobility AGP */ /* Mach64 major ASIC revisions */ @@ -953,15 +960,43 @@ #define MACH64_NUM_CLOCKS 16 #define MACH64_NUM_FREQS 50 -/* Power Management register constants (LTG and LT Pro) */ +/* Power Management register constants (LT & LT Pro) */ #define PWR_MGT_ON 0x00000001 #define PWR_MGT_MODE_MASK 0x00000006 #define AUTO_PWR_UP 0x00000008 +#define USE_F32KHZ 0x00000400 +#define TRISTATE_MEM_EN 0x00000800 #define SELF_REFRESH 0x00000080 #define PWR_BLON 0x02000000 #define STANDBY_NOW 0x10000000 #define SUSPEND_NOW 0x20000000 #define PWR_MGT_STATUS_MASK 0xC0000000 #define PWR_MGT_STATUS_SUSPEND 0x80000000 + +/* PM Mode constants */ +#define PWR_MGT_MODE_PIN 0x00000000 +#define PWR_MGT_MODE_REG 0x00000002 +#define PWR_MGT_MODE_TIMER 0x00000004 +#define PWR_MGT_MODE_PCI 0x00000006 + +/* LCD registers (LT Pro) */ + +/* LCD Index register */ +#define LCD_INDEX_MASK 0x0000003F +#define LCD_DISPLAY_DIS 0x00000100 +#define LCD_SRC_SEL 0x00000200 +#define CRTC2_DISPLAY_DIS 0x00000400 + +/* LCD register indices */ +#define LCD_CONFIG_PANEL 0x00 +#define LCD_GEN_CTRL 0x01 +#define LCD_DSTN_CONTROL 0x02 +#define LCD_HFB_PITCH_ADDR 0x03 +#define LCD_HORZ_STRETCHING 0x04 +#define LCD_VERT_STRETCHING 0x05 +#define LCD_EXT_VERT_STRETCH 0x06 +#define LCD_LT_GIO 0x07 +#define LCD_POWER_MANAGEMENT 0x08 +#define LCD_ZVGPIO 0x09 #endif /* REGMACH64_H */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/aty128.h linux/drivers/video/aty128.h --- v2.4.0-test1/linux/drivers/video/aty128.h Tue Mar 14 19:10:40 2000 +++ linux/drivers/video/aty128.h Tue Jun 20 14:14:51 2000 @@ -266,6 +266,8 @@ #define DAC_MASK 0xFF000000 #define DAC_BLANKING 0x00000004 #define DAC_RANGE_CNTL 0x00000003 +#define DAC_RANGE_CNTL 0x00000003 +#define PALETTE_ACCESS_CNTL 0x00000020 /* GEN_RESET_CNTL bit constants */ #define SOFT_RESET_GUI 0x00000001 diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/aty128fb.c linux/drivers/video/aty128fb.c --- v2.4.0-test1/linux/drivers/video/aty128fb.c Thu May 11 15:30:08 2000 +++ linux/drivers/video/aty128fb.c Tue Jun 20 14:14:51 2000 @@ -80,6 +80,7 @@ #define DBG(x) #endif +#ifndef CONFIG_PPC /* default mode */ static struct fb_var_screeninfo default_var __initdata = { /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */ @@ -89,6 +90,18 @@ 0, FB_VMODE_NONINTERLACED }; +#else /* CONFIG_PPC */ +/* 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 = { + /* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */ + 1024, 768, 1024, 768, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 12699, 160, 32, 28, 1, 96, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED +}; +#endif /* CONFIG_PPC */ + #ifndef MODULE /* default modedb mode */ static struct fb_videomode defaultmode __initdata = { @@ -96,25 +109,35 @@ NULL, 60, 640, 480, 39722, 48, 16, 33, 10, 96, 2, 0, FB_VMODE_NONINTERLACED }; -#endif +#endif /* MODULE */ -/* chip description information */ +/* struct to hold chip description information */ struct aty128_chip_info { const char *name; unsigned short device; + int chip_gen; +}; + +/* Chip generations */ +enum { + rage_128, + rage_128_pro, + rage_M3 }; /* supported Rage128 chipsets */ static const struct aty128_chip_info aty128_pci_probe_list[] __initdata = { - { "Rage128 RE (PCI)", PCI_DEVICE_ID_ATI_RAGE128_RE }, - { "Rage128 RF (AGP)", PCI_DEVICE_ID_ATI_RAGE128_RF }, - { "Rage128 RK (PCI)", PCI_DEVICE_ID_ATI_RAGE128_RK }, - { "Rage128 RL (AGP)", PCI_DEVICE_ID_ATI_RAGE128_RL }, - { "Rage128 Pro PF (AGP)", PCI_DEVICE_ID_ATI_RAGE128_PF }, - { "Rage128 Pro PR (PCI)", PCI_DEVICE_ID_ATI_RAGE128_PR }, - { NULL, 0 } -}; + {"Rage128 RE (PCI)", PCI_DEVICE_ID_ATI_RAGE128_RE, rage_128}, + {"Rage128 RF (AGP)", PCI_DEVICE_ID_ATI_RAGE128_RF, rage_128}, + {"Rage128 RK (PCI)", PCI_DEVICE_ID_ATI_RAGE128_RK, rage_128}, + {"Rage128 RL (AGP)", PCI_DEVICE_ID_ATI_RAGE128_RL, rage_128}, + {"Rage128 Pro PF (AGP)", PCI_DEVICE_ID_ATI_RAGE128_PF, rage_128_pro}, + {"Rage128 Pro PR (PCI)", PCI_DEVICE_ID_ATI_RAGE128_PR, rage_128_pro}, + {"Rage Mobility M3 (PCI)", PCI_DEVICE_ID_ATI_RAGE128_LE, rage_M3}, + {"Rage Mobility M3 (AGP)", PCI_DEVICE_ID_ATI_RAGE128_LF, rage_M3}, + {NULL, 0, rage_128} + }; /* packed BIOS settings */ #ifndef CONFIG_PPC @@ -251,6 +274,7 @@ u32 frame_buffer; /* remaped framebuffer */ u32 io_base; /* unmapped io */ u32 vram_size; /* onboard video ram */ + int chip_gen; const struct aty128_meminfo *mem; /* onboard mem info */ struct aty128fb_par default_par, current_par; struct display disp; @@ -287,8 +311,6 @@ int aty128fb_setup(char *options); -static int aty128fb_open(struct fb_info *info, int user); -static int aty128fb_release(struct fb_info *info, int user); static int aty128fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info); static int aty128fb_get_var(struct fb_var_screeninfo *var, int con, @@ -386,10 +408,15 @@ #endif static struct fb_ops aty128fb_ops = { - aty128fb_open, aty128fb_release, aty128fb_get_fix, - aty128fb_get_var, aty128fb_set_var, aty128fb_get_cmap, - aty128fb_set_cmap, aty128fb_pan_display, aty128fb_ioctl, - NULL, aty128fb_rasterimg + owner: THIS_MODULE, + fb_get_fix: aty128fb_get_fix, + fb_get_var: aty128fb_get_var, + fb_set_var: aty128fb_set_var, + fb_get_cmap: aty128fb_get_cmap, + fb_set_cmap: aty128fb_set_cmap, + fb_pan_display: aty128fb_pan_display, + fb_ioctl: aty128fb_ioctl, + fb_rasterimg: aty128fb_rasterimg, }; @@ -630,6 +657,8 @@ { u32 pitch_value; + wait_for_idle(info); + /* 3D scaler not spoken here */ wait_for_fifo(1, info); aty_st_le32(SCALE_3D_CNTL, 0x00000000); @@ -725,9 +754,12 @@ aty_st_le32(CRTC_PITCH, crtc->pitch); aty_st_le32(CRTC_OFFSET, crtc->offset); aty_st_le32(CRTC_OFFSET_CNTL, crtc->offset_cntl); - - /* Disable ATOMIC updating. Is this the right place? */ + /* Disable ATOMIC updating. Is this the right place? + * -- BenH: Breaks on my G4 + */ +#if 0 aty_st_le32(PPLL_CNTL, aty_ld_le32(PPLL_CNTL) & ~(0x00030000)); +#endif } @@ -969,7 +1001,6 @@ return 0; } - static void aty128_set_pll(struct aty128_pll *pll, const struct fb_info_aty128 *info) { @@ -1207,25 +1238,6 @@ #endif /* CONFIG_FB_COMPAT_XPMAC */ } - - /* - * Open/Release the frame buffer device - */ - -static int aty128fb_open(struct fb_info *info, int user) -{ - MOD_INC_USE_COUNT; - return(0); -} - - -static int aty128fb_release(struct fb_info *info, int user) -{ - MOD_DEC_USE_COUNT; - return(0); -} - - /* * encode/decode the User Defined Part of the Display */ @@ -1699,6 +1711,7 @@ /* put a name with the face */ while (aci->name && info->pdev->device != aci->device) { aci++; } video_card = (char *)aci->name; + info->chip_gen = aci->chip_gen; printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] ", video_card, chip_rev); @@ -1745,14 +1758,13 @@ if (mac_vmode_to_var(default_vmode, default_cmode, &var)) var = default_var; } - } else { + } else #endif /* CONFIG_PPC */ + { if (fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, &defaultmode, initdepth) == 0) var = default_var; -#ifdef CONFIG_PPC } -#endif #endif /* MODULE */ if (noaccel) @@ -1847,6 +1859,7 @@ u32 fb_addr, reg_addr, io_addr = 0; int err; +#if 0 /* Request resources we're going to use */ io_addr = pci_resource_start(pdev, 1); if (!request_region(io_addr, pci_resource_len(pdev, 1), @@ -1854,6 +1867,7 @@ printk(KERN_ERR "aty128fb: cannot reserve I/O ports\n"); goto err_out_none; } +#endif fb_addr = pci_resource_start(pdev, 0); if (!request_mem_region(fb_addr, pci_resource_len(pdev, 0), @@ -2226,24 +2240,53 @@ info->palette[regno].green = green; info->palette[regno].blue = blue; + /* Note: For now, on M3, we set palette on both heads, which may + * be useless. Can someone with a M3 check this ? */ + /* initialize gamma ramp for hi-color+ */ + if ((info->current_par.crtc.bpp > 8) && (regno == 0)) { int i; + if (info->chip_gen == rage_M3) + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~PALETTE_ACCESS_CNTL); + for (i=16; i<256; i++) { aty_st_8(PALETTE_INDEX, i); col = (i << 16) | (i << 8) | i; aty_st_le32(PALETTE_DATA, col); } + + if (info->chip_gen == rage_M3) { + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | PALETTE_ACCESS_CNTL); + + for (i=16; i<256; i++) { + aty_st_8(PALETTE_INDEX, i); + col = (i << 16) | (i << 8) | i; + aty_st_le32(PALETTE_DATA, col); + } + } } /* initialize palette */ + + if (info->chip_gen == rage_M3) + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~PALETTE_ACCESS_CNTL); + if (info->current_par.crtc.bpp == 16) aty_st_8(PALETTE_INDEX, (regno << 3)); else aty_st_8(PALETTE_INDEX, regno); col = (red << 16) | (green << 8) | blue; aty_st_le32(PALETTE_DATA, col); + if (info->chip_gen == rage_M3) { + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | PALETTE_ACCESS_CNTL); + if (info->current_par.crtc.bpp == 16) + aty_st_8(PALETTE_INDEX, (regno << 3)); + else + aty_st_8(PALETTE_INDEX, regno); + aty_st_le32(PALETTE_DATA, col); + } if (regno < 16) switch (info->current_par.crtc.bpp) { diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c --- v2.4.0-test1/linux/drivers/video/atyfb.c Tue Apr 11 15:09:21 2000 +++ linux/drivers/video/atyfb.c Tue Jun 20 14:14:51 2000 @@ -1,4 +1,4 @@ -/* $Id: atyfb.c,v 1.141 2000/03/12 03:53:16 davem Exp $ +/* $Id: atyfb.c,v 1.142 2000/04/12 01:39:41 davem Exp $ * linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64 * * Copyright (C) 1997-1998 Geert Uytterhoeven @@ -475,14 +475,20 @@ static int currcon = 0; static struct fb_ops atyfb_ops = { - atyfb_open, atyfb_release, atyfb_get_fix, atyfb_get_var, atyfb_set_var, - atyfb_get_cmap, atyfb_set_cmap, atyfb_pan_display, atyfb_ioctl, + owner: THIS_MODULE, + fb_open: atyfb_open, + fb_release: atyfb_release, + fb_get_fix: atyfb_get_fix, + fb_get_var: atyfb_get_var, + fb_set_var: atyfb_set_var, + fb_get_cmap: atyfb_get_cmap, + fb_set_cmap: atyfb_set_cmap, + fb_pan_display: atyfb_pan_display, + fb_ioctl: atyfb_ioctl, #ifdef __sparc__ - atyfb_mmap, -#else - NULL, + fb_mmap: atyfb_mmap, #endif - atyfb_rasterimg + fb_rasterimg: atyfb_rasterimg, }; static char atyfb_name[16] = "ATY Mach64"; @@ -536,7 +542,7 @@ /* mach64CT family / mach64GT (3D RAGE) class */ { 0x4c42, 0x4c42, "3D RAGE LT PRO (AGP)" }, { 0x4c44, 0x4c44, "3D RAGE LT PRO" }, - { 0x4c47, 0x4c47, "3D RAGE LT PRO" }, + { 0x4c47, 0x4c47, "3D RAGE LT-G" }, { 0x4c49, 0x4c49, "3D RAGE LT PRO" }, { 0x4c50, 0x4c50, "3D RAGE LT PRO" }, { 0x4c54, 0x4c54, "3D RAGE LT" }, @@ -606,6 +612,27 @@ writeb (val, info->ati_regbase + regindex); } +static void aty_st_lcd(int index, u32 val, const struct fb_info_aty *info) +{ + unsigned long temp; + + /* write addr byte */ + temp = aty_ld_le32(LCD_INDEX, info); + aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, info); + /* write the register value */ + aty_st_le32(LCD_DATA, val, info); +} + +static u32 aty_ld_lcd(int index, const struct fb_info_aty *info) +{ + unsigned long temp; + + /* write addr byte */ + temp = aty_ld_le32(LCD_INDEX, info); + aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, info); + /* read the register value */ + return aty_ld_le32(LCD_DATA, info); +} /* * Generic Mach64 routines @@ -1031,7 +1058,7 @@ static struct fb_info_aty *fb_list = NULL; -static struct aty_cursor * __init +static struct aty_cursor * __init aty_init_cursor(struct fb_info_aty *fb) { struct aty_cursor *cursor; @@ -1267,7 +1294,7 @@ gModeReg = 0; devSetupRegA = 0; - + switch (bpp) { case 8: gModeReg = 0x83; @@ -1583,7 +1610,7 @@ /* Calculate the programming word */ MHz100 = 100000000 / period_in_ps; - + program_bits = -1; post_divider = 1; @@ -1691,7 +1718,7 @@ udelay(50000); /* delay for 50 (15) ms */ aty_st_8(CLOCK_CNTL + info->clk_wr_offset, ((pll->locationAddr & 0x0F) | CLOCK_STROBE), info); - + return; } @@ -1711,7 +1738,7 @@ mach64MinFreq = MIN_FREQ_2595; mach64MaxFreq = MAX_FREQ_2595; mach64RefFreq = REF_FREQ_2595; /* 14.32 MHz */ - + /* Calculate program word */ if (mhz100 == 0) program_bits = 0xFF; @@ -1843,7 +1870,7 @@ mach64MinFreq = MIN_FREQ_2595; mach64MaxFreq = MAX_FREQ_2595; mach64RefFreq = REF_FREQ_2595; /* 14.32 MHz */ - + /* Calculate program word */ if (mhz100 == 0) program_bits = 0xE0; @@ -1945,7 +1972,7 @@ mach64MinFreq = MIN_FREQ_2595; mach64MaxFreq = MAX_FREQ_2595; mach64RefFreq = REF_FREQ_2595; /* 14.32 MHz */ - + save_m = 0; save_n = 0; @@ -2359,7 +2386,7 @@ int accelmode; int muxmode; u8 tmp; - + accelmode = par->accel_flags; /* hack */ info->current_par = *par; @@ -2441,7 +2468,7 @@ break; } aty_st_le32(MEM_CNTL, i, info); - + } else { aty_set_pll_ct(info, &par->pll.ct); i = aty_ld_le32(MEM_CNTL, info) & 0xf00fffff; @@ -2618,7 +2645,6 @@ fb->consolecnt++; } #endif - MOD_INC_USE_COUNT; return(0); } @@ -2674,7 +2700,6 @@ fb->consolecnt--; } #endif - MOD_DEC_USE_COUNT; return(0); } @@ -2967,7 +2992,7 @@ #ifdef __sparc__ struct fbtype fbtyp; struct display *disp; - + if (con >= 0) disp = &fb_display[con]; else @@ -3080,7 +3105,7 @@ { unsigned long j, align; int max = -1; - + map_offset = off + size; for (i = 0; fb->mmap_map[i].size; i++) { if (fb->mmap_map[i].voff < off) @@ -3118,7 +3143,7 @@ } } } -#endif +#endif /* Each page, see which map applies */ for (page = 0; page < size; ) { @@ -3452,8 +3477,8 @@ if (default_mclk) mclk = default_mclk; - printk("%d%c %s, %s MHz XTAL, %d MHz PLL, %d Mhz MCLK\n", - info->total_vram == 0x80000 ? 512 : (info->total_vram >> 20), + printk("%d%c %s, %s MHz XTAL, %d MHz PLL, %d Mhz MCLK\n", + info->total_vram == 0x80000 ? 512 : (info->total_vram >> 20), info->total_vram == 0x80000 ? 'K' : 'M', ramname, xtal, pll, mclk); if (mclk < 44) @@ -3517,6 +3542,14 @@ info->fb_info.blank = &atyfbcon_blank; info->fb_info.flags = FBINFO_FLAG_DEFAULT; +#ifdef CONFIG_PPC + if (Gx == LI_CHIP_ID && machine_is_compatible("PowerBook1,1")) { + /* these bits let the 101 powerbook wake up from sleep -- paulus */ + aty_st_lcd(LCD_POWER_MANAGEMENT, aty_ld_lcd(LCD_POWER_MANAGEMENT, info) + | (USE_F32KHZ | TRISTATE_MEM_EN), info); + } +#endif /* CONFIG_PPC */ + #ifdef MODULE var = default_var; #else /* !MODULE */ @@ -3539,13 +3572,16 @@ } #endif if (default_vmode == VMODE_CHOOSE) { - if (Gx == LG_CHIP_ID) + if (Gx == LG_CHIP_ID || Gx == LI_CHIP_ID) /* G3 PowerBook with 1024x768 LCD */ default_vmode = VMODE_1024_768_60; - else { - sense = read_aty_sense(info); - default_vmode = mac_map_monitor_sense(sense); - } + else if (machine_is_compatible("iMac")) + default_vmode = VMODE_1024_768_75; + else + default_vmode = VMODE_640_480_67; + sense = read_aty_sense(info); + printk(KERN_INFO "atyfb: monitor sense=%x, mode %d\n", + sense, mac_map_monitor_sense(sense)); } if (default_vmode <= 0 || default_vmode > VMODE_MAX) default_vmode = VMODE_640_480_60; @@ -3608,7 +3644,7 @@ info->dispsw.set_font = atyfb_set_font; } } - + atyfb_set_var(&var, -1, &info->fb_info); if (register_framebuffer(&info->fb_info) < 0) @@ -3653,7 +3689,7 @@ break; if (i < 0) continue; - + info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC); if (!info) { printk("atyfb_init: can't alloc fb_info_aty\n"); @@ -3714,7 +3750,7 @@ io = (rp->flags & IORESOURCE_IO); size = rp->end - base + 1; - + pci_read_config_dword(pdev, breg, &pbase); if (io) @@ -4253,7 +4289,7 @@ if (Gx == GT_CHIP_ID || Gx == GU_CHIP_ID || Gx == GV_CHIP_ID || Gx == GW_CHIP_ID || Gx == GZ_CHIP_ID || Gx == LG_CHIP_ID || Gx == GB_CHIP_ID || Gx == GD_CHIP_ID || Gx == GI_CHIP_ID || - Gx == GP_CHIP_ID || Gx == GQ_CHIP_ID) + Gx == GP_CHIP_ID || Gx == GQ_CHIP_ID || Gx == LI_CHIP_ID) i |= 0x2; /*DAC_CNTL|0x2 turns off the extra brightness for gt*/ aty_st_8(DAC_CNTL, i, info); aty_st_8(DAC_MASK, 0xff, info); @@ -4702,6 +4738,124 @@ #endif #ifdef CONFIG_PMAC_PBOOK + +/* Power management routines. Those are used for PowerBook sleep. + * + * It appears that Rage LT and Rage LT Pro have different power + * management registers. There's is some confusion about which + * chipID is a Rage LT or LT pro :( + */ +static int +aty_power_mgmt_LT(int sleep, struct fb_info_aty *info) +{ + unsigned int pm; + int timeout; + + pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); + pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG; + aty_st_le32(POWER_MANAGEMENT_LG, pm, info); + pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); + + timeout = 200000; + if (sleep) { + /* Sleep */ + pm &= ~PWR_MGT_ON; + aty_st_le32(POWER_MANAGEMENT_LG, pm, info); + pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); + udelay(10); + pm &= ~(PWR_BLON | AUTO_PWR_UP); + pm |= SUSPEND_NOW; + aty_st_le32(POWER_MANAGEMENT_LG, pm, info); + pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); + udelay(10); + pm |= PWR_MGT_ON; + aty_st_le32(POWER_MANAGEMENT_LG, pm, info); + do { + pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); + udelay(10); + if ((--timeout) == 0) + break; + } while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND); + } else { + /* Wakeup */ + pm &= ~PWR_MGT_ON; + aty_st_le32(POWER_MANAGEMENT_LG, pm, info); + pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); + udelay(10); + pm |= (PWR_BLON | AUTO_PWR_UP); + pm &= ~SUSPEND_NOW; + aty_st_le32(POWER_MANAGEMENT_LG, pm, info); + pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); + udelay(10); + pm |= PWR_MGT_ON; + aty_st_le32(POWER_MANAGEMENT_LG, pm, info); + do { + pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); + udelay(10); + if ((--timeout) == 0) + break; + } while ((pm & PWR_MGT_STATUS_MASK) != 0); + } + mdelay(500); + + return timeout ? PBOOK_SLEEP_OK : PBOOK_SLEEP_REFUSE; +} + +static int +aty_power_mgmt_LTPro(int sleep, struct fb_info_aty *info) +{ + unsigned int pm; + int timeout; + + pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info); + pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG; + aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info); + pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info); + + timeout = 200; + if (sleep) { + /* Sleep */ + pm &= ~PWR_MGT_ON; + aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info); + pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info); + udelay(10); + pm &= ~(PWR_BLON | AUTO_PWR_UP); + pm |= SUSPEND_NOW; + aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info); + pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info); + udelay(10); + pm |= PWR_MGT_ON; + aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info); + do { + pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info); + udelay(1000); + if ((--timeout) == 0) + break; + } while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND); + } else { + /* Wakeup */ + pm &= ~PWR_MGT_ON; + aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info); + pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info); + udelay(10); + pm &= ~SUSPEND_NOW; + pm |= (PWR_BLON | AUTO_PWR_UP); + aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info); + pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info); + udelay(10); + pm |= PWR_MGT_ON; + aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info); + do { + pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info); + udelay(1000); + if ((--timeout) == 0) + break; + } while ((pm & PWR_MGT_STATUS_MASK) != 0); + } + + return timeout ? PBOOK_SLEEP_OK : PBOOK_SLEEP_REFUSE; +} + /* * Save the contents of the frame buffer when we go to sleep, * and restore it when we wake up again. @@ -4710,86 +4864,71 @@ aty_sleep_notify(struct pmu_sleep_notifier *self, int when) { struct fb_info_aty *info; - unsigned int pm; - + int result; + + result = PBOOK_SLEEP_OK; + for (info = first_display; info != NULL; info = info->next) { struct fb_fix_screeninfo fix; int nb; - + atyfb_get_fix(&fix, fg_console, (struct fb_info *)info); nb = fb_display[fg_console].var.yres * fix.line_length; switch (when) { + case PBOOK_SLEEP_REQUEST: + info->save_framebuffer = vmalloc(nb); + if (info->save_framebuffer == NULL) + return PBOOK_SLEEP_REFUSE; + break; + case PBOOK_SLEEP_REJECT: + if (info->save_framebuffer) { + vfree(info->save_framebuffer); + info->save_framebuffer = 0; + } + break; case PBOOK_SLEEP_NOW: + if (info->blitter_may_be_busy) + wait_for_idle(info); /* Stop accel engine (stop bus mastering) */ if (info->current_par.accel_flags & FB_ACCELF_TEXT) reset_engine(info); -#if 1 + /* Backup fb content */ - info->save_framebuffer = vmalloc(nb); if (info->save_framebuffer) - memcpy(info->save_framebuffer, + memcpy_fromio(info->save_framebuffer, (void *)info->frame_buffer, nb); -#endif - /* Blank display and LCD */ - atyfbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info); - - /* Set chip to "suspend" mode. Note: There's an HW bug in the - chip which prevents proper resync on wakeup with automatic - power management, we handle suspend manually using the - following (weird) sequence described by ATI. Note2: - We could enable this for all Rage LT Pro chip ids */ - if ((Gx == LG_CHIP_ID) || (Gx == LT_CHIP_ID) || (Gx == LP_CHIP_ID)) { - pm = aty_ld_le32(POWER_MANAGEMENT, info); - pm &= ~PWR_MGT_ON; - aty_st_le32(POWER_MANAGEMENT, pm, info); - pm = aty_ld_le32(POWER_MANAGEMENT, info); - pm &= ~(PWR_BLON | AUTO_PWR_UP); - pm |= SUSPEND_NOW; - aty_st_le32(POWER_MANAGEMENT, pm, info); - pm = aty_ld_le32(POWER_MANAGEMENT, info); - pm |= PWR_MGT_ON; - aty_st_le32(POWER_MANAGEMENT, pm, info); - do { - pm = aty_ld_le32(POWER_MANAGEMENT, info); - } while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND); - mdelay(500); - } + + /* Blank display and LCD */ + atyfbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info); + + /* Set chip to "suspend" mode */ + if (Gx == LG_CHIP_ID) + result = aty_power_mgmt_LT(1, info); + else + result = aty_power_mgmt_LTPro(1, info); break; case PBOOK_WAKE: /* Wakeup chip */ - if ((Gx == LG_CHIP_ID) || (Gx == LT_CHIP_ID) || (Gx == LP_CHIP_ID)) { - pm = aty_ld_le32(POWER_MANAGEMENT, info); - pm &= ~PWR_MGT_ON; - aty_st_le32(POWER_MANAGEMENT, pm, info); - pm = aty_ld_le32(POWER_MANAGEMENT, info); - pm |= (PWR_BLON | AUTO_PWR_UP); - pm &= ~SUSPEND_NOW; - aty_st_le32(POWER_MANAGEMENT, pm, info); - pm = aty_ld_le32(POWER_MANAGEMENT, info); - pm |= PWR_MGT_ON; - aty_st_le32(POWER_MANAGEMENT, pm, info); - do { - pm = aty_ld_le32(POWER_MANAGEMENT, info); - } while ((pm & PWR_MGT_STATUS_MASK) != 0); - mdelay(500); - } -#if 1 + if (Gx == LG_CHIP_ID) + result = aty_power_mgmt_LT(0, info); + else + result = aty_power_mgmt_LTPro(0, info); + /* Restore fb content */ if (info->save_framebuffer) { - memcpy((void *)info->frame_buffer, + memcpy_toio((void *)info->frame_buffer, info->save_framebuffer, nb); vfree(info->save_framebuffer); info->save_framebuffer = 0; } -#endif - /* Restore display */ + /* Restore display */ atyfb_set_par(&info->current_par, info); atyfbcon_blank(0, (struct fb_info *)info); break; } } - return PBOOK_SLEEP_OK; + return result; } #endif /* CONFIG_PMAC_PBOOK */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/chipsfb.c linux/drivers/video/chipsfb.c --- v2.4.0-test1/linux/drivers/video/chipsfb.c Thu Feb 10 17:11:15 2000 +++ linux/drivers/video/chipsfb.c Tue Jun 20 14:14:51 2000 @@ -115,8 +115,6 @@ int chips_init(void); void chips_of_init(struct device_node *dp); -static int chips_open(struct fb_info *info, int user); -static int chips_release(struct fb_info *info, int user); static int chips_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info); static int chips_get_var(struct fb_var_screeninfo *var, int con, @@ -133,15 +131,14 @@ u_long arg, int con, struct fb_info *info); static struct fb_ops chipsfb_ops = { - chips_open, - chips_release, - chips_get_fix, - chips_get_var, - chips_set_var, - chips_get_cmap, - chips_set_cmap, - chips_pan_display, - chips_ioctl + owner: THIS_MODULE, + fb_get_fix: chips_get_fix, + fb_get_var: chips_get_var, + fb_set_var: chips_set_var, + fb_get_cmap: chips_get_cmap, + fb_set_cmap: chips_set_cmap, + fb_pan_display: chips_pan_display, + fb_ioctl: chips_ioctl, }; static int chipsfb_getcolreg(u_int regno, u_int *red, u_int *green, @@ -150,19 +147,6 @@ u_int transp, struct fb_info *info); static void do_install_cmap(int con, struct fb_info *info); static void chips_set_bitdepth(struct fb_info_chips *p, struct display* disp, int con, int bpp); - - -static int chips_open(struct fb_info *info, int user) -{ - MOD_INC_USE_COUNT; - return 0; -} - -static int chips_release(struct fb_info *info, int user) -{ - MOD_DEC_USE_COUNT; - return 0; -} static int chips_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/clgenfb.c linux/drivers/video/clgenfb.c --- v2.4.0-test1/linux/drivers/video/clgenfb.c Thu May 11 15:30:08 2000 +++ linux/drivers/video/clgenfb.c Tue Jun 20 14:14:51 2000 @@ -31,10 +31,9 @@ * */ -#define CLGEN_VERSION "1.9.6" +#define CLGEN_VERSION "1.9.8" #include -#include #include #include #include @@ -481,18 +480,17 @@ #endif /* function table of the above functions */ -static struct fb_ops clgenfb_ops = -{ - clgenfb_open, - clgenfb_release, - fbgen_get_fix, /* using the generic functions */ - fbgen_get_var, /* makes things much easier... */ - fbgen_set_var, - fbgen_get_cmap, - fbgen_set_cmap, - fbgen_pan_display, - clgenfb_ioctl, - NULL +static struct fb_ops clgenfb_ops = { + owner: THIS_MODULE, + fb_open: clgenfb_open, + fb_release: clgenfb_release, + fb_get_fix: fbgen_get_fix, + fb_get_var: fbgen_get_var, + fb_set_var: fbgen_set_var, + fb_get_cmap: fbgen_get_cmap, + fb_set_cmap: fbgen_set_cmap, + fb_pan_display: fbgen_pan_display, + fb_ioctl: clgenfb_ioctl, }; /*--- Hardware Specific Routines -------------------------------------------*/ @@ -628,12 +626,6 @@ long *nom, long *den, long *div, long maxfreq); -#ifdef CONFIG_PCI -static struct pci_dev *clgen_pci_dev_get (clgen_board_t *btype); -static unsigned int clgen_get_memsize (caddr_t regbase); -static int clgen_pci_setup (struct clgenfb_info *fb_info, clgen_board_t *btype); -#endif /* CONFIG_PCI */ - #ifdef CLGEN_DEBUG static void clgen_dump (void); static void clgen_dbg_reg_dump (caddr_t regbase); @@ -650,7 +642,6 @@ /*--- Open /dev/fbx ---------------------------------------------------------*/ static int clgenfb_open (struct fb_info *info, int user) { - MOD_INC_USE_COUNT; if (opencount++ == 0) switch_monitor ((struct clgenfb_info *) info, 1); return 0; @@ -661,7 +652,6 @@ { if (--opencount == 0) switch_monitor ((struct clgenfb_info *) info, 0); - MOD_DEC_USE_COUNT; return 0; } @@ -2493,20 +2483,25 @@ static struct pci_dev * __init clgen_pci_dev_get (clgen_board_t *btype) { - struct pci_dev *pdev = NULL; + struct pci_dev *pdev; int i; DPRINTK ("ENTER\n"); - for (i = 0; i < arraysize(clgen_pci_probe_list) && !pdev; i++) - pdev = pci_find_device (PCI_VENDOR_ID_CIRRUS, - clgen_pci_probe_list[i].device, NULL); + for (i = 0; i < arraysize(clgen_pci_probe_list); i++) { + pdev = NULL; + while ((pdev = pci_find_device (PCI_VENDOR_ID_CIRRUS, + clgen_pci_probe_list[i].device, pdev)) != NULL) { + if (pci_enable_device(pdev) == 0) { + *btype = clgen_pci_probe_list[i - 1].btype; + DPRINTK ("EXIT, returning pdev=%p\n", pdev); + return pdev; + } + } + } - if (pdev) - *btype = clgen_pci_probe_list[i - 1].btype; - - DPRINTK ("EXIT, returning %p\n", pdev); - return pdev; + DPRINTK ("EXIT, returning NULL\n"); + return NULL; } @@ -2526,53 +2521,32 @@ /* This is a best-guess for now */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13) - - *display = pdev->base_address[0]; - if ((*display & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) { - *registers = *display; - *display = pdev->base_address[1]; - } else { - *registers = pdev->base_address[1]; - } - -#else - - if (pdev->resource[0].flags & IORESOURCE_IO) { - *display = pdev->resource[1].start; - *registers = pdev->resource[0].start; + if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) { + *display = pci_resource_start(pdev, 1); + *registers = pci_resource_start(pdev, 0); } else { - *display = pdev->resource[0].start; - *registers = pdev->resource[1].start; + *display = pci_resource_start(pdev, 0); + *registers = pci_resource_start(pdev, 1); } -#endif /* kernel older than 2.3.13 */ - assert (*display != 0); DPRINTK ("EXIT\n"); } - - -/* clgen_pci_unmap only used in modules */ -#ifdef MODULE -static void clgen_pci_unmap (struct clgenfb_info *info) +static void __exit clgen_pci_unmap (struct clgenfb_info *info) { iounmap (info->fbmem); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13) release_mem_region(info->fbmem_phys, info->size); #if 0 /* if system didn't claim this region, we would... */ release_mem_region(0xA0000, 65535); #endif + if (release_io_ports) release_region(0x3C0, 32); -#endif } -#endif /* MODULE */ static int __init clgen_pci_setup (struct clgenfb_info *info, @@ -2604,12 +2578,6 @@ pcibios_write_config_dword (0, pdev->devfn, PCI_BASE_ADDRESS_0, 0x00000000); #endif - pci_read_config_word (pdev, PCI_COMMAND, &tmp16); - if (!(tmp16 & (PCI_COMMAND_MEMORY | PCI_COMMAND_IO))) { - u16 tmp16_o = tmp16 | PCI_COMMAND_MEMORY | PCI_COMMAND_IO; - pci_write_config_word (pdev, PCI_COMMAND, tmp16_o); - } - #ifdef CONFIG_FB_OF /* Ok, so its an ugly hack, since we could have passed it down from * clgen_of_init() if we'd done it right. */ @@ -2649,8 +2617,6 @@ board_size = clgen_get_memsize (info->regs); } -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13) - if (!request_mem_region(board_addr, board_size, "clgenfb")) { pci_write_config_word (pdev, PCI_COMMAND, tmp16); printk(KERN_ERR "clgen: cannot reserve region 0x%lx, abort\n", @@ -2669,8 +2635,6 @@ if (request_region(0x3C0, 32, "clgenfb")) release_io_ports = 1; -#endif /* kernel > 2.3.13 */ - info->fbmem = ioremap (board_addr, board_size); info->fbmem_phys = board_addr; info->size = board_size; @@ -2721,14 +2685,10 @@ } - -/* clgen_zorro_unmap only used in modules */ -#ifdef MODULE -static void clgen_zorro_unmap (struct clgenfb_info *info) +static void __exit clgen_zorro_unmap (struct clgenfb_info *info) { -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13) release_mem_region(info->board_addr, info->board_size); -#endif + if (info->btype == BT_PICASSO4) { iounmap (info->board_addr); iounmap (info->fbmem_phys); @@ -2737,8 +2697,6 @@ iounmap (info->board_addr); } } -#endif /* MODULE */ - static int __init clgen_zorro_setup (struct clgenfb_info *info, @@ -2835,7 +2793,7 @@ } #else -#error Unsupported bus. Supported: PCI, Zorro +#error This driver requires Zorro or PCI bus. #endif /* !CONFIG_PCI, !CONFIG_ZORRO */ /* sanity checks */ diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/controlfb.c linux/drivers/video/controlfb.c --- v2.4.0-test1/linux/drivers/video/controlfb.c Thu Feb 10 17:11:15 2000 +++ linux/drivers/video/controlfb.c Tue Jun 20 14:14:51 2000 @@ -110,8 +110,6 @@ }; /******************** Prototypes for exported functions ********************/ -static int control_open(struct fb_info *info, int user); -static int control_release(struct fb_info *info, int user); static int control_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info); static int control_get_var(struct fb_var_screeninfo *var, int con, @@ -170,35 +168,20 @@ static int controlfb_updatevar(int con, struct fb_info *info); static struct fb_ops controlfb_ops = { - control_open, - control_release, - control_get_fix, - control_get_var, - control_set_var, - control_get_cmap, - control_set_cmap, - control_pan_display, - control_ioctl + owner: THIS_MODULE, + fb_get_fix: control_get_fix, + fb_get_var: control_get_var, + fb_set_var: control_set_var, + fb_get_cmap: control_get_cmap, + fb_set_cmap: control_set_cmap, + fb_pan_display: control_pan_display, + fb_ioctl: control_ioctl, }; /******************** The functions for controlfb_ops ********************/ -/********** Dummies for loading control as a module **********/ - -int control_open(struct fb_info *info, int user) -{ - MOD_INC_USE_COUNT; - return 0; -} - -static int control_release(struct fb_info *info, int user) -{ - MOD_DEC_USE_COUNT; - return 0; -} - #ifdef MODULE int init_module(void) { @@ -805,14 +788,10 @@ * bitfields, horizontal timing, vertical timing. */ /* swiped by jonh from atyfb.c */ - if (xres <= 512 && yres <= 384) - par->vmode = VMODE_512_384_60; /* 512x384, 60Hz */ - else if (xres <= 640 && yres <= 480) + if (xres <= 640 && yres <= 480) par->vmode = VMODE_640_480_67; /* 640x480, 67Hz */ else if (xres <= 640 && yres <= 870) par->vmode = VMODE_640_870_75P; /* 640x870, 75Hz (portrait) */ - else if (xres <= 768 && yres <= 576) - par->vmode = VMODE_768_576_50I; /* 768x576, 50Hz (PAL full frame) */ else if (xres <= 800 && yres <= 600) par->vmode = VMODE_800_600_75; /* 800x600, 75Hz */ else if (xres <= 832 && yres <= 624) diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/cyber2000fb.c linux/drivers/video/cyber2000fb.c --- v2.4.0-test1/linux/drivers/video/cyber2000fb.c Tue May 23 15:31:35 2000 +++ linux/drivers/video/cyber2000fb.c Tue Jun 20 14:14:51 2000 @@ -12,8 +12,13 @@ * especially for the colourmap stuff. Once fbcon has been fully migrated, * we can kill the last 5 references to cfb->currcon. * - * We also use the new hotplug PCI subsystem. This doesn't work fully in - * the case of multiple CyberPro cards yet however. + * We also use the new hotplug PCI subsystem. I'm not sure if there are any + * such cards, but I'm erring on the side of caution. We don't want to go + * pop just because someone does have one. + * + * Note that this doesn't work fully in the case of multiple CyberPro cards + * with grabbers. We currently can only attach to the first CyberPro card + * found. */ #include #include @@ -47,7 +52,7 @@ /* * This is the offset of the PCI space in physical memory */ -#ifdef CONFIG_ARCH_FOOTBRIDGE +#ifdef CONFIG_FOOTBRIDGE #define PCI_PHYS_OFFSET 0x80000000 #else #define PCI_PHYS_OFFSET 0x00000000 @@ -62,6 +67,8 @@ struct display_switch *dispsw; struct pci_dev *dev; signed int currcon; + int func_use_count; + u_long ref_ps; /* * Clock divisors @@ -72,7 +79,10 @@ u8 red, green, blue; } palette[NR_PALETTE]; + u_char mem_ctl1; u_char mem_ctl2; + u_char mclk_mult; + u_char mclk_div; }; /* -------------------- Hardware specific routines ------------------------- */ @@ -363,7 +373,7 @@ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18 }; -static void cyber2000fb_set_timing(struct par_info *hw) +static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw) { u_int i; @@ -416,11 +426,10 @@ cyber2000_attrw(0x14, 0x00); /* PLL registers */ - cyber2000_grphw(0xb0, hw->clock_mult); - cyber2000_grphw(0xb1, hw->clock_div); - - cyber2000_grphw(0xb2, 0xdb); - cyber2000_grphw(0xb3, 0x54); /* MCLK: 75MHz */ + cyber2000_grphw(DCLK_MULT, hw->clock_mult); + cyber2000_grphw(DCLK_DIV, hw->clock_div); + cyber2000_grphw(MCLK_MULT, cfb->mclk_mult); + cyber2000_grphw(MCLK_DIV, cfb->mclk_div); cyber2000_grphw(0x90, 0x01); cyber2000_grphw(0xb9, 0x80); cyber2000_grphw(0xb9, 0x00); @@ -438,7 +447,9 @@ cyber2000_grphw(0x15, ((hw->fetch >> 8) & 0x03) | ((hw->pitch >> 4) & 0x30)); cyber2000_grphw(0x77, hw->visualid); - cyber2000_grphw(0x33, 0x0c); + + /* make sure we stay in linear mode */ + cyber2000_grphw(0x33, 0x0d); /* * Set up accelerator registers @@ -468,21 +479,6 @@ } /* - * Open/Release the frame buffer device - */ -static int cyber2000fb_open(struct fb_info *info, int user) -{ - MOD_INC_USE_COUNT; - return 0; -} - -static int cyber2000fb_release(struct fb_info *info, int user) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -/* * Set the Colormap */ static int @@ -535,6 +531,7 @@ Htotal = var->xres + var->right_margin + var->hsync_len + var->left_margin; + if (Htotal > 2080) return -EINVAL; @@ -619,7 +616,7 @@ struct fb_var_screeninfo *var) { u_long pll_ps = var->pixclock; - const u_long ref_ps = 69842; + const u_long ref_ps = cfb->ref_ps; u_int div2, t_div1, best_div1, best_mult; int best_diff; @@ -641,7 +638,6 @@ if (div2 == 4) return -EINVAL; -#if 1 /* * Step 2: * Given pll_ps and ref_ps, find: @@ -689,94 +685,7 @@ if (diff == 0) break; } -#else - /* Note! This table will be killed shortly. --rmk */ - /* - * 1600x1200 1280x1024 1152x864 1024x768 800x600 640x480 - * 5051 5051 yes 76* - * 5814 5814 no 66 - * 6411 6411 no 60 - * 7408 7408 yes 75* - * 74* - * 7937 7937 yes 70* - * 9091 4545 yes 80* - * 75* 100* - * 9260 4630 yes 60* - * 10000 5000 no 70 90 - * 12500 6250 yes 47-lace* 60* - * 43-lace* - * 12699 6349 yes 75* - * 13334 6667 no 72 - * 70 - * 14815 7407 yes 100* - * 15385 7692 yes 47-lace* 60* - * 43-lace* - * 17656 4414 no 90 - * 20000 5000 no 72 - * 20203 5050 yes 75* - * 22272 5568 yes 43-lace* 70* 100* - * 25000 6250 yes 60* - * 25057 6264 no 90 - * 27778 6944 yes 56* - * 48-lace* - * 31747 7936 yes 75* - * 32052 8013 no 72 - * 39722 /6 6620 no - * 39722 /8 4965 yes 60* - */ - /* /1 /2 /4 /6 /8 */ - /* (2010) (2000) */ - if (pll_ps >= 4543 && pll_ps <= 4549) { - best_mult = 169; /*u220.0 110.0 54.99 36.663 27.497 */ - best_div1 = 11; /* 4546 9092 18184 27276 36367 */ - } else if (pll_ps >= 4596 && pll_ps <= 4602) { - best_mult = 243; /* 217.5 108.7 54.36 36.243 27.181 */ - best_div1 = 16; /* 4599 9197 18395 27592 36789 */ - } else if (pll_ps >= 4627 && pll_ps <= 4633) { - best_mult = 181; /*u216.0, 108.0, 54.00, 36.000 27.000 */ - best_div1 = 12; /* 4630 9260 18520 27780 37040 */ - } else if (pll_ps >= 4962 && pll_ps <= 4968) { - best_mult = 211; /*u201.0, 100.5, 50.25, 33.500 25.125 */ - best_div1 = 15; /* 4965 9930 19860 29790 39720 */ - } else if (pll_ps >= 5005 && pll_ps <= 5011) { - best_mult = 251; /* 200.0 99.8 49.92 33.280 24.960 */ - best_div1 = 18; /* 5008 10016 20032 30048 40064 */ - } else if (pll_ps >= 5047 && pll_ps <= 5053) { - best_mult = 83; /*u198.0, 99.0, 49.50, 33.000 24.750 */ - best_div1 = 6; /* 5050 10100 20200 30300 40400 */ - } else if (pll_ps >= 5490 && pll_ps <= 5496) { - best_mult = 89; /* 182.0 91.0 45.51 30.342 22.756 */ - best_div1 = 7; /* 5493 10986 21972 32958 43944 */ - } else if (pll_ps >= 5567 && pll_ps <= 5573) { - best_mult = 163; /*u179.5 89.8 44.88 29.921 22.441 */ - best_div1 = 13; /* 5570 11140 22281 33421 44562 */ - } else if (pll_ps >= 6246 && pll_ps <= 6252) { - best_mult = 190; /*u160.0, 80.0, 40.00, 26.671 20.003 */ - best_div1 = 17; /* 6249 12498 24996 37494 49992 */ - } else if (pll_ps >= 6346 && pll_ps <= 6352) { - best_mult = 209; /*u158.0, 79.0, 39.50, 26.333 19.750 */ - best_div1 = 19; /* 6349 12698 25396 38094 50792 */ - } else if (pll_ps >= 6648 && pll_ps <= 6655) { - best_mult = 210; /*u150.3 75.2 37.58 25.057 18.792 */ - best_div1 = 20; /* 6652 13303 26606 39909 53213 */ - } else if (pll_ps >= 6943 && pll_ps <= 6949) { - best_mult = 181; /*u144.0 72.0 36.00 23.996 17.997 */ - best_div1 = 18; /* 6946 13891 27782 41674 55565 */ - } else if (pll_ps >= 7404 && pll_ps <= 7410) { - best_mult = 198; /*u134.0 67.5 33.75 22.500 16.875 */ - best_div1 = 21; /* 7407 14815 29630 44445 59260 */ - } else if (pll_ps >= 7689 && pll_ps <= 7695) { - best_mult = 227; /*u130.0 65.0 32.50 21.667 16.251 */ - best_div1 = 25; /* 7692 15384 30768 46152 61536 */ - } else if (pll_ps >= 7808 && pll_ps <= 7814) { - best_mult = 152; /* 128.0 64.0 32.00 21.337 16.003 */ - best_div1 = 17; /* 7811 15623 31245 46868 62490 */ - } else if (pll_ps >= 7934 && pll_ps <= 7940) { - best_mult = 44; /*u126.0 63.0 31.498 20.999 15.749 */ - best_div1 = 5; /* 7937 15874 31748 47622 63494 */ - } else - return -EINVAL; -#endif + /* * Step 3: * combine values @@ -1018,7 +927,7 @@ cfb->fb.changevar(con); cyber2000fb_update_start(cfb, var); - cyber2000fb_set_timing(&hw); + cyber2000fb_set_timing(cfb, &hw); fb_set_cmap(&cfb->fb.cmap, 1, cyber2000_setcolreg, &cfb->fb); return 0; @@ -1180,10 +1089,8 @@ return 0; } -static struct fb_ops cyber2000fb_ops = -{ - fb_open: cyber2000fb_open, - fb_release: cyber2000fb_release, +static struct fb_ops cyber2000fb_ops = { + owner: THIS_MODULE, fb_set_var: cyber2000fb_set_var, fb_set_cmap: cyber2000fb_set_cmap, fb_pan_display: cyber2000fb_pan_display, @@ -1195,26 +1102,32 @@ /* * Enable access to the extended registers - * Bug: this should track the usage of these registers */ -static void cyber2000fb_enable_extregs(void) +static void cyber2000fb_enable_extregs(struct cfb_info *cfb) { - int old; + cfb->func_use_count += 1; - old = cyber2000_grphr(FUNC_CTL); - cyber2000_grphw(FUNC_CTL, old | FUNC_CTL_EXTREGENBL); + if (cfb->func_use_count == 1) { + int old; + + old = cyber2000_grphr(FUNC_CTL); + cyber2000_grphw(FUNC_CTL, old | FUNC_CTL_EXTREGENBL); + } } /* * Disable access to the extended registers - * Bug: this should track the usage of these registers */ -static void cyber2000fb_disable_extregs(void) +static void cyber2000fb_disable_extregs(struct cfb_info *cfb) { - int old; + if (cfb->func_use_count == 1) { + int old; - old = cyber2000_grphr(FUNC_CTL); - cyber2000_grphw(FUNC_CTL, old & ~FUNC_CTL_EXTREGENBL); + old = cyber2000_grphr(FUNC_CTL); + cyber2000_grphw(FUNC_CTL, old & ~FUNC_CTL_EXTREGENBL); + } + + cfb->func_use_count -= 1; } /* @@ -1227,7 +1140,7 @@ /* * Attach a capture/tv driver to the core CyberX0X0 driver. */ -int cyber2000fb_attach(struct cyberpro_info *info) +int cyber2000fb_attach(struct cyberpro_info *info, int idx) { if (int_cfb_info != NULL) { info->dev = int_cfb_info->dev; @@ -1236,6 +1149,7 @@ info->fb_size = int_cfb_info->fb.fix.smem_len; info->enable_extregs = cyber2000fb_enable_extregs; info->disable_extregs = cyber2000fb_disable_extregs; + info->info = int_cfb_info; strncpy(info->dev_name, int_cfb_info->fb.fix.id, sizeof(info->dev_name)); @@ -1248,7 +1162,7 @@ /* * Detach a capture/tv driver from the core CyberX0X0 driver. */ -void cyber2000fb_detach(void) +void cyber2000fb_detach(int idx) { MOD_DEC_USE_COUNT; } @@ -1281,8 +1195,8 @@ } static char igs_regs[] __devinitdata = { - 0x10, 0x10, 0x12, 0x00, 0x13, 0x00, - 0x31, 0x00, 0x32, 0x00, 0x33, 0x01, + 0x12, 0x00, 0x13, 0x00, + 0x31, 0x00, 0x32, 0x00, 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x01, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, @@ -1290,22 +1204,129 @@ 0x74, 0x0b, 0x75, 0x17, 0x76, 0x00, 0x7a, 0xc8 }; -static inline void cyberpro_init_hw(struct cfb_info *cfb) +/* + * We need to wake up the CyberPro, and make sure its in linear memory + * mode. Unfortunately, this is specific to the platform and card that + * we are running on. + * + * On x86 and ARM, should we be initialising the CyberPro first via the + * IO registers, and then the MMIO registers to catch all cases? Can we + * end up in the situation where the chip is in MMIO mode, but not awake + * on an x86 system? + * + * Note that on the NetWinder, the firmware automatically detects the + * type, width and size, and leaves this in extended registers 0x71 and + * 0x72 for us. + */ +static inline void cyberpro_init_hw(struct cfb_info *cfb, int at_boot) { int i; /* - * Wake up the CyberPro + * Wake up the CyberPro. + */ +#ifdef __sparc__ +#ifdef __sparc_v9__ +#error "You loose, consult DaveM." +#else + /* + * SPARC does not have an "outb" instruction, so we generate + * I/O cycles storing into a reserved memory space at + * physical address 0x3000000 + */ + { + unsigned char *iop; + + iop = ioremap(0x3000000, 0x5000); + if (iop == NULL) { + prom_printf("iga5000: cannot map I/O\n"); + return -ENOMEM; + } + + writeb(0x18, iop + 0x46e8); + writeb(0x01, iop + 0x102); + writeb(0x08, iop + 0x46e8); + writeb(0x33, iop + 0x3ce); + writeb(0x01, iop + 0x3cf); + + iounmap((void *)iop); + } +#endif + + if (at_boot) { + /* + * Use mclk from BIOS. Only read this if we're + * initialising this card for the first time. + * FIXME: what about hotplug? + */ + cfb->mclk_mult = cyber2000_grphr(MCLK_MULT); + cfb->mclk_div = cyber2000_grphr(MCLK_DIV); + } +#endif +#ifdef __i386__ + /* + * x86 is simple, we just do regular outb's instead of + * cyber2000_outb. */ + outb(0x18, 0x46e8); + outb(0x01, 0x102); + outb(0x08, 0x46e8); + outb(0x33, 0x3ce); + outb(0x01, 0x3cf); + + if (at_boot) { + /* + * Use mclk from BIOS. Only read this if we're + * initialising this card for the first time. + * FIXME: what about hotplug? + */ + cfb->mclk_mult = cyber2000_grphr(MCLK_MULT); + cfb->mclk_div = cyber2000_grphr(MCLK_DIV); + } +#endif +#ifdef __arm__ cyber2000_outb(0x18, 0x46e8); cyber2000_outb(0x01, 0x102); cyber2000_outb(0x08, 0x46e8); + cyber2000_outb(0x33, 0x3ce); + cyber2000_outb(0x01, 0x3cf); + + /* + * MCLK on the NetWinder is fixed at 75MHz + */ + cfb->mclk_mult = 0xdb; + cfb->mclk_div = 0x54; +#endif /* * Initialise the CyberPro */ for (i = 0; i < sizeof(igs_regs); i += 2) cyber2000_grphw(igs_regs[i], igs_regs[i+1]); + + if (at_boot) { + /* + * get the video RAM size and width from the VGA register. + * This should have been already initialised by the BIOS, + * but if it's garbage, claim default 1MB VRAM (woody) + */ + cfb->mem_ctl1 = cyber2000_grphr(MEM_CTL1); + cfb->mem_ctl2 = cyber2000_grphr(MEM_CTL2); + } else { + /* + * Reprogram the MEM_CTL1 and MEM_CTL2 registers + */ + cyber2000_grphw(MEM_CTL1, cfb->mem_ctl1); + cyber2000_grphw(MEM_CTL2, cfb->mem_ctl2); + } + + /* + * Ensure thatwe are using the correct PLL. + * (CyberPro 5000's may be programmed to use + * an additional set of PLLs. + */ + cyber2000_outb(0xba, 0x3ce); + cyber2000_outb(cyber2000_inb(0x3cf) & 0x80, 0x3cf); } static struct cfb_info * __devinit @@ -1323,6 +1344,7 @@ cfb->currcon = -1; cfb->dev = dev; + cfb->ref_ps = 69842; cfb->divisors[0] = 1; cfb->divisors[1] = 2; cfb->divisors[2] = 4; @@ -1466,13 +1488,6 @@ u_long smem_size; int err; - /* - * We can only accept one CyberPro device at the moment. We can - * kill this once int_cfb_info and CyberRegs have been killed. - */ - if (int_cfb_info) - return -EBUSY; - err = pci_enable_device(dev); if (err) return err; @@ -1486,14 +1501,7 @@ if (err) goto failed; - cyberpro_init_hw(cfb); - - /* - * get the video RAM size and width from the VGA register. - * This should have been already initialised by the BIOS, - * but if it's garbage, claim default 1MB VRAM (woody) - */ - cfb->mem_ctl2 = cyber2000_grphr(MEM_CTL2); + cyberpro_init_hw(cfb, 1); switch (cfb->mem_ctl2 & MEM_CTL2_SIZE_MASK) { case MEM_CTL2_SIZE_4MB: smem_size = 0x00400000; break; @@ -1519,6 +1527,12 @@ cyber2000fb_set_var(&cfb->fb.var, -1, &cfb->fb); + /* + * Calculate the hsync and vsync frequencies. Note that + * we split the 1e12 constant up so that we can preserve + * the precision and fit the results into 32-bit registers. + * (1953125000 * 512 = 1e12) + */ h_sync = 1953125000 / cfb->fb.var.pixclock; h_sync = h_sync * 512 / (cfb->fb.var.xres + cfb->fb.var.left_margin + cfb->fb.var.right_margin + cfb->fb.var.hsync_len); @@ -1538,7 +1552,8 @@ * Our driver data */ dev->driver_data = cfb; - int_cfb_info = cfb; + if (int_cfb_info == NULL) + int_cfb_info = cfb; return 0; @@ -1555,7 +1570,15 @@ struct cfb_info *cfb = (struct cfb_info *)dev->driver_data; if (cfb) { - unregister_framebuffer(&cfb->fb); + /* + * If unregister_framebuffer fails, then + * we will be leaving hooks that could cause + * oopsen laying around. + */ + if (unregister_framebuffer(&cfb->fb)) + printk(KERN_WARNING "%s: danger Will Robinson, " + "danger danger! Oopsen imminent!\n", + cfb->fb.fix.id); cyberpro_unmap_smem(cfb); cyberpro_unmap_mmio(cfb); cyberpro_free_fb_info(cfb); @@ -1565,7 +1588,8 @@ * valid. */ dev->driver_data = NULL; - int_cfb_info = NULL; + if (cfb == int_cfb_info) + int_cfb_info = NULL; } } @@ -1581,12 +1605,7 @@ struct cfb_info *cfb = (struct cfb_info *)dev->driver_data; if (cfb) { - cyberpro_init_hw(cfb); - - /* - * Reprogram the MEM_CTL2 register - */ - cyber2000_grphw(MEM_CTL2, cfb->mem_ctl2); + cyberpro_init_hw(cfb, 0); /* * Restore the old video mode and the palette. @@ -1620,7 +1639,8 @@ /* * I don't think we can use the "module_init" stuff here because - * the fbcon stuff may not be initialised yet. + * the fbcon stuff may not be initialised yet. Hence the #ifdef + * around module_init. */ int __init cyber2000fb_init(void) { @@ -1636,5 +1656,3 @@ module_init(cyber2000fb_init); #endif module_exit(cyberpro_exit); - -MODULE_DEVICE_TABLE(pci, cyberpro_pci_table); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/cyber2000fb.h linux/drivers/video/cyber2000fb.h --- v2.4.0-test1/linux/drivers/video/cyber2000fb.h Tue May 23 15:31:35 2000 +++ linux/drivers/video/cyber2000fb.h Tue Jun 20 14:14:51 2000 @@ -127,6 +127,8 @@ #define CAP_DDA_Y_INIT 0x6c #define CAP_DDA_Y_INC 0x6e +#define MEM_CTL1 0x71 + #define MEM_CTL2 0x72 #define MEM_CTL2_SIZE_2MB 0x01 #define MEM_CTL2_SIZE_4MB 0x02 @@ -156,6 +158,11 @@ #define CAP_MODE1_MIRRORY 0x40 /* mirror vertically */ #define CAP_MODE1_MIRRORX 0x80 /* mirror horizontally */ +#define DCLK_MULT 0xb0 +#define DCLK_DIV 0xb1 +#define MCLK_MULT 0xb2 +#define MCLK_DIV 0xb3 + #define CAP_MODE2 0xa5 #define Y_TV_CTL 0xae @@ -281,6 +288,11 @@ #define CO_REG_DEST_PTR 0xbf178 #define CO_REG_DEST_WIDTH 0xbf218 +/* + * Private structure + */ +struct cfb_info; + struct cyberpro_info { struct pci_dev *dev; unsigned char *regs; @@ -289,16 +301,27 @@ unsigned int fb_size; /* - * Use these to enable the BM or TV registers. + * The following is a pointer to be passed into the + * functions below. The modules outside the main + * cyber2000fb.c driver have no knowledge as to what + * is within this structure. + */ + struct cfb_info *info; + + /* + * Use these to enable the BM or TV registers. In an SMP + * environment, these two function pointers should only be + * called from the module_init() or module_exit() + * functions. */ - void (*enable_extregs)(void); - void (*disable_extregs)(void); + void (*enable_extregs)(struct cfb_info *); + void (*disable_extregs)(struct cfb_info *); }; /* * Note! Writing to the Cyber20x0 registers from an interrupt * routine is definitely a bad idea atm. */ -int cyber2000fb_attach(struct cyberpro_info *info); -void cyber2000fb_detach(void); +int cyber2000fb_attach(struct cyberpro_info *info, int idx); +void cyber2000fb_detach(int idx); diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/cyberfb.c linux/drivers/video/cyberfb.c --- v2.4.0-test1/linux/drivers/video/cyberfb.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/video/cyberfb.c Tue Jun 20 14:14:51 2000 @@ -241,8 +241,6 @@ int cyberfb_setup(char *options); -static int cyberfb_open(struct fb_info *info, int user); -static int cyberfb_release(struct fb_info *info, int user); static int cyberfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info); static int cyberfb_get_var(struct fb_var_screeninfo *var, int con, @@ -827,28 +825,6 @@ DPRINTK("EXIT\n"); } - -/* - * Open/Release the frame buffer device - */ - -static int cyberfb_open(struct fb_info *info, int user) -{ - /* - * Nothing, only a usage count for the moment - */ - - MOD_INC_USE_COUNT; - return(0); -} - -static int cyberfb_release(struct fb_info *info, int user) -{ - MOD_DEC_USE_COUNT; - return(0); -} - - /* * Get the Fixed Part of the Display */ @@ -1056,11 +1032,15 @@ static struct fb_ops cyberfb_ops = { - cyberfb_open, cyberfb_release, cyberfb_get_fix, cyberfb_get_var, - cyberfb_set_var, cyberfb_get_cmap, cyberfb_set_cmap, - cyberfb_pan_display, cyberfb_ioctl + owner: THIS_MODULE, + fb_get_fix: cyberfb_get_fix, + fb_get_var: cyberfb_get_var, + fb_set_var: cyberfb_set_var, + fb_get_cmap: cyberfb_get_cmap, + fb_set_cmap: cyberfb_set_cmap, + fb_pan_display: cyberfb_pan_display, + fb_ioctl: cyberfb_ioctl, }; - int __init cyberfb_setup(char *options) { diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/dn_cfb4.c linux/drivers/video/dn_cfb4.c --- v2.4.0-test1/linux/drivers/video/dn_cfb4.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/video/dn_cfb4.c Tue Jun 20 14:14:51 2000 @@ -111,8 +111,6 @@ /* frame buffer operations */ -static int dn_fb_open(struct fb_info *info,int user); -static int dn_fb_release(struct fb_info *info,int user); static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info); static int dn_fb_get_var(struct fb_var_screeninfo *var, int con, @@ -136,9 +134,15 @@ static struct display disp[MAX_NR_CONSOLES]; static struct fb_info fb_info; -static struct fb_ops dn_fb_ops = { - dn_fb_open,dn_fb_release, dn_fb_get_fix, dn_fb_get_var, dn_fb_set_var, - dn_fb_get_cmap, dn_fb_set_cmap, dn_fb_pan_display, dn_fb_ioctl +static struct fb_ops dn_fb_ops = { + owner: THIS_MODULE, + fb_get_fix: dn_fb_get_fix, + fb_get_var: dn_fb_get_var, + fb_set_var: dn_fb_set_var, + fb_get_cmap: dn_fb_get_cmap, + fb_set_cmap: dn_fb_set_cmap, + fb_pan_display: dn_fb_pan_display, + fb_ioctl: dn_fb_ioctl, }; static int currcon=0; @@ -156,22 +160,6 @@ #define USE_DN_ACCEL static struct display_switch dispsw_apollofb; - -static int dn_fb_open(struct fb_info *info,int user) -{ - /* - * Nothing, only a usage count for the moment - */ - - MOD_INC_USE_COUNT; - return(0); -} - -static int dn_fb_release(struct fb_info *info,int user) -{ - MOD_DEC_USE_COUNT; - return(0); -} static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) { diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/dn_cfb8.c linux/drivers/video/dn_cfb8.c --- v2.4.0-test1/linux/drivers/video/dn_cfb8.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/video/dn_cfb8.c Tue Jun 20 14:14:51 2000 @@ -112,8 +112,6 @@ /* frame buffer operations */ -static int dn_fb_open(struct fb_info *info); -static int dn_fb_release(struct fb_info *info); static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info); static int dn_fb_get_var(struct fb_var_screeninfo *var, int con, @@ -137,9 +135,15 @@ static struct display disp[MAX_NR_CONSOLES]; static struct fb_info fb_info; -static struct fb_ops dn_fb_ops = { - dn_fb_open,dn_fb_release, dn_fb_get_fix, dn_fb_get_var, dn_fb_set_var, - dn_fb_get_cmap, dn_fb_set_cmap, dn_fb_pan_display, dn_fb_ioctl +static struct fb_ops dn_fb_ops = { + owner: THIS_MODULE, + fb_get_fix: dn_fb_get_fix, + fb_get_var: dn_fb_get_var, + fb_set_var: dn_fb_set_var, + fb_get_cmap: dn_fb_get_cmap, + fb_set_cmap: dn_fb_set_cmap, + fb_pan_display: dn_fb_pan_display, + fb_ioctl: dn_fb_ioctl, }; static int currcon=0; @@ -157,22 +161,6 @@ #define USE_DN_ACCEL static struct display_switch dispsw_apollofb; - -static int dn_fb_open(struct fb_info *info) -{ - /* - * Nothing, only a usage count for the moment - */ - - MOD_INC_USE_COUNT; - return(0); -} - -static int dn_fb_release(struct fb_info *info) -{ - MOD_DEC_USE_COUNT; - return(0); -} static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) { diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/dnfb.c linux/drivers/video/dnfb.c --- v2.4.0-test1/linux/drivers/video/dnfb.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/video/dnfb.c Tue Jun 20 14:14:51 2000 @@ -117,8 +117,6 @@ /* frame buffer operations */ -static int dn_fb_open(struct fb_info *info,int user); -static int dn_fb_release(struct fb_info *info,int user); static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info); static int dn_fb_get_var(struct fb_var_screeninfo *var, int con, @@ -142,9 +140,15 @@ static struct display disp[MAX_NR_CONSOLES]; static struct fb_info fb_info; -static struct fb_ops dn_fb_ops = { - dn_fb_open,dn_fb_release, dn_fb_get_fix, dn_fb_get_var, dn_fb_set_var, - dn_fb_get_cmap, dn_fb_set_cmap, dn_fb_pan_display, dn_fb_ioctl +static struct fb_ops dn_fb_ops = { + owner: THIS_MODULE, + fb_get_fix: dn_fb_get_fix, + fb_get_var: dn_fb_get_var, + fb_set_var: dn_fb_set_var, + fb_get_cmap: dn_fb_get_cmap, + fb_set_cmap: dn_fb_set_cmap, + fb_pan_display: dn_fb_pan_display, + fb_ioctl: dn_fb_ioctl, }; static int currcon=0; @@ -162,22 +166,6 @@ #define USE_DN_ACCEL static struct display_switch dispsw_apollofb; - -static int dn_fb_open(struct fb_info *info,int user) -{ - /* - * Nothing, only a usage count for the moment - */ - - MOD_INC_USE_COUNT; - return(0); -} - -static int dn_fb_release(struct fb_info *info,int user) -{ - MOD_DEC_USE_COUNT; - return(0); -} static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) { diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/fbcon.c linux/drivers/video/fbcon.c --- v2.4.0-test1/linux/drivers/video/fbcon.c Thu May 11 15:30:08 2000 +++ linux/drivers/video/fbcon.c Tue Jun 20 14:28:05 2000 @@ -289,9 +289,17 @@ if (newidx != con2fb_map[unit]) { oldfb = registered_fb[oldidx]; newfb = registered_fb[newidx]; - if (newfb->fbops->fb_open(newfb,0)) - return; - oldfb->fbops->fb_release(oldfb,0); + if (newfb->fbops->owner) + __MOD_INC_USE_COUNT(newfb->fbops->owner); + if (newfb->fbops->fb_open && newfb->fbops->fb_open(newfb,0)) { + if (newfb->fbops->owner) + __MOD_DEC_USE_COUNT(newfb->fbops->owner); + return; + } + if (oldfb->fbops->fb_release) + oldfb->fbops->fb_release(oldfb,0); + if (oldfb->fbops->owner) + __MOD_DEC_USE_COUNT(oldfb->fbops->owner); conp = fb_display[unit].conp; fontdata = fb_display[unit].fontdata; fontwidth = fb_display[unit]._fontwidth; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c --- v2.4.0-test1/linux/drivers/video/fbmem.c Mon Jun 19 16:32:00 2000 +++ linux/drivers/video/fbmem.c Wed Jun 21 22:31:02 2000 @@ -61,6 +61,8 @@ extern int retz3fb_setup(char*); extern int clgenfb_init(void); extern int clgenfb_setup(char*); +extern int hitfb_init(void); +extern int hitfb_setup(char*); extern int vfb_init(void); extern int vfb_setup(char*); extern int offb_init(void); @@ -162,6 +164,9 @@ #ifdef CONFIG_FB_ATY { "atyfb", atyfb_init, atyfb_setup }, #endif +#ifdef CONFIG_FB_MATROX + { "matrox", matroxfb_init, matroxfb_setup }, +#endif #ifdef CONFIG_FB_ATY128 { "aty128fb", aty128fb_init, aty128fb_setup }, #endif @@ -205,9 +210,6 @@ #ifdef CONFIG_FB_HGA { "hga", hgafb_init, hgafb_setup }, #endif -#ifdef CONFIG_FB_MATROX - { "matrox", matroxfb_init, matroxfb_setup }, -#endif #ifdef CONFIG_FB_HP300 { "hpfb", hpfb_init, hpfb_setup }, #endif @@ -229,6 +231,9 @@ #ifdef CONFIG_FB_SUN3 { "sun3", sun3fb_init, sun3fb_setup }, #endif +#ifdef CONFIG_FB_HIT + { "hitfb", hitfb_init, hitfb_setup }, +#endif #ifdef CONFIG_GSP_RESOLVER /* Not a real frame buffer device... */ { "resolver", NULL, resolver_video_setup }, @@ -528,6 +533,8 @@ */ pgprot_val(vma->vm_page_prot) &= ~(PTE_CACHEABLE | PTE_BUFFERABLE); #endif +#elif defined(__sh__) + pgprot_val(vma->vm_page_prot) &= ~_PAGE_CACHABLE; #else #warning What do we have to do here?? #endif @@ -562,6 +569,7 @@ { int fbidx = GET_FB_IDX(inode->i_rdev); struct fb_info *info; + int res = 0; #ifdef CONFIG_KMOD if (!(info = registered_fb[fbidx])) @@ -569,7 +577,14 @@ #endif /* CONFIG_KMOD */ if (!(info = registered_fb[fbidx])) return -ENODEV; - return info->fbops->fb_open(info,1); + if (info->fbops->owner) + __MOD_INC_USE_COUNT(info->fbops->owner); + if (info->fbops->fb_open) { + res = info->fbops->fb_open(info,1); + if (res && info->fbops->owner) + __MOD_DEC_USE_COUNT(info->fbops->owner); + } + return res; } static int @@ -578,11 +593,15 @@ int fbidx = GET_FB_IDX(inode->i_rdev); struct fb_info *info = registered_fb[fbidx]; - info->fbops->fb_release(info,1); + if (info->fbops->fb_release) + info->fbops->fb_release(info,1); + if (info->fbops->owner) + __MOD_DEC_USE_COUNT(info->fbops->owner); return 0; } static struct file_operations fb_fops = { + owner: THIS_MODULE, read: fb_read, write: fb_write, ioctl: fb_ioctl, @@ -610,13 +629,22 @@ fb_info->node = MKDEV(FB_MAJOR, i); registered_fb[i] = fb_info; if (!fb_ever_opened[i]) { + struct module *owner = fb_info->fbops->owner; /* * We assume initial frame buffer devices can be opened this * many times */ for (j = 0; j < MAX_NR_CONSOLES; j++) - if (con2fb_map[j] == i) - fb_info->fbops->fb_open(fb_info,0); + if (con2fb_map[j] == i) { + if (owner) + __MOD_INC_USE_COUNT(owner); + if (!fb_info->fbops->fb_open) + continue; + if (!fb_info->fbops->fb_open(fb_info,0)) + continue; + if (owner) + __MOD_DEC_USE_COUNT(owner); + } fb_ever_opened[i] = 1; } @@ -626,8 +654,8 @@ } sprintf (name_buf, "%d", i); fb_info->devfs_handle = - devfs_register (devfs_handle, name_buf, 0, DEVFS_FL_NONE, - FB_MAJOR, i, S_IFCHR | S_IRUGO | S_IWUGO, 0, 0, + devfs_register (devfs_handle, name_buf, DEVFS_FL_DEFAULT, + FB_MAJOR, i, S_IFCHR | S_IRUGO | S_IWUGO, &fb_fops, NULL); return 0; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/fm2fb.c linux/drivers/video/fm2fb.c --- v2.4.0-test1/linux/drivers/video/fm2fb.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/video/fm2fb.c Tue Jun 20 14:14:51 2000 @@ -183,8 +183,6 @@ * Interface used by the world */ -static int fm2fb_open(struct fb_info *info, int user); -static int fm2fb_release(struct fb_info *info, int user); static int fm2fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info); static int fm2fb_get_var(struct fb_var_screeninfo *var, int con, @@ -223,31 +221,15 @@ static struct fb_ops fm2fb_ops = { - fm2fb_open, fm2fb_release, fm2fb_get_fix, fm2fb_get_var, fm2fb_set_var, - fm2fb_get_cmap, fm2fb_set_cmap, fm2fb_pan_display, fm2fb_ioctl + owner: THIS_MODULE, + fb_get_fix: fm2fb_get_fix, + fb_get_var: fm2fb_get_var, + fb_set_var: fm2fb_set_var, + fb_get_cmap: fm2fb_get_cmap, + fb_set_cmap: fm2fb_set_cmap, + fb_pan_display: fm2fb_pan_display, + fb_ioctl: fm2fb_ioctl, }; - - - /* - * Open/Release the frame buffer device - */ - -static int fm2fb_open(struct fb_info *info, int user) -{ - /* - * Nothing, only a usage count for the moment - */ - - MOD_INC_USE_COUNT; - return(0); -} - -static int fm2fb_release(struct fb_info *info, int user) -{ - MOD_DEC_USE_COUNT; - return(0); -} - /* * Get the Fixed Part of the Display diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/g364fb.c linux/drivers/video/g364fb.c --- v2.4.0-test1/linux/drivers/video/g364fb.c Thu Aug 26 13:05:40 1999 +++ linux/drivers/video/g364fb.c Tue Jun 20 14:14:51 2000 @@ -91,8 +91,6 @@ /* * Interface used by the world */ -static int g364fb_open(struct fb_info *info, int user); -static int g364fb_release(struct fb_info *info, int user); static int g364fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info); static int g364fb_get_var(struct fb_var_screeninfo *var, int con, @@ -129,8 +127,14 @@ static struct fb_ops g364fb_ops = { - g364fb_open, g364fb_release, g364fb_get_fix, g364fb_get_var, g364fb_set_var, - g364fb_get_cmap, g364fb_set_cmap, g364fb_pan_display, g364fb_ioctl + owner: THIS_MODULE, + fb_get_fix: g364fb_get_fix, + fb_get_var: g364fb_get_var, + fb_set_var: g364fb_set_var, + fb_get_cmap: g364fb_get_cmap, + fb_set_cmap: g364fb_set_cmap, + fb_pan_display: g364fb_pan_display, + fb_ioctl: g364fb_ioctl, }; @@ -155,26 +159,6 @@ fbcon_cfb8_putcs, fbcon_cfb8_revc, fbcon_g364fb_cursor, NULL, fbcon_cfb8_clear_margins, FONTWIDTH(8) }; - - -/* - * Open/Release the frame buffer device - */ -static int g364fb_open(struct fb_info *info, int user) -{ - /* - * Nothing, only a usage count for the moment - */ - MOD_INC_USE_COUNT; - return(0); -} - -static int g364fb_release(struct fb_info *info, int user) -{ - MOD_DEC_USE_COUNT; - return(0); -} - /* * Get the Fixed Part of the Display diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/hgafb.c linux/drivers/video/hgafb.c --- v2.4.0-test1/linux/drivers/video/hgafb.c Tue Mar 14 19:10:40 2000 +++ linux/drivers/video/hgafb.c Tue Jun 20 14:14:51 2000 @@ -377,25 +377,6 @@ * * ------------------------------------------------------------------------- */ - - /* - * Open/Release the frame buffer device - */ - -static int hgafb_open(struct fb_info *info, int user) -{ - /* Nothing, only a usage count for the moment */ - MOD_INC_USE_COUNT; - return 0; -} - -static int hgafb_release(struct fb_info *info, int user) -{ - MOD_DEC_USE_COUNT; - return 0; -} - - /* * Get the Fixed Part of the Display */ @@ -549,8 +530,14 @@ static struct fb_ops hgafb_ops = { - hgafb_open, hgafb_release, hga_get_fix, hga_get_var, hga_set_var, - hga_get_cmap, hga_set_cmap, hga_pan_display, hga_ioctl + owner: THIS_MODULE, + fb_get_fix: hga_get_fix, + fb_get_var: hga_get_var, + fb_set_var: hga_set_var, + fb_get_cmap: hga_get_cmap, + fb_set_cmap: hga_set_cmap, + fb_pan_display: hga_pan_display, + fb_ioctl: hga_ioctl, }; diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/hitfb.c linux/drivers/video/hitfb.c --- v2.4.0-test1/linux/drivers/video/hitfb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/hitfb.c Tue Jun 20 14:14:51 2000 @@ -0,0 +1,369 @@ +/* + * $Id: hitfb.c,v 1.1 2000/06/10 21:45:40 yaegashi Exp $ + * linux/drivers/video/hitfb.c -- Hitachi LCD frame buffer device + * (C) 1999 Mihai Spatar + * (C) 2000 YAEGASHI Takeshi + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include