]> git.neil.brown.name Git - history.git/commitdiff
Import 2.4.0-test2pre1 2.4.0-test2pre1
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:35:19 +0000 (15:35 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:35:19 +0000 (15:35 -0500)
312 files changed:
CREDITS
Documentation/Changes
Documentation/DocBook/Makefile
Documentation/DocBook/kernel-api.tmpl
Documentation/DocBook/kernel-locking.tmpl
Documentation/DocBook/mousedrivers.tmpl [new file with mode: 0644]
Documentation/DocBook/via-audio.tmpl [new file with mode: 0644]
Documentation/filesystems/bfs.txt
Documentation/floppy.txt
Documentation/ioctl-number.txt
Documentation/kernel-doc-nano-HOWTO.txt
Documentation/kernel-parameters.txt
Documentation/networking/tlan.txt
Documentation/serial-console.txt
Documentation/sound/Maestro
Documentation/sysrq.txt
Documentation/watchdog.txt
MAINTAINERS
arch/i386/Makefile
arch/i386/config.in
arch/i386/defconfig
arch/i386/kernel/acpi.c
arch/i386/kernel/apm.c
arch/i386/kernel/pci-i386.c
arch/i386/kernel/process.c
arch/i386/kernel/setup.c
arch/i386/math-emu/get_address.c
arch/ia64/config.in
arch/m68k/amiga/amiga_ksyms.c
arch/m68k/amiga/amiints.c
arch/m68k/amiga/chipram.c
arch/m68k/config.in
arch/m68k/defconfig
arch/m68k/kernel/setup.c
arch/ppc/8260_io/enet.c
arch/ppc/8260_io/uart.c
arch/ppc/8xx_io/commproc.c
arch/ppc/8xx_io/enet.c
arch/ppc/8xx_io/fec.c
arch/ppc/8xx_io/uart.c
arch/s390/config.in
arch/s390/defconfig
arch/s390/kernel/traps.c
drivers/char/amigamouse.c
drivers/char/amikeyb.c
drivers/char/amiserial.c
drivers/char/atixlmouse.c
drivers/char/busmouse.h
drivers/char/console.c
drivers/char/dn_keyb.c
drivers/char/logibusmouse.c
drivers/char/msbusmouse.c
drivers/char/mxser.c
drivers/char/qpmouse.c
drivers/char/radio-aimslab.c
drivers/char/random.c
drivers/char/rocket.c
drivers/char/sbc60xxwdt.c [new file with mode: 0644]
drivers/char/stradis.c
drivers/char/vt.c
drivers/i2o/Makefile
drivers/i2o/README
drivers/i2o/README.ioctl
drivers/i2o/i2o_block.c
drivers/i2o/i2o_config.c
drivers/i2o/i2o_core.c
drivers/i2o/i2o_lan.c
drivers/i2o/i2o_lan.h
drivers/i2o/i2o_pci.c
drivers/i2o/i2o_scsi.h
drivers/isdn/hisax/gazel.c
drivers/isdn/hisax/hfc_pci.c
drivers/isdn/hisax/netjet.c
drivers/isdn/hisax/niccy.c
drivers/isdn/hisax/sedlbauer.c
drivers/isdn/hisax/telespci.c
drivers/isdn/hisax/w6692.c
drivers/isdn/hysdn/hysdn_init.c
drivers/isdn/isdn_audio.c
drivers/isdn/isdn_tty.c
drivers/net/3c503.c
drivers/net/3c507.c
drivers/net/3c515.c
drivers/net/3c523.c
drivers/net/3c59x.c
drivers/net/8139too.c
drivers/net/8390.c
drivers/net/8390.h
drivers/net/Config.in
drivers/net/Makefile
drivers/net/Space.c
drivers/net/a2065.c
drivers/net/ac3200.c
drivers/net/aironet4500_card.c
drivers/net/am79c961a.c
drivers/net/apne.c
drivers/net/appletalk/ltpc.c
drivers/net/ariadne.c
drivers/net/ariadne2.c
drivers/net/arlan.c
drivers/net/at1700.c
drivers/net/atari_bionet.c
drivers/net/atari_pamsnet.c
drivers/net/atp.c
drivers/net/bonding.c
drivers/net/cs89x0.c
drivers/net/daynaport.c
drivers/net/de4x5.c
drivers/net/de600.c
drivers/net/de620.c
drivers/net/defxx.c
drivers/net/dgrs.c
drivers/net/dmfe.c
drivers/net/e2100.c
drivers/net/eepro.c
drivers/net/eepro100.c
drivers/net/eexpress.c
drivers/net/epic100.c
drivers/net/es3210.c
drivers/net/eth16i.c
drivers/net/fc/iph5526.c
drivers/net/fmv18x.c
drivers/net/hamradio/pi2.c
drivers/net/hamradio/pt.c
drivers/net/hp-plus.c
drivers/net/hp.c
drivers/net/hp100.c
drivers/net/hplance.c
drivers/net/ibmlana.c [new file with mode: 0644]
drivers/net/ibmlana.h [new file with mode: 0644]
drivers/net/ioc3-eth.c
drivers/net/lance.c
drivers/net/lne390.c
drivers/net/mac89x0.c
drivers/net/myri_sbus.c
drivers/net/ne.c
drivers/net/ne2.c
drivers/net/ne2k-pci.c
drivers/net/ne3210.c
drivers/net/ni52.c
drivers/net/oaknet.c
drivers/net/pcmcia/Config.in
drivers/net/pcnet32.c
drivers/net/ptifddi.c
drivers/net/rcpci45.c
drivers/net/rrunner.c
drivers/net/rtl8129.c
drivers/net/seeq8005.c
drivers/net/sis900.c
drivers/net/sk98lin/skge.c
drivers/net/sk_g16.c
drivers/net/sk_mca.c
drivers/net/sk_mca.h
drivers/net/skfp/skfddi.c
drivers/net/smc-mca.c
drivers/net/smc-ultra.c
drivers/net/smc-ultra32.c
drivers/net/smc9194.c
drivers/net/sonic.c
drivers/net/stnic.c
drivers/net/strip.c
drivers/net/sunbmac.c
drivers/net/sunhme.c
drivers/net/sunlance.c
drivers/net/sunqe.c
drivers/net/tlan.c
drivers/net/tlan.h
drivers/net/tokenring/ibmtr.c
drivers/net/tokenring/lanstreamer.c
drivers/net/tokenring/olympic.c
drivers/net/tokenring/olympic.h
drivers/net/tulip/21142.c
drivers/net/tulip/eeprom.c
drivers/net/tulip/interrupt.c
drivers/net/tulip/media.c
drivers/net/tulip/pnic.c
drivers/net/tulip/timer.c
drivers/net/tulip/tulip.h
drivers/net/tulip/tulip_core.c
drivers/net/wd.c
drivers/net/znet.c
drivers/parport/BUGS-parport
drivers/parport/ChangeLog
drivers/parport/Config.in
drivers/parport/TODO-parport
drivers/parport/daisy.c
drivers/parport/parport_amiga.c
drivers/parport/parport_pc.c
drivers/parport/procfs.c
drivers/parport/share.c
drivers/pci/pci.c
drivers/pci/pci.ids
drivers/pci/quirks.c
drivers/scsi/advansys.c
drivers/scsi/aha152x.c
drivers/scsi/aic7xxx.c
drivers/scsi/atp870u.c
drivers/scsi/dmx3191d.c
drivers/scsi/eata.c
drivers/scsi/eata_dma.c
drivers/scsi/eata_pio.c
drivers/scsi/fdomain.c
drivers/scsi/gdth.c
drivers/scsi/in2000.h
drivers/scsi/ini9100u.c
drivers/scsi/ini9100u.h
drivers/scsi/inia100.c
drivers/scsi/inia100.h
drivers/scsi/ips.c
drivers/scsi/megaraid.c
drivers/scsi/pci2000.c
drivers/scsi/pci2220i.c
drivers/scsi/qla1280.c
drivers/scsi/qlogicfc.c
drivers/scsi/qlogicisp.c
drivers/scsi/sd.c
drivers/scsi/seagate.c
drivers/scsi/tmscsim.c
drivers/sound/awe_wave.c
drivers/sound/cs4232.c
drivers/sound/msnd.c
drivers/sound/nm256_audio.c
drivers/sound/pas2_mixer.c
drivers/sound/sb_card.c
drivers/sound/skeleton.c
drivers/usb/Config.in
drivers/usb/Makefile
drivers/usb/acm.c
drivers/usb/audio.c
drivers/usb/dabusb.c
drivers/usb/dabusb.h
drivers/usb/dc2xx.c
drivers/usb/devio.c
drivers/usb/dsbr100.c
drivers/usb/evdev.c
drivers/usb/hid-debug.h
drivers/usb/hid.c
drivers/usb/hid.h
drivers/usb/hub.c
drivers/usb/hub.h
drivers/usb/input.c
drivers/usb/joydev.c
drivers/usb/keybdev.c
drivers/usb/mdc800.c
drivers/usb/microtek.c [new file with mode: 0644]
drivers/usb/microtek.h [new file with mode: 0644]
drivers/usb/mousedev.c
drivers/usb/ov511.c
drivers/usb/ov511.h
drivers/usb/pegasus.c
drivers/usb/printer.c
drivers/usb/scanner.c
drivers/usb/scanner.h
drivers/usb/serial/digi_acceleport.c
drivers/usb/usb-core.c
drivers/usb/usb-ohci.c
drivers/usb/usb-uhci.c
drivers/usb/usb.c
drivers/usb/usbkbd.c
drivers/usb/usbmouse.c
drivers/usb/uss720.c
drivers/usb/wacom.c
drivers/usb/wmforce.c
include/asm-alpha/socket.h
include/asm-i386/mc146818rtc.h [new file with mode: 0644]
include/asm-i386/processor.h
include/asm-i386/semaphore.h
include/asm-i386/sigcontext.h
include/asm-i386/socket.h
include/asm-ia64/socket.h
include/asm-m68k/amigaints.h
include/asm-m68k/socket.h
include/asm-mips/socket.h
include/asm-mips64/socket.h
include/asm-sparc64/socket.h
include/linux/awe_voice.h
include/linux/bitops.h
include/linux/elevator.h
include/linux/interrupt.h
include/linux/list.h
include/linux/major.h
include/linux/miscdevice.h
include/linux/module.h
include/linux/pci_ids.h
include/linux/skbuff.h
include/linux/socket.h
include/linux/sysctl.h
include/linux/tqueue.h
include/linux/usb.h
include/linux/usbdevice_fs.h
include/net/tcp.h
ipc/util.c
kernel/acct.c
kernel/module.c
mm/mremap.c
mm/slab.c
net/Config.in
net/appletalk/ddp.c
net/bridge/br.c
net/bridge/br_stp.c
net/ipv4/ipconfig.c
net/ipx/af_ipx.c
net/socket.c
net/sunrpc/clnt.c
scripts/Configure
scripts/Menuconfig
scripts/cramfs/mkcramfs.c
scripts/header.tk
scripts/lxdialog/Makefile
scripts/tail.tk
scripts/tkgen.c
scripts/tkparse.c

diff --git a/CREDITS b/CREDITS
index a749e65788c36a954e3e2c03bc9595dfafcf61c1..53968d7772038103946d125b3f48b53539961a32 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -38,10 +38,11 @@ S: University of Limerick
 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: Device driver hacker (eexpress, 3c505, c-qcam, ...)
 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 @@ S: USA
 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 @@ W: http://www.linux-ide.org/
 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: Alleenstrasse 27
 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: IJsselstraat 23a
 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: Research School of Information Science and Engineering
 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 @@ S: Germany
 
 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: 2612 XV Delft
 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
index 2c4699d6713feb0e2d76b789d01ac004229eeb9a..0b9e549fc6f7b522467b8f0df8433811dc316681 100644 (file)
@@ -2,7 +2,7 @@ Intro
 =====
 
 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 @@ additional information; most of that information will not be repeated
 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 ;-).
+'net).
 
-   For those of you in Europe,
-http://www.datanet.hu/generations/linux/Changes2.html is an
-English-language HTML version.
+The latest revision of this document, in various formats, can always
+be found at http://cyberbuzz.gatech.edu/kaboom/linux/Changes-2.4/
+<http://cyberbuzz.gatech.edu/kaboom/linux/Changes-2.4/>.
 
-   The most current version should always be available from
-http://cyberbuzz.gatech.edu/kaboom/linux/ as well.
+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.
 
-   Voir
-http://www.linux-france.com/article/sys/Changes-2.2/Changes-2.2.1.html
-pour la traduction français.
+Last updated: June 11, 2000
 
-   Also, don't forget http://www.linuxhq.com/ for all your Linux kernel
-needs.
-
-Last updated: Feb 21, 2000
-Current Author: Chris Ricker (kaboom@gatech.edu or chris.ricker@m.cc.utah.edu).
+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.
-
-   <CTRL><ALT><DEL> 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
-======
+GCC
+---
 
-   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.
+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.
 
-Network File System
-===================
+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).
 
-   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.
-
-   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.]
-
-   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
-===
-
-   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.
-
-DOSEMU
-======
+Binutils
+--------
 
-   A new "stable" version of DOSEMU is available for 2.2 kernels.
-Upgrade to 0.98.4 or later.
+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.
 
-Loadlin
-=======
+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.
 
-   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 utils
+============
 
-Sh-utils
-========
+Architectural changes
+---------------------
 
-   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.
+DevFS is now in the kernel.  See Documentation/filesystems/devfs/* in
+the kernel source tree for all the gory details.
 
-Parallel Ports
-==============
+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:
 
-   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.
+none           /dev/shm        shm             defaults        0 0
 
-Setserial
-=========
+Remember to create the directory that you intend to mount shm on if
+necessary.
 
-   If you experience random problems (stuck lines, lost characters,
-etc.) with serial lines under recent kernels, upgrading setserial
-should help.
+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.
 
-Syncookies
-==========
+32-bit UID support is now in place.  Have fun!
 
-   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
+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.
 
-Bash
-====
+Util-linux
+----------
 
-   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.
+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.
 
-Sysklogd
-========
+Ksymoops
+--------
 
-   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.
+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.
 
-Ncpfs
-=====
+Modutils
+--------
 
-   To mount NetWare shares, you'll need to upgrade to a more recent
-version of the ncpfs utils.
+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.
 
-SMBfs
-=====
+E2fsprogs
+---------
 
-   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:
+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.
 
-       mknod /dev/ppp c 108 0
+Intel P6 microcode
+------------------
 
-   If you have built ppp support as modules, you should put the lines
-below in your /etc/modules.conf file.
+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:
 
-       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
+mkdir /dev/cpu
+mknod /dev/cpu/microcode c 10 184
+chmod 0644 /dev/cpu/microcode
 
-If you are using devfsd and you have ppp_generic as a module, put the
-following line in your /etc/devfsd.conf:
+as root before you can use this.  You'll probably also want to
+get the user-space microcode_ctl utility to use with this.
 
-       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
-======
-
-   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.
-
-PCI utils
-=========
-
-   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.
-
-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
-=======
-
-   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
+General changes
+---------------
 
-   If you're lucky, you'll then have sound....
+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.
 
-   You may also need to edit it with
+If you have advanced network configuration needs, you should probably
+consider using the network tools from ip-route2.
 
-   dd if=/dev/zero of=rvplayer bs=1 count=1 seek=702554 conv=notrunc
+PPP
+---
 
-   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).
+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.
 
-Quotas
-======
+If you are not using devfs, you must have the device file /dev/ppp
+which can be made by:
 
-   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.
+mknod /dev/ppp c 108 0
 
-Ping
-====
+as root.
 
-   Most distributed ping clients are buggy.  Get an updated one from the
-iputils package.
+If you build ppp support as modules, you will need the following in
+your /etc/modules.conf file:
 
-Patch
-=====
+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
 
-   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.
+If you use devfsd and build ppp support as modules, you will need
+the following in your /etc/devfsd.conf file:
 
-Process accounting
-==================
+LOOKUP PPP     MODLOAD
 
-   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
+Isdn4k-utils
+------------
 
-   #define HAVE_LINUX_ACCT_H
+Due to changes in the length of the phone number field, isdn4k-utils
+needs to be recompiled or (preferably) upgraded.
 
-   but instead it often has
+Getting updated software
+========================
 
-   /* #undef HAVE_LINUX_ACCT_H */
+Compilers
+*********
 
-   so be sure to check that when you recompile.
+gcc 2.7.2.3
+-----------
+o  ftp://ftp.gnu.org/gnu/gcc/gcc-2.7.2.3.tar.gz
+     <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
+     <ftp://metalab.unc.edu/pub/gnu/gcc-2.7.2.3.tar.gz>
 
-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.
-
-
-Where to get the files
-**********************
+egcs 1.12
+---------
+o  ftp://ftp.varesearch.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-glibc.x86.tar.bz2
+     <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
+     <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
+     <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
-================
+2.9.1 series
+------------
+o  ftp://ftp.varesearch.com/pub/support/hjl/binutils/2.9.1/binutils-2.9.1.0.25.tar.gz
+     <ftp://ftp.varesearch.com/pub/support/hjl/binutils/2.9.1/binutils-2.9.1.0.25.tar.gz>
 
-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
+2.9.5 series
+------------
+o  ftp://ftp.varesearch.com/pub/support/hjl/binutils/binutils-2.9.5.0.29.tar.gz
+     <ftp://ftp.varesearch.com/pub/support/hjl/binutils/binutils-2.9.5.0.29.tar.bz2>
 
-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
-=======
-
-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
+     <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
+     <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
+     <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
+     <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
+     <http://web.mit.edu/tytso/www/linux/dist/e2fsprogs-1.18.src.rpm>
+
+LVM toolset
+-----------
+o  http://linux.msede.com/lvm/ <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
+     <ftp://sourceforge.org/pcmcia/pcmcia-cs-3.1.13.tar.gz>
 
 Jade
-====
+----
+o  ftp://ftp.jclark.com/pub/jade/jade-1.2.1.tar.gz
+     <ftp://ftp.jclark.com/pub/jade/jade-1.2.1.tar.gz>
 
-The 1.2.1 release:
-ftp://ftp.jclark.com/pub/jade/jade-1.2.1.tar.gz
+DocBook Stylesheets
+-------------------
+o  http://nwalsh.com/docbook/dsssl/
+     <http://nwalsh.com/docbook/dsssl/>
 
-DSSSL Stylesheets for the DocBook DTD
-=====================================
+Intel P6 microcode
+------------------
+o  http://www.urbanmyth.org/microcode/
+     <http://www.urbanmyth.org/microcode/>
 
-http://nwalsh.com/docbook/dsssl/
-
-
-Other Info
-==========
-
-   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).
+Network
+*******
 
+PPP
+---
+o  ftp://linuxcare.com.au/pub/ppp/ppp-2.4.0b1.tar.gz
+     <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
+     <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
+     <http://netfilter.filewatcher.org/iptables-1.1.0.tar.bz2>
+o  http://www.samba.org/netfilter/iptables-1.1.0.tar.bz2
+     <http://www.samba.org/netfilter/iptables-1.1.0.tar.bz2>
+o  http://netfilter.kernelnotes.org/iptables-1.1.0.tar.bz2
+     <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
+     <ftp://ftp.inr.ac.ru/ip-routing/iproute2-2.2.4-now-ss991023.tar.gz>
+
+Suggestions and corrections
+===========================
+
+Please feel free to submit changes, corrections, gripes, flames,
+money, etc. to me <chris.ricker@genetics.utah.edu>.  Happy Linuxing!
index 0f84cb2186f41804c919d60f290125ad6ec57367..b487825c79fd9b422a6295864db0b2b085b35a0e 100644 (file)
@@ -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 @@ ps:   $(PS)
 
 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 @@ db2ps db2pdf:
 %.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.tmpl >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.tmpl >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.tmpl >via-audio.sgml
+
+mcabook.sgml: mcabook.tmpl $(TOPDIR)/arch/i386/kernel/mca.c
        $(TOPDIR)/scripts/docgen $(TOPDIR)/arch/i386/kernel/mca.c \
                <mcabook.tmpl >mcabook.sgml
 
-videobook.sgml: videobook.tmpl
+videobook.sgml: videobook.tmpl $(TOPDIR)/drivers/char/videodev.c
        $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/char/videodev.c \
                <videobook.tmpl >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 @@ kernel-api.sgml: kernel-api.tmpl
                $(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.tmpl >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.tmpl >parportbook.sgml
 
@@ -74,23 +95,28 @@ DVI :=      $(patsubst %.sgml, %.dvi, $(BOOKS))
 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
 
index 688cdf351cd0e9fa93c9bfb58444e88aaff6eb70..268a9ddc9ce3ea3841825b7bcbdca778030de0b5 100644 (file)
  </bookinfo>
 
 <toc></toc>
+  <chapter id="adt">
+     <title>Data Types</title>
+     <sect1><title>Doubly Linked Lists</title>
+!Iinclude/linux/list.h
+     </sect1>
+  </chapter>
+
+  <chapter id="mm">
+     <title>Memory Management in Linux</title>
+     <sect1><title>The Slab Cache</title>
+!Emm/slab.c
+      </sect1>
+  </chapter>
+
   <chapter id="vfs">
      <title>The Linux VFS</title>
      <sect1><title>The Directory Cache</title>
index 397e7e9544011345921579c7caf9a868777f7693..5b687eb7683a1213f0ee641daf625e574ba7f1e2 100644 (file)
      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 <xref linkend="sleeping-things">), and so
+     have to use a spinlock instead.
+   </para>
+   <para>
+     Neither type of lock is recursive: see
+     <xref linkend="techniques-deadlocks">.
    </para>
  
    <sect1 id="uniprocessor">
 
    <para>
      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.
    </para>
 
     <para>
       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.
     </para>
     </para>
 
     <para>
-      Dropping or gaining a spinlock, and any atomic operation are
-      all defined to act as memory barriers (ie. as per the 
-      <function>mb()</function> macro).
-    </para>
-
-    <para>
-      There is a similar, but unrelated, problem with code like the
-      following:
-    </para>
-
-    <programlisting>
-        if (!(ctrack-&gt;status &amp; IPS_CONFIRMED)) {
-                spin_lock_bh(&amp;ip_conntrack_lock);
-                if (!(ctrack-&gt;status &amp; IPS_CONFIRMED)) {
-                        clean_from_lists(h-&gt;ctrack);
-                        h-&gt;ctrack-&gt;status |= IPS_CONFIRMED;
-                }
-                spin_unlock_bh(&amp;ip_conntrack_lock);
-        }
-    </programlisting>
-
-    <para>
-      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 <function>mb()</function> macro).  Also,
+      spinlock operations act as partial barriers: operations after
+      gaining a spinlock will never be moved to precede the
+      <function>spin_lock()</function> call, and operations before
+      releasing a spinlock will never be moved after the
+      <function>spin_unlock()</function> call.
+      <!-- Manfred Spraul <manfreds@colorfullife.com>
+           24 May 2000 2.3.99-pre9 -->
     </para>
    </sect1>
 
 
     <para>
       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.
     </para>
 
     <itemizedlist>
 
      <listitem>
       <para>
-        <function>printk()</function>, which can be called from
-        user context, interestingly enough.
+      <function>down_interruptible()</function> and
+      <function>down()</function>
+      </para>
+      <para>
+       There is a <function>down_trylock()</function> which can be
+       used inside interrupt context, as it will not sleep.
+       <function>up()</function> will also never sleep.
       </para>
      </listitem>
     </itemizedlist>
+
+    <function>printk()</function> can be called in
+    <emphasis>any</emphasis> context, interestingly enough.
    </sect1>
 
    <sect1 id="sparc">
       Another common problem is deleting timers which restart
       themselves (by calling <function>add_timer()</function> at the end 
       of their timer function).  Because this is a fairly common case 
-      which is prone to races, the function <function>del_timer_sync()</function> 
-      (<filename class=headerfile>include/linux/timer.h</filename>) 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
+      <function>timer_exit()</function> at the very end of your timer function,
+      and user <function>del_timer_sync()</function> 
+      (<filename class=headerfile>include/linux/timer.h</filename>)
+      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.
     </para>
 
     <para>
       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.
     </para>
 
     <para>
diff --git a/Documentation/DocBook/mousedrivers.tmpl b/Documentation/DocBook/mousedrivers.tmpl
new file mode 100644 (file)
index 0000000..5d7be51
--- /dev/null
@@ -0,0 +1,1022 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+
+<book id="MouseGuide">
+ <bookinfo>
+  <title>Mouse Drivers</title>
+  
+  <authorgroup>
+   <author>
+    <firstname>Alan</firstname>
+    <surname>Cox</surname>
+    <affiliation>
+     <address>
+      <email>alan@redhat.com</email>
+     </address>
+    </affiliation>
+   </author>
+  </authorgroup>
+
+  <copyright>
+   <year>2000</year>
+   <holder>Alan Cox</holder>
+  </copyright>
+
+  <legalnotice>
+   <para>
+     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.
+   </para>
+      
+   <para>
+     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.
+   </para>
+      
+   <para>
+     You 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
+   </para>
+      
+   <para>
+     For more details see the file COPYING in the source
+     distribution of Linux.
+   </para>
+  </legalnotice>
+ </bookinfo>
+
+ <toc></toc>
+
+ <chapter id="intro">
+  <title>Introduction</title>
+  <note>
+   <title>Earlier publication</title>
+    <para>
+      Parts of this document first appeared in Linux Magazine under a
+      ninety day exclusivity.
+   </para>
+  </note> 
+
+  <para>
+    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.
+  </para>
+
+  <para>
+    The kernel mouse drivers and userspace drivers for the serial mice are
+    all managed by a system daemon called <application>gpm</application> 
+    - the general purpose mouse driver. <application>gpm</application> 
+    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 
+    <application>X Window System</application> user interface.
+  </para>
+  <para>
+    Sometimes a mouse speaks a sufficiently convoluted protocol that the
+    protocol is handled by <application>Gpm</application> itself. Most 
+    of the mouse drivers follow a common interface called the bus mouse 
+    protocol.
+  </para>
+  <para>
+    Each read from a bus mouse interface device returns a block of data. 
+    The first three bytes of each read are defined as follows: 
+
+   <table frame=all>
+    <title>Mouse Data Encoding</title>
+    <tgroup cols=2 align=left>
+     <tbody>
+      <row>
+       <entry>Byte 0</entry>
+       <entry>0x80 + the buttons currently down.</entry>
+      </row>
+      <row>
+       <entry>Byte 1</entry>
+       <entry>A signed value for the shift in X position</entry>
+      </row>
+      <row>
+       <entry>Byte 2</entry>
+       <entry>A signed value for the shift in Y position</entry>
+      </row>
+     </tbody>
+    </tgroup>
+   </table>
+
+    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.
+  </para>
+  <para>
+    The position values are truncated if they exceed the 8bit range (that
+    is -127 &lt;= delta &lt;= 127). While the value -128 does fit into a 
+    byte is not allowed.
+  </para>
+  <para>
+    The <mousebutton>buttons</mousebutton> 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.
+  </para>
+  <para>
+    All mice are required to support the <function>poll</function> 
+    operation. Indeed pretty much every user of a mouse device uses 
+    <function>poll</function> to wait for mouse events to occur.
+  </para>
+  <para>
+    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.
+  </para>
+ </chapter>
+
+ <chapter id="driver">
+  <title>A simple mouse driver</title>
+  <para>
+    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.
+  </para>
+
+  <programlisting>
+#define OURMOUSE_BASE        0x300
+
+static struct miscdevice our_mouse = {
+        OURMOUSE_MINOR, "ourmouse", &amp;our_mouse_fops
+};
+
+__init ourmouse_init(void)
+{
+
+        if(check_region(OURMOUSE_BASE, 3))
+                return -ENODEV;
+        request_region(OURMOUSE_BASE, 3, "ourmouse");
+
+        misc_register(&amp;our_mouse);
+        return 0;
+}
+  </programlisting>
+
+  <para>
+    The <structname>miscdevice</structname> 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.
+  </para>
+  <para>
+    Minor numbers in this space are allocated by a central source, although 
+    you can look in the kernel <filename>Documentation/devices.txt</filename>
+    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.
+  </para>
+  <para>
+    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.
+  </para>
+  <para>
+    Then we tell the misc driver that we wish to own a minor number. We also
+    hand it our name (which is used in 
+    <filename class="directory">/proc/misc</filename>) 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.
+  </para>
+  <para>
+    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:
+  </para>
+  <programlisting>
+#ifdef MODULE
+
+int init_module(void)
+{
+        if(ourmouse_init()&lt;0)
+                return -ENODEV:
+        return 0;
+}
+
+void cleanup_module(void)
+{
+        misc_deregister(&amp;our_mouse);
+        free_region(OURMOUSE_BASE, 3);
+}
+
+
+#endif
+  </programlisting>
+
+  <para>
+    The module code provides the normal two functions. The 
+    <function>init_module</function> 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.
+  </para>
+  <para>
+    The <function>cleanup_module</function> 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.
+  </para>
+  <para>
+    Once the <function>misc_deregister</function> has been called any 
+    attempts to open the mouse device will fail with the error  
+    <errorcode>ENODEV</errorcode> (<errorname>No such device</errorname>).
+  </para>
+  <para>
+    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:
+  </para>
+
+  <programlisting>
+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 */
+};
+  </programlisting>
+
+  <para>
+    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.
+  </para>
+  <para>
+    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. 
+  </para>
+
+  <programlisting>
+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;
+}
+  </programlisting>
+  <para>
+    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
+    <returnvalue>0</returnvalue> for success.
+  </para>
+  <para>
+    Firstly we use <function>MOD_INC_USE_COUNT</function> 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.
+  </para>
+  <para>
+    We grab the interrupt and thus start mouse interrupts. If the interrupt 
+    has been borrowed by some other driver then <function>request_irq</function>
+    will fail and we will return an error. If we were capable of sharing an 
+    interrupt line we would specify <constant>SA_SHIRQ</constant> instead of 
+    <constant>zero</constant>. Provided that everyone claiming an interrupt 
+    sets this flag, they get to share the line. <hardware>PCI</hardware> can 
+    share interrupts, <hardware>ISA</hardware> normally however cannot. 
+  </para>
+  <para>
+    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.
+  </para>
+  <para>
+    The release function needs to unwind all these:
+  </para>
+  <programlisting>
+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;
+}
+  </programlisting>
+  <para>
+    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 <function>MOD_DEC_USE_COUNT</function> so 
+    that the mouse can now be unloaded.
+  </para>
+  <para>
+    We can fill in the write handler at this point as the write function for 
+    our mouse simply declines to allow writes:
+  </para>
+
+  <programlisting>
+static ssize_t write_mouse(struct file *file, const char *buffer, size_t
+                                count, loff_t *ppos)
+{
+        return -EINVAL;
+}
+  </programlisting>
+
+  <para>
+    This is pretty much self-explanatory. Whenever you write you get told 
+    it was an invalid function.
+  </para>
+  <para>
+    To make the poll and read functions work we have to consider how we 
+    handle the mouse interrupt. 
+  </para>
+
+  <programlisting>
+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(&amp;mouse_lock);
+                mouse_event = 1;
+                mouse_dx += delta_x;
+                mouse_dy += delta_y;
+                mouse_buttons = new_buttons;
+                spin_unlock(&amp;mouse_lock);
+                
+                wake_up_interruptible(&amp;mouse_wait);
+        }
+}
+  </programlisting>
+
+  <para>
+    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. 
+  </para>
+  <para>
+    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.
+  </para>
+  <para>
+    If a change has occured we also need to wake sleeping processes, so we 
+    add a wakeup call and a <structname>wait_queue</structname> to use when 
+    we wish to await a mouse event.
+  </para>
+  <para>
+    Now we have the wait queue we can implement the poll function for the 
+    mouse relatively easily:
+  </para>
+
+  <programlisting>
+static unsigned int mouse_poll(struct file *file, poll_table *wait)
+{
+        poll_wait(file, &amp;mouse_wait, wait);
+        if(mouse_event)
+                return POLLIN | POLLRDNORM;
+        return 0;
+}
+  </programlisting>
+
+  <para>
+    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 
+    <varname>mouse_event</varname> 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.
+  </para>
+  <para>
+    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 
+    <function>poll</function> call will exit back to the user.
+  </para>
+  <para>
+    After the poll completes the user will want to read the data. We now 
+    need to think about how our <function>mouse_read</function> function 
+    will work:
+  </para>
+  <programlisting>
+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&lt;3)
+                return -EINVAL;
+
+        /*
+          *        Wait for an event
+         */
+
+        while(!mouse_event)
+        {
+                if(file-&gt;f_flags&amp;O_NDELAY)
+                        return -EAGAIN;
+                interruptible_sleep_on(&amp;mouse_wait);
+                if(signal_pending(current))
+                        return -ERESTARTSYS;
+        }
+  </programlisting>
+
+  <para>
+    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.
+  </para>
+  <para>
+    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. 
+  </para>
+  <para>
+    A user process can set the <constant>O_NDELAY</constant> 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. 
+  </para>
+  <para>
+    Next we sleep until the mouse or a signal awakens us. A signal will 
+    awaken us as we have used <function>wakeup_interruptible</function>. 
+    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.
+  </para>
+  <para>
+    This code contains a classic Linux bug. All will be revealed later in this
+    article as well as explanations for how to avoid it.
+  </para>
+  <programlisting>
+        /* Grab the event */
+
+        spinlock_irqsave(&amp;mouse_lock, flags);
+
+        dx = mouse_dx;
+        dy = mouse_dy;
+        button = mouse_buttons;
+
+        if(dx&lt;=-127)
+                dx=-127;
+        if(dx&gt;=127)
+                dx=127;
+        if(dy&lt;=-127)
+                dy=-127;
+        if(dy&gt;=127)
+                dy=127;
+
+        mouse_dx -= dx;
+        mouse_dy -= dy;
+        
+        if(mouse_dx == 0 &amp;&amp; mouse_dy == 0)
+                mouse_event = 0;
+
+        spin_unlock_irqrestore(&amp;mouse_lock, flags);
+  </programlisting>
+  <para>
+    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 <function>spinlock_irqsave</function>. We 
+    need to disable interrupts on the local processor otherwise bad things 
+    will happen.
+  </para>
+  <para>
+    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.
+  </para>
+  <para>
+    By blocking the interrupt on this processor we ensure that the lock 
+    holder will always give the lock back without deadlocking.
+  </para>
+  <para>
+    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 
+    <varname>mouse_dx</varname> and <varname>mouse_dy</varname>. Eventually 
+    when these counts hit zero we clear the <varname>mouse_event</varname>
+    flag as there is nothing else left to report.
+  </para>
+
+  <programlisting>
+        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;
+}
+  </programlisting>
+
+  <para>
+    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 
+    <function>put_user call</function> 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.
+  </para>
+  <para>
+    Having written the data we blank the rest of the buffer that was read 
+    and report the read as being successful.
+  </para>
+ </chapter>
+
+ <chapter id="debugging">
+  <title>Debugging the mouse driver</title>
+
+  <para>
+    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.
+  </para>
+  <para>
+    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:
+  </para>
+
+  <programlisting>
+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(&amp;mouse_lock);
+                mouse_event = 1;
+                mouse_dx += delta_x;
+                mouse_dy += delta_y;
+
+                if(mouse_dx &lt; -4096)
+                        mouse_dx = -4096;
+                if(mouse_dx &gt; 4096)
+                        mouse_dx = 4096;
+
+                if(mouse_dy &lt; -4096)
+                        mouse_dy = -4096;
+                if(mouse_dy &gt; 4096)
+                        mouse_dy = 4096;
+
+                mouse_buttons = new_buttons;
+                spin_unlock(&amp;mouse_lock);
+                
+                wake_up_interruptible(&amp;mouse_wait);
+        }
+}
+  </programlisting>
+
+  <para>
+    By adding these checks we limit the range of accumulated movement to
+    something sensible. 
+  </para>
+  <para>
+    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:
+  </para>
+
+  <programlisting>
+        while(!mouse_event)
+        {
+  </programlisting>
+
+  <para>
+    and an interrupt occurs at this point here. This causes a mouse movement
+    and wakes up the queue. 
+  </para>
+
+  <programlisting>
+                interruptible_sleep_on(&amp;mouse_wait);
+  </programlisting>
+
+  <para>
+    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.
+  </para>
+  <para>
+    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:
+  </para>
+
+  <programlisting>
+        save_flags(flags);
+        cli();
+
+        while(!mouse_event)
+        {
+                if(file-&gt;f_flags&amp;O_NDELAY)
+                {
+                        restore_flags(flags);
+                        return -EAGAIN;
+                }
+                interruptible_sleep_on(&amp;mouse_wait);
+                if(signal_pending(current))
+                {
+                        restore_flags(flags);
+                        return -ERESTARTSYS;
+                }
+        }
+        restore_flags(flags);
+  </programlisting>
+
+  <para>
+    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.
+  </para>
+  <para>
+    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.
+  </para>
+
+  <programlisting>
+        struct wait_queue wait = { current, NULL };
+
+        add_wait_queue(&amp;mouse_wait, &amp;wait);
+        current-&gt;state = TASK_INTERRUPTIBLE;
+        
+        while(!mouse_event)
+        {
+                if(file-&gt;f_flags&amp;O_NDELAY)
+                {
+                        remove_wait_queue(&amp;mouse_wait, &amp;wait);
+                        current-&gt;state = TASK_RUNNING;
+                        return -EWOULDBLOCK;
+                }
+                if(signal_pending(current))
+                {
+                        remove_wait_queue(&amp;mouse_wait, &amp;wait);
+                        current-&gt;state = TASK_RUNNING;
+                        return -ERESTARTSYS;
+                }
+                schedule();
+                current-&gt;state = TASK_INTERRUPTIBLE;
+        }
+        
+        remove_wait_wait(&amp;mouse_wait, &amp;wait);
+        current-&gt;state = TASK_RUNNING;
+  </programlisting>
+
+  <para>
+    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.
+  </para>
+  <para>
+    <function>add_wait_queue</function> does what its name suggests. It adds 
+    an entry to the <varname>mouse_wait</varname> list. The entry in this 
+    case is the entry for our current process (<varname>current</varname>
+    is the current task pointer). 
+  </para>
+  <para>
+    So we start by adding an entry for ourself onto the 
+    <varname>mouse_wait</varname> list. This does not put us to sleep 
+    however. We are merely tagged onto the list. 
+  </para>
+  <para>
+    Next we set our status to <constant>TASK_INTERRUPTIBLE</constant>. Again 
+    this does not mean we are now asleep. This flag says what should happen 
+    next time the process sleeps. <constant>TASK_INTERRUPTIBLE</constant> says 
+    that the process should not be rescheduled. It will run from now until it 
+    sleeps and then will need to be woken up.
+  </para>
+  <para>
+    The <function>wakeup_interruptible</function> 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 <constant>TASK_INTERRUPTIBLE</constant> it changes 
+    to <constant>TASK_RUNNING</constant> and tells the kernel that new 
+    processes are runnable.
+  </para>
+  <para>
+    Behind all the wrappers in the original code what is happening is this
+  </para>
+
+  <procedure>
+   <step>
+    <para>
+      We add ourself to the mouse wait queue
+    </para>
+   </step>
+   <step>
+    <para>
+      We mark ourself as sleeping
+    </para>
+   </step>
+   <step>
+    <para>
+      We ask the kernel to schedule tasks again
+    </para>
+   </step>
+   <step>
+    <para>
+      The kernel sees we are asleep and schedules someone else.
+    </para>
+   </step>
+   <step>
+    <para>
+      The mouse interrupt sets our state to <constant>TASK_RUNNING</constant> 
+      and makes a note that the kernel should reschedule tasks
+    </para>
+   </step>
+   <step>
+    <para>
+      The kernel sees we are running again and continues our execution
+    </para>
+   </step>
+  </procedure>
+  <para>
+    This is why the apparent magic works. Because we mark ourself as
+    <constant>TASK_INTERRUPTIBLE</constant> and as we add ourselves 
+    to the queue before we check if there are events pending, the race 
+    condition is removed.
+  </para>
+  <para>
+    Now if an interrupt occurs after we check the queue status and before 
+    we call the <function>schedule</function> function in order to sleep, 
+    things work out. Instead of missing an event, we are set back to 
+    <constant>TASK_RUNNING</constant> by the mouse interrupt. We still call 
+    <function>schedule</function> but it will continue running our task. 
+    We go back around the loop and this time there may be an event.
+  </para>
+  <para>
+    There will not always be an event. Thus we set ourselves back to
+    <constant>TASK_INTERRUPTIBLE</constant> 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.
+  </para>
+  <para>
+    Finally when we exit the loop we remove ourselves from the 
+    <varname>mouse_wait</varname> queue as we are no longer interested
+    in mouse events, and we set ourself back to 
+    <constant>TASK_RUNNABLE</constant> as we do not wish to go to sleep 
+    again just yet.
+  </para>
+  <note>
+   <title>Note</title> 
+   <para>
+     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.
+   </para>
+  </note>
+ </chapter>
+
+ <chapter id="asyncio">
+  <title>Asynchronous I/O</title>
+  <para>
+    This leaves the missing feature - Asynchronous I/O. Normally UNIX 
+    programs use the <function>poll</function> call (or its variant form 
+    <function>select</function>) to wait for an event to occur on one of 
+    multiple input or output devices. This model works well for most tasks 
+    but because <function>poll</function> and <function>select</function> 
+    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.
+  </para>
+  <para>
+    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.
+  </para>
+  <para>
+    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.
+  </para>
+  <para>
+    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.
+  </para>
+  <para>
+    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:
+  </para>
+
+  <programlisting>
+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 */
+};
+  </programlisting>
+
+  <para>
+    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 <function>fasync_mouse</function> routine 
+    we just added. This routine uses the helper functions to keep the queue 
+    of handles up to date:
+  </para>
+
+  <programlisting>
+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, &amp;mouse_fasync);
+
+         if (retval &lt; 0)
+                 return retval;
+        return 0;
+}
+  </programlisting>
+
+  <para>
+    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:
+  </para>
+
+  <programlisting>
+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;
+}
+  </programlisting>
+
+  <para>
+    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.
+  </para>
+  <para>
+    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.
+  </para>
+  <para>
+    We update our interrupt handler a little:
+  </para>
+
+  <programlisting>
+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(&amp;mouse_lock);
+                mouse_event = 1;
+                mouse_dx += delta_x;
+                mouse_dy += delta_y;
+
+                if(mouse_dx &lt; -4096)
+                        mouse_dx = -4096;
+                if(mouse_dx &gt; 4096)
+                        mouse_dx = 4096;
+
+                if(mouse_dy &lt; -4096)
+                        mouse_dy = -4096;
+                if(mouse_dy &gt; 4096)
+                        mouse_dy = 4096;
+
+                mouse_buttons = new_buttons;
+                spin_unlock(&amp;mouse_lock);
+
+                /* Now we do asynchronous I/O */
+                kill_fasync(&amp;mouse_fasync, SIGIO); 
+                
+                wake_up_interruptible(&amp;mouse_wait);
+        }
+}
+  </programlisting>
+
+  <para>
+    The new code simply calls the <function>kill_fasync</function> 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.
+  </para>
+  <para>
+    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 <application>X window system</application>, will work 
+    with <application>GPM</application> and should work with every other 
+    application you need. <application>Doom</application> is of course the 
+    ideal way to test your new mouse driver is functioning properly. Be sure 
+    to test it thoroughly.
+  </para>
+ </chapter>
+</book>
+
diff --git a/Documentation/DocBook/via-audio.tmpl b/Documentation/DocBook/via-audio.tmpl
new file mode 100644 (file)
index 0000000..f1fc19a
--- /dev/null
@@ -0,0 +1,383 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+
+<book id="ViaAudioGuide">
+ <bookinfo>
+  <title>Via 686 Audio Driver for Linux</title>
+  
+  <authorgroup>
+   <author>
+    <firstname>Jeff</firstname>
+    <surname>Garzik</surname>
+    <affiliation>
+     <address>
+      <email>jgarzik@mandrakesoft.com</email>
+     </address>
+    </affiliation>
+   </author>
+  </authorgroup>
+
+  <copyright>
+   <year>2000</year>
+   <holder>Jeff Garzik</holder>
+  </copyright>
+
+  <legalnotice>
+   <para>
+     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.
+   </para>
+      
+   <para>
+     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.
+   </para>
+      
+   <para>
+     You 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
+   </para>
+      
+   <para>
+     For more details see the file COPYING in the source
+     distribution of Linux.
+   </para>
+  </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+
+  <chapter id="intro">
+      <title>Introduction</title>
+  <para>
+       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.
+  </para>
+  <para>
+       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.
+  </para>
+  <para>
+       This driver supports any Linux kernel version after 2.3.50.
+  </para>
+  <para>
+       Please send bug reports to the mailing list <email>linux-via@gtf.org</email>.
+       To subscribe, e-mail <email>majordomo@gtf.org</email> with
+  </para>
+  <programlisting>
+       subscribe linux-via
+  </programlisting>
+  <para>
+       in the body of the message.
+  </para>
+  </chapter>
+  
+  <chapter id="install">
+      <title>Driver Installation</title>
+  <para>
+       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.
+  </para>
+  <para>
+       To make this driver the default audio driver, you can add the
+       following to your /etc/conf.modules file:
+  </para>
+  <programlisting>
+       alias sound via82cxxx_audio
+  </programlisting>
+  <para>
+       Note that soundcore and ac97_codec support modules
+       are also required for working audio, in addition to
+       the via82cxxx_audio module itself.
+  </para>
+  </chapter>
+  
+  <chapter id="reportbug">
+      <title>Submitting a bug report</title>
+  <sect1 id="bugrepdesc"><title>Description of problem</title>
+  <para>
+       Describe the application you were using to play/record sound, and how
+       to reproduce the problem.
+  </para>
+  </sect1>
+  <sect1 id="bugrepdiag"><title>Diagnostic output</title>
+  <para>
+       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:
+  </para>
+  <programlisting>
+       ./via-audio-diag -aps > diag-output.txt
+  </programlisting>
+  </sect1>
+  <sect1 id="bugrepdebug"><title>Driver debug output</title>
+  <para>
+       Define <constant>VIA_DEBUG</constant> 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:
+  </para>
+  <programlisting>
+       dmesg > /tmp/dmesg-output.txt
+  </programlisting>
+  </sect1>
+  <sect1 id="bugrepprintk"><title>Bigger kernel message buffer</title>
+  <para>
+       If you wish to increase the size of the buffer displayed by dmesg, then
+       change the <constant>LOG_BUF_LEN</constant> macro at the top of linux/kernel/printk.c, recompile
+       your kernel, and pass the <constant>LOG_BUF_LEN</constant> value to dmesg.  Sample command line with
+       <constant>LOG_BUF_LEN</constant> == 32768:
+  </para>
+  <programlisting>
+       dmesg -s 32768 > /tmp/dmesg-output.txt
+  </programlisting>
+  </sect1>
+  </chapter>
+  
+  <chapter id="bugs">
+     <title>Known Bugs And Assumptions</title>
+  <para>
+  <variablelist>
+    <varlistentry><term>Recording support</term>
+    <listitem>
+    <para>
+       Recording support is currently missing.
+    </para>
+    </listitem></varlistentry>
+
+    <varlistentry><term>MMAP support</term>
+    <listitem>
+    <para>
+       MMAP support is currently missing.  Make sure to
+       test with Quake.
+    </para>
+    </listitem></varlistentry>
+
+    <varlistentry><term>AC97 codec timeout during init</term>
+    <listitem>
+    <para>
+       A warning message "via82cxxx: timeout while reading AC97
+       codec" is printed during driver initialization.  This
+       message can safely be ignored.
+    </para>
+    </listitem></varlistentry>
+
+    <varlistentry><term>Low volume</term>
+    <listitem>
+    <para>
+       Volume too low on many systems.  Workaround:  use mixer program
+       such as xmixer to increase volume.
+    </para>
+    </listitem></varlistentry>
+
+    <varlistentry><term>RealPlayer trouble</term>
+    <listitem>
+    <para>
+       RealPlayer output very scratchy.  Workaround:  use esd, and
+       configure RealPlayer to output to esd.
+    </para>
+    </listitem></varlistentry>
+
+    <varlistentry><term>Broken apps</term>
+    <listitem>
+    <para>
+       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.
+    </para>
+    </listitem></varlistentry>
+
+  </variablelist>
+       
+  </para>
+  </chapter>
+
+  <chapter id="thanks">
+      <title>Thanks</title>
+  <para>
+       Via for providing e-mail support, specs, and NDA'd source code.
+  </para>
+  <para>
+       MandrakeSoft for providing hacking time.
+  </para>
+  <para>
+       AC97 mixer interface fixes and debugging by Ron Cemer <email>roncemer@gte.net</email>.
+  </para>
+  </chapter>
+  
+  <chapter id="notes">
+     <title>Random Notes</title>
+  <para>
+       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:
+  </para>
+  <programlisting>
+       /proc/driver/via/0/info
+       /proc/driver/via/0/ac97
+  </programlisting>
+  <para>
+       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.
+  </para>
+  <para>
+       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.
+  </para>
+  <para>
+       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.
+  </para>
+  <para>
+       GNU indent formatting options:  -kr -i8 -pcs
+  </para>
+  <para>
+       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.
+  </para>
+  <para>
+       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?)
+  </para>
+  </chapter>
+
+  <chapter id="changelog">
+      <title>Driver ChangeLog</title>
+
+<sect1 id="version118"><title>
+Version 1.1.8
+</title>
+  <itemizedlist spacing=compact>
+   <listitem>
+    <para>
+       Clean up interrupt handler output.  Fixes the following kernel error message:
+    </para>
+       <programlisting>
+       unhandled interrupt ...
+       </programlisting>
+   </listitem>
+
+   <listitem>
+    <para>
+       Convert documentation to DocBook, so that PDF, HTML and PostScript (.ps) output is readily
+       available.
+    </para>
+   </listitem>
+
+  </itemizedlist>
+</sect1>
+
+<sect1 id="version117"><title>
+Version 1.1.7
+</title>
+  <itemizedlist spacing=compact>
+   <listitem>
+    <para>
+ Fix module unload bug where mixer device left registered
+  after driver exit
+    </para>
+   </listitem>
+  </itemizedlist>
+</sect1>
+
+<sect1 id="version116"><title>
+Version 1.1.6
+</title>
+  <itemizedlist spacing=compact>
+   <listitem>
+    <para>
+ Rewrite via_set_rate to mimic ALSA basic AC97 rate setting
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+ Remove much dead code
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+ Complete spin_lock_irqsave -> spin_lock_irq conversion in via_dsp_ioctl
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+ Fix build problem in via_dsp_ioctl
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+ Optimize included headers to eliminate headers found in linux/drivers/sound
+       </para>
+   </listitem>
+  </itemizedlist>
+</sect1>
+
+<sect1 id="version115"><title>
+Version 1.1.5
+</title>
+  <itemizedlist spacing=compact>
+   <listitem>
+    <para>
+ Disable some overly-verbose debugging code
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+ Remove unnecessary sound locks
+   </para>
+   </listitem>
+   <listitem>
+    <para>
+ Fix some ioctls for better time resolution
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+ Begin spin_lock_irqsave -> spin_lock_irq conversion in via_dsp_ioctl
+    </para>
+   </listitem>
+  </itemizedlist>
+</sect1>
+
+<sect1 id="version114"><title>
+Version 1.1.4
+</title>
+  <itemizedlist spacing=compact>
+   <listitem>
+    <para>
+ Completed rewrite of driver.  Eliminated SoundBlaster compatibility
+  completely, and now uses the much-faster scatter-gather DMA engine.
+    </para>
+   </listitem>
+  </itemizedlist>
+</sect1>
+
+  </chapter>
+  
+  <chapter id="intfunctions">
+     <title>Internal Functions</title>
+!Idrivers/sound/via82cxxx_audio.c
+  </chapter>
+
+</book>
index 892fb5137c71814754c6be7bfdd364c0c1d27cbe..d2841e0bcf0258cb9b06b0fec372bae14b0ff3ba 100644 (file)
@@ -54,4 +54,4 @@ The first 4 bytes should be 0x1badface.
 If you have any patches, questions or suggestions regarding this BFS
 implementation please contact the author:
 
-Tigran A. Aivazian <tigran@ocston.org>.
+Tigran A. Aivazian <tigran@veritas.com>
index 7bd117ee89ae4773df9a06f3ce29687e7d426a08..463937232e0bcc9c5e0a3a99521d3f0b694948b2 100644 (file)
@@ -201,11 +201,10 @@ It also contains additional documentation about the floppy driver.
 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
 ==========================================
index 273c954e5a9cb128a09bfbfaf355e2d2973ccb46..0edc635ff2909393a87884ac0869e8a7b8e602de 100644 (file)
@@ -74,6 +74,8 @@ Code  Seq#    Include File            Comments
 0x22   all     scsi/sg.h
 '1'    00-1F   <linux/timepps.h>       PPS kit from Ulrich Windl
                                        <ftp://ftp.de.kernel.org/pub/linux/daemons/ntp/PPS/>
+'6'    00-10   <asm-i386/processor.h>  Intel P6 microcode update driver
+                                       <tigran@veritas.com>
 '8'    all                             SNP8023 advanced NIC card
                                        <mailto:mcr@solidum.com>
 'A'    00-1F   linux/apm_bios.h
@@ -101,6 +103,7 @@ Code        Seq#    Include File            Comments
 '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
                                        <http://lrcwww.epfl.ch/linux-atm/magic.html>
index 585d557abace533afcc7974fce5d204fa26ee10e..228a0602dcc4dfacbd05117e9e2fd02b16f0c9e0 100644 (file)
@@ -57,7 +57,7 @@ format of your choice (for example, 'db2html ...').
 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:
 
@@ -123,6 +123,25 @@ patterns, which are highlighted appropriately.
 
 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<filename> is replaced by the documentation, in <filename>, for
+functions that are exported using EXPORT_SYMBOL: the function list is
+collected from files listed in Documentation/DocBook/Makefile.
+
+!I<filename> is replaced by the documentation for functions that are
+_not_ exported using EXPORT_SYMBOL.
+
+!F<filename> <function [functions...]> is replaced by the
+documentation, in <filename>, for the functions listed.
+
+
 Tim.
 */ <twaugh@redhat.com>
 
index 2821f515d0165424a6c266ab8b819507e109da1f..611d8be802cc6a9f109cb18fe479a04abe4cc9d2 100644 (file)
@@ -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 @@ The text in square brackets at the beginning of the description state the
 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 @@ restrictions referred to are that the relevant option is valid if:
        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 @@ running once the system is up.
 
        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 @@ running once the system is up.
 
        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 @@ running once the system is up.
 
        cdu31a=         [HW,CD]
 
+       chandev=        [HW,NET] 
        cm206=          [HW,CD]
 
        com20020=       [HW,NET]
@@ -100,15 +122,29 @@ running once the system is up.
 
        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 @@ running once the system is up.
 
        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 @@ running once the system is up.
 
        gscd=           [HW,CD]
 
+       gus=            [HW,SOUND] 
        gvp11=          [HW,SCSI]
 
        hd=             [EIDE] (E)IDE hard drive subsystem geometry
@@ -148,8 +192,6 @@ running once the system is up.
 
        hfmodem=        [HW,AX25]
 
-       HiSax=          [HW,ISDN]
-
        hisax=          [HW,ISDN]
 
        in2000=         [HW,SCSI]
@@ -166,15 +208,11 @@ running once the system is up.
        
        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 @@ running once the system is up.
 
        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 @@ running once the system is up.
 
        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 @@ running once the system is up.
 
        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 @@ running once the system is up.
 
        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 @@ running once the system is up.
 
        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 @@ running once the system is up.
                                        order they are specified on the command
                                        line, starting with parport0.
 
+       pas2=           [HW,SOUND]
        pas16=          [HW,SCSI]
 
        pcbit=          [HW,ISDN]
@@ -329,10 +407,17 @@ running once the system is up.
        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 @@ running once the system is up.
 
        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 @@ running once the system is up.
 
        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 @@ running once the system is up.
 
        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]
index 1485930fba862bffe187e48fe7ba232f0e9bcc00..901eb44bc58cde588cae1fad5692093479528c4c 100644 (file)
@@ -2,7 +2,10 @@
 (C) 1998 James Banks
 (C) 1999-2000 Torben Mathiasen <tmm@image.dk, torben.mathiasen@compaq.com>
 
-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 @@ II.   Driver Options
           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 @@ II.   Driver Options
           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 @@ III.  Things to try if you have problems.
 
 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
 
index 80fd38300a5a968e28c5a42dc9dfea545cf79c41..6c689b0df2b81e9c5b1f914ca7a2c9068bdfea17 100644 (file)
@@ -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 @@ Replace the sample values as needed.
 
    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 @@ Replace the sample values as needed.
 
    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 <geert@linux-m68k.org>
    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 <miquels@cistron.nl>, 21-Mar-1998
+Miquel van Smoorenburg <miquels@cistron.nl>, 11-Jun-2000
index 940156fc68b1432d186f417e2a27e6d17e253947..f572112ffc4983025264583c6a8e3221a26aefac 100644 (file)
@@ -6,7 +6,7 @@ Driver Status and Availability
 ------------------------------
 
 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.
index b68e71cf9c9b63b2df70ed772f990a8359cd520b..7643922320f815acbe7fac7bd9ccc8e42b2501d2 100644 (file)
@@ -25,6 +25,10 @@ On x86   - You press the key combo 'ALT-SysRQ-<command key>'. Note - Some
 
 On SPARC - You press 'ALT-STOP-<command key>', 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. 
 
index 599eda965821fa54954d1ec140bbfccc5f794abd..893ead8a8bda922b8a4445a54d543a0ee963c26a 100644 (file)
@@ -77,17 +77,23 @@ int main(int argc, const char *argv[])
 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.
 
index 069e3b2ed38b2cf1c46036999a2d74767a483329..634e370706b4b0a31f5d94ef2667f3bc1332045f 100644 (file)
@@ -178,7 +178,7 @@ S:  Maintained
 
 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
@@ -234,6 +234,11 @@ M: kas@fi.muni.cz
 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 +305,19 @@ S:      Maintained
 
 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 +489,7 @@ S:  Maintained
 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 +553,7 @@ S:  Maintained
 
 INTEL P6 MICROCODE UPDATE SUPPORT
 P:     Tigran Aivazian
-M:     tigran@sco.com
+M:     tigran@veritas.com
 S:     Maintained
 
 IP MASQUERADING:
@@ -580,6 +593,13 @@ L: isdn4linux@listserv.isdn4linux.de
 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 +679,8 @@ S:  Maintained
 
 MISCELLANEOUS MCA-SUPPORT
 P:     David Weinehall
-M:     tao@acc.umu.se (personal)
+M:     Project MCA Team <mcalinux@acc.umu.se>
+M:     David Weinehall <tao@acc.umu.se>
 W:     http://www.acc.umu.se/~tao/
 W:     http://www.acc.umu.se/~mcalinux/
 L:     linux-kernel@vger.rutgers.edu
@@ -699,12 +720,12 @@ S:        Maintained
 
 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 +765,8 @@ S:      Maintained
 
 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 <jvbest@qv3pluto.leidenuniv.nl>
+M:     Andreas Mohr <100.30936@germany.net>
 L:     linux-net@vger.rutgers.edu
 S:     Maintained
 
@@ -793,12 +814,12 @@ M:        campbell@torque.net
 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 +1072,8 @@ P:        Torben Mathiasen
 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
index 755cc877a01a2ad8bf218003334a0601962cc80a..3c418f4ef0f8c75d57fb3ebc51ec716c8fe2c6f0 100644 (file)
@@ -49,7 +49,7 @@ ifdef CONFIG_M686
 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
 
@@ -61,6 +61,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
 
 SUBDIRS += arch/i386/kernel arch/i386/mm arch/i386/lib
index a928efb334840bb7bbca803ee990ca4908721018..c8af53dea6c439920a89874fb69a99a125eb303f 100644 (file)
@@ -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 @@ mainmenu_option next_comment
 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 @@ if [ "$CONFIG_M686" = "y" ]; then
    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 @@ if [ "$CONFIG_MCRUSOE" = "y" ]; then
    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 @@ if [ "$CONFIG_HIGHMEM64G" = "y" ]; then
    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
index 281a82cea24d763cccd1ac01775644b55090490a..8d785656dbfbfbe8c908d6ebb9e825ad78af5c2a 100644 (file)
@@ -19,10 +19,13 @@ CONFIG_UID16=y
 # 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_TSC=y
 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
@@ -148,6 +152,7 @@ CONFIG_SKB_LARGE=y
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
 # CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
 
 #
 # Telephony Support
index 2e220bc06ec702c36949e3f1eaa263481d589ec0..4e220dafb979c8606b28a30beafe1d331aaebd4e 100644 (file)
@@ -700,7 +700,7 @@ static int __init acpi_init_piix4(struct pci_dev *dev)
        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 @@ static int __init acpi_init_via(struct pci_dev *dev)
                if (!base)
                        return -ENODEV;
        }
-       base &= PCI_BASE_ADDRESS_IO_MASK;
 
        pci_read_config_byte(dev, 0x42, &irq);
 
@@ -824,7 +823,7 @@ const static struct
        {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 @@ static int acpi_enter_sx(acpi_sstate_t state)
 
        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 @@ static int acpi_enter_sx(acpi_sstate_t state)
        // 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;
index 0b4517137498aa97291b88fbb694318ef53be42b..c78a8f512d63b359ff69b62044ec2d65d2b1b06c 100644 (file)
  *         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 <pavel@suse.cz>
+ *         modified by sfr).
+ *         Disable interrupts while we are suspended (Andy Henroid
+ *         <andy_henroid@yahoo.com> fixed by sfr).
+ *         Make power off work on SMP again (Tony Hoyle
+ *         <tmh@magenta-logic.com> and <zlatko@iskon.hr>) modified by sfr.
  *
  * APM 1.1 Reference:
  *
@@ -864,19 +871,51 @@ static void reinit_timer(void)
 #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 @@ static apm_event_t get_event(void)
        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 @@ static void check_events(void)
                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 @@ static void check_events(void)
                        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 @@ static void check_events(void)
                        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 @@ static void check_events(void)
                        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 @@ static void apm_mainloop(void)
        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 @@ static void apm_mainloop(void)
                 * 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 @@ static void apm_mainloop(void)
                        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 @@ repeat:
                        schedule();
                        goto repeat;
                }
-               current->state = TASK_RUNNING;
+               set_current_state(TASK_RUNNING);
                remove_wait_queue(&apm_waitqueue, &wait);
        }
        i = count;
@@ -1199,8 +1214,10 @@ static int do_ioctl(struct inode * inode, struct file *filp,
                        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 @@ static int do_ioctl(struct inode * inode, struct file *filp,
                        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 @@ static int do_ioctl(struct inode * inode, struct file *filp,
                                        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 @@ static int do_release(struct inode * inode, struct file * filp)
                        as1->next = as->next;
        }
        kfree_s(as, sizeof(*as));
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
@@ -1276,13 +1294,10 @@ static int do_open(struct inode * inode, struct file * filp)
 {
        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 @@ static int apm(void *unused)
 
        strcpy(current->comm, "kapmd");
        sigfillset(&current->blocked);
+       current->tty = NULL;    /* get rid of controlling tty */
 
        if (apm_bios_info.version > 0x100) {
                /*
@@ -1487,27 +1503,15 @@ static int apm(void *unused)
 #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 @@ static int __init apm_setup(char *str)
 __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 @@ static int __init apm_init(void)
                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 @@ static void __exit apm_exit(void)
 {
        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);
index 53349bd0a665c002f8707e0e7d7b2ffaca047c80..0e48d44d34b95bcd4516aaa31abb1227c7b16b5c 100644 (file)
@@ -106,6 +106,7 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root,
                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 */
index dddd807c8469dedca8a8763df03b1db519abae11..e3edb7c2f878ad1984347dc30c0485688a907361 100644 (file)
@@ -471,7 +471,7 @@ void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
        return;
 }
 
-#ifdef CONFIG_X86_FX
+#ifdef CONFIG_X86_FXSR
 
 int i387_hard_to_user ( struct _fpstate * user,
                        struct i387_hard_struct * hard)
index 3ea101d6935872e6b9b9367df83d52434fbfb4fd..c59951cd18e331db4e292f2ef37ee0f092774ba7 100644 (file)
@@ -528,6 +528,7 @@ static inline void parse_mem_cmdline (char ** cmdline_p)
                                else {
                                        start_at = HIGH_MEMORY;
                                        mem_size -= HIGH_MEMORY;
+                                       usermem=0;
                                }
                                add_memory_region(start_at, mem_size, E820_RAM);
                        }
@@ -801,7 +802,7 @@ void __init setup_arch(char **cmdline_p)
        conswitchp = &dummy_con;
 #endif
 #endif
-#ifdef CONFIG_X86_FX
+#ifdef CONFIG_X86_FXSR
        if (boot_cpu_data.x86_capability & X86_FEATURE_FXSR)
        {
                printk("Enabling extended fast FPU save and restore ... ");
@@ -921,8 +922,8 @@ static int __init amd_model(struct cpuinfo_x86 *c)
        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 +1156,8 @@ static void __init centaur_model(struct cpuinfo_x86 *c)
                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 +1340,8 @@ static struct cpu_model_info cpu_models[] __initdata = {
        { 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 +1353,7 @@ static struct cpu_model_info cpu_models[] __initdata = {
            "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 +1370,30 @@ static struct cpu_model_info cpu_models[] __initdata = {
            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 +1402,32 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
                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 +1444,9 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
                        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 +1461,26 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
                                        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 +1520,14 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
 
                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 +1660,9 @@ int get_cpuinfo(char * buffer)
                                        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 +1722,18 @@ int get_cpuinfo(char * buffer)
        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 +1755,13 @@ void __init cpu_init (void)
 
        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));
index 6462f0fa2415202de60539f75d268a5fb70db355..50f9be663b850d43521eb80ebc76fdc9f64d16d6 100644 (file)
@@ -155,6 +155,7 @@ static long pm_address(u_char FPU_modrm, u_char segment,
 { 
   struct desc_struct descriptor;
   unsigned long base_address, limit, address, seg_top;
+  unsigned short selector;
 
   segment--;
 
@@ -174,12 +175,15 @@ static long pm_address(u_char FPU_modrm, u_char segment,
     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);
index 2d1a119800bf2138c580175208829fa61728b59d..3008c615288a07667132077a44be28096576fb35 100644 (file)
@@ -1,3 +1,6 @@
+# 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
index 4de6e4167daddfa77449016f15a2c22ac3d6f91a..9b686100a4ead21240b4e02d2c24b1ba9181b1ee 100644 (file)
@@ -2,7 +2,9 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/zorro.h>
+#include <asm/ptrace.h>
 #include <asm/amigahw.h>
+#include <asm/amigaints.h>
 #include <asm/amipcmcia.h>
 
 extern volatile u_short amiga_audio_min_period;
@@ -12,6 +14,7 @@ extern u_short amiga_audio_period;
  * 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_avail);
 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);
index 099119178641c59ca80185ab3b3400d9d9daf15c..58759ba3601a552dbf933c12159cb5d9fafaac30 100644 (file)
@@ -58,7 +58,7 @@ extern int cia_get_irq_list(struct ciabase *base, char *buf);
 /* 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 @@ int amiga_request_irq(unsigned int irq,
 
        /* 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 @@ void amiga_free_irq(unsigned int irq, void *dev_id)
                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 @@ void amiga_free_irq(unsigned int irq, void *dev_id)
                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 @@ void amiga_enable_irq(unsigned int irq)
        }
 
        /* 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 @@ void amiga_disable_irq(unsigned int irq)
        }
 
        /* 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 @@ void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server)
        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 */
index 1ea26c631b377cfdc1047f6781dd00953bdd4016..43df3f6c2278e9fa93187a3e99c334f2af9f187f 100644 (file)
@@ -42,7 +42,7 @@ void __init amiga_chip_init (void)
   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 */
index bc6eec37a9db0a5328d9464dbeb63990f1ba29fd..ab67c8a460a3b97f10c7919bf690bb34742bd117 100644 (file)
@@ -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
index 76a204f622d1c5202c0c51bba0acb0b4cacd4101..b84dbcf982080bf121a8e2a42802a2b5982b44c5 100644 (file)
@@ -67,10 +67,6 @@ CONFIG_AMIGA_FLOPPY=y
 # 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
index 5f010dd76c217c51cc019b6bf440f0246f6e4eac..7a6637a2eb132d27896e012c39c051067e4a8d5a 100644 (file)
@@ -111,6 +111,7 @@ long m68k_serial_console_init(void);
 #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;
index 4a7c20df35af911c234be95fffffc76b69095d7d..4c8c672fdcfbe5a1613c872daaefdadda827794d 100644 (file)
@@ -177,7 +177,7 @@ scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 #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 @@ scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
        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 @@ scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
        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 @@ scc_enet_timeout(struct net_device *dev)
                       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 @@ scc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
                 * full.
                 */
                if (cep->tx_full) {
+                       cep->tx_full = 0;
                        if (netif_queue_stopped(dev)) {
                                netif_wake_queue(dev);
                        }
@@ -385,6 +384,7 @@ scc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
                 * _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,
index c039a452c0d7c3113c88e0a0b378986faadf86e6..ff91c6a4552ef1c570647dc330fa841e34196b5c 100644 (file)
@@ -2461,6 +2461,8 @@ int __init rs_8xx_init(void)
                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;
index c975513f0fc8d616455a60b7fdc639d4925a90b2..4b871c230945f9825f90535548325e4bc532f581 100644 (file)
@@ -94,9 +94,9 @@ m8xx_cpm_reset(uint host_page_addr)
        */
        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.
        */
index 00a0d776fb32ded8227ea9a754804905f351bacb..4d95bc9ebf604f9bc9f2e98b8648e239070956a6 100644 (file)
@@ -263,8 +263,10 @@ scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
        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 @@ scc_enet_interrupt(void *dev_id)
                 * full.
                 */
                if (cep->tx_full) {
+                       cep->tx_full = 0;
                        if (netif_queue_stopped(dev))
                                netif_wake_queue(dev);
                }
@@ -835,7 +838,7 @@ int __init scc_enet_init(void)
 
                /* 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);
 
index f0036981ed389610fa7823ed2a6a6831cc3cb0ee..f69d0dfbdc142b087733fb3a2ee4016a672acc45 100644 (file)
@@ -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,
  * 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 <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#ifdef CONFIG_FEC_PACKETHOOK
+#include <linux/pkthook.h>
+#endif
 
 #include <asm/8xx_immap.h>
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 #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 @@ struct fec_enet_private {
        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 @@ static   ushort  my_enet_addr[] = { 0x0800, 0x3e26, 0x1559 };
  */
 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;
 
-       dev->tbusy = 0;
-       dev->interrupt = 0;
-       dev->start = 1;
+       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;
 
-       return 0;                                       /* Always succeed */
+       out:
+       fep->ph_lock = 0;
+
+       return retval;
 }
 
-static int
-fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+
+int
+fec_unregister_ph(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
+       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 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
                 * 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 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
        /* 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 @@ static  void
 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);
+       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);
+               }
 
-       /* 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;
+               /* 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 @@ for (;;) {
                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 @@ for (;;) {
         * 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 @@ for (;;) {
         * 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 @@ fec_enet_mii(struct net_device *dev)
        }
 
        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 @@ fec_enet_mii(struct net_device *dev)
 }
 
 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,198 +798,579 @@ mii_queue(int regval, void (*func)(int))
        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);
+
+       *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)
+{
+       printk("reg %u = 0x%04x\n", (mii_reg >> 18) & 0x1f, mii_reg & 0xffff);
+}
+#endif
 
-static void
-mii_relink(uint mii_reg)
+/* ------------------------------------------------------------------------- */
+/* The Level one LXT970 is used by many boards                              */
+
+#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)
 {
-       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");
+       struct fec_enet_private *fep = dev->priv;
+       volatile uint *s = &(fep->phy_status);
 
-               if (mii_saved_reg1 & 0x0010)
-                       printk(", remote fault");
-               if (mii_saved_reg1 & 0x0020)
-                       printk(", auto complete");
+       *s &= ~(PHY_STAT_SPMASK);
 
-               if (mii_reg & 0x0800)
-                       printk(", 100 Mbps");
+       if (mii_reg & 0x0800) {
+               if (mii_reg & 0x1000)
+                       *s |= PHY_STAT_100FDX;
                else
-                       printk(", 10 Mbps");
-
+                       *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;
+       *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 @@ int __init fec_enet_init(void)
        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 @@ int __init fec_enet_init(void)
        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 @@ int __init fec_enet_init(void)
 
        /* 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 @@ int __init fec_enet_init(void)
 
                /* 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 @@ int __init fec_enet_init(void)
        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; i<NMII-1; i++)
+               mii_cmds[i].mii_next = &mii_cmds[i+1];
+       mii_free = mii_cmds;
+
+       /* Configure all of port D for MII.
+       */
+       immap->im_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; i<RX_RING_SIZE; i++) {
+
+               /* Initialize the BD for every fragment in the page.
+               */
+               bdp->cbd_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 @@ int __init fec_enet_init(void)
        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; i<NMII-1; i++)
-               mii_cmds[i].mii_next = &mii_cmds[i+1];
-       mii_free = mii_cmds;
+       /* Whack a reset.  We should wait for this.
+       */
+       fecp->fec_ecntrl = 1;
+       udelay(10);
 
-       mii_startup_cmds();
+       /* Clear outstanding MII command interrupts.
+       */
+       fecp->fec_ievent = FEC_ENET_MII;
 
-       return 0;
-}
+       /* Enable MII command finihed interrupt 
+       */
+       fecp->fec_ivec = (FEC_INTERRUPT/2) << 29;
+       fecp->fec_imask = FEC_ENET_MII;
 
+       /* Set MII speed.
+       */
+       fecp->fec_mii_speed = fep->phy_speed;
+}
index 2ae320e7a5f70b1bbb1aca228d3cc00b9356dd4b..0c53be922105f7397044e702f98f96ca15b3f347 100644 (file)
@@ -101,11 +101,15 @@ static int serial_console_setup(struct console *co, char *options);
  */
 #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 @@ static struct serial_state rs_table[] = {
 #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 @@ int __init rs_8xx_init(void)
                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;
index 5ffd230a0d2b147eaa2da8a1b29e640ea202d438..9e946365ffeb86c329d65e991af5ad8111ff8643 100644 (file)
@@ -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 @@ mainmenu_option next_comment
 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
index aa0440919fc50f1670785fed6b334446fc475d50..459d51ebb3d11455d0347fdee9ed8c9f0bc6e9ed 100644 (file)
@@ -174,5 +174,4 @@ CONFIG_IBM_PARTITION=y
 #
 # Kernel hacking
 #
-# CONFIG_PROFILE is not set
 # CONFIG_REMOTE_DEBUG is not set
index b207d78aad863e9d6d0eaa113df376bc6855c1e5..71fbe46651063f40856469289302fb5eb9d97c69 100644 (file)
@@ -62,9 +62,6 @@ asmlinkage void name(struct pt_regs * regs, long error_code) \
         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);
index 0cdfc264afe4469b98a7016066ad7a7500c9bd7c..b7b6c3cc221c0cd9aa255b898fd516d0e5f6d3cc 100644 (file)
@@ -151,7 +151,6 @@ static int release_mouse(struct inode * inode, struct file * file)
 #if AMIGA_OLD_INT
        AMI_MSE_INT_OFF();
 #endif
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
@@ -162,10 +161,6 @@ static int release_mouse(struct inode * inode, struct file * file)
 
 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 @@ static int open_mouse(struct inode * inode, struct file * file)
        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 int open_mouse(struct inode * inode, struct file * file)
 }
 
 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)
index 41bb7ac159fdd0806a7366003e98e04b36b7bf71..15e21be68ccf7c86ecb51ec90f5a0ab26d892fa0 100644 (file)
@@ -186,8 +186,8 @@ static void amikeyb_rep(unsigned long ignore)
 
     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 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
        } 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);
index b41ec922998bda6b0a7c2b5bf99660b8938652b2..29614cfd96dec22d1fbbe436d510e9fc379fc725 100644 (file)
@@ -2104,6 +2104,13 @@ int __init rs_init(void)
        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 @@ void cleanup_module(void)
                free_page((unsigned long) tmp_buf);
                tmp_buf = NULL;
        }
+       release_mem_region(CUSTOM_PHYSADDR+0x30, 4);
 }
 #endif /* MODULE */
 
index 22379337427fec657ae86dc3f00e13bf7ceb1d2d..e515d0fa5bad2e67160a19e52747df48fa22c7f1 100644 (file)
@@ -86,25 +86,19 @@ static int release_mouse(struct inode * inode, struct file * file)
 {
        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)
index 641e66d497d1fc3dae937f90e30a67be1fc89dab..487c4820df69c02913860936aa947e5e1ac43ecb 100644 (file)
@@ -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;
index 4e69f8f4babbffac2f99d50d89a4a62d6559e89f..4b33e7433321a1ce298fbd3e6b0ac2d9ff5d6a48 100644 (file)
@@ -2290,10 +2290,13 @@ static void con_start(struct tty_struct *tty)
 
 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);
 }
 
 /*
index f663790db122e1789b097d66671bdcf014a7a2e6..8d8766b85a7fc951cf5ec9dab50e4db9d7f3d1c0 100644 (file)
@@ -357,17 +357,14 @@ static void dn_keyb_process_mouse_event(unsigned char mouse_data) {
                                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 @@ void write_keyb_cmd(u_short length, u_char *cmd) {
 
 }
 
-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){
index f9eae25eb6aa82809b29807e27c92afd59715122..5e9ef9360ac34bdfd0844d48a6e04c1aa49ce124 100644 (file)
@@ -107,7 +107,6 @@ static int close_mouse(struct inode * inode, struct file * file)
 {
        MSE_INT_OFF();
        free_irq(mouse_irq, NULL);
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
@@ -119,13 +118,12 @@ static int open_mouse(struct inode * inode, struct file * file)
 {
        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)
index c3148a9cc3c9aae935daa1ed5e312ca40bb492d4..e47817fae7a70490bfc52581ab2d804893cc20c4 100644 (file)
@@ -108,7 +108,6 @@ static int release_mouse(struct inode * inode, struct file * file)
 {
        MS_MSE_INT_OFF();
        free_irq(mouse_irq, NULL);
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
@@ -118,13 +117,12 @@ static int open_mouse(struct inode * inode, struct file * file)
                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)
index 8de8336d1b8d3bef298db97604d346dff9e4607b..fbbec0fb18505e2ad19199ad43ef6cb6d623b14d 100644 (file)
@@ -618,6 +618,8 @@ int mxser_init(void)
                                               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",
index 096cf6afb47c6e8bdfd3a673c28a3872cb294c0d..f221249284d9c58f8114319b92c808373a20e438 100644 (file)
@@ -151,7 +151,6 @@ static int release_qp(struct inode * inode, struct file * file)
                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 +195,6 @@ static int open_qp(struct inode * inode, struct file * file)
        }
 
        outb_p(AUX_ENABLE_DEV, qp_data);        /* Wake up mouse */
-       MOD_INC_USE_COUNT;
        return 0;
 }
 
@@ -290,6 +288,7 @@ repeat:
 }
 
 struct file_operations qp_fops = {
+       owner:          THIS_MODULE,
        read:           read_qp,
        write:          write_qp,
        poll:           poll_qp,
index ee986b3353c4d716a69ab0aa6a575f497a7fb34e..d716c54bd368bd64102f594bf2f7e3f6c3ed1da3 100644 (file)
@@ -355,7 +355,7 @@ static int __init rtrack_init(void)
                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 */
        
index b983ae8252fc606c39b8426dd98e1e1f144ab46a..9f0e1374c921c2d1c8f8ce1359d9c7f2402b3862 100644 (file)
  * 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.
index 29d4227ff5d5b53dca2055bed877663a641e9243..943ea6a6160fa7baff929cab306141a8fbdcafb3 100644 (file)
@@ -1957,7 +1957,10 @@ int __init register_PCI(int i, unsigned int bus, unsigned int device_fn)
        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 --git a/drivers/char/sbc60xxwdt.c b/drivers/char/sbc60xxwdt.c
new file mode 100644 (file)
index 0000000..a0bea62
--- /dev/null
@@ -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 <jakob@ostenfeld.dk>
+ *
+ *           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 <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+
+#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)
index f157d4e52c4786de52dcb47b7039a0cc1bf299b0..949aa9532b114fa2da745d1443781cd3314e8f2f 100644 (file)
@@ -2055,10 +2055,13 @@ static int configure_saa7146(struct pci_dev *dev, int num)
        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);
index 7ba9779243efe3a037d2a650696510ee36649cd9..3620f7e0785b12c0fb5d443708267c20038304ed 100644 (file)
@@ -62,7 +62,7 @@ struct vt_struct *vt_cons[MAX_NR_CONSOLES];
  */
 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 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                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 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
 
        case KDGETKEYCODE:
        case KDSETKEYCODE:
+               if(!capable(CAP_SYS_ADMIN))
+                       perm=0;
                return do_kbkeycode_ioctl(cmd, (struct kbkeycode *)arg, perm);
 
        case KDGKBENT:
index 95207337f363819088de31f15738a9b215a1f403..3d16f1ff153d4847f42523d9cfcd20bc02d9a1dc 100644 (file)
@@ -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
+O_TARGET := i2o.o
 
-ifeq ($(CONFIG_I2O_LAN),y)
-LX_OBJS += i2o_lan.o
-else
-  ifeq ($(CONFIG_I2O_LAN),m)
-  MX_OBJS += i2o_lan.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_SCSI),y)
-LX_OBJS += i2o_scsi.o
-else
-  ifeq ($(CONFIG_I2O_SCSI),m)
-  MX_OBJS += i2o_scsi.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
 
-ifeq ($(CONFIG_I2O_PROC),y)
-LX_OBJS += i2o_proc.o
-else
-  ifeq ($(CONFIG_I2O_PROC),m)
-  MX_OBJS += i2o_proc.o
-  endif
-endif
+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
 
index cebb79ac5d67c98bac8733430d72425a37e5e071..a81f851f7b5de08d08a0c22d33097c0b2731e38c 100644 (file)
@@ -92,7 +92,6 @@ o     Find the right way to associate drives/luns/busses
 Lan:   
 o      Performance tuning
 o      Test Fibre Channel code
-o      Fix lan_set_mc_list()
 
 Tape:
 o      Anyone seen anything implementing this ?
index 50537501ff3200e370c3d78aac4d0b535c03b792..b35ad165fd6e13f2e97e3971b16d8c955f8cebca 100644 (file)
@@ -25,10 +25,10 @@ deepak@csociety.purdue.edu
 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 @@ XII. Events
 
     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.
 
index c365b0a1200cceffeb533b0d10c9970e8697b6a6..14281f55fca048a081700c45b05665d89cfce8dd 100644 (file)
@@ -1575,7 +1575,7 @@ static struct block_device_operations i2ob_fops =
 static struct gendisk i2ob_gendisk = 
 {
        MAJOR_NR,
-       "i2ohd",
+       "i2o/hd",
        4,
        1<<4,
        i2ob,
index 5f51f6ca12ee145b8ea7b1c03440e5a6932a66d7..7a50f64e946dd4ac274c7f1c670d2adc26b20ae5 100644 (file)
@@ -161,8 +161,7 @@ static void i2o_cfg_reply(struct i2o_handler *h, struct i2o_controller *c, struc
 //             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 @@ static int cfg_open(struct inode *inode, struct file *file)
        open_files = tmp;
        spin_unlock_irqrestore(&i2o_config_lock, flags);
        
-       MOD_INC_USE_COUNT;
        return 0;
 }
 
@@ -873,7 +871,6 @@ static int cfg_release(struct inode *inode, struct file *file)
        }
        spin_unlock_irqrestore(&i2o_config_lock, flags);
 
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
@@ -894,6 +891,7 @@ static int cfg_fasync(int fd, struct file *fp, int on)
 
 static struct file_operations config_fops =
 {
+       owner:          THIS_MODULE,
        llseek:         cfg_llseek,
        read:           cfg_read,
        write:          cfg_write,
index d8cc9b2c050822858efbb8f1121cb3838cf721ed..d39e32529fed46646258a3030cd9c80e44de7586 100644 (file)
@@ -189,7 +189,8 @@ static int evt_q_len = 0;
  * 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 @@ static int i2o_core_evt(void *reply_data)
                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 @@ static int i2o_dyn_lct(void *foo)
                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 @@ static int i2o_dyn_lct(void *foo)
                        } 
                        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 @@ void i2o_run_queue(struct i2o_controller *c)
        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 @@ void i2o_run_queue(struct i2o_controller *c)
                m=(struct i2o_message *)bus_to_virt(mv);
                msg=(u32*)m;
 
-               count++;
-
                /*
                 *      Temporary Debugging
                 */
@@ -1148,7 +1146,6 @@ void i2o_run_queue(struct i2o_controller *c)
                /* That 960 bug again... */     
                if((mv=I2O_REPLY_READ32(c))==0xFFFFFFFF)
                        mv=I2O_REPLY_READ32(c);
-
        }               
 }
 
@@ -1281,7 +1278,6 @@ void i2o_report_controller_unit(struct i2o_controller *c, struct i2o_device *d)
        }
        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 @@ static int i2o_reset_controller(struct i2o_controller *c)
                 * 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 @@ int i2o_status_get(struct i2o_controller *c)
        
        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 @@ static void __init i2o_sys_init(void)
 {
        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 @@ rebuild_sys_tab:
         * 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 @@ rebuild_sys_tab:
        /* 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 @@ int i2o_activate_controller(struct i2o_controller *iop)
        /* 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 @@ int i2o_activate_controller(struct i2o_controller *iop)
                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 @@ int i2o_init_outbound_q(struct i2o_controller *c)
        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 @@ int i2o_online_controller(struct i2o_controller *iop)
 
        /* 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 @@ static int i2o_build_sys_table(void)
                 */
                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 @@ int i2o_post_this(struct i2o_controller *c, u32 *data, int len)
        }
        while(m==0xFFFFFFFF && (jiffies-t)<HZ);
        
-       
        if(m==0xFFFFFFFF)
        {
                printk(KERN_ERR "%s: Timeout waiting for message frame!\n",
@@ -2483,7 +2480,7 @@ int i2o_issue_params(int cmd, struct i2o_controller *iop, int tid,
        msg[8] = virt_to_bus(reslist);
 
        if((wait_status = i2o_post_wait(iop, msg, sizeof(msg), 10)))
-       return wait_status;     /* -DetailedStatus */
+               return wait_status;     /* -DetailedStatus */
 
        /*
         * Calculate number of bytes of Result LIST
@@ -2535,7 +2532,7 @@ int i2o_query_scalar(struct i2o_controller *iop, int tid,
                return size;    
 
        memcpy(buf, resblk+8, buflen);  /* cut off header */
-       return buflen < size ? buflen : size;
+       return size;
 }
 
 /*
@@ -2585,7 +2582,7 @@ int i2o_set_scalar(struct i2o_controller *iop, int tid,
  *             else return specific fields
  *                     ibuf contains fieldindexes
  *
- *     if oper == I2O_PARAMS_LIST_GET, gte form specific rows
+ *     if oper == I2O_PARAMS_LIST_GET, get from specific rows
  *             if fieldcount == -1 return all fields
  *                     ibuf contains rowcount, keyvalues
  *             else return specific fields
@@ -3053,9 +3050,8 @@ void i2o_report_status(const char *severity, const char *str, u32 *msg)
        i2o_report_common_status(req_status);
 
        if (cmd < 0x1F || (cmd >= 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 @@ int init_module(void)
                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 @@ void cleanup_module(void)
                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 @@ int __init i2o_init(void)
 {
        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 
@@ -3286,9 +3280,6 @@ int __init i2o_init(void)
 #ifdef CONFIG_I2O_BLOCK
        i2o_block_init();
 #endif
-#ifdef CONFIG_I2O_SCSI
-       i2o_scsi_init();
-#endif
 #ifdef CONFIG_I2O_LAN
        i2o_lan_init();
 #endif
index 90b252041ebc0bc60f28ae7a459a1321360d776c..9bc7d825f88fdb61594ff3c4d242b157d8482357 100644 (file)
@@ -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 u32 i2o_event_mask  = I2O_LAN_EVENT_MASK;
 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 @@ static struct i2o_handler i2o_lan_send_handler = {
        NULL,
        NULL,
        NULL,
-       "I2O Lan OSM send",
+       "I2O LAN OSM send",
        -1,
        I2O_CLASS_LAN
 };
@@ -97,7 +95,7 @@ static struct i2o_handler i2o_lan_receive_handler = {
        NULL,
        NULL,
        NULL,
-       "I2O Lan OSM receive",
+       "I2O LAN OSM receive",
        -1,
        I2O_CLASS_LAN
 };
@@ -108,7 +106,7 @@ static struct i2o_handler i2o_lan_handler = {
        NULL,
        NULL,
        NULL,
-       "I2O Lan OSM",
+       "I2O LAN OSM",
        -1,
        I2O_CLASS_LAN
 };
@@ -133,7 +131,6 @@ static void i2o_lan_handle_failure(struct net_device *dev, u32 *msg)
        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 @@ static void i2o_lan_send_post_reply(struct i2o_handler *h,
        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 @@ static void i2o_lan_receive_post_reply(struct i2o_handler *h,
                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 @@ static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop,
                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 @@ static void i2o_lan_release_buckets(struct net_device *dev, u32 *msg)
        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 @@ static void i2o_lan_handle_event(struct net_device *dev, u32 *msg)
        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 @@ static void i2o_lan_handle_event(struct net_device *dev, u32 *msg)
                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 @@ static void i2o_lan_handle_event(struct net_device *dev, u32 *msg)
                        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 @@ static void i2o_set_ddm_parameters(struct net_device *dev)
                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 @@ static int i2o_lan_open(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;
+       u32 mc_addr_group[64];
 
        MOD_INC_USE_COUNT;
 
@@ -756,6 +756,18 @@ static int i2o_lan_open(struct net_device *dev)
 
        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 @@ static void i2o_lan_tx_timeout(struct net_device *dev)
 /*
  * 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 @@ static int i2o_lan_sdu_send(struct sk_buff *skb, struct net_device *dev)
         * 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 @@ static int i2o_lan_packet_send(struct sk_buff *skb, struct net_device *dev)
        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 @@ static struct net_device_stats *i2o_lan_get_stats(struct net_device *dev)
        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];
-
-// This isn't safe yet in SMP. Needs to be async.
-// Seems to work in uniprocessor environment.
-
-return;
-
-//     read_lock_bh(&dev_mc_lock);
-       spin_lock(&dev->xmit_lock);
-       dev->xmit_lock_owner = smp_processor_id();
+       u32 msg[10]; 
+
+       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 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 <iop,tid> */
-
-               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 <iop,tid> */
-
-       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);
 }
 
 /*
index 17064a29a089eb6b4842d89667b2e62e2e905488..075f6438d4e7bfff71a4ff47c75abf595657399c 100644 (file)
@@ -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
 #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;
@@ -144,6 +144,8 @@ struct i2o_lan_local {
 
        spinlock_t tx_lock;
 
+       u32 max_size_mc_table;          /* max number of multicast addresses */
+
        /* LAN OSM configurable parameters are here: */
 
        u16 max_buckets_out;            /* max nbr of buckets to send to DDM */
index 0961d5624f7e1c1e4da057d7f5e3ec742023163e..6b646a1d8864b684238fef739acab1067957064f 100644 (file)
@@ -132,9 +132,9 @@ int __init i2o_pci_install(struct pci_dev *dev)
        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 @@ int __init i2o_pci_scan(void)
                        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);
index c059c05f42e0875965fdf5d105b72b5b82afdb15..c62d2849b11881aedb4d16b1d3b03147c37be1c2 100644 (file)
@@ -22,6 +22,7 @@ extern int i2o_scsi_abort(Scsi_Cmnd *);
 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,                               \
index c104253c7ca08fc90c30fe11ad9b9a144fcec255..4121de13323bc9b93aaa0a684525aa3a1d4ead58 100644 (file)
@@ -589,7 +589,8 @@ setup_gazelpci(struct IsdnCardState *cs)
        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;
index f2e7abf1027f88fe00a2ae53397767d9780fdd13..300bfb1f7e7f301cb857426af46db4ed3116adef 100644 (file)
@@ -1738,7 +1738,9 @@ __initfunc(int
                                                     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;
index b1b0fd8d4e6f98ccfcd5f1fc60530806bcefb627..a41536f22b60f0d446a4d5d04d33c93ea1eddfc1 100644 (file)
@@ -1130,13 +1130,14 @@ setup_netjet(struct IsdnCard *card))
        }
        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);
index 2cfbd146cf33e531cca22d7d116fb1f1a1e4c7c1..6639018bf6c9fcfb3c8f95eddbeabfe8e9640dae 100644 (file)
@@ -313,6 +313,8 @@ setup_niccy(struct IsdnCard *card))
                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 @@ setup_niccy(struct IsdnCard *card))
                                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");
index dd1c53d044beeefacc8e73af490b18a9e9ffc465..fc0b7ff9b3ccbd8e7ed38ae48aaba85458209482 100644 (file)
@@ -641,23 +641,22 @@ setup_sedlbauer(struct IsdnCard *card))
                }
                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",
index e90510b35a4d7980dc5e3c3b36823859a97417ba..692fbddcfa003837bc7b4bfe174e01c624e13406 100644 (file)
@@ -325,6 +325,8 @@ setup_telespci(struct IsdnCard *card))
                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");
index f9ce1767544f223eeafa358c5c74929415e261d2..46fe29f757d4961b55e37fff0ecdf2f87cc86f7e 100644 (file)
@@ -1009,8 +1009,11 @@ __initfunc(int setup_w6692(struct IsdnCard *card))
                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 @@ __initfunc(int setup_w6692(struct IsdnCard *card))
                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 @@ __initfunc(int setup_w6692(struct IsdnCard *card))
                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);
index eb3fed4d33a192293c24db725a42b16b410465c2..23b79ddd91645093bc5e6c4a3d28e25eb45d6efb 100644 (file)
@@ -84,7 +84,8 @@ search_cards(void)
        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 @@ search_cards(void)
                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 */
index 2be90eb6fad95840d94cdcca603da45bc0bf39d6..9bc7a08b04ea82dbb4274a85b031bca8a97d18f7 100644 (file)
@@ -307,8 +307,10 @@ isdn_audio_tlookup(const void *table, void *buff, unsigned long n)
        :       "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
 }
 
index 1e314128c3bc453d23cb59f6560b45d15fc97590..665ac46e8ba9cae487f0b038e8c8c30ab09a6d2e 100644 (file)
@@ -381,8 +381,14 @@ static int isdn_tty_countDLE(unsigned char *, int);
 #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] =
index 55de6fd6c737cdbbb9d31bdc49a97257cc55da51..3dc9b42f091c17821b80d23a45d3eff9cec124dc 100644 (file)
@@ -99,7 +99,7 @@ el2_probe(struct net_device *dev)
     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 @@ el2_probe(struct net_device *dev)
 #if ! defined(no_probe_nonshared_memory) && ! defined (HAVE_DEVLIST)
     return el2_pio_probe(dev);
 #else
-    return ENODEV;
+    return -ENODEV;
 #endif
 }
 
@@ -134,7 +134,7 @@ el2_pio_probe(struct net_device *dev)
     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 @@ el2_pio_probe(struct net_device *dev)
            return 0;
     }
 
-    return ENODEV;
+    return -ENODEV;
 }
 #endif
 
@@ -161,7 +161,7 @@ el2_probe1(struct net_device *dev, int ioaddr)
     /* 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 @@ el2_probe1(struct net_device *dev, int ioaddr)
     /* 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 @@ el2_probe1(struct net_device *dev, int ioaddr)
     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 @@ init_module(void)
 {
        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 @@ init_module(void)
                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 @@ cleanup_module(void)
                        kfree(priv);
                }
        }
-       unlock_8390_module();
+       unload_8390_module();
 }
 #endif /* MODULE */
 \f
index a59d69f5a3dc7633c36c9a72d23b3278ad60ecf7..eab61b55e9c2da32a829cda1762d16e5c59a7453 100644 (file)
@@ -315,7 +315,7 @@ int __init el16_probe(struct net_device *dev)
        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 @@ int __init el16_probe(struct net_device *dev)
                        return 0;
        }
 
-       return ENODEV;
+       return -ENODEV;
 }
 
 static int __init el16_probe1(struct net_device *dev, int ioaddr)
@@ -351,7 +351,7 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr)
                && 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 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr)
        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. */
index e52d1d4ee9d9a9d56fb7269018a7e521865de04f..4bd49bfe9e2cc280d379c9d116a0242fba72ffe9 100644 (file)
@@ -448,7 +448,7 @@ static int corkscrew_scan(struct net_device *dev)
                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 @@ static int boomerang_rx(struct net_device *dev)
                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) {
index d22b847a82bf531f5e8fb1eaf27f468bc4b8408e..9be7f31a8943ce0be7e3d1191aac63fcd039ed6a 100644 (file)
@@ -417,7 +417,7 @@ int __init elmc_probe(struct net_device *dev)
        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 @@ int __init elmc_probe(struct net_device *dev)
                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' */
 
index d90732d8a2bb221846c926d4423b57a6aeed03c6..776345f215dfd20e7e01b4e2007ceb6e665c2069 100644 (file)
@@ -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 <jdaniel@etresoft.com> said these work...)
     - Some extra diagnostics
     - In vortex_error(), reset the Tx on maxCollisions.  Otherwise most
       chips usually get a Tx timeout.
     - 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 <ilh@sls.lcs.mit.edu>)
+    - 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.
 */
 
  * 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 const int mtu = 1500;
 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 @@ static int extra_reset = 0;
  * 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 @@ static int vortex_debug = 1;
    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 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
 #include <asm/bitops.h>
 #include <asm/io.h>
 
-/* John Daniel <jdaniel@etresoft.com> 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 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
 #include <linux/delay.h>
 
 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 <becker@cesdis.gsfc.nasa.gov>");
+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 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(extra_reset, "i");
 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 @@ enum pci_flags_bit {
        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 @@ enum vortex_chips {
        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 @@ static struct vortex_chip_info {
        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 @@ static struct vortex_chip_info {
 
        {"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 @@ static struct vortex_chip_info {
         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 @@ static struct pci_device_id vortex_pci_tbl[] __devinitdata = {
        { 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 Window2 {                    /* Window 2. */
 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 @@ enum MasterCtrl {
 /* 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 @@ static int __devinit vortex_probe1(struct pci_dev *pdev,
        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 @@ static int __devinit vortex_probe1(struct pci_dev *pdev,
        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 @@ static int __devinit vortex_probe1(struct pci_dev *pdev,
        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 @@ static int __devinit vortex_probe1(struct pci_dev *pdev,
        /* 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 @@ static int __devinit vortex_probe1(struct pci_dev *pdev,
                }
 
                /* 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 @@ static int __devinit vortex_probe1(struct pci_dev *pdev,
        /* 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 @@ static int __devinit vortex_probe1(struct pci_dev *pdev,
                        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 @@ static int __devinit vortex_probe1(struct pci_dev *pdev,
                           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 int __devinit vortex_probe1(struct pci_dev *pdev,
 
        {
                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 ? "<invalid transceiver>" :
-                          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 ? "<invalid transceiver>" :
+                          media_tbl[XCVR(config)].name);
+               vp->default_media = XCVR(config);
+               vp->autoselect = AUTOSELECT(config);
        }
 
        if (vp->media_override != 7) {
@@ -1037,12 +1063,12 @@ static int __devinit vortex_probe1(struct pci_dev *pdev,
        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 @@ vortex_up(struct net_device *dev)
 {
        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 @@ vortex_up(struct net_device *dev)
        
        /* 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 @@ vortex_up(struct net_device *dev)
                           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 @@ vortex_up(struct net_device *dev)
 
        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 @@ vortex_up(struct net_device *dev)
        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 @@ vortex_up(struct net_device *dev)
                }
                outw(TxEnable, ioaddr + EL3_CMD);
        }
+       netif_start_queue (dev);
 }
 
 static int
@@ -1321,9 +1346,11 @@ static void vortex_timer(unsigned long data)
        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 @@ static void vortex_timer(unsigned long data)
                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 @@ static void vortex_timer(unsigned long data)
                         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 @@ static void vortex_timer(unsigned long data)
          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 @@ static void vortex_tx_timeout(struct net_device *dev)
        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 @@ static void vortex_tx_timeout(struct net_device *dev)
                }
        }
 
-       if (vortex_debug > 1)
+       if (vortex_debug > 0)
                dump_tx_ring(dev);
 
        wait_for_completion(dev, TxReset);
@@ -1481,8 +1509,10 @@ static void vortex_tx_timeout(struct net_device *dev)
                        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 @@ vortex_error(struct net_device *dev, int status)
                } else {
                        wait_for_completion(dev, TxReset);
                        outw(TxEnable, ioaddr + EL3_CMD);
+                       netif_wake_queue(dev);
                }
        }
 }
@@ -1875,9 +1906,15 @@ static void boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                        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 @@ static void boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                                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 @@ static void boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                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 @@ boomerang_rx(struct net_device *dev)
 
                        /* 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 @@ boomerang_rx(struct net_device *dev)
                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 @@ vortex_down(struct net_device *dev)
 
        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 @@ dump_tx_ring(struct net_device *dev)
                        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));
index c1b9701432ce642d4e7fe1bc4ddae92b6d12dea5..7bc5e03ce90424b6f7e783e22fd4b4de4acca150 100644 (file)
@@ -97,7 +97,7 @@ an MMIO register read.
 #include <asm/io.h>
 
 
-#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 @@ enum RTL8139_registers {
        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 @@ struct ring_info {
 
 typedef enum {
        CH_8139 = 0,
+       CH_8139_K,
        CH_8139A,
-       CH_8139A_G,
        CH_8139B,
        CH_8130,
        CH_8139C,
@@ -403,36 +404,36 @@ typedef enum {
 /* 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 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
        }
        
        /* 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 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
        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 @@ static void rtl8139_hw_start (struct net_device *dev)
        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 @@ static void rtl8139_hw_start (struct net_device *dev)
        /* 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);
 
-       if (tp->chipset > CH_8139) {
+       tp->cur_rx = 0;
+
+       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 @@ static void rtl8139_hw_start (struct net_device *dev)
        /* 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 @@ static void rtl8139_timer (unsigned long data)
 
        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 @@ static void rtl8139_timer (unsigned long data)
                                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 @@ static void rtl8139_rx_interrupt (struct net_device *dev,
                        } 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);
index 416e9ce948de17a30665961cb809549633b503c6..1957b189f69f499fe70168f9fed9ad67ecabfcbb 100644 (file)
@@ -1152,17 +1152,13 @@ EXPORT_SYMBOL(ei_interrupt);
 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 */
index 068ead40df2472f58b5a12987cded9686023f907..715c95501ca884015d14f1e8a832b40fc232314b 100644 (file)
@@ -53,24 +53,49 @@ extern unsigned long autoirq_report(int waittime);
 #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 @@ extern __inline__ int load_8390_module(const char *driver)
                        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 @@ extern __inline__  void unlock_8390_module(void)
 #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);
index 43c9d00affc553f1bf0ed8e4df6d59ede8823426..7592e0bc8bc7f918a37a0090dd6582ba71a4485b 100644 (file)
@@ -49,7 +49,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
       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 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
       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 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
          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_NET_ETHERNET" = "y" ]; then
    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,15 +183,16 @@ endmenu
 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
@@ -223,7 +225,7 @@ if [ ! "$CONFIG_PPP" = "n" ]; then
    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
 
index 35e8aff805f3015daf6a8d6959efb40057518014..006cb2a8ada9a5975386d7066ac43db62e824d67 100644 (file)
@@ -83,16 +83,8 @@ else
   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_EL1) += 3c501.o
 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
index de0946642196eb48872f5b6c74a6dae734d49930..51201c557e002abf6e30a7ef58e46ee51e8404bf 100644 (file)
@@ -86,8 +86,6 @@ extern int smc_init( struct net_device * );
 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 *);
@@ -331,12 +329,6 @@ struct devprobe m68k_probes[] __initdata = {
 #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},
 #endif
index 25364d9207fa35f950e858a92bab85092ee024cd..a89bff2b8704bbeb7947f3cfe6a8f08d26ed1df7 100644 (file)
@@ -132,8 +132,14 @@ struct lance_private {
        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 void lance_set_multicast (struct net_device *dev)
 
 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 @@ static int __init a2065_probe(void)
 
                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 @@ static int __init a2065_probe(void)
                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 @@ static int __init a2065_probe(void)
                       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 @@ static int __init a2065_probe(void)
                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
 }
 
index e86be3824f2e1fe21af4accc4ebc20d414d4d030..5551311f38e01bc86136313639f6cb2e597eac7f 100644 (file)
@@ -102,10 +102,10 @@ int __init ac3200_probe(struct net_device *dev)
        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 @@ int __init ac3200_probe(struct net_device *dev)
                        return 0;
        }
 
-       return ENODEV;
+       return -ENODEV;
 }
 
 static int __init ac_probe1(int ioaddr, struct net_device *dev)
@@ -151,7 +151,7 @@ static int __init ac_probe1(int ioaddr, struct net_device *dev)
                || 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 @@ static int __init ac_probe1(int ioaddr, struct net_device *dev)
                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 @@ static int __init ac_probe1(int ioaddr, struct net_device *dev)
                        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 @@ static int __init ac_probe1(int ioaddr, struct net_device *dev)
                        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 @@ init_module(void)
 {
        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 @@ init_module(void)
                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 @@ cleanup_module(void)
                        kfree(priv);
                }
        }
-       unlock_8390_module();
+       unload_8390_module();
 }
 #endif /* MODULE */
 \f
index 5bbef8a553d4a05d6620ef43a1492c433d9d2282..ea256f78981471afd2daea6ec3e951edeea1821c 100644 (file)
@@ -98,6 +98,8 @@ int awc4500_pci_probe(struct net_device *dev)
                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;
index 83012de44910e67cea8da76c934240462b75c9ed..91f6313d16b2ced6a66404de2b22d8aa624fbca0 100644 (file)
@@ -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 @@ write_rreg (unsigned long base, unsigned int reg, unsigned short val)
                " : : "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 @@ write_ireg (unsigned long base, unsigned int reg, unsigned short val)
                "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 @@ am_writebuffer(struct net_device *dev, unsigned int offset, unsigned char *buf,
        }
 }
 
-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 @@ am_readword (struct net_device *dev, unsigned long off)
 }
 
 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 @@ static void
 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 @@ am79c961_init_for_open(struct net_device *dev)
        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 @@ am79c961_close(struct net_device *dev)
 
        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 @@ static void am79c961_setmulticastlist (struct net_device *dev)
        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 @@ am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev)
        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 @@ am79c961_rx(struct net_device *dev, struct dev_priv *priv)
                        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 @@ static void
 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 @@ am79c961_tx(struct net_device *dev, struct dev_priv *priv)
                        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 @@ am79c961_tx(struct net_device *dev, struct dev_priv *priv)
        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 @@ am79c961_hw_init(struct net_device *dev)
 
        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);
 
index 33da607fe7220cae9d07ca6d45a9be4901471290..af1e5de112d01d73250350f44ea01e9431b527c7 100644 (file)
@@ -178,9 +178,6 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr)
                 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 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr)
        stop_page = (wordlength == 2) ? 0x40 : 0x20;
     } else {
        printk(" not found.\n");
-       return ENXIO;
+       return -ENXIO;
 
     }
 
@@ -572,12 +569,16 @@ static struct net_device apne_dev =
 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 @@ void cleanup_module(void)
 
        pcmcia_reset();
 
-       unlock_8390_module();
+       unload_8390_module();
 
        apne_owned = 0;
 }
index ee1c90c0270b41eaac3332688e022db92e4495e4..e5a60310c1e157e18187492ad5d52f242f992f7a 100644 (file)
@@ -224,6 +224,7 @@ static int dma=0;
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/dma.h>
+#include <asm/io.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 
index 89d5fd599ba981af0f6a40bcb3ae6ed85d024115..f4a3835be98e0b3a72b758440d39fa68bb7c80c1 100644 (file)
@@ -104,7 +104,8 @@ struct ariadne_private {
     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 @@ struct lancedata {
     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 @@ static void memcpyw(volatile u_short *dest, u_short *src, int len)
 }
 
 
-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 @@ int __init ariadne_probe(struct net_device *dev)
 
        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 @@ static int ariadne_open(struct net_device *dev)
     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 @@ static int ariadne_open(struct net_device *dev)
     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 @@ static void ariadne_init_ring(struct net_device *dev)
     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 @@ static int ariadne_close(struct net_device *dev)
     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 @@ static int ariadne_close(struct net_device *dev)
 
     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 @@ static void ariadne_interrupt(int irq, void *data, struct pt_regs *fp)
     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 @@ static void ariadne_interrupt(int irq, void *data, struct pt_regs *fp)
            }
 #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 @@ static void ariadne_interrupt(int irq, void *data, struct pt_regs *fp)
        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 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev)
     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 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev)
     }
 #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 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
     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 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
     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 @@ static int ariadne_rx(struct net_device *dev)
     /* 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 @@ static struct net_device_stats *ariadne_get_stats(struct net_device *dev)
     lance->RAP = saved_addr;
     restore_flags(flags);
 
-    return(&priv->stats);
+    return &priv->stats;
 }
 
 
@@ -809,6 +787,11 @@ static void set_multicast_list(struct net_device *dev)
 {
     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 @@ static void set_multicast_list(struct net_device *dev)
 
     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 =
+static void __exit ariadne_cleanup(void)
 {
-    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)
-{
-    int err;
-
-    if ((err = register_netdev(&ariadne_dev))) {
-       if (err == -EIO)
-           printk("No Ariadne board found. Module not loaded.\n");
-       return(err);
+#ifdef MODULE
+    struct ariadne_private *next;
+    struct net_device *dev;
+
+    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);
index 14ab3f3214cbce34cfa59a8918e683e7f5230cfe..c736c04107950d5d40aaeb409e450fb5bdb1a667 100644 (file)
@@ -113,9 +113,6 @@ static int __init ariadne2_init(struct net_device *dev, unsigned long board)
     };
     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 @@ static void ariadne2_get_8390_hdr(struct net_device *dev,
     /* 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 @@ static void ariadne2_block_input(struct net_device *dev, int count,
     /* 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 @@ static void ariadne2_block_output(struct net_device *dev, int count,
     /* 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 @@ static struct net_device ariadne2_dev =
 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 @@ void cleanup_module(void)
     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 */
index 846db3d8e716a81a8b93d32c3cd5a637afb8996a..8636bfa11f234f28a0e296b9db6d83e212c74824 100644 (file)
@@ -1091,14 +1091,14 @@ int __init arlan_probe_everywhere(struct net_device *dev)
        {
                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 @@ int __init arlan_probe(struct net_device *dev)
        printk("Arlan driver %s\n", arlan_version);
 
        if (arlan_probe_everywhere(dev))
-               return ENODEV;
+               return -ENODEV;
 
        arlans_found++;
 
index b59131a62707e666136f51338e14dbc6b55ef1a2..67f8dbd3ff44a98a12c10667f88c88c477c0006b 100644 (file)
@@ -206,7 +206,7 @@ int at1700_probe(struct net_device *dev)
        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 @@ int at1700_probe(struct net_device *dev)
                if (at1700_probe1(dev, ioaddr) == 0)
                        return 0;
        }
-       return ENODEV;
+       return -ENODEV;
 }
 #endif
 
index cb8b20918f753d8639ed61b331119aee7c0acf12..b0d8e73d46e03a6d3342461f09e24f0f68d235e0 100644 (file)
@@ -332,7 +332,7 @@ bionet_probe(struct net_device *dev){
        int i;
 
        if (!MACH_IS_ATARI || no_more_found)
-               return ENODEV;
+               return -ENODEV;
 
        printk("Probing for BioNet 100 Adapter...\n");
 
@@ -350,12 +350,12 @@ bionet_probe(struct net_device *dev){
        ||  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);
 
index 38effe36d0deacc41b37f2cf02c1693b2b767b34..f9b1eef796916dd40d144981bfe9127d86d7233b 100644 (file)
@@ -574,7 +574,7 @@ pamsnet_probe (dev)
        static int no_more_found = 0;
 
        if (no_more_found)
-               return ENODEV;
+               return -ENODEV;
 
        no_more_found = 1;
 
@@ -619,7 +619,7 @@ pamsnet_probe (dev)
                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);
 
index cfb2fdefd41b4722d93c13dd529a010d20e0fd4e..39939746dc3cf74d691d05908b5c9396c22d5554 100644 (file)
@@ -162,7 +162,7 @@ int __init atp_init(struct net_device *dev)
        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 @@ int __init atp_init(struct net_device *dev)
                        return 0;
        }
 
-       return ENODEV;
+       return -ENODEV;
 }
 
 static int __init atp_probe1(struct net_device *dev, short ioaddr)
index b1234af8d3fa25987d08eef8cb30304a6f6b8aef..67f076d460240d205ae6970ae6ce2f270e9f522a 100644 (file)
@@ -85,35 +85,49 @@ static int bond_open(struct net_device *dev)
        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 @@ static int bond_release(struct net_device *master, struct net_device *dev)
        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 @@ static int bond_xmit(struct sk_buff *skb, struct net_device *dev)
                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;
 
index 3153a692ea99bc9064983eb8ca3248df8dc34527..841b314ee8fa4d4cdee48b1f7215380a69adebb2 100644 (file)
@@ -238,7 +238,7 @@ int __init cs89x0_probe(struct net_device *dev)
        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 @@ int __init cs89x0_probe(struct net_device *dev)
                        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 @@ cs89x0_probe1(struct net_device *dev, int ioaddr)
        if (ioaddr & 1) {
                ioaddr &= ~1;
                if ((inw(ioaddr + ADD_PORT) & ADD_MASK) != ADD_SIG)
-                       return ENODEV;
+                       return -ENODEV;
                outw(PP_ChipID, ioaddr + ADD_PORT);
        }
 
index 724369bb8fcd20dec222232204d8c87a0e9220a6..f94b189fb75e5eb60141d6fd9e8263d622b1f34a 100644 (file)
@@ -633,6 +633,7 @@ int __init ns8390_probe1(struct net_device *dev, int word16, char *model_name,
 
 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 @@ static int ns8390_open(struct net_device *dev)
        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;
 }
 
index ceddc07c3b91234917a58728486100eda5802862..e136e01324085edc13cbab6d5ffd4245b6858714 100644 (file)
@@ -2229,7 +2229,7 @@ pci_probe(struct net_device *dev, u_long ioaddr)
        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 @@ srom_search(struct pci_dev *dev)
        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;
index 9e9abe7041e1a2653785c3f5db600eb644dd168e..b81074ee06fb2a62a057fd0b7b494c3743ab6306 100644 (file)
@@ -650,7 +650,7 @@ de600_probe(struct net_device *dev)
        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 @@ de600_probe(struct net_device *dev)
                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");
index 43541521226d9cebc30f703725b955d71b413ae0..22a41cd042441911d19bfdee495903ec13f6a4c5 100644 (file)
@@ -834,13 +834,13 @@ int __init de620_probe(struct net_device *dev)
 
        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");
index 00fb093410c56cff71781fb33858d0885190306f..1a8fedb5d924001f0c487045ce772aaa596ec2ba 100644 (file)
@@ -500,6 +500,9 @@ int __init dfx_probe(void)
                                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 @@ int __init dfx_probe(void)
 
                                /* 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 */
 
index 428f0cabd0bc4435d0d86368da5aa27917cc6272..a947845d81e45cc39a12096787897e52c14ec14d 100644 (file)
@@ -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 <linux/version.h>
 #include <linux/module.h>
@@ -206,7 +206,7 @@ typedef struct
         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 @@ dgrs_probe1(struct net_device *dev)
         */
        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);
 
index 6d44ab654ef7c63f3cfd3bc33db882a23b4f41f5..d0f4257daab18b2c870883b6a1c85d06a49d0c27 100644 (file)
 #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)
 
@@ -359,15 +359,16 @@ static int __init dmfe_probe(void)
                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))
+               if ((net_dev->device != PCI_DM9102_ID) && (net_dev->device != PCI_DM9132_ID))
                        continue;
 
-               pci_iobase = net_dev->resource[0].start;
+               pci_iobase = pci_resource_start (net_dev, 0);
                pci_irqline = net_dev->irq;
                                
                /* Enable Master/IO access, Disable memory access */
                
-               pci_enable_device (net_dev); /* XXX check return val */
+               if (pci_enable_device(net_dev))
+                       continue;
                pci_set_master(net_dev);
                
                /* Set Latency Timer 80h */
@@ -382,7 +383,6 @@ static int __init dmfe_probe(void)
                
                /* 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 */
index d31aac565658df1614f3944821411496ed259dc9..ab425dfee78d9b80b50d71f85163136a0c01f202 100644 (file)
@@ -125,7 +125,7 @@ int  __init e2100_probe(struct net_device *dev)
        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 @@ int  __init e2100_probe(struct net_device *dev)
                        return 0;
        }
 
-       return ENODEV;
+       return -ENODEV;
 }
 
 int __init e21_probe1(struct net_device *dev, int ioaddr)
@@ -147,14 +147,14 @@ int __init e21_probe1(struct net_device *dev, int ioaddr)
        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 @@ int __init e21_probe1(struct net_device *dev, int ioaddr)
        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 @@ int __init e21_probe1(struct net_device *dev, int ioaddr)
                        }
                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 @@ e21_open(struct net_device *dev)
        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 @@ init_module(void)
 {
        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 @@ init_module(void)
                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 @@ cleanup_module(void)
                        kfree(priv);
                }
        }
-       unlock_8390_module();
+       unload_8390_module();
 }
 #endif /* MODULE */
 \f
index ebbe5742ee31e5e60d1c7475e6e34e9b2ca30d93..fa7a5befd1b49d6ff0be8096a8660e500176509b 100644 (file)
@@ -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 <linux/module.h>
 
@@ -174,6 +176,7 @@ static unsigned int net_debug = NET_DEBUG;
 #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 struct enet_statistics *eepro_get_stats(struct net_device *dev);
 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 @@ it is reset to the default of 24K, and, hence, 8K for the trasnmit
 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 @@ buffer (transmit-buffer = 32K - receive-buffer).
 #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 @@ buffer (transmit-buffer = 32K - receive-buffer).
 #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 @@ buffer (transmit-buffer = 32K - receive-buffer).
 #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 @@ int __init eepro_probe(struct net_device *dev)
                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 @@ int __init eepro_probe(struct net_device *dev)
                        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_SIZE; i++)
-               j+=read_eeprom(ioaddr,i);
+               j+=read_eeprom(ioaddr,i,dev);
        printk("Checksum: %#x\n",j&0xffff);
 
-       Word=read_eeprom(ioaddr, 0);
+       Word=read_eeprom(ioaddr, 0, dev);
        printk(KERN_DEBUG "Word0:\n");
        printk(KERN_DEBUG " Plug 'n Pray: %d\n",GetBit(Word,ee_PnP));
        printk(KERN_DEBUG " Buswidth: %d\n",(GetBit(Word,ee_BusWidth)+1)*8 );
@@ -511,7 +593,7 @@ void printEEPROMInfo(short ioaddr)
        printk(KERN_DEBUG " IO Address: %#x\n", (Word>>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 @@ void printEEPROMInfo(short ioaddr)
                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 @@ void printEEPROMInfo(short ioaddr)
        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 @@ int eepro_probe1(struct net_device *dev, short ioaddr)
 {
        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 @@ int eepro_probe1(struct net_device *dev, short ioaddr)
 
        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 @@ int eepro_probe1(struct net_device *dev, short ioaddr)
                        (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);
+
+                       /* 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);
 
-                       /* 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 */
+                       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 @@ int eepro_probe1(struct net_device *dev, short ioaddr)
                                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 @@ int eepro_probe1(struct net_device *dev, short ioaddr)
                                
                        /* ............... */
 
-                       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 @@ int eepro_probe1(struct net_device *dev, short ioaddr)
 
 
                        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 @@ int eepro_probe1(struct net_device *dev, short ioaddr)
                                                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 @@ int eepro_probe1(struct net_device *dev, short ioaddr)
                                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 @@ int eepro_probe1(struct net_device *dev, short ioaddr)
                        /* 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 @@ int eepro_probe1(struct net_device *dev, short ioaddr)
 
                        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 @@ static int        eepro_grab_irq(struct net_device *dev)
        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 @@ static int eepro_open(struct net_device *dev)
 {
        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 @@ static int eepro_open(struct net_device *dev)
 
        /* 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 @@ static int eepro_open(struct net_device *dev)
                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 @@ static int eepro_open(struct net_device *dev)
        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 @@ static int eepro_open(struct net_device *dev)
        /* 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 @@ static int eepro_open(struct net_device *dev)
        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 @@ static int eepro_open(struct net_device *dev)
                        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 @@ static int eepro_open(struct net_device *dev)
                }
        }
        
-       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 @@ static int eepro_open(struct net_device *dev)
        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 @@ static void eepro_tx_timeout (struct net_device *dev)
 {
        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 @@ static void eepro_tx_timeout (struct net_device *dev)
        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 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev)
                lp->stats.tx_bytes+=skb->len;
 
                hardware_send_packet(dev, buf, length);
+
                dev->trans_start = jiffies;
 
        }
@@ -1053,31 +1166,34 @@ eepro_interrupt(int irq, void *dev_id, struct pt_regs * regs)
        
        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 @@ static int eepro_close(struct net_device *dev)
 {
        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 @@ static int eepro_close(struct net_device *dev)
 
        /* 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 @@ set_multicast_list(struct net_device *dev)
                 */
                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 @@ set_multicast_list(struct net_device *dev)
                /* 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 @@ set_multicast_list(struct net_device *dev)
                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 @@ set_multicast_list(struct net_device *dev)
                } 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 @@ set_multicast_list(struct net_device *dev)
 #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 @@ read_eeprom(int ioaddr, int location)
        eeprom_delay();
        outb(ctrl_val, ee_addr);
        eeprom_delay();
-       outb(BANK0_SELECT, ioaddr);
+       eepro_sw2bank0(ioaddr);
        return retval;
 }
 
@@ -1320,7 +1440,6 @@ hardware_send_packet(struct net_device *dev, void *buf, short length)
 {
        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 @@ hardware_send_packet(struct net_device *dev, void *buf, short length)
                /* 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 @@ hardware_send_packet(struct net_device *dev, void *buf, short length)
                        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 @@ hardware_send_packet(struct net_device *dev, void *buf, short length)
                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 @@ hardware_send_packet(struct net_device *dev, void *buf, short length)
 
                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 @@ static void
 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 @@ eepro_rx(struct net_device *dev)
 
        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 @@ eepro_transmit_interrupt(struct net_device *dev)
        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 @@ eepro_transmit_interrupt(struct net_device *dev)
                        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 @@ eepro_transmit_interrupt(struct net_device *dev)
                        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_DESCRIPTION("Intel i82595 ISA EtherExpressPro10/10+ driver");
 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;
 
index 048f7edd1657bd8343d938dad41e0a5537b79304..10477c624446cd756829f4b289371c6edf8183ca 100644 (file)
@@ -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 <saw@saw.sw.com.sg>.
+       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 <saw@saw.sw.com.sg>.
-       Please use this email address and linux-kernel mailing list for bug reports.
-
        Version history:
        1998 Apr - 2000 Feb  Andrey V. Savochkin <saw@saw.sw.com.sg>
                Serious fixes for multicast filter list setting, TX timeout routine;
                Convert to new PCI driver interface
        2000 Mar 24  Dragan Stancevic <visitor@valinux.com>
                Disabled FC and ER, to avoid lockups when when we get FCP interrupts.
-               Dragan Stancevic <visitor@valinux.com> 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 <saw@saw.sw.com.sg> and others\n";
+"eepro100.c: $Revision: 1.33 $ 2000/05/24 Modified by Andrey V. Savochkin <saw@saw.sw.com.sg> 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 @@ extern inline void pci_dma_sync_single(struct pci_dev *hwdev,
 }
 #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 @@ having to sign an Intel NDA when I'm helping Intel sell their own product!
 
 */
 
-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 @@ static inline void wait_for_cmd_done(long cmd_ioaddr)
        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 @@ enum commands {
 #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 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev,
 
        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 @@ err_out_none:
 }
 
 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 @@ static int speedo_found1(struct pci_dev *pdev,
           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 @@ static int speedo_found1(struct pci_dev *pdev,
                        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 @@ static int speedo_found1(struct pci_dev *pdev,
                                   "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 @@ static int speedo_found1(struct pci_dev *pdev,
 #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 @@ static int speedo_found1(struct pci_dev *pdev,
        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 @@ static int speedo_found1(struct pci_dev *pdev,
 #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
+   <visitor@valinux.com> 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 @@ static void speedo_timer(unsigned long data)
                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 @@ static void speedo_timer(unsigned long data)
        /* 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 @@ static void speedo_show_state(struct net_device *dev)
                           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 @@ static void speedo_purge_tx(struct net_device *dev)
        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 @@ static void speedo_tx_timeout(struct net_device *dev)
                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 @@ static void speedo_tx_timeout(struct net_device *dev)
                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 @@ static void speedo_tx_timeout(struct net_device *dev)
                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 @@ speedo_start_xmit(struct sk_buff *skb, struct net_device *dev)
                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 @@ speedo_get_stats(struct net_device *dev)
                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 @@ static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        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:
@@ -2206,6 +2242,10 @@ static struct pci_device_id eepro100_pci_tbl[] __devinitdata = {
                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,}
 };
 MODULE_DEVICE_TABLE(pci, eepro100_pci_tbl);
index b96da10ddf1e2daf5694979c1e796e5a2e3b7fd9..f8cf5004aa7cd79803dba7b8f62bf1c803e21a32 100644 (file)
@@ -396,7 +396,7 @@ int __init express_probe(struct net_device *dev)
        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 @@ static int __init eexp_hw_probe(struct net_device *dev, unsigned short ioaddr)
 
        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 @@ static int __init eexp_hw_probe(struct net_device *dev, unsigned short ioaddr)
        default:
                printk(") bad memory size (%dk).\n", memory_size);
                kfree(dev->priv);
-               return ENODEV;
+               return -ENODEV;
                break;
        }
 
index 6e6af292f8d377a41ccf4fb85b0d668ad74ebceb..0a5f229b9739f7218911fdd4e1076aa6e630233e 100644 (file)
@@ -384,6 +384,8 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
                        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 @@ static int epic_rx(struct net_device *dev)
                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 @@ static void __devexit epic_remove_one (struct pci_dev *pdev)
 {
        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 @@ static void epic_suspend (struct pci_dev *pdev)
        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);
@@ -1328,9 +1324,6 @@ static void epic_resume (struct pci_dev *pdev)
 {
        struct net_device *dev = pdev->driver_data;
 
-       if (!dev)
-               BUG();
-
        epic_restart (dev);
 }
 
index 2327ffad41146cf9c366af58de3d076141179b96..cabe97e14693a6df2a1aa5f8b606098df98bd296 100644 (file)
@@ -181,9 +181,6 @@ int __init es_probe1(struct net_device *dev, int ioaddr)
                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 @@ init_module(void)
 {
        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 @@ init_module(void)
                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 @@ cleanup_module(void)
                        kfree(priv);
                }
        }
-       unlock_8390_module();
+       unload_8390_module();
 }
 #endif /* MODULE */
index 56f2600d0fa7e7c84d7c5240e97ee1326519b9b6..96d8058b8d421254ca6547446147f8926cbf66ac 100644 (file)
@@ -448,7 +448,7 @@ int __init eth16i_probe(struct net_device *dev)
        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 @@ int __init eth16i_probe(struct net_device *dev)
                        return 0;
        }
 
-       return ENODEV;
+       return -ENODEV;
 }
 
 static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
index 28d50eb8c2c87fc4788bf8c65b6f8494d5a4e75d..83a87a635bf164d018c4a26009ec2285c198d220 100644 (file)
@@ -3771,7 +3771,9 @@ struct pci_dev *pdev = NULL;
 
        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 @@ struct pci_dev *pdev = NULL;
                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]);
index b26351886ccea5a4e4ddaadbc36a45d7e5729f1a..2d4cfa29899750bb7aed35d18e31ad98c7eae694 100644 (file)
@@ -137,7 +137,7 @@ int __init fmv18x_probe(struct net_device *dev)
        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 @@ int __init fmv18x_probe(struct net_device *dev)
                        return 0;
        }
 
-       return ENODEV;
+       return -ENODEV;
 }
 
 /* The Fujitsu datasheet suggests that the NIC be probed for by checking its
@@ -194,7 +194,7 @@ int __init fmv18x_probe1(struct net_device *dev, short ioaddr)
        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. */
index 220c4d920290f1368a4e5888648a0562a8f3f5d3..4f0150c37f89ffb33dba03e2871273db27ea3dd2 100644 (file)
@@ -1378,7 +1378,7 @@ static int pi_probe(struct net_device *dev, int card_type)
            if (irqval) {
                printk(KERN_ERR "PI: unable to get IRQ %d (irqval=%d).\n",
                       dev->irq, irqval);
-               return EAGAIN;
+               return -EAGAIN;
            }
        }
 
index 8baff63ff503d5b05f2e65cef8b048bb4d367240..37cd118a4af45584a0b0362a8578a1a28a07f8ed 100644 (file)
@@ -833,7 +833,7 @@ static int pt_probe(struct net_device *dev)
             if (irqval) {
                 printk(KERN_ERR "PT: ERROR: Unable to get IRQ %d (irqval = %d).\n",
                     dev->irq, irqval);
-                return EAGAIN;
+                return -EAGAIN;
             }
         }
 
index 7afe9bf4462041871cf9cbf3fa86f8e579e409e7..71952f54e14edc278e089960e5f746024b2ee2b1 100644 (file)
@@ -131,7 +131,7 @@ int __init hp_plus_probe(struct net_device *dev)
        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 @@ int __init hp_plus_probe(struct net_device *dev)
                        return 0;
        }
 
-       return ENODEV;
+       return -ENODEV;
 }
 #endif
 
@@ -157,10 +157,7 @@ int __init hpp_probe1(struct net_device *dev, int ioaddr)
        /* 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 @@ int __init hpp_probe1(struct net_device *dev, int ioaddr)
 
        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 @@ init_module(void)
 {
        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 @@ init_module(void)
                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 @@ cleanup_module(void)
                        kfree(priv);
                }
        }
-       unlock_8390_module();
+       unload_8390_module();
 }
 #endif /* MODULE */
 \f
index 2300e6a7a197ee53582db131bd2ca49721538d6d..4af1228a50249570552a724e01c19f8fec25970c 100644 (file)
@@ -92,7 +92,7 @@ int __init hp_probe(struct net_device *dev)
        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 @@ int __init hp_probe(struct net_device *dev)
                        return 0;
        }
 
-       return ENODEV;
+       return -ENODEV;
 }
 #endif
 
@@ -119,7 +119,7 @@ int __init hp_probe1(struct net_device *dev, int ioaddr)
                || 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 @@ int __init hp_probe1(struct net_device *dev, int ioaddr)
                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 @@ int __init hp_probe1(struct net_device *dev, int ioaddr)
                        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 @@ int __init hp_probe1(struct net_device *dev, int ioaddr)
                        printk (" unable to get IRQ %d.\n", dev->irq);
                        kfree(dev->priv);
                        dev->priv = NULL;
-                       return EBUSY;
+                       return -EBUSY;
                }
        }
 
@@ -407,6 +404,9 @@ init_module(void)
 {
        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 @@ init_module(void)
                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 @@ cleanup_module(void)
                        kfree(priv);
                }
        }
-       unlock_8390_module();
+       unload_8390_module();
 }
 #endif /* MODULE */
 \f
index 443eaffd2446c210bf65f185f49707d14924dae8..a328fde656f360e277e348880de403a389785c5c 100644 (file)
@@ -8,7 +8,7 @@
 ** Extended for new busmaster capable chipsets by 
 ** Siegfried "Frieder" Loeffler (dg1sek) <floeff@mathematik.uni-stuttgart.de>
 **
-** Maintained by: Jaroslav Kysela <perex@jcu.cz>
+** Maintained by: Jaroslav Kysela <perex@suse.cz>
 ** 
 ** This driver has only been tested with
 ** -- HP J2585B 10/100 Mbit/s PCI Busmaster
 #include <linux/delay.h>
 #include <linux/init.h>
 
-#if LINUX_VERSION_CODE >= 0x020100
 #define LINUX_2_1
 typedef struct net_device_stats hp100_stats_t;
 EXPORT_NO_SYMBOLS;
-#else
-#include <linux/bios32.h>
-#define ioremap vremap
-#define iounmap vfree
-typedef struct enet_statistics hp100_stats_t;
-#endif
 
 #include "hp100.h"
 
@@ -187,12 +180,7 @@ struct hp100_private {
   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_rx_ratio = HP100_DEFAULT_RX_RATIO;
 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,24 +343,11 @@ int __init hp100_probe( struct net_device *dev )
     {
       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 @@ int __init hp100_probe( struct net_device *dev )
   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 @@ int __init hp100_probe( struct net_device *dev )
             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 @@ int __init hp100_probe( struct net_device *dev )
            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 @@ int __init hp100_probe( struct net_device *dev )
   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;
 }
 
 \f
-#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 @@ static int __init hp100_probe1( struct net_device *dev, int ioaddr, u_char bus,
 #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 @@ static int __init hp100_probe1( struct net_device *dev, int ioaddr, u_char bus,
   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 @@ static int __init hp100_probe1( struct net_device *dev, int ioaddr, u_char bus,
   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 @@ static int hp100_start_xmit_bm( struct sk_buff *skb, struct net_device *dev )
 
   if ( skb==NULL )
     {
-#ifndef LINUX_2_1
-      dev_tint( dev );
-#endif
       return 0;
     }
        
@@ -1754,9 +1649,7 @@ static int hp100_start_xmit_bm( struct sk_buff *skb, struct net_device *dev )
        
   /* 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 @@ static void hp100_clean_txring( struct net_device *dev )
             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 @@ static int hp100_start_xmit( struct sk_buff *skb, struct net_device *dev )
 
   if ( skb==NULL )
     {
-#ifndef LINUX_2_1
-      dev_tint( dev );
-#endif
       return 0;
     }
        
@@ -1953,17 +1839,11 @@ static int hp100_start_xmit( struct sk_buff *skb, struct net_device *dev )
   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 @@ static void hp100_rx( struct net_device *dev )
 
          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 @@ static void hp100_rx_bm( struct net_device *dev )
              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 @@ static void hp100_rx_bm( struct net_device *dev )
           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 @@ void hp100_RegisterDump( struct net_device *dev )
 
 /* 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 };
index f10944ababddae7c3bcc3e22ec1a9c35a54526ab..c69e52563e2ea7fb439efad2554dccb427ec9e44 100644 (file)
@@ -93,7 +93,7 @@ int __init hplance_probe(struct net_device *dev)
         }
         /* OK, return success, or ENODEV if we didn't find any cards */
         if (!cards)
-                return ENODEV;
+                return -ENODEV;
         return 0;
 }
 
diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c
new file mode 100644 (file)
index 0000000..9db2fca
--- /dev/null
@@ -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 <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/time.h>
+#include <linux/mca.h>
+#include <asm/processor.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#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 --git a/drivers/net/ibmlana.h b/drivers/net/ibmlana.h
new file mode 100644 (file)
index 0000000..e8e477d
--- /dev/null
@@ -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_ */
index 8a3952df44e16b246cad965938c6d9c8bdf516c6..7342b98b58b7e171557bd85382e7c89e0c61dd0e 100644 (file)
@@ -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.
  *
  * 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 <linux/errno.h>
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/pci_ids.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 /* 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);
+/* 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 */
 
-static const char ioc3_str[] = "IOC3 Ethernet";
+/* 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 @@ struct ioc3_private {
        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 @@ struct ioc3_private {
 #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 @@ nic_reset(struct ioc3 *ioc3)
         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 @@ nic_read_byte(struct ioc3 *ioc3)
        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 @@ nic_write_byte(struct ioc3 *ioc3, int byte)
                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 void nic_show_regnr(struct ioc3 *ioc3)
+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 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);
 
-       switch(regnr[0]) {
-       case 0x01:      type = "DS1990A"; break;
-       case 0x91:      type = "DS1981U"; break;
-       default:        type = "unknown"; break;
+               /* 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;
        }
 
-       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]);
+       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");
+
+       return 0;
 }
 
 /*
@@ -251,14 +342,22 @@ static void ioc3_get_eaddr(struct net_device *dev, struct ioc3 *ioc3)
 {
        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 @@ static void ioc3_get_eaddr(struct net_device *dev, struct ioc3 *ioc3)
        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 @@ ioc3_rx(struct net_device *dev, struct ioc3_private *ip, struct ioc3 *ioc3)
        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 @@ ioc3_rx(struct net_device *dev, struct ioc3_private *ip, struct ioc3 *ioc3)
                        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 @@ next:
        }
        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 @@ ioc3_tx(struct ioc3_private *ip, struct ioc3 *ioc3)
                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 @@ ioc3_error(struct net_device *dev, struct ioc3_private *ip,
 {
        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 @@ static void ioc3_interrupt(int irq, void *_dev, struct pt_regs *regs)
        struct net_device *dev = (struct net_device *)_dev;
        struct ioc3_private *ip = dev->priv;
        struct ioc3 *ioc3 = ip->regs;
-       u32 eisr, eier;
+       const u32 enabled = EISR_RXTIMERINT | EISR_TXEXPLICIT |
+                           EISR_RXMEMERR | EISR_TXMEMERR;
+       u32 eisr;
 
-       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);
-       }
+       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 @@ ioc3_eth_init(struct net_device *dev, struct ioc3_private *p, struct ioc3 *ioc3)
                }
        }
        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 @@ ioc3_eth_init(struct net_device *dev, struct ioc3_private *p, struct ioc3 *ioc3)
 
        /* 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;
+       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;
+                       }
 
-       /* 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;
+                       ip->rx_skbs[i] = skb;
+                       skb->dev = dev;
 
-               skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, 0);
-               if (!skb) {
-                       show_free_areas();
-                       continue;
+                       /* 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;
+       }
 
-               p->rx_skbs[i] = skb;
-               skb->dev = dev;
-
-               /* 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;
+       ioc3->ercir  = (ip->rx_ci << 3);
+       ioc3->erpir  = (ip->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);
+       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 @@ ioc3_ssram_disc(struct ioc3_private *ip)
        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 @@ static void ioc3_probe1(struct net_device *dev, struct ioc3 *ioc3)
        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;
+       }
+
+       ((struct ioc3_private *)dev->priv)->ehar_h = 0;
+       ((struct ioc3_private *)dev->priv)->ehar_l = 0;
+       ioc3_init(dev);
 
-       nid = get_nasid();
-       ioc3 = (struct ioc3 *) KL_CONFIG_CH_CONS_INFO(nid)->memory_base;
-       ioc3_probe1(dev, ioc3);
+       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);
 
-        return 0;
+        ioc3_get_eaddr(dev, ioc3);
+
+       /* 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 @@ ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev)
        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 @@ ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev)
        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 @@ ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
 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 @@ ioc3_hash(const unsigned char *addr)
        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 @@ static void ioc3_set_multicast_list(struct net_device *dev)
 
                                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 <ralf@oss.sgi.com>");
 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);
index bff27f09870b7b992f56bce7eb27d93b856b0fbb..c6b11ecf5a423d2cbf772a7907927a1dd8ac855d 100644 (file)
@@ -361,7 +361,6 @@ int lance_probe(struct net_device *dev)
                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 @@ int lance_probe(struct net_device *dev)
 
                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 <marks@schooner.sys.hou.compaq.com>)
-                        */
-                       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);
index bc6ab00059a82a369bfc463ad608d73916734e08..33952e0ad628f740d0e2108322e275f716d7d6e2 100644 (file)
@@ -107,13 +107,13 @@ int __init lne390_probe(struct net_device *dev)
        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 @@ int __init lne390_probe(struct net_device *dev)
                        return 0;
        }
 
-       return ENODEV;
+       return -ENODEV;
 }
 
 int __init lne390_probe1(struct net_device *dev, int ioaddr)
@@ -144,7 +144,7 @@ int __init lne390_probe1(struct net_device *dev, int ioaddr)
 /*     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 @@ int __init lne390_probe1(struct net_device *dev, int ioaddr)
                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 @@ int __init lne390_probe1(struct net_device *dev, int ioaddr)
                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 @@ int __init lne390_probe1(struct net_device *dev, int ioaddr)
                        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 @@ int __init lne390_probe1(struct net_device *dev, int ioaddr)
                        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 init_module(void)
 {
        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 @@ int init_module(void)
                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 @@ void cleanup_module(void)
                        kfree(priv);
                }
        }
-       unlock_8390_module();
+       unload_8390_module();
 }
 #endif /* MODULE */
 
index ce43ad7526f202de607d5484a47e4521078a592f..cf1666b1b7cae7e8ee8ca00bcc16f4386c325b05 100644 (file)
@@ -180,14 +180,14 @@ int __init mac89x0_probe(struct net_device *dev)
        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 @@ int __init mac89x0_probe(struct net_device *dev)
                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 @@ int __init mac89x0_probe(struct net_device *dev)
        /* 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??!) */
index bd1406e1f65a11a9842caeb2e909edc6749cabb4..ba9c60250d456ce6291ca41af23b5c10ed24db8a 100644 (file)
@@ -982,7 +982,7 @@ static int __init myri_ether_init(struct net_device *dev, struct sbus_dev *sdev,
                                        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 @@ static int __init myri_ether_init(struct net_device *dev, struct sbus_dev *sdev,
        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 @@ static int __init myri_sbus_probe(void)
 #endif
 
        if (called)
-               return ENODEV;
+               return -ENODEV;
        called++;
 
        for_each_sbus(bus) {
@@ -1125,7 +1125,7 @@ static int __init myri_sbus_probe(void)
                }
        }
        if (!cards)
-               return ENODEV;
+               return -ENODEV;
        return 0;
 }
 
index 9e651fb8f2f99c78ed98d985845b72c60a365ae9..881515b682cc1b4797ff2e427035ad357707fdbb 100644 (file)
@@ -195,7 +195,7 @@ int __init ne_probe(struct net_device *dev)
        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 @@ int __init ne_probe(struct net_device *dev)
        }
 #endif
 
-       return ENODEV;
+       return -ENODEV;
 }
 #endif
 
@@ -232,7 +232,9 @@ static int __init ne_probe_pci(struct net_device *dev)
                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 int __init ne_probe1(struct net_device *dev, int ioaddr)
        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 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
                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 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
                                break;
                        } else {
                                printk(" not found (no reset ack).\n");
-                               return ENODEV;
+                               return -ENODEV;
                        }
                }
        
@@ -466,11 +465,11 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
                {
                        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 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
 
        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 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
                        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 init_module(void)
 {
        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 @@ int init_module(void)
                        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 @@ void cleanup_module(void)
                        kfree(priv);
                }
        }
-       unlock_8390_module();
+       unload_8390_module();
 }
 #endif /* MODULE */
 \f
index c48ad24ce28f0deaf3473e84446d188f01b9f166..5c3892f9f434be73041a2e4809b91c2928c65918 100644 (file)
@@ -171,7 +171,7 @@ int __init ne2_probe(struct net_device *dev)
                        return ne2_probe1(dev, current_mca_slot);
                }
        }
-       return ENODEV;
+       return -ENODEV;
 }
 
 
@@ -222,7 +222,7 @@ static int __init ne2_probe1(struct net_device *dev, int slot)
        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 @@ static int __init ne2_probe1(struct net_device *dev, int slot)
        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 @@ static int __init ne2_probe1(struct net_device *dev, int slot)
                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 @@ static int __init ne2_probe1(struct net_device *dev, int slot)
                if (irqval) {
                        printk (" unable to get IRQ %d (irqval=%d).\n", 
                                        dev->irq, +irqval);
-                       return EAGAIN;
+                       return -EAGAIN;
                }
        }
 
index 3f40f5aaed9e7618da55c3940365906a9e536366..6ce703927fdbd946a8fa1478a2cb4279c736e147 100644 (file)
@@ -242,11 +242,6 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
                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 @@ static int __init ne2k_pci_init(void)
 {
        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 int __init ne2k_pci_init(void)
 static void __exit ne2k_pci_cleanup(void)
 {
        pci_unregister_driver (&ne2k_driver);
-       unlock_8390_module();
+       unload_8390_module();
 }
 
 module_init(ne2k_pci_init);
index ad39dd40b52862f8c7151b3b40fe3531b84cad25..1fceea2fd5e016a20005000d318623109b8bfdd3 100644 (file)
@@ -102,13 +102,13 @@ int __init ne3210_probe(struct net_device *dev)
        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 @@ int __init ne3210_probe(struct net_device *dev)
                        return 0;
        }
 
-       return ENODEV;
+       return -ENODEV;
 }
 
 int __init ne3210_probe1(struct net_device *dev, int ioaddr)
@@ -140,7 +140,7 @@ int __init ne3210_probe1(struct net_device *dev, int ioaddr)
 /*     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 @@ int __init ne3210_probe1(struct net_device *dev, int ioaddr)
                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 @@ int __init ne3210_probe1(struct net_device *dev, int ioaddr)
                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 @@ int __init ne3210_probe1(struct net_device *dev, int ioaddr)
                        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 @@ int __init ne3210_probe1(struct net_device *dev, int ioaddr)
                        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 init_module(void)
 {
        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 @@ int init_module(void)
                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 @@ void cleanup_module(void)
                        kfree(priv);
                }
        }
-       unlock_8390_module();
+       unload_8390_module();
 }
 #endif /* MODULE */
 
index 3ffdfabd4927f8d69ea625737cd41662f3892089..910906aa2a2162c7edd08220b63f837e41fce979 100644 (file)
@@ -367,7 +367,7 @@ int __init ni52_probe(struct net_device *dev)
                                (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 @@ int __init ni52_probe(struct net_device *dev)
 #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 @@ static int __init ni52_probe1(struct net_device *dev,int ioaddr)
 
        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 @@ static int __init ni52_probe1(struct net_device *dev,int ioaddr)
        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 @@ static int __init ni52_probe1(struct net_device *dev,int ioaddr)
                        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 @@ static int __init ni52_probe1(struct net_device *dev,int ioaddr)
                {
                        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 */
index 1f6243f9f684cd59125ffb0ddf523f6b107204b1..e24e0e4f0498b8cde2fb0418433ed4be9c2e779f 100644 (file)
@@ -143,16 +143,6 @@ static int __init oaknet_init(void)
                return (ENODEV);
        }
 
-       /*
-        * 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 @@ static int __init oaknet_init_module (void)
 {
        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 @@ static void __exit oaknet_cleanup_module (void)
 
        oaknet_devs = NULL;
 
-       unlock_8390_module();
+       unload_8390_module();
 }
 
 module_init(oaknet_init_module);
index 2052c6eaf933e2b68b51bc0bfd1f35a2cce6724f..e1070f8f0e0057dcd05ccc17531bd2dfa0a85c17 100644 (file)
@@ -21,12 +21,12 @@ if [ "$CONFIG_NET_PCMCIA" = "y" ]; then
       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
 
index dc580b0fe5ccef08317c6f2a50b81721d2a59815..44276a3d90483a700edf0c276ecf17a32706500f 100644 (file)
@@ -311,21 +311,6 @@ struct pcnet32_pci_id_info {
     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 @@ pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int car
     }
 
     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 @@ pcnet32_rx(struct net_device *dev)
                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 @@ static int __init pcnet32_init_module(void)
     /* 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
     {
index 83fd53daeb36c366d5f5159319a78e3f4d60be0d..ec0dcd23bd8dd9f4c8b1977fd411421aa8e279e4 100644 (file)
@@ -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 @@ static inline int pti_fddi_init(struct net_device *dev, struct sbus_dev *sdev, i
            &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 @@ static inline int pti_fddi_init(struct net_device *dev, struct sbus_dev *sdev, i
            &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 @@ static inline int pti_fddi_init(struct net_device *dev, struct sbus_dev *sdev, i
            &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 @@ static inline int pti_fddi_init(struct net_device *dev, struct sbus_dev *sdev, i
        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 __init ptifddi_sbus_probe(struct net_device *dev)
        int cards = 0, v;
 
        if(called)
-               return ENODEV;
+               return -ENODEV;
        called++;
 
        for_each_sbus(bus) {
@@ -228,7 +228,7 @@ int __init ptifddi_sbus_probe(struct net_device *dev)
                }
        }
        if(!cards)
-               return ENODEV;
+               return -ENODEV;
        return 0;
 }
 
index 96df996dea609d44e8e5fd26e15262a0b1c7e562..767d0a43414dd9d659ad863e48bb0f03a9013891 100644 (file)
@@ -205,7 +205,7 @@ static int RCscan(void)
            !((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 @@ static int RCscan(void)
         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,
index dbd12bdb989ae6d212f6bbb4a4aea8e3c647b843..c3dc74c937c7a57c42c91c0a76a57410c2e0a6ec 100644 (file)
@@ -146,6 +146,9 @@ int __init rr_hippi_probe (struct net_device *dev)
                                      PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER,
                                      pdev)))
        {
+               if (pci_enable_device(pdev))
+                       continue;
+
                if (pdev == opdev)
                        return 0;
 
index 725f16a4a51ad8eec30d036e1772c861adaddb7b..d72b811b0e652809a32a9b2a3aba782219b2bb1b 100644 (file)
@@ -353,9 +353,13 @@ static int __init rtl8129_probe(void)
                        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))
                        continue;
index 283602e44e31a5a0cbc43aa686d10ce4f398e81c..13e66f96e20bfe57fb73b713b2cc84a6a0df88c8 100644 (file)
@@ -119,7 +119,7 @@ seeq8005_probe(struct net_device *dev)
        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 @@ seeq8005_probe(struct net_device *dev)
                        return 0;
        }
 
-       return ENODEV;
+       return -ENODEV;
 }
 #endif
 
@@ -153,27 +153,27 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
 
        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 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
                outw( old_stat, SEEQ_STATUS);
                outw( old_dmaar, SEEQ_DMAAR);
                outw( old_cfg1, SEEQ_CFG1);
-               return ENODEV;
+               return -ENODEV;
        }
 #endif
 
@@ -309,7 +309,7 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
                 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 @@ static int seeq8005_open(struct net_device *dev)
                 if (irqval) {
                         printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
                                         dev->irq, irqval);
-                        return EAGAIN;
+                        return -EAGAIN;
                 }
        }
 
index c92e73180dc972f3b99655a2d0171061a86d7123..ddc98a3d52cd87493c1c883654fb23a092c9e7d8 100644 (file)
@@ -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 <jgarzik@mandrakesoft.com> 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 @@ static struct net_device * sis900_mac_probe (struct pci_dev * pci_dev,
                                             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 @@ struct sis900_private {
        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 sis900_private {
        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 @@ static int __init sis900_probe (struct pci_dev *pci_dev, const struct pci_device
                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 @@ static int __init sis900_probe (struct pci_dev *pci_dev, const struct pci_device
 
        /* 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 int __init sis900_probe (struct pci_dev *pci_dev, const struct pci_device
 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 @@ sis900_open(struct net_device *net_dev)
        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 @@ static void __exit sis900_remove(struct pci_dev *pci_dev)
        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);
index 2fb6a697047d02efdffee796183ee405399637bb..8e95f0a05da57f4e1086f65b29b7c9d0056d6bc9 100644 (file)
@@ -369,24 +369,18 @@ static int __init skge_probe (void)
        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 @@ static int __init skge_probe (void)
 
                pci_set_master(pdev);
 
-               base_address = pdev->resource[0].start;
+               base_address = pci_resource_start (pdev, 0);
 
 #ifdef SK_BIG_ENDIAN
                /*
index fad404a4dd28ec105d356174ae211c7b5715ba9c..0699fc879dfd2633d5b03a18f8f9d58ee642bcef 100644 (file)
@@ -556,11 +556,11 @@ int __init SK_init(struct net_device *dev)
                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 @@ int __init SK_init(struct net_device *dev)
 
        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 @@ int __init SK_probe(struct net_device *dev, short ioaddr)
     {
         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",
index 27379bfdb93af1a797f1a8b390ad15ee446cceab..f28196a2fe190bee2623c4050ddfea468ea7abe1 100644 (file)
@@ -62,14 +62,25 @@ History:
        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 <linux/module.h>
-#include <linux/version.h>
-
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
@@ -84,6 +95,11 @@ History:
 #include <asm/bitops.h>
 #include <asm/io.h>
 
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
@@ -96,11 +112,11 @@ History:
  * 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 @@ static unsigned char poly[] = {
 /* 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 @@ static void PrTime(void)
        do_gettimeofday(&tv);
        printk("%9d:%06d: ", tv.tv_sec, tv.tv_usec);
 }
-
 #endif
 
 /* deduce resources out of POS registers */
@@ -169,10 +184,10 @@ static void getaddrs(int slot, int junior, int *base, int *irq,
                        *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 @@ static int dofind(int *junior, int firstslot)
 
 /* 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 @@ static void SetLANCE(struct net_device *dev, u16 addr, u16 value)
 
        /* 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 @@ static void SetLANCE(struct net_device *dev, u16 addr, u16 value)
 
 /* 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 @@ static u16 GetLANCE(struct net_device *dev, u16 addr)
 
        /* 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 @@ static u16 GetLANCE(struct net_device *dev, u16 addr)
 
 /* 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 @@ static void InitDscrs(struct net_device *dev)
                        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 @@ static void InitDscrs(struct net_device *dev)
                        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 @@ static unsigned int GetHash(char *address)
 
 /* 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 @@ static void InitLANCE(struct net_device *dev)
 
        /* 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 @@ static void InitLANCE(struct net_device *dev)
 
 /* 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 @@ static void StopLANCE(struct net_device *dev)
 
 /* 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 @@ static void InitBoard(struct net_device *dev)
        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 @@ static void InitBoard(struct net_device *dev)
 
 /* deinitialize card and LANCE */
 
-static void DeinitBoard(struct net_device *dev)
+static void DeinitBoard(struct SKMCA_NETDEV *dev)
 {
        /* stop LANCE */
 
@@ -483,44 +524,97 @@ static void DeinitBoard(struct net_device *dev)
        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 @@ static u16 irqrx_handler(struct net_device *dev, u16 oldcsr0)
                        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 @@ static u16 irqrx_handler(struct net_device *dev, u16 oldcsr0)
                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 @@ static u16 irqrx_handler(struct net_device *dev, u16 oldcsr0)
 
 /* 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 @@ static u16 irqtx_handler(struct net_device *dev, u16 oldcsr0)
            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 @@ static u16 irqtx_handler(struct net_device *dev, u16 oldcsr0)
 
        /* 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 u16 irqtx_handler(struct net_device *dev, u16 oldcsr0)
 
 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 @@ static void irq_handler(int irq, void *device, struct pt_regs *regs)
        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 @@ static void irq_handler(int irq, void *device, struct pt_regs *regs)
                        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 void irq_handler(int irq, void *device, struct pt_regs *regs)
 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 @@ static int skmca_getinfo(char *buf, int slot, void *d)
 
 /* 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 @@ static int skmca_open(struct net_device *dev)
        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 @@ static int skmca_open(struct net_device *dev)
 
 /* 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 @@ static int skmca_close(struct net_device *dev)
 
 /* 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 @@ static int skmca_tx(struct sk_buff *skb, struct net_device *dev)
        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 @@ static int skmca_tx(struct sk_buff *skb, struct net_device *dev)
 
        /* 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 @@ static int skmca_tx(struct sk_buff *skb, struct net_device *dev)
                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 @@ static int skmca_tx(struct sk_buff *skb, struct net_device *dev)
        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 @@ static int skmca_tx(struct sk_buff *skb, struct net_device *dev)
 
        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 @@ static int skmca_config(struct net_device *dev, struct ifmap *map)
 /* 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 @@ static void skmca_set_multicast_list(struct net_device *dev)
        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 @@ static void skmca_set_multicast_list(struct net_device *dev)
                }
        }
 
-       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 @@ static void skmca_set_multicast_list(struct net_device *dev)
  * 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 @@ int skmca_probe(struct net_device *dev)
        /* 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 @@ int skmca_probe(struct net_device *dev)
 
                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 @@ int skmca_probe(struct net_device *dev)
        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 @@ int skmca_probe(struct net_device *dev)
        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 @@ int skmca_probe(struct net_device *dev)
 
        /* 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 @@ int skmca_probe(struct net_device *dev)
 
        ResetBoard(dev);
 
-#ifdef MODULE
        startslot = slot + 1;
-#endif
 
        return 0;
 }
@@ -1068,13 +1231,24 @@ int skmca_probe(struct net_device *dev)
 
 #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 @@ int init_module(void)
 
 void cleanup_module(void)
 {
-       struct net_device *dev;
+       struct SKMCA_NETDEV *dev;
        skmca_priv *priv;
        int z;
 
index 089f11ade73369c9df6bac37657547ed87608676..b107ecfb8fbd76a7b656cf3b37fd6e5b49aaa970 100644 (file)
 
 #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 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 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            */
 
 /* 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_ */
index 5b5ffc9f9e9c6aa1d685690f3c31a36da456759d..0d67bbb01b92a72f8f7360c27cf7ca2ecd9a7f57 100644 (file)
@@ -305,6 +305,8 @@ int skfp_probe(struct net_device *dev)
                        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 @@ int skfp_probe(struct net_device *dev)
                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){
index 03c624a9dfe29ae56a266749333d372ef0b88b11..0f41a233db1f3143e95a9f601f23e6561b1fcb6c 100644 (file)
@@ -118,7 +118,7 @@ int __init ultramca_probe(struct net_device *dev)
        int irq = dev ? dev->irq : 0;
 
        if (!MCA_bus) {
-               return ENODEV;
+               return -ENODEV;
        }
 
        if (base_addr || irq) {
@@ -252,9 +252,6 @@ int __init ultramca_probe(struct net_device *dev)
        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 init_module(void)
 {
        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 @@ int init_module(void)
 
                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 @@ void cleanup_module(void)
                        kfree(priv);
                }
        }
-       unlock_8390_module();
+       unload_8390_module();
 }
 #endif /* MODULE */
 
index 7477bcb50d860d134bcfd4975e597d6da8fc5094..f884458f56b2b5fa30667003bb9f1f1830f9e673 100644 (file)
@@ -114,7 +114,7 @@ int __init ultra_probe(struct net_device *dev)
        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 @@ int __init ultra_probe(struct net_device *dev)
                        return 0;
        }
 
-       return ENODEV;
+       return -ENODEV;
 }
 #endif
 
@@ -143,7 +143,7 @@ int __init ultra_probe1(struct net_device *dev, int ioaddr)
        /* 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 @@ int __init ultra_probe1(struct net_device *dev, int ioaddr)
        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 @@ init_module(void)
 {
        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 @@ init_module(void)
                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 @@ cleanup_module(void)
                        kfree(dev->priv);
                }
        }
-       unlock_8390_module();
+       unload_8390_module();
 }
 #endif /* MODULE */
 \f
index a7ba60dfa70ad788bbbc8984ad02f047cee40acb..c371aebabb9ca88eb7e2b7c91f11d65d7c93a06e 100644 (file)
@@ -108,7 +108,7 @@ int __init ultra32_probe(struct net_device *dev)
        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 @@ int __init ultra32_probe(struct net_device *dev)
                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 @@ int __init ultra32_probe1(struct net_device *dev, int ioaddr)
 
        /* 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 @@ int __init ultra32_probe1(struct net_device *dev, int ioaddr)
        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 @@ int __init ultra32_probe1(struct net_device *dev, int ioaddr)
        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 init_module(void)
 {
        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 @@ void cleanup_module(void)
                        kfree(priv);
                }
        }
-       unlock_8390_module();
+       unload_8390_module();
 }
 #endif /* MODULE */
index 661c1b36355f8bb2eaab42b83f1e1f5efaf767d3..86c04c5c7a182d650110de43a69c4f1e405f703e 100644 (file)
  .                              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 <linux/module.h>
 #include <linux/version.h>
@@ -517,11 +519,15 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de
 
        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");
index e6d1800944710fed57cc2b7416fd7d036b7a4b1c..b0c6d66153ec89260e18f20431c67fdda7975224 100644 (file)
@@ -44,7 +44,7 @@ static int sonic_open(struct net_device *dev)
 //    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;
     }
 
     /*
index 991b2125896d49e40b517643084ded1aeabde34a..9e08c0c9abb58c8bedb157ec6b4177f0fd9f3f63 100644 (file)
@@ -175,7 +175,7 @@ stnic_reset (struct net_device *dev)
   *(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 @@ static void
 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 @@ do_stnic_intr (int irq, void *dev_id, struct pt_regs *regs)
 }
 
 module_init(stnic_probe);
+/* No cleanup routine - if there were one, it should do a:
+   unload_8390_module()
+*/
index b37b86df054314c86b46e7b3eac4102f091f85b4..3f3bd8a4ac6b72c120dd4ef257e52d5a4eda53fd 100644 (file)
@@ -2870,7 +2870,7 @@ int strip_init_ctrl_dev(struct net_device *dummy)
     /* Return "not found", so that dev_init() will unlink
      * the placeholder device entry for us.
      */
-    return ENODEV;
+    return -ENODEV;
 #endif
 }
 
index 6a773b66d3fa9a3206ae16c8bb7337bd57b5fa14..3b7f76700fb5f19681c73539e05d9c184b1feca1 100644 (file)
@@ -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 @@ static int __init bigmac_probe(void)
 #endif
 
        if (called)
-               return ENODEV;
+               return -ENODEV;
        called++;
 
        for_each_sbus(sbus) {
@@ -1278,7 +1278,7 @@ static int __init bigmac_probe(void)
                }
        }
        if (!cards)
-               return ENODEV;
+               return -ENODEV;
        return 0;
 }
 
index 70884ec5324a16c44e1ec438af76a7db78696387..23ba505c3dae4edb317625adde05593d10e7e638 100644 (file)
@@ -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 @@ static int __init happy_meal_sbus_init(struct net_device *dev,
        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 @@ static int __init happy_meal_sbus_init(struct net_device *dev,
                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 @@ static int __init happy_meal_sbus_init(struct net_device *dev,
                                 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 @@ static int __init happy_meal_pci_init(struct net_device *dev, struct pci_dev *pd
        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 @@ static int __init happy_meal_pci_init(struct net_device *dev, struct pci_dev *pd
        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 @@ static int __init happy_meal_pci_init(struct net_device *dev, struct pci_dev *pd
                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 @@ static int __init happy_meal_pci_init(struct net_device *dev, struct pci_dev *pd
 
        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 @@ static int __init happy_meal_probe(void)
 #endif
 
        if (called)
-               return ENODEV;
+               return -ENODEV;
        called++;
 
        cards = 0;
@@ -2933,7 +2932,7 @@ static int __init happy_meal_probe(void)
        cards += happy_meal_pci_probe(dev);
 #endif
        if (!cards)
-               return ENODEV;
+               return -ENODEV;
        return 0;
 }
 
index 3a210c02462cb1c6161c567e6b753dcdd87e933a..ada2ba5ca9fbc1608c544bf0181151cf20c98dd4 100644 (file)
@@ -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 @@ no_link_test:
 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 @@ static int __init sparc_lance_probe(void)
 #endif
 
        if (called)
-               return ENODEV;
+               return -ENODEV;
        called++;
 
        if ((idprom->id_machtype == (SM_SUN4|SM_4_330)) ||
@@ -1542,7 +1542,7 @@ static int __init sparc_lance_probe(void)
                sdev.irqs[0] = 6;
                return sparc_lance_init(NULL, &sdev, 0, 0);
        }
-       return ENODEV;
+       return -ENODEV;
 }
 
 #else /* !CONFIG_SUN4 */
@@ -1562,7 +1562,7 @@ static int __init sparc_lance_probe(void)
 #endif
 
        if (called)
-               return ENODEV;
+               return -ENODEV;
        called++;
 
        for_each_sbus (bus) {
@@ -1593,7 +1593,7 @@ static int __init sparc_lance_probe(void)
                } /* for each sbusdev */
        } /* for each sbus */
        if (!cards)
-               return ENODEV;
+               return -ENODEV;
        return 0;
 }
 #endif /* !CONFIG_SUN4 */
index 62fac115f668568344ed097748771ecad2f496fe..f4ea45189e396d9315cdccdac255ef026c318432 100644 (file)
@@ -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 @@ static int __init qec_probe(void)
 #endif
 
        if (called)
-               return ENODEV;
+               return -ENODEV;
        called++;
 
        for_each_sbus(bus) {
@@ -1015,7 +1015,7 @@ static int __init qec_probe(void)
                }
        }
        if (!cards)
-               return ENODEV;
+               return -ENODEV;
        return 0;
 }
 
index 5c466ecf05735f2860d2a1db2001de0810fa5d57..165d611b83862af942e8a70dacf10fa3ec6d885c 100644 (file)
  *                          - 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             aui = 0;
 static int             duplex = 0; 
 static int             speed = 0;
 
+MODULE_AUTHOR("Maintainer: Torben Mathiasen <torben.mathiasen@compaq.com>");
+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                debug = 0;
 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 void TLan_HandleInterrupt(int, void *, struct pt_regs *);
 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 @@ static int __init tlan_probe(void)
        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 @@ static int __init tlan_probe(void)
                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 @@ static int __init TLan_PciProbe(u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_
                                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 __init TLan_PciProbe(u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_
 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 @@ static int TLan_Init( struct net_device *dev )
                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 @@ static int TLan_Init( struct net_device *dev )
        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 @@ static int TLan_Open( struct net_device *dev )
 
 
 
+       /**************************************************************
+        *      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 @@ TLan_FinishReset( struct net_device *dev )
        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 @@ TLan_FinishReset( struct net_device *dev )
                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<<i))
+                                                       printk("%s", media[i-5]);
+                                                       printk("\n");
+                       }
+
                        TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK );
                }
        }
@@ -1946,7 +2063,7 @@ TLan_FinishReset( struct net_device *dev )
                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 @@ void TLan_PhyPowerUp( struct net_device *dev )
        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 @@ void TLan_PhyReset( struct net_device *dev )
        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 @@ void TLan_PhyStartLink( struct net_device *dev )
        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;
+               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;
                }
-
-               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;
-       }
-
+               
+       }       
+       
        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 @@ void TLan_PhyStartLink( struct net_device *dev )
                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 @@ void TLan_PhyFinishAutoNeg( struct net_device *dev )
                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" );
index e44d03107b07da9b9ccaa9f1d78c11fda129fc23..f04ca6996da50ab1da1f05d13997cc3c034b1333 100644 (file)
@@ -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 @@ typedef struct tlan_private_tag {
 #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
 
index 58f71b96323bd49bf711262184e1be2407ccbf96..971bea2cfac95f23510bddbb5b831618ab283d85 100644 (file)
@@ -781,6 +781,9 @@ static int __init trdev_init(struct net_device *dev)
 {
        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 @@ static int tok_open(struct net_device *dev)
 {
        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 @@ static void tr_rx(struct net_device *dev)
        /* 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));
index 1714d34d12780d5f4dcb96110034648fd34f6f6b..2ef7ec903075841c4be86aacb7f8746975826576 100644 (file)
@@ -207,12 +207,14 @@ static int __init streamer_scan(struct net_device *dev)
        {
                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 @@ static int __init streamer_scan(struct net_device *dev)
                               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;
index 0787d8d75fe5b2356d17f07d128a810cb64e5260..73cd6a194e72b0c531c3e847c192d78ce7a0cf18 100644 (file)
  *  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 @@ static int __init olympic_scan(struct net_device *dev)
        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 @@ static int __init olympic_scan(struct net_device *dev)
                        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 @@ static int __init olympic_init(struct net_device *dev)
                }
        }
   
-       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 @@ static int __init olympic_init(struct net_device *dev)
 
        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 @@ static int olympic_open(struct net_device *dev)
                /* 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 @@ static int olympic_open(struct net_device *dev)
 #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 @@ static int olympic_open(struct net_device *dev)
        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 @@ static int olympic_open(struct net_device *dev)
 
                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 @@ static int olympic_open(struct net_device *dev)
                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 @@ static int olympic_open(struct net_device *dev)
                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 @@ static void olympic_rx(struct net_device *dev)
        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 @@ static void olympic_rx(struct net_device *dev)
                                                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 @@ static void olympic_rx(struct net_device *dev)
                                                        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 @@ static int olympic_xmit(struct sk_buff *skb, struct net_device *dev)
        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 @@ static void olympic_arb_cmd(struct net_device *dev)
        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 @@ static void olympic_arb_cmd(struct net_device *dev)
 
                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 @@ static void olympic_arb_cmd(struct net_device *dev)
                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 @@ static int sprintf_info(char *buffer, struct net_device *dev)
          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 @@ static int sprintf_info(char *buffer, struct net_device *dev)
          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),
index 5974e4e4fdebbfc61dc2b832fe53a7debd457d9f..ba7a314fdc32d299c26f0af428d997810701efe7 100644 (file)
 
 /* 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_tx_status {
 
 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 mac_receive_buffer {
 
 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;
index 2bc0a8652187634e3f40ff7790ba317d1ce49f5c..24d0d49c9cf756181b717e75efb3b2afb08d3e52 100644 (file)
 */
 
 #include "tulip.h"
+#include <linux/pci.h>
+#include <linux/delay.h>
 
 
 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 @@ void t21142_timer(unsigned long data)
                        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 @@ void t21142_start_nway(struct net_device *dev)
        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 @@ void t21142_lnk_change(struct net_device *dev, int csr5)
                        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 @@ void t21142_lnk_change(struct net_device *dev, int csr5)
                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);
        }
 }
 
index 27ea89232ac5b993e3429c4cecfbe00bcecc2d2e..17d81a53456554533e9f64396f90e8b733cc366d 100644 (file)
@@ -162,6 +162,13 @@ subsequent_board:
                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);
index 0a48a27f0c84f22b45b340ece39a8c4c4673aa77..918357aff34df1616b4b171a21e52aa4513a02cf 100644 (file)
@@ -178,7 +178,7 @@ void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
        int maxtx = TX_RING_SIZE;
        int maxoi = TX_RING_SIZE;
        int work_count = tulip_max_interrupt_work;
-
+       
        tp->nir++;
 
        do {
@@ -236,13 +236,7 @@ void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
                                        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 @@ void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
                                        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 @@ void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
                                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)
index e704c6c7d10d5cdb7d896f80fd26a9d08f99a54f..aa3019098e6e5f4b1e8231032c43a415ea79da5b 100644 (file)
@@ -388,8 +388,7 @@ int tulip_check_duplex(struct net_device *dev)
                        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",
index 2f408684fdc78dbf848c7a8d9acb6753c70e20c2..bdbaf7da820f398f7aff03f16d72403765183fa0 100644 (file)
@@ -44,8 +44,7 @@ void pnic_do_nway(struct net_device *dev)
                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 @@ void pnic_lnk_change(struct net_device *dev, int csr5)
                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 @@ void pnic_timer(unsigned long data)
                        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 "
index 16e048b828ee28ac9c99cbdda063974c94bd24e0..f8b06c58f0fa4211fd3521976192e98ab82b09c0 100644 (file)
@@ -154,8 +154,7 @@ void tulip_timer(unsigned long data)
                                           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;
                }
index a0943758269ba6e2e9dedf4772d8471bc120d5b6..4e21319ba4e106f4bce143a007c85895cc00f6bd 100644 (file)
@@ -169,31 +169,54 @@ enum t21143_csr6_bits {
        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_csr14[];
 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);
 }
 
 
index 12cee4da53900644dc71a90aea15d030fd042efc..ae777d16530fa4439766cf50875ea66d49aae571 100644 (file)
@@ -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 <linux/module.h>
 #include "tulip.h"
@@ -50,7 +50,8 @@ const char * const medianame[] = {
 };
 
 /* 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 @@ static int rx_copybreak = 100;
 
 #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 @@ static void tulip_up(struct net_device *dev)
        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 @@ media_picked:
        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 @@ media_picked:
                                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 @@ media_picked:
                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 @@ static void tulip_tx_timeout(struct net_device *dev)
        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 @@ static void tulip_tx_timeout(struct net_device *dev)
 #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 @@ static void tulip_init_ring(struct net_device *dev)
        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 @@ tulip_start_xmit(struct sk_buff *skb, struct net_device *dev)
        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 @@ tulip_start_xmit(struct sk_buff *skb, struct net_device *dev)
        /* 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 @@ static void tulip_down (struct net_device *dev)
        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 @@ static void set_rx_mode(struct net_device *dev)
 {
        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 @@ static void set_rx_mode(struct net_device *dev)
                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 @@ static void set_rx_mode(struct net_device *dev)
                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 @@ static void set_rx_mode(struct net_device *dev)
                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 @@ static void set_rx_mode(struct net_device *dev)
                                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 @@ static void set_rx_mode(struct net_device *dev)
                        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 @@ static void set_rx_mode(struct net_device *dev)
                        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 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
        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 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
        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 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
        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 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
        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 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
        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 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
                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 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
        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 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
                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 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
 
        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 @@ static void __devexit tulip_remove_one (struct pci_dev *pdev)
                                    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);
        }
 }
index 1792b1852cfcbe74b40b1fb4800062fb168033e9..8ce05ba8dd11242abf7143da3e694ff9ee5f9b62 100644 (file)
@@ -94,7 +94,7 @@ int __init wd_probe(struct net_device *dev)
        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 @@ int __init wd_probe(struct net_device *dev)
                        return 0;
        }
 
-       return ENODEV;
+       return -ENODEV;
 }
 #endif
 
@@ -122,11 +122,7 @@ int __init wd_probe1(struct net_device *dev, int ioaddr)
        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 @@ int __init wd_probe1(struct net_device *dev, int ioaddr)
                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 @@ init_module(void)
 {
        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 @@ init_module(void)
                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 @@ cleanup_module(void)
                        release_region(ioaddr, WD_IO_EXTENT);
                        unregister_netdev(dev);
                        kfree(priv);
-                       unlock_8390_module();
                }
        }
+       unload_8390_module();
 }
 #endif /* MODULE */
 \f
index 7ca88c26a6a7cf22ea4a9336d41c981ef4d3734f..d4e52f92b9ca5dce0f6241de8356daf24381fd1b 100644 (file)
@@ -218,7 +218,7 @@ int __init znet_probe(struct net_device *dev)
        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 @@ int __init znet_probe(struct net_device *dev)
                || 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
index 2329adde6de3e394c9f1e41659e3ca303946e38d..a41276a62acea27f855ebd868c5260b6a5549f16 100644 (file)
@@ -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 <URL:http://www.cyberelk.demon.co.uk/parport.html>.
+See <URL:http://people.redhat.com/twaugh/parport/>.
index 97b7c53c99d907fc03c69d31b420b81109c4d7f5..1dd9a4ae22f1ea5e6f374500c3414086365383d8 100644 (file)
@@ -1,3 +1,27 @@
+2000-06-13  Tim Waugh  <twaugh@redhat.com>
+
+       * procfs.c: Break 'hardware' out into separate files.
+
+2000-05-28  Gunther Mayer  <gunther.mayer@braunschweig.okersurf.de>
+
+       * Fix PCI ID printk for non-superio PCI cards.
+
+2000-05-28  Tim Waugh  <twaugh@redhat.com>
+
+       * 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  <twaugh@redhat.com>
+
+       * daisy.c (assign_addrs): Avoid double-probing daisy-chain devices
+       if the first probe succeeds.
+
 2000-05-16  Tim Waugh  <twaugh@redhat.com>
 
        * share.c (parport_claim): Fix SMP race.
index 1e486c6b35045dc5ad30dc98c06bc9b23f8e04f2..5cf05e85a8d6342609d9d9a3e4bba07cc06a038f 100644 (file)
@@ -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.
 #
index bf91351ea97e475b5aee227c0027f41a85a0b670..089b14ee446f6340397b3bbc0a8be018ac4b37fa 100644 (file)
@@ -17,4 +17,4 @@ Things to be done.
 
 4. A better PLIP (make use of bidirectional/ECP/EPP ports).
 
-See <URL:http://www.cyberelk.demon.co.uk/parport.html>.
+See <URL:http://people.redhat.com/twaugh/parport/>.
index b99d5a344ed0169be6d594c3f3727023cd531198..e2f681c3a4826a18aa42429a8453b494e095872c 100644 (file)
@@ -428,6 +428,7 @@ static int assign_addrs (struct parport *port)
        unsigned char s, last_dev;
        unsigned char daisy;
        int thisdev = numdevs;
+       int detected;
        char *deviceid;
 
        parport_data_forward (port);
@@ -484,8 +485,9 @@ static int assign_addrs (struct parport *port)
        }
 
        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 @@ static int assign_addrs (struct parport *port)
                parport_device_id (thisdev, deviceid, 1000);
 
        kfree (deviceid);
-       return numdevs - thisdev;
+       return detected;
 }
 
 /* Find a device with a particular manufacturer and model string,
index dc4fc69456142b44df7b2c3f1bec717f4a074444..3c675b88ebc31f1e96a18dc6f8770b98743f1e2a 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/parport.h>
+#include <linux/ioport.h>
 #include <asm/setup.h>
 #include <asm/amigahw.h>
 #include <asm/irq.h>
@@ -239,14 +240,19 @@ int __init parport_amiga_init(void)
        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 @@ int init_module(void)
 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
 
index a759b2d7462e37b61f20d1c8f38b1b488e4ea4d0..13a4faea41896d2925393b90e6da2deeba59fded 100644 (file)
@@ -2430,8 +2430,9 @@ static int __devinit parport_pc_pci_probe (struct pci_dev *dev,
                                         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++;
index 07b30b009046581e04e3df834828c3415e7944a4..15efdd65733ffd86ac3a15b0a74b423e3d3ffbf6 100644 (file)
@@ -109,38 +109,106 @@ static int do_autoprobe(ctl_table *table, int write, struct file *filp,
 }
 #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 @@ PARPORT_MAX_SPINTIME_VALUE;
 
 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 @@ static const struct parport_sysctl_table parport_sysctl_template = {
                  &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 @@ int parport_proc_register(struct parport *port)
                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 */
index c85addc5601f6eed5c8935632233160283591840..5ada06a83ccbaefaf6168532431cdb88b85ba22d 100644 (file)
@@ -87,12 +87,14 @@ static void call_driver_chain(int attach, struct parport *port)
 {
        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 @@ int parport_register_driver (struct parport_driver *drv)
        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 @@ void parport_unregister_driver (struct parport_driver *arg)
                        /* 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 @@ void parport_unregister_driver (struct parport_driver *arg)
 
 struct parport *parport_enumerate(void)
 {
+       /* Don't use this: use parport_register_driver instead. */
+
        if (!portlist)
                get_lowlevel_driver ();
 
@@ -297,7 +307,18 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
         * 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 @@ void parport_unregister_port(struct parport *port)
 #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 @@ void parport_unregister_port(struct parport *port)
        }
        spin_unlock(&parportlist_lock);
 
+       /* Yes, parport_enumerate _is_ unsafe.  Don't use it. */
        if (!port->devices)
                free_port (port);
 }
@@ -565,6 +591,9 @@ parport_register_device(struct parport *port, const char *name,
        }
 
        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 @@ void parport_unregister_device(struct pardevice *dev)
         * 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 @@ int parport_claim(struct pardevice *dev)
                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 @@ int parport_claim(struct pardevice *dev)
                        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 @@ void parport_release(struct pardevice *dev)
        }
 
        /* 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);
index 8866a4b56dd382639a09c33954c30aa76b5eb405..0b59ec0b61b2e5984067c71ac545e4cab9571248 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <linux/ioport.h>
+#include <linux/spinlock.h>
 #include <linux/pm.h>
 
 #include <asm/page.h>
index 9adaf86a4a0a9cb2d67e6a81b7a3034101c5007f..9219557f4449ad0133fe010dc6b28262fabe3e84 100644 (file)
 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
 1058  Electronics & Telecommunications RSH
 1059  Teknor Industrial Computers Inc
 105a  Promise Technology, Inc.
+       4d30  20267
        4d33  20246
        4d38  20262
        5300  DC5300
        0646  PCI0646
        0647  PCI0647
        0648  PCI0648
+       0649  PCI0649
        0650  PBC0650A
        0670  USB0670
        0673  USB0673
        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
        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]
                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
                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)
index 3e14858376990522a5ee2b39aeff8f563d04c905..1d5efdfc4e40e885967cb6e0527d042c2ddbaf93 100644 (file)
@@ -138,7 +138,7 @@ static void __init quirk_io_region(struct pci_dev *dev, unsigned region, unsigne
  *     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 @@ static void __init quirk_ali7101(struct pci_dev *dev)
  *     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 @@ static void __init quirk_piix4acpi(struct pci_dev *dev)
  * 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;
@@ -180,6 +180,48 @@ static void __init quirk_via_acpi(struct pci_dev *dev)
        }
 }
 
+/*
+ * 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 @@ static struct pci_fixup pci_fixups[] __initdata = {
        { 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 }
 };
 
index eb3c22cf0c1c0a043eb181552bb93fe5c256c040..02315dc574d9081f45023af5e3d00e38f64b9267 100644 (file)
@@ -4699,7 +4699,8 @@ advansys_detect(Scsi_Host_Template *tpnt)
                             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 @@ advansys_detect(Scsi_Host_Template *tpnt)
 #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 @@ advansys_detect(Scsi_Host_Template *tpnt)
 #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);
index 240041cf04361a0e7eb163d5090c22cb3840ac48..3f17ad86f1ac6ce930628d5cd1b8291498caf9e9 100644 (file)
@@ -1301,10 +1301,11 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
 
                        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");
index 8d041639b000dfce379fa701d7249d2554114314..67648bc75e2add45351fa30b239f320e18dc7e31 100644 (file)
@@ -9551,14 +9551,15 @@ aic7xxx_detect(Scsi_Host_Template *template)
       pdev = NULL;
       while ((pdev = pci_find_device(aic_pdevs[i].vendor_id,
                                      aic_pdevs[i].device_id,
-                                     pdev)))
+                                     pdev))) {
+       if (pci_enable_device(pdev))
+               continue;
 #else
       index = 0;
       while (!(pcibios_find_device(aic_pdevs[i].vendor_id,
                                    aic_pdevs[i].device_id,
-                                   index++, &pci_bus, &pci_devfn)) )
+                                   index++, &pci_bus, &pci_devfn)) ) {
 #endif
-      {
         if ( i == 0 ) /* We found one, but it's the 7810 RAID cont. */
         {
           if (aic7xxx_verbose & (VERBOSE_PROBE|VERBOSE_PROBE2))
@@ -9587,8 +9588,8 @@ aic7xxx_detect(Scsi_Host_Template *template)
           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)
          {
index 6c92531fc97cb3d69a4302ba7b0c283e19f6dfbb..3eb3021f22ea0d51a838f26d1327ebd934a24df8 100644 (file)
@@ -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 <marcelo@conectiva.com.br> : SMP fixes 
- * 
+ *
+ * Marcelo Tosatti <marcelo@conectiva.com.br> : 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 <linux/module.h>
@@ -100,19 +104,19 @@ irq_numok:
        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 @@ irq_numok:
                                if ((inb(tmpcip) & 0x01) == 0)
                                {
                                        goto stop_dma;
-                               }    
+                               }
                        }
                }
 stop_dma:
@@ -133,9 +137,9 @@ stop_dma:
                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 @@ stop_dma:
                /*
                 *      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 @@ stop_dma:
                        dev->in_int = 0;
                        return;
                }
-               if (i == 0x21) 
+               if (i == 0x21)
                {
                        tmport -= 0x05;
                        adrcntu = 0;
@@ -200,7 +206,7 @@ stop_dma:
                        dev->in_int = 0;
                        return;
                }
-               if ((i == 0x80) || (i == 0x8f)) 
+               if ((i == 0x80) || (i == 0x8f))
                {
                        lun = 0;
                        tmport -= 0x07;
@@ -209,7 +215,7 @@ stop_dma:
                                tmport += 0x0d;
                                lun = inb(tmport) & 0x07;
                        } else {
-                               if (j == 0x41) 
+                               if (j == 0x41)
                                {
                                        tmport += 0x02;
                                        adrcntu = 0;
@@ -225,7 +231,7 @@ stop_dma:
                                        dev->in_int = 0;
                                        return;
                                }
-                               else 
+                               else
                                {
                                        outb(0x46, tmport);
                                        dev->id[target_id].dirctu = 0x00;
@@ -246,7 +252,7 @@ stop_dma:
                        /*
                         *      Remap wide identifiers
                         */
-                       if ((target_id & 0x10) != 0) 
+                       if ((target_id & 0x10) != 0)
                        {
                                target_id = (target_id & 0x07) | 0x08;
                        } else {
@@ -271,8 +277,21 @@ stop_dma:
                        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 @@ stop_dma:
                                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 @@ stop_dma:
                                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 @@ stop_dma:
                        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 @@ go_42:
                         */
                        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 @@ go_42:
                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 @@ host_ok:
        /*
         *      Fake a timeout for missing targets
         */
-        
+
        if ((m & dev->active_idu) == 0) {
                req_p->result = 0x00040000;
                done(req_p);
@@ -550,7 +575,17 @@ void send_s870(unsigned char h)
        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 @@ oktosend:
                        workrequ->request_bufflen = 0x08;
                }
        }
+       if (dev->ata_cdbu[0] == 0x00) {
+               workrequ->request_bufflen = 0;
+       }
        /*
         *      Why limit this ????
         */
@@ -600,11 +638,11 @@ oktosend:
                        dev->ata_cdbu[4] = 0x24;
                }
        }
-       
+
        tmport = workportu + 0x1b;
-       j = inb(tmport) & 0x0e;
+       j = 0;
        target_id = workrequ->target;
-       
+
        /*
         *      Wide ?
         */
@@ -612,13 +650,17 @@ oktosend:
        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 @@ oktosend:
         *      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 @@ oktosend:
        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 @@ oktosend:
        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 @@ oktosend:
                restore_flags(flags);
                return;
        }
-       if (inb(tmport) == 0) 
+       if (inb(tmport) == 0)
        {
                tmport = workportu + 0x18;
                outb(0x08, tmport);
@@ -798,20 +853,20 @@ FUN_D7:
                        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 @@ void tscam(unsigned char host)
                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 @@ wait_rdyok:
 
        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 @@ TCM_SYNC:
        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 @@ TCM_5:                  /* isolation complete..  */
        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 @@ small_id:
                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 @@ G2Q_LP:
                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 @@ G2Q_QUIN:               /* k=binID#,       */
 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 @@ void is870(unsigned long host, unsigned int wkport)
                        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 @@ sel_ok:
                        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 @@ inq_ok:
                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 @@ inq_ok:
                        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 @@ widep_cmd:
                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 @@ try_sync:
                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 atp870u_detect(Scsi_Host_Template * tpnt)
        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 @@ int atp870u_detect(Scsi_Host_Template * tpnt)
        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 @@ int atp870u_detect(Scsi_Host_Template * tpnt)
                }
 
                /* 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 @@ int atp870u_detect(Scsi_Host_Template * tpnt)
                        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 @@ int atp870u_detect(Scsi_Host_Template * tpnt)
                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 @@ int atp870u_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
        }
        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 @@ const char *atp870u_info(struct Scsi_Host *notused)
 {
        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 @@ int atp870u_proc_info(char *buffer, char **start, off_t offset, int length,
        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_biosparam(Scsi_Disk * disk, kdev_t dev, int *ip)
 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 @@ int atp870u_release (struct Scsi_Host *pshost)
                }
        }
        panic("atp870u: bad scsi host passed.\n");
-               
+
 }
 
 #ifdef MODULE
index 2bc31ea281d7bc1691d49970d59677043618e5fe..4d1eecef4cdf6c483980ea1c90fbb36e73a42ef0 100644 (file)
@@ -68,11 +68,10 @@ int __init dmx3191d_detect(Scsi_Host_Template *tmpl) {
        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",
index c1939a817a40c4f3a6562e90af1abe62d1a682c7..4f3c09d6c88dd6efb58d4cd1a0461650c93f2a0e 100644 (file)
@@ -829,7 +829,9 @@ static inline void tune_pci_port(unsigned long port_base) {
 
       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",
index 0f072c46eeaddbca9bf65cc52c07e8a92272ab0b..ca3b481108921e39fb346976cd59d672c349861e 100644 (file)
@@ -1388,20 +1388,22 @@ void find_PCI(struct get_conf *buf, Scsi_Host_Template * tpnt)
 #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);
index dca7ca7659a67225e9125443d4ddfaa3255e4781..b276f86293f0bb642bac41c12c8fbffa80ec9814 100644 (file)
@@ -878,19 +878,21 @@ void find_pio_PCI(struct get_conf *buf, Scsi_Host_Template * tpnt)
 #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  */
index 59d9f2415322710ae246c3dc2c173c3318b1addb..71cd7337a64165821c62016b174e77276d8746e6 100644 (file)
@@ -828,6 +828,7 @@ static int fdomain_pci_bios_detect( int *irq, int *iobase )
                               PCI_DEVICE_ID_FD_36C70,
                               pdev)) == NULL)
      return 0;
+   if (pci_enable_device(pdev)) return 0;
        
 #if DEBUG_DETECT
    printk( "scsi: <fdomain> TMC-3260 detect:"
@@ -840,7 +841,7 @@ static int fdomain_pci_bios_detect( int *irq, int *iobase )
    /* 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
index cb42f6b7a855b84f57c692b48babcfcabbf53119..d04270af905a82f0ae23944300be1405725221cf 100644 (file)
@@ -533,6 +533,8 @@ static int __init gdth_search_pci(gdth_pci_str *pcistr)
         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 */
index 63bfa6d650499d7fb25b1c57ba551dcdd53f4e88..2b7121a9b329faad913d5c63c67bc843ae34c4b2 100644 (file)
 #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 @@ int __dummy_1,__dummy_2; \
    : "2" (f), "0" (sp), "1" (i)  /* input */    \
    );       /* trashed */ \
 })
+#endif
 
 /* IN2000 io_port offsets */
 #define IO_WD_ASR       0x00     /* R - 3393 auxstat reg */
index e44bc79297a10df36582cdca45d5469786ba889c..4b903ea98f19018e66ad3932109ccfbdf12ff0c2 100644 (file)
@@ -290,6 +290,8 @@ int tul_NewReturnNumberOfAdapters(void)
        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 @@ int i91u_detect(Scsi_Host_Template * tpnt)
                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 @@ int i91u_detect(Scsi_Host_Template * tpnt)
                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;
@@ -813,3 +815,13 @@ static void i91u_panic(char *msg)
        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;
+}
index a7bef8790f19a9ed67741cdb4bd5e7889fd6ba28..7f7b039a7ad226b8c06cd666fc875bd2ffcfcc1a 100644 (file)
@@ -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 @@ extern int i91u_biosparam(Scsi_Disk *, kdev_t, int *);        /*for linux v2.0 */
        proc_info:      NULL,                           \
        name:           i91u_REVID, \
        detect:         i91u_detect, \
-       release:        NULL, \
+       release:        i91u_release, \
        info:           NULL,                                   \
        command:        i91u_command, \
        queuecommand:   i91u_queue, \
index 7dfc22fc1fe491be9173808ae78d85fec02d2478..6ca6ca7f925e399d2d9578b5d6404beb81ec4371 100644 (file)
@@ -247,6 +247,8 @@ int orc_ReturnNumberOfAdapters(void)
                                        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 @@ int orc_ReturnNumberOfAdapters(void)
                                         */
                                        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 @@ int inia100_detect(Scsi_Host_Template * tpnt)
                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 @@ int inia100_detect(Scsi_Host_Template * tpnt)
                        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 @@ int inia100_detect(Scsi_Host_Template * tpnt)
                /* 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");
@@ -785,4 +787,14 @@ static void inia100_panic(char *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" */
index 509a42b5e166b0ab43007ba7c2f3ecb55a2bc0c6..cc38bca81cdd911a87a295de734c2b17f2eb3d9f 100644 (file)
@@ -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 @@ extern int inia100_biosparam(Scsi_Disk *, kdev_t, int *);     /*for linux v2.0 */
        proc_info:      NULL,                           \
        name:           inia100_REVID, \
        detect:         inia100_detect, \
-       release:        NULL, \
+       release:        inia100_release, \
        info:           NULL,                                   \
        command:        inia100_command, \
        queuecommand:   inia100_queue, \
index 22f98b60df812ab54b4f08a9efdbfb575c0f9f0d..e5c5ca10fc6695b4a38687d49fea79d25f17e68a 100644 (file)
@@ -325,12 +325,13 @@ ips_detect(Scsi_Host_Template *SHT) {
 
       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 @@ ips_detect(Scsi_Host_Template *SHT) {
       }
 
       /* 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 */
index f051d391ad7fee2ff2501f7d781f6d6515f2f08f..03e6d62ab9676b2939f6c337fa922ad66191cc49 100644 (file)
@@ -1478,6 +1478,8 @@ int mega_findCard (Scsi_Host_Template * pHostTmpl,
   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 @@ int mega_findCard (Scsi_Host_Template * pHostTmpl,
     }          
 
     /* 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 @@ int mega_findCard (Scsi_Host_Template * pHostTmpl,
 "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;
index 94007c5a831b0ed8baf3880d944e6a705b70b1c3..2681c520da0140f3c12751f4d5d10020f5c0b340 100644 (file)
@@ -679,10 +679,12 @@ int Pci2000_Detect (Scsi_Host_Template *tpnt)
 
        while ( (pdev = pci_find_device (VENDOR_PSI, DEVICE_ROY_1, pdev)) != NULL )
                {
+               if (pci_enable_device(pdev))
+                       continue;
                pshost = scsi_register (tpnt, sizeof(ADAPTER2000));
                padapter = HOSTDATA(pshost);
 
-               padapter->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;
index ca5c5798182cac019993f5bf9f28e3807fca1ad6..8a59351aac5481aad5468648ef06a8069e2d6c5a 100644 (file)
@@ -2386,8 +2386,8 @@ static USHORT GetRegs (struct Scsi_Host *pshost, BOOL bigd, struct pci_dev *pcid
        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 @@ int Pci2220i_Detect (Scsi_Host_Template *tpnt)
 
        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);
 
index 42f2080620864c2f7aea1b28194c08b37f44c5b4..f3d059df88f2f871748840cab2ff6f14263e2a00 100644 (file)
@@ -801,13 +801,13 @@ qla1280_detect(Scsi_Host_Template *template)
        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 @@ qla1280_detect(Scsi_Host_Template *template)
                /* 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 @@ qla1280_detect(Scsi_Host_Template *template)
                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");
                }
index df9ba38d429585b1790b0cbbf3b52994714899d0..825c777825ac324b8e3259b68b637846a979efed 100644 (file)
@@ -746,6 +746,8 @@ int isp2x00_detect(Scsi_Host_Template * tmpt)
 
        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 @@ static int isp2x00_init(struct Scsi_Host *sh)
                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;
 
 
index b5da20220c5a12ac429c1f9ddf2ea1de4e991ea2..b48a873265562a7e0287846ed83c04e4a4bae278 100644 (file)
@@ -678,6 +678,9 @@ int isp1020_detect(Scsi_Host_Template *tmpt)
 
        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 @@ static int isp1020_init(struct Scsi_Host *sh)
                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) {
index 280cda345991dbb2c4ffe18c68bc4390cd5ddd00..bcdc4aab320394d50d60fc54276f7c3b96e330f7 100644 (file)
@@ -338,6 +338,15 @@ static int sd_init_command(Scsi_Cmnd * SCpnt)
                        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 @@ static void rw_intr(Scsi_Cmnd * SCpnt)
                                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 @@ static int sd_init_onedisk(int i)
                         */
                        rscsi_disks[i].capacity = 0;
                }
-               if (sector_size == 2048) {
+               if (sector_size > 1024) {
                        int m;
 
                        /*
@@ -899,7 +913,7 @@ static int sd_init_onedisk(int i)
                         * of partial sectors.
                         */
                        for (m = i << 4; m < ((i + 1) << 4); m++) {
-                               sd_blocksizes[m] = 2048;
+                               sd_blocksizes[m] = sector_size;
                        }
                } {
                        /*
index c8c5dd54dd2b53df9949cef15a69f9af08d9cf75..ff68dca96a43a465cc1d25623c5bae29f5574ee3 100644 (file)
@@ -311,6 +311,8 @@ static const Signature __initdata signatures[] =
   {"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))
index 4b6b5d510af89834c1b4a2ad972c8358bab6f9a2..a1779ad1095394de9ada3f986572f6b915fd7f9f 100644 (file)
 # 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 <linux/bios32.h>
 # define PDEV pbus, pdevfn
@@ -2002,6 +2002,8 @@ int __init DC390_detect (Scsi_Host_Template *psht)
     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);)
index ac00add8f7e5d6c066184e14683093f757157c47..4fee7b72f5b1dfd125a4455b3de27df952590222 100644 (file)
@@ -3252,7 +3252,7 @@ remove_info(sf_list *sf, int bank, int instr)
        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 @@ remove_info(sf_list *sf, int bank, int instr)
                        sf->num_info--;
                        removed++;
                        kfree(p);
-               }
+               } else
+                       prev = p;
        }
+       if (removed)
+               rebuild_preset_list();
        return removed;
 }
 
@@ -3318,7 +3321,7 @@ awe_load_info(awe_patch_info *patch, const char *addr, int count)
                }
                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;
        }
index 2098c85a8b12cce708509ec91eab697090984c75..8c7f907774b921afe6b4eed45911145dbe6360ca 100644 (file)
@@ -346,6 +346,11 @@ static int __init init_cs4232(void)
        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;
index e47c30f9081dbfb156580fc439d577311fc0b8f5..d0b4f9d6c4d36bce823fbaff918513e7f99ee759 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/malloc.h>
+#include <linux/vmalloc.h>
 #include <linux/types.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
index ef0a1ce2e7262d4f40d983e7640b57b780cb8148..ef87c6293a3cf8c0120ef8cf7b202503b0d39c81 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/pm.h>
+#include <linux/delay.h>
 #include "sound_config.h"
 #include "soundmodule.h"
 #include "nm256.h"
index 86e9a50cad89dd13faf87d35fda8091d41fd7ff8..fa85a927847d6fa3d6776f12b1fefad4f31e414b 100644 (file)
@@ -69,7 +69,7 @@ mix_write(unsigned char data, int ioaddr)
 
        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);
index a6e5448567adf4d6fdbdc8faa5c50b3a90912d53..f66c0b6048279aee9545203ff61b12cdc7eec559 100644 (file)
@@ -42,6 +42,9 @@
  *
  * 06-05-2000 added another card. Daniel M. Newman <dmnewman@pobox.com>
  *
+ * 25-05-2000 Added Creative SB AWE64 Gold (CTL00B2). 
+ *     PÃ¥l-Kristian Engstad <engstad@att.net>
+ * 
  */
 
 #include <linux/config.h>
@@ -264,6 +267,11 @@ static struct {
                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(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),
@@ -344,6 +352,11 @@ static struct {
                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},
        {"Sound Blaster AWE 64",
                ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00C1), 
                ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042),
index f011058a2e8b0618956bbd97c6e26e012c9130d7..fcd5c9ed13beb05e14806b5d6eb320b217153259 100644 (file)
@@ -78,9 +78,9 @@ static int mycard_install(struct pci_dev *pcidev)
         *      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 @@ int init_mycard(void)
                
        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;
index 74253ed994f226d2e7dde9ac1156ed82b9aad289..042f742da5abd660de21679e097b4f1ef419782d 100644 (file)
@@ -10,6 +10,11 @@ if [ ! "$CONFIG_USB" = "n" ]; then
 
 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 @@ comment 'USB Devices'
       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'
index f0ca0476e02fe1df789430a2d0bb86b855544950..ec8687ae6af3d3d094ddaa8afd5169b068bc30f7 100644 (file)
@@ -82,6 +82,7 @@ obj-$(CONFIG_USB_OV511)               += ov511.o
 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.
index 9dbd5197399eb5ac40815f1267cd5f968838efc8..b60733b4adb68d22fea0b79bb964f9ee0b88ceb8 100644 (file)
@@ -329,6 +329,7 @@ static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned c
 
        if (!ACM_READY(acm)) return -EINVAL;
        if (acm->writeurb.status == -EINPROGRESS) return 0;
+       if (!count) return 0;
 
        count = (count > acm->writesize) ? acm->writesize : count;
 
index ad94fef5562bdfc67ace092d8b1e9559a175047d..67f1635a672cbcb5ead56a6edbf183c2b59bdd33 100644 (file)
@@ -1788,7 +1788,7 @@ static int get_rec_src(struct usb_mixerdev *ms)
                               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 @@ static int set_rec_src(struct usb_mixerdev *ms, int srcmask)
                }
                /* 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 @@ static int set_rec_src(struct usb_mixerdev *ms, int srcmask)
                        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 @@ static int usb_audio_open_mixdev(struct inode *inode, struct file *file)
        file->private_data = ms;
        s->count++;
 
-       MOD_INC_USE_COUNT;
        up(&open_sem);
        return 0;
 }
@@ -1949,7 +1948,6 @@ static int usb_audio_release_mixdev(struct inode *inode, struct file *file)
 
        down(&open_sem);
        release(s);
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
@@ -2045,6 +2043,7 @@ static int usb_audio_ioctl_mixdev(struct inode *inode, struct file *file, unsign
 }
 
 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 @@ static int usb_audio_open(struct inode *inode, struct file *file)
        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 @@ static int usb_audio_release(struct inode *inode, struct file *file)
        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 @@ static void usb_audio_mixerunit(struct consmixstate *state, unsigned char *mixer
        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 @@ static void usb_audio_selectorunit(struct consmixstate *state, unsigned char *se
        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 @@ static void usb_audio_selectorunit(struct consmixstate *state, unsigned char *se
                }
                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 @@ static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum)
 #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;
        }
        /*
index c13c4a02ed74e2a8adecad965717f1134d7434c6..8b1df4edfba68359fbd8b37e8837cb7957433af6 100644 (file)
@@ -573,10 +573,9 @@ static int dabusb_open (struct inode *inode, struct file *file)
        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 @@ static int dabusb_open (struct inode *inode, struct file *file)
                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 @@ static int dabusb_release (struct inode *inode, struct file *file)
        else
                wake_up (&s->remove_ok);
 
-       MOD_DEC_USE_COUNT;
        s->opened = 0;
        return 0;
 }
@@ -692,6 +687,7 @@ static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cm
 
 static struct file_operations dabusb_fops =
 {
+       owner:          THIS_MODULE,
        llseek:         dabusb_llseek,
        read:           dabusb_read,
        ioctl:          dabusb_ioctl,
index ddb3685a4ac1b80c6d93e89e492febd6a85ac056..82877003c00874d274699cea527adcab2d810aee 100644 (file)
@@ -49,7 +49,7 @@ typedef struct
 
 
 #define _DABUSB_IF 2
-#define _DABUSB_ISOPIPE 0x89
+#define _DABUSB_ISOPIPE 0x09
 #define _ISOPIPESIZE   16384
 
 #define _BULK_DATA_LEN 64
index b440a82af44207e61cb107a32cec615a2eaf8e7b..4fcfa640c164874ea930d812ff7f671cc48a6f58 100644 (file)
@@ -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 @@ static const struct camera {
     { 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 @@ static int camera_open (struct inode *inode, struct file *file)
        }
 
        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 @@ static int camera_release (struct inode *inode, struct file *file)
                kfree (camera);
        }
 
-       MOD_DEC_USE_COUNT;
-
        dbg ("close"); 
 
        return 0;
@@ -319,6 +314,7 @@ static int camera_release (struct inode *inode, struct file *file)
         */
 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,
index c5d24ec4fcb23dc8a8334efb7b07c667a1d7736a..235385515157a79739682dfdb9aad24eddf8e479 100644 (file)
@@ -187,26 +187,60 @@ static ssize_t usbdev_read(struct file *file, char * buf, size_t nbytes, loff_t
        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 @@ static void driver_disconnect(struct usb_device *dev, void *context)
 }
 
 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 @@ static int findintfif(struct usb_device *dev, unsigned int ifn)
        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 @@ static int proc_resetep(struct dev_state *ps, void *arg)
        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 @@ static int proc_releaseinterface(struct dev_state *ps, void *arg)
        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, size, 0);
+       }
+
+       /* 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 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                        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 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                ret = proc_releaseinterface(ps, (void *)arg);
                break;
 
+       case USBDEVFS_IOCTL:
+               ret = proc_ioctl(ps, (void *) arg);
+               break;
        }
        up_read(&ps->devsem);
        if (ret >= 0)
index 50bbafb3189c34f82df1890e8bbb3d9fdea0e09f..e2056a2e332052599aa35adccbfe197c7738db4f 100644 (file)
@@ -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 @@ static void usb_dsbr100_close(struct video_device *dev);
 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;
index ad3a8ffaced3d11f1f206a0b8d317010e3cf24cd..3e21f6cb526ab26d5962b0c801911b04f6ffc895 100644 (file)
@@ -1,7 +1,7 @@
 /*
- *  evdev.c  Version 0.1
+ * $Id: evdev.c,v 1.8 2000/05/29 09:01:52 vojtech Exp $
  *
- *  Copyright (c) 1999 Vojtech Pavlik
+ *  Copyright (c) 1999-2000 Vojtech Pavlik
  *
  *  Event char devices, giving access to raw input device events.
  *
@@ -72,8 +72,7 @@ static void evdev_event(struct input_handle *handle, unsigned int type, unsigned
                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;
        }
@@ -111,7 +110,6 @@ static int evdev_release(struct inode * inode, struct file * file)
 
        kfree(list);
 
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
@@ -123,10 +121,7 @@ static int evdev_open(struct inode * inode, struct file * file)
        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;
                return -ENOMEM;
        }
        memset(list, 0, sizeof(struct evdev_list));
@@ -207,14 +202,20 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
        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 +223,8 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 
                        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 +236,40 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                                        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,
@@ -286,7 +307,7 @@ static struct input_handle *evdev_connect(struct input_handler *handler, struct
 
        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;
 }
index b72565fb95ee65422a885d7324c73bdabb278c9e..26f5e9e1b640bba361e7bb88ca8e49da60649585 100644 (file)
@@ -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       <gal@cs.uni-magdeburg.de>
  *  (c) 2000 Vojtech Pavlik    <vojtech@suse.cz>
index 6c1f7f1d715e6fc9c40bec87fe4a867a1cb3e6a7..ae529b7464a6483754a7e807cb3b1f78eb7103a9 100644 (file)
@@ -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 @@ static struct {
        __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 @@ static int hid_event(struct input_dev *dev, unsigned int type, unsigned int code
        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 @@ static void hid_init_input(struct hid_device *hid)
 
        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 @@ struct hid_blacklist {
        { 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 @@ static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum)
 
                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 @@ static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum)
        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 struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum)
 
 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 @@ static void* hid_probe(struct usb_device *dev, unsigned int ifnum)
        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;
 }
index 18e7481c2b74cc25394244ea5d8fdb7c53ac87da..88ab5eacade3cdd50c6772ba0af9c0cedde02475 100644 (file)
@@ -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 hid_device {                                                 /* device report descriptor */
        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
index 0b7cf6b0936086012d3a28df26b2a172e2ec5fd6..75794f3ca48bfb280a36462ec5f8cd1beec56423 100644 (file)
@@ -18,7 +18,9 @@
        #undef DEBUG
 #endif
 #include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
 
+#include <asm/semaphore.h>
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 
@@ -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 void usb_hub_power_on(struct usb_hub *hub)
 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));
+               /* <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 @@ static int usb_hub_configure(struct usb_hub *hub)
 
        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 @@ static void *hub_probe(struct usb_device *dev, unsigned int i)
        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 @@ static void hub_disconnect(struct usb_device *dev, void *ptr)
        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 @@ static void usb_hub_port_connect_change(struct usb_device *hub, int port)
                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;tries++) {
-               
+       /* Reset the port */
+       for (tries = 0; tries < MAX_TRIES ; tries++) {
                usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);
-               wait_ms(200);   
-               
-               if (usb_get_port_status(hub, port + 1, &portsts)<0) {
-                       err("get_port_status failed");
-                       return;
+               wait_ms(200);
+
+               ret = usb_get_port_status(hub, port + 1, &portsts);
+               if (ret < 0) {
+                       err("get_port_status(%d) failed (err = %d)", port + 1, ret);
+                       goto out;
                }
+
                portstatus = le16_to_cpu(portsts.wPortStatus);
                portchange = le16_to_cpu(portsts.wPortChange);
                dbg("portstatus %x, change %x, %s", portstatus ,portchange,
@@ -373,7 +419,7 @@ static void usb_hub_port_connect_change(struct usb_device *hub, int port)
 
                if ((portchange & USB_PORT_STAT_C_CONNECTION) ||
                    !(portstatus & USB_PORT_STAT_CONNECTION))
-                       return;
+                       goto out;
 
                if (portstatus & USB_PORT_STAT_ENABLE)
                        break;
@@ -381,20 +427,19 @@ static void usb_hub_port_connect_change(struct usb_device *hub, int port)
                wait_ms(200);
        }
 
-       if (tries==MAX_TRIES) {
+       if (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 @@ static void usb_hub_port_connect_change(struct usb_device *hub, int port)
        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 @@ he_unlock:
 
 static int usb_hub_thread(void *__hub)
 {
-/*
-       MOD_INC_USE_COUNT;
-*/
-       
        khubd_running = 1;
 
        lock_kernel();
@@ -545,10 +599,6 @@ static int usb_hub_thread(void *__hub)
                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 int usb_hub_thread(void *__hub)
 }
 
 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 usb_hub_init(void)
 {
        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 @@ void usb_hub_cleanup(void)
        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;
+
+       down(&usb_address0_sem);
+
+       /* Send a reset to the device */
+       usb_set_port_feature(parent, port + 1, USB_PORT_FEAT_RESET);
+
+       wait_ms(200);
 
-                       usb_disconnect(&dev);
-                       usb_hub_port_connect_change(parent, i);
+       usb_clear_port_feature(parent, port + 1, USB_PORT_FEAT_C_RESET);
 
-                       return 0;
+       /* 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;
 }
 
index 913c44a2d7ade3624c2356412030fec2804d6c49..1be8422dae7eb0455aa07b1a0e3888a04c25e60f 100644 (file)
@@ -72,6 +72,8 @@ struct usb_hub_status {
 #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;
index 35f268fac5b1d3d3b6b19a24bc9ae81856dcb1ae..66a3d2911631e179322e6c1db7e8d10307e31d6c 100644 (file)
@@ -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 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in
                
                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 @@ void input_unregister_handler(struct input_handler *handler)
 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,
 };
 
index 73ebc4e413fa3ef75056ca0083231b3ef4d9a504..0f0bb277325a9daf6724a250259f50ba73c74f2c 100644 (file)
@@ -1,7 +1,7 @@
 /*
- *  joydev.c  Version 0.1
+ * $Id: joydev.c,v 1.7 2000/05/29 09:01:52 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.
@@ -53,7 +53,6 @@ struct joydev {
        int used;
        int open;
        int minor;
-       char name[32];
        struct input_handle handle;
        wait_queue_head_t wait;
        devfs_handle_t devfs;
@@ -139,8 +138,7 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne
                        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;
        }
@@ -178,7 +176,6 @@ static int joydev_release(struct inode * inode, struct file * file)
 
        kfree(list);
 
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
@@ -190,10 +187,7 @@ static int joydev_open(struct inode *inode, struct file *file)
        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;
                return -ENOMEM;
        }
        memset(list, 0, sizeof(struct joydev_list));
@@ -322,6 +316,8 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
 {
        struct joydev_list *list = file->private_data;
        struct joydev *joydev = list->joydev;
+       struct input_dev *dev = joydev->handle.dev;
+
 
        switch (cmd) {
 
@@ -360,9 +356,11 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                                                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 +368,7 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
 }
 
 static struct file_operations joydev_fops = {
+       owner:          THIS_MODULE,
        read:           joydev_read,
        write:          joydev_write,
        poll:           joydev_poll,
@@ -401,8 +400,6 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct
 
        init_waitqueue_head(&joydev->wait);
 
-       sprintf(joydev->name, "joydev%d", joydev->minor);
-
        joydev->minor = minor;
        joydev_table[minor] = joydev;
 
@@ -449,7 +446,7 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct
 
        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;
 }
index 5ba9869e93e3c44899c1ceff497e27480d249a61..76496349b6213685e3d480f80e1d1f1d4245f0b9 100644 (file)
@@ -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 @@ static struct input_handle *keybdev_connect(struct input_handler *handler, struc
 
        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);
 }
index 96fa3a151425e4a09906affb2c1c13fce69e9459..dc578df335d1acc54f93373ee3ec9716bb694532 100644 (file)
@@ -539,17 +539,13 @@ static int mdc800_device_open (struct inode* inode, struct file *file)
 {
        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 @@ static int mdc800_device_open (struct inode* inode, struct file *file)
        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 @@ static int mdc800_device_release (struct inode* inode, struct file *file)
                retval=-EIO;
        }
 
-       MOD_DEC_USE_COUNT;
-
        return retval;
 }
 
@@ -833,6 +826,7 @@ static ssize_t mdc800_device_write (struct file *file, const char *buf, size_t l
 /* 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 --git a/drivers/usb/microtek.c b/drivers/usb/microtek.c
new file mode 100644 (file)
index 0000000..6586b8c
--- /dev/null
@@ -0,0 +1,1051 @@
+/* Driver for Microtek Scanmaker X6 USB scanner, and possibly others.
+ *
+ * (C) Copyright 2000 John Fremlin <vii@penguinpowered.com>
+ * (C) Copyright 2000 Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de>
+ *
+ * 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 <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/usb.h>
+#include <linux/proc_fs.h>
+
+#include <asm/atomic.h>
+#include <linux/blk.h>
+#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 --git a/drivers/usb/microtek.h b/drivers/usb/microtek.h
new file mode 100644 (file)
index 0000000..9392345
--- /dev/null
@@ -0,0 +1,73 @@
+ /*
+ * Driver for Microtek Scanmaker X6 USB scanner and possibly others.
+ * 
+ * (C) Copyright 2000 John Fremlin <vii@penguinpowered.com>
+ * (C) Copyright 2000 Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de>
+ *
+ * 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 */ 
+
index d80385bad75f00a7c10d1c064626fdaa3675984e..399d2a0c018c5441a4b18a9a9d11b0a026783f20 100644 (file)
@@ -1,7 +1,7 @@
 /*
- *  mousedev.c  Version 0.1
+ * $Id: mousedev.c,v 1.8 2000/05/28 17:31:36 vojtech Exp $
  *
- *  Copyright (c) 1999 Vojtech Pavlik
+ *  Copyright (c) 1999-2000 Vojtech Pavlik
  *
  *  Input driver to PS/2 or ImPS/2 device driver module.
  *
@@ -138,8 +138,7 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig
                                        
                        list->ready = 1;
 
-                       if (list->fasync)
-                               kill_fasync(list->fasync, SIGIO, POLL_IN);
+                       kill_fasync(&list->fasync, SIGIO, POLL_IN);
 
                        list = list->next;
                }
@@ -191,7 +190,6 @@ static int mousedev_release(struct inode * inode, struct file * file)
 
        kfree(list);
 
-       MOD_DEC_USE_COUNT;
        return 0;
 }
 
@@ -203,12 +201,8 @@ static int mousedev_open(struct inode * inode, struct file * file)
        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];
@@ -311,8 +305,7 @@ static ssize_t mousedev_write(struct file * file, const char * buffer, size_t co
                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 +369,7 @@ static unsigned int mousedev_poll(struct file *file, poll_table *wait)
 }
 
 struct file_operations mousedev_fops = {
+       owner:          THIS_MODULE,
        read:           mousedev_read,
        write:          mousedev_write,
        poll:           mousedev_poll,
@@ -421,7 +415,7 @@ static struct input_handle *mousedev_connect(struct input_handler *handler, stru
        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;
 }
@@ -459,7 +453,7 @@ static int __init mousedev_init(void)
        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;
 }
index 3ffb6f8eb3dc86f25b51f34dc2c1580fbdb9fdb6..faf057c1693c1c30bb467a582f095e72343ccea5 100644 (file)
@@ -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 <bwallac1@san.rr.com>
+ * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
  * Snapshot code by Kevin Moore
  * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
  * Changes by Claudio Matsuoka <claudio@conectiva.com>
@@ -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 @@ static const char version[] = "1.15";
 
 #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 @@ static const char version[] = "1.15";
 #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 @@ static int ov511_read_proc(char *page, char **start, off_t off,
        /* 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 @@ static int ov511_read_proc(char *page, char **start, off_t off,
                        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 @@ static int ov511_read_proc(char *page, char **start, off_t off,
                        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 @@ ov7610_get_picture(struct usb_ov511 *ov511, struct video_picture *p)
        return 0;
 }
 
-/* FIXME: add 400x300, 176x144, 160x140 */
+/* FIXME: 176x144, 160x140 */
+/* LNCNT values fixed by Lawrence Glaister <lg@jfm.bc.ca> */
 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 @@ static int
 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 @@ ov511_mode_init_regs(struct usb_ov511 *ov511,
                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 @@ ov511_mode_init_regs(struct usb_ov511 *ov511,
                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 @@ ov511_move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v,
  *      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 @@ ov511_move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v,
 
 #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 @@ ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0,
        }
 #endif
 }
+#endif
 
 /*
  * For 640x480 RAW BW images, data shows up in 1200 256 byte segments.
@@ -1252,7 +1257,7 @@ ov511_parse_data_grey(unsigned char *pIn0, unsigned char *pOut0,
                        for (m = 0; m < 8; m++) {
                                *pOut1++ = *pIn++;
                        }
-                       pOut1 += iWidth - WDIV;
+                       pOut1 += iWidth - 8;
                }
                pOut += 8;
        }
@@ -1350,12 +1355,10 @@ static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
 
                /* 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 @@ check_middle:
                        }
 
                        /* 
-                        * 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 @@ check_middle:
                        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 @@ check_middle:
                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_new_frame(struct usb_ov511 *ov511, int framenum)
 
 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 @@ static int ov511_open(struct video_device *dev, int flags)
 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 @@ open_free_ret:
                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 @@ static void ov511_close(struct video_device *dev)
        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 @@ static void ov511_close(struct video_device *dev)
                video_unregister_device(&ov511->vdev);
                kfree(ov511);
        }
+
+       MOD_DEC_USE_COUNT;
+
 }
 
 static int ov511_init_done(struct video_device *dev)
@@ -1887,18 +1895,11 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
                        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 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
        case VIDIOCMCAPTURE:
        {
                struct video_mmap vm;
+               int ret;
 
                if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
                        return -EFAULT;
@@ -2017,8 +2019,12 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
                           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 @@ static int ov76xx_configure(struct usb_ov511 *ov511)
        int i, success;
        int rc;
 
+       /* Lawrence Glaister <lg@jfm.bc.ca> 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 @@ static int ov76xx_configure(struct usb_ov511 *ov511)
                { 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 @@ static int ov76xx_configure(struct usb_ov511 *ov511)
                { 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 @@ error:
        usb_driver_release_interface(&ov511_driver,
                &dev->actconfig->interface[ov511->iface]);
 
-       kfree(ov511);
-       ov511 = NULL;
-
        return -EBUSY;  
 }
 
@@ -2570,9 +2584,12 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
        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 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
        /* 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 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
        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 @@ error:
                ov511 = NULL;
        }
 
+       MOD_DEC_USE_COUNT;
        return NULL;
 }
 
@@ -2649,7 +2667,7 @@ static void ov511_disconnect(struct usb_device *dev, void *ptr)
 {
        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 @@ static void ov511_disconnect(struct usb_device *dev, void *ptr)
 #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 = {
index d3a9a78bad66517e66a8df2a61e721da8c444912..92827afb3321d357137a37bb7c54f705bb762039 100644 (file)
@@ -339,16 +339,11 @@ struct palette_list {
 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;
index b40a947edc83d3f8eea752b1250d8bbfa9ab340b..80b82bba28c3ff237a7abc414d1af92394728506 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/usb.h>
 
 
-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.3.14 2000/06/09 (C) 1999-2000 Petko Manolov (petkan@spct.net)\n";
 
 
 #define        PEGASUS_MTU             1500
@@ -64,8 +64,11 @@ static struct usb_eth_dev usb_dev_id[] = {
        {"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-10", 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},
@@ -80,8 +83,8 @@ static struct usb_eth_dev usb_dev_id[] = {
 #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);}
+       { __u8  __data = value;                 \
+       usb_control_msg(dev, usb_sndctrlpipe(dev,0), 0xf1, 0x40, __data, indx, &__data, 1, HZ);}
 
 
 static int pegasus_read_phy_word(struct usb_device *dev, __u8 index, __u16 *regdata)
@@ -223,7 +226,7 @@ static void pegasus_read_bulk(struct urb *urb)
        __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;
        }
 
@@ -369,9 +372,12 @@ static int pegasus_close(struct net_device *net)
 
        netif_stop_queue(net);
 
-       usb_unlink_urb(&pegasus->rx_urb);
-       usb_unlink_urb(&pegasus->tx_urb);
-       usb_unlink_urb(&pegasus->intr_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;
 
@@ -510,9 +516,12 @@ static void pegasus_disconnect(struct usb_device *dev, void *ptr)
 
        unregister_netdev(pegasus->net);
 
-       usb_unlink_urb(&pegasus->rx_urb);
-       usb_unlink_urb(&pegasus->tx_urb);
-       usb_unlink_urb(&pegasus->intr_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);
 }
index c013a815402939f60eb37d8d1fe0e9825de2701a..a36cd70d17cc819dd05f5295f734ce09f46d5f85 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * printer.c  Version 0.4
+ * printer.c  Version 0.5
  *
- * Copyright (c) 1999 Michael Gee      <michael@linuxspecific.com>
- * Copyright (c) 1999 Pavel Machek      <pavel@suse.cz>
- * Copyright (c) 2000 Vojtech Pavlik    <vojtech@suse.cz>
+ * Copyright (c) 1999 Michael Gee      <michael@linuxspecific.com>
+ * Copyright (c) 1999 Pavel Machek     <pavel@suse.cz>
+ * Copyright (c) 2000 Vojtech Pavlik   <vojtech@suse.cz>
+ * Copyright (c) 2000 Randy Dunlap     <randy.dunlap@intel.com>
  *
  * 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
  */
 
 /*
 #include <linux/usb.h>
 
 #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 @@ struct usblp {
        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 @@ static struct usblp *usblp_table[USBLP_MINORS] = { NULL, /* ... */ };
  * 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 @@ static int usblp_check_status(struct usblp *usblp)
                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 @@ static int usblp_open(struct inode *inode, struct file *file)
        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 @@ static int usblp_release(struct inode *inode, struct file *file)
        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 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait
                              | (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 @@ static ssize_t usblp_write(struct file *file, const char *buffer, size_t count,
                                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 @@ static ssize_t usblp_write(struct file *file, const char *buffer, size_t count,
                        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 @@ static ssize_t usblp_read(struct file *file, char *buffer, size_t count, loff_t
                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 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum)
        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 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum)
                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 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum)
                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 @@ static void usblp_disconnect(struct usb_device *dev, void *ptr)
 
        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 = {
index 38021887eca9f8ae3def2fd333a3e2851f1f0327..d326e58922af322180dad3fd4d396380e6678d97 100644 (file)
@@ -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
  *
  *    - Added wait queues to read_scanner().
  *
  *
+ * 0.4.3.1
+ *
+ *    - Fixed HP S20 ID's...again..sigh.  Thanks to Ruud
+ *      Linders <rlinders@xs4all.nl>.
+ *
+ *
  *  TODO
  *
  *    - Performance
index f8a4d2163645dc220f0b6ca56eb1218df65ba27a..7662f125e1f424a5cdba96086357e3b9c204d224 100644 (file)
@@ -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 @@ static const struct scanner_device {
                { 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 */
index fe2d2013b3251f9e61d818133a8fb79309419f15..c3cce34c36683f852527250b7d03f2c51e89ad19 100644 (file)
 *  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.
 *  (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 <linux/config.h>
 #include <linux/tty.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
-#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/tqueue.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
        #define DEBUG
        #undef DEBUG
 #endif
 
+#include <linux/usb.h>
+#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 */
 #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
 
 /* 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_device( struct usb_serial *serial );
 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 @@ struct usb_serial_device_type digi_acceleport_device = {
 /* 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 @@ struct usb_serial_device_type digi_acceleport_device = {
 *  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 @@ dbg( "digi_write_oob: TOP: port=%d, count=%d", oob_port->number, count );
                        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( &oob_priv->dp_port_lock );
+       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; i<port->write_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_irqrestore( &priv->dp_port_lock, flags );
 
        return( ret );
 
@@ -369,35 +640,35 @@ static int digi_set_modem_signals( struct usb_serial_port *port,
        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 @@ port->number, modem_signals );
                        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 @@ dbg( "digi_rx_throttle: TOP: port=%d", port->number );
 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 @@ static void digi_set_termios( struct usb_serial_port *port,
        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 @@ static void digi_set_termios( struct usb_serial_port *port,
        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 @@ dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, ol
 
                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 @@ dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, ol
                }
 
                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 @@ dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, ol
 
                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 @@ dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, ol
                        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 @@ dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, ol
                        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 @@ dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, ol
                        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 @@ dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, ol
                        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 @@ dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, ol
 
 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 @@ static int digi_ioctl( struct usb_serial_port *port, struct file *file,
 
        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 @@ dbg( "digi_ioctl: TOP: port=%d, cmd=0x%x", port->number, cmd );
        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 @@ static int digi_write( struct usb_serial_port *port, int from_user,
 
        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 @@ port->number, count, from_user, in_interrupt() );
                        new_len = 0;
                }
 
-               spin_unlock( &priv->dp_port_lock );
+               spin_unlock_irqrestore( &priv->dp_port_lock, flags );
 
                return( new_len );
 
@@ -736,43 +1082,41 @@ port->number, count, from_user, in_interrupt() );
        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; i<port->write_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 @@ port->number, count, from_user, in_interrupt() );
        } 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 @@ static void digi_write_bulk_callback( struct urb *urb )
 
        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 @@ dbg( "digi_write_bulk_callback: TOP: port=%d", port->number );
                        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; i<port->write_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 @@ dbg( "digi_write_bulk_callback: TOP: port=%d", port->number );
                }
 
        }
-       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 @@ static int digi_write_room( struct usb_serial_port *port )
 
        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 @@ static int digi_chars_in_buffer( struct usb_serial_port *port )
        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 @@ dbg( "digi_chars_in_buffer: port=%d, chars=%d", port->number, priv->dp_buf_len )
 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 @@ dbg( "digi_open: TOP: port %d, active:%d", port->number, port->active );
 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 @@ dbg( "digi_close: TOP: port %d, active:%d", port->number, port->active );
                        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 @@ static int digi_startup( struct usb_serial *serial )
 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 @@ dbg( "digi_startup: TOP" );
                        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 @@ static void digi_read_bulk_callback( struct urb *urb )
        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 @@ static void digi_read_bulk_callback( struct urb *urb )
        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 @@ dbg( "digi_read_bulk_callback: TOP: port=%d", port->number );
        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; i<urb->actual_length; ++i ) {
                printk( "%.2x ", ((unsigned char *)urb->transfer_buffer)[i] );
        }
@@ -1196,7 +1607,7 @@ if( urb->actual_length ) {
 #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 @@ if( urb->actual_length ) {
 
        /* 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; i<urb->actual_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 );
        }
 
 }
-
index f2e11fc285eea21d001a91d4acba7f185af4f046..25d1d24cf8eca5b633efa7bded9297525f20f6bf 100644 (file)
@@ -65,7 +65,7 @@ int usb_init(void)
 #endif
 {
        usb_major_init();
-        usbdevfs_init();
+       usbdevfs_init();
        usb_hub_init();
 
 #ifndef CONFIG_USB_MODULE
index a37e805f0f018cb5eae35e610c43e0312d7bfec2..b1d2d2a0189a3e42dd65a4a55cf29f6e6fdb3f7d 100644 (file)
@@ -527,12 +527,12 @@ static int sohci_unlink_urb (urb_t * urb)
 #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 @@ static int sohci_unlink_urb (urb_t * urb)
                        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 @@ static int hc_start_ohci (struct pci_dev * dev)
                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) {
index f2c51f2058cabacb81ca477f38a016e52d44a20b..ba9b44ac314157651398bd00b36018ea3dfc4de7 100644 (file)
@@ -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 <linux/config.h>
@@ -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 <linux/usb.h>
 #include "usb-uhci.h"
@@ -2600,7 +2600,7 @@ _static void start_hc (uhci_t *s)
        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;
 
index 75e1c1b92bd96ab04e8af4a76d7b7363dc619d6e..08ef79fe42408a94137af1aa00ac1decfae7ee8a 100644 (file)
@@ -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
 #endif
 #include <linux/usb.h>
 
+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 @@ int usb_register(struct usb_driver *new_driver)
        }
 
        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 @@ static void usb_drivers_purge(struct usb_driver *driver,struct usb_device *dev)
                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 @@ void usb_deregister(struct usb_driver *driver)
        }
 }
 
+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 @@ static long calc_bus_time (int low_speed, int input_dir, int isoc, int bytecount
 
        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 <bustime in us> if successful,
+ * or USB_ST_BANDWIDTH_ERROR if bandwidth request fails.
  *
  * FIXME:
  * This initial implementation does not use Endpoint.bInterval
@@ -204,21 +227,67 @@ static long calc_bus_time (int low_speed, int input_dir, int isoc, int bytecount
  * 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 @@ struct usb_bus *usb_alloc_bus(struct usb_operations *op)
        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 @@ static int usb_find_interface_driver(struct usb_device *dev, unsigned ifnum)
                                                       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 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus)
        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);
 
@@ -658,21 +730,6 @@ int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
        return usb_start_wait_urb(urb,timeout,actual_length);
 }
 
-/*
- * 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()
  *
@@ -684,6 +741,7 @@ int usb_get_current_frame_number(struct usb_device *usb_dev)
        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 @@ static int usb_parse_interface(struct usb_device *dev, struct usb_interface *int
                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 @@ void usb_destroy_configuration(struct usb_device *dev)
        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 @@ void usb_disconnect(struct usb_device **pdev)
                        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 @@ void usb_disconnect(struct usb_device **pdev)
        }
 
        /* 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 @@ int usb_set_idle(struct usb_device *dev, int ifnum, int duration, int report_id)
                (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_clear_halt(struct usb_device *dev, int pipe)
 
 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; i<dev->actconfig->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_set_report(struct usb_device *dev, int ifnum, unsigned char type, unsign
 
 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 @@ int usb_get_configuration(struct usb_device *dev)
        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 @@ int usb_get_configuration(struct usb_device *dev)
                        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_string(struct usb_device *dev, int index, char *buf, size_t size)
  */
 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 @@ int usb_new_device(struct usb_device *dev)
        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 @@ int usb_new_device(struct usb_device *dev)
                        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 @@ int usb_new_device(struct usb_device *dev)
 #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 @@ static int usb_open(struct inode * inode, struct file * file)
 {
        int minor = MINOR(inode->i_rdev);
        struct usb_driver *c = usb_minors[minor/16];
-
-       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;
+       int err = -ENODEV;
+       struct file_operations *old_fops;
+
+       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 @@ struct list_head *usb_bus_get_list(void)
  * 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_new_device);
 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);
index 6eb49248c84042465ca39dac020f6da9fa90ddab..42f82604e78d2039d8d84dbc690efb6c76fa1632 100644 (file)
@@ -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 usb_kbd {
        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 @@ static void usb_kbd_led(struct urb *urb)
                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 @@ static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum)
        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 @@ static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum)
        
        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 @@ static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum)
        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);
 
-       printk(KERN_INFO "input%d: USB HIDBP keyboard\n", kbd->dev.number);
+       kfree(buf);
+
+       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;
 }
index a6d0fe8cf9e2703d8252ccbd3610920010d93dad..55bd14fdbba8338326211e97bdeca9caf06a9414 100644 (file)
@@ -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
  *
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 
-#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 @@ static void usb_mouse_irq(struct urb *urb)
 
        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 @@ static void *usb_mouse_probe(struct usb_device *dev, unsigned int ifnum)
        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 @@ static void *usb_mouse_probe(struct usb_device *dev, unsigned int ifnum)
        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 @@ static void *usb_mouse_probe(struct usb_device *dev, unsigned int ifnum)
        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;
 
-               FILL_INT_URB(&mouse->irq, dev, pipe, mouse->data, maxp > 8 ? 8 : maxp,
-                       usb_mouse_irq, mouse, endpoint->bInterval);
-       }
+       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;
 
-       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;
 }
index 4a0d3accd0b4b445689fe8d99ad7f1c6d68a47e2..12cb880e4b81a6397e5d836bbe9ec88a28050f62 100644 (file)
@@ -546,14 +546,14 @@ static void * uss720_probe(struct usb_device *usbdev, unsigned int ifnum)
        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)
                return NULL;
index 3fa4a2d35b715c028675721c9d137bdf7c82f7f4..de2821e4709756664056b8e10f435e0bd66ec3c0 100644 (file)
@@ -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          <vojtech@suse.cz>
  *  Copyright (c) 2000 Andreas Bach Aaen       <abach@stofanet.dk>
@@ -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 wacom {
        struct urb irq;
        struct wacom_features *features;
        int tool;
+       int open;
 };
 
 static void wacom_graphire_irq(struct urb *urb)
@@ -137,18 +141,18 @@ static void wacom_graphire_irq(struct urb *urb)
        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 @@ static void wacom_graphire_irq(struct urb *urb)
 
        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 @@ static void wacom_intuos_irq(struct urb *urb)
 
                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 @@ static void wacom_intuos_irq(struct urb *urb)
        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 @@ static void *wacom_probe(struct usb_device *dev, unsigned int ifnum)
        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;
 }
index 1d8402f9715000a01451aec2ebea6641d771aebf..dff963b7499611c0aab19d76d17fab8637eaabb0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  wmforce.c  Version 0.1
+ * $Id: wmforce.c,v 1.6 2000/05/29 09:01:52 vojtech Exp $
  *
  *  Copyright (c) 2000 Vojtech Pavlik
  *
@@ -44,6 +44,7 @@ struct wmforce {
        signed char data[8];
        struct input_dev dev;
        struct urb irq;
+       int open;
 };
 
 static struct {
@@ -51,6 +52,8 @@ static struct {
         __s32 y;
 } wmforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
 
+static char *wmforce_name = "Logitech WingMan Force";
+
 static void wmforce_irq(struct urb *urb)
 {
        struct wmforce *wmforce = urb->context;
@@ -71,15 +74,36 @@ static void wmforce_irq(struct urb *urb)
        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));
+       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 int wmforce_open(struct input_dev *dev)
+{
+       struct wmforce *wmforce = dev->private;
+
+       if (wmforce->open++)
+               return 0;
+
+       if (usb_submit_urb(&wmforce->irq))
+               return -EIO;
+
+       return 0;
+}
+
+static void wmforce_close(struct input_dev *dev)
+{
+       struct wmforce *wmforce = dev->private;
+
+       if (!--wmforce->open)
+               usb_unlink_urb(&wmforce->irq);
 }
 
 static void *wmforce_probe(struct usb_device *dev, unsigned int ifnum)
@@ -105,33 +129,34 @@ static void *wmforce_probe(struct usb_device *dev, unsigned int ifnum)
        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;
+       wmforce->dev.absmax[ABS_THROTTLE] = 255;
+       wmforce->dev.absmin[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;
        }
 
+       wmforce->dev.private = wmforce;
+       wmforce->dev.open = wmforce_open;
+       wmforce->dev.close = wmforce_close;
+
+       wmforce->dev.name = wmforce_name;
+       wmforce->dev.idbus = BUS_USB;
+       wmforce->dev.idvendor = dev->descriptor.idVendor;
+       wmforce->dev.idproduct = dev->descriptor.idProduct;
+       wmforce->dev.idversion = dev->descriptor.bcdDevice;
+
        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);
+       printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n",
+                wmforce->dev.number, wmforce_name, dev->bus->busnum, dev->devnum, ifnum);
 
        return wmforce;
 }
index d782aa248f7ee829c449c3cb7090f72e54c249e5..a7ad1fbf0369093d25a698006038fcf323bd5cc8 100644 (file)
 #define SO_SECURITY_ENCRYPTION_TRANSPORT       20
 #define SO_SECURITY_ENCRYPTION_NETWORK         21
 
+/* Nast libc5 fixup - bletch */
+#if defined(__KERNEL__)
+/* Socket types. */
+#define SOCK_STREAM    1               /* stream (connection) socket   */
+#define SOCK_DGRAM     2               /* datagram (conn.less) socket  */
+#define SOCK_RAW       3               /* raw socket                   */
+#define SOCK_RDM       4               /* reliably-delivered message   */
+#define SOCK_SEQPACKET 5               /* sequential packet socket     */
+#define SOCK_PACKET    10              /* linux specific way of        */
+                                       /* getting packets at the dev   */
+                                       /* level.  For writing rarp and */
+                                       /* other similar things on the  */
+                                       /* user level.                  */
+#endif
+
 #endif /* _ASM_SOCKET_H */
diff --git a/include/asm-i386/mc146818rtc.h b/include/asm-i386/mc146818rtc.h
new file mode 100644 (file)
index 0000000..8729c5d
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Machine dependent access functions for RTC registers.
+ */
+#ifndef _ASM_MC146818RTC_H
+#define _ASM_MC146818RTC_H
+
+#include <asm/io.h>
+
+#ifndef RTC_PORT
+#define RTC_PORT(x)    (0x70 + (x))
+#define RTC_ALWAYS_BCD 1       /* RTC operates in binary mode */
+#endif
+
+/*
+ * The yet supported machines all access the RTC index register via
+ * an ISA port access but the way to access the date register differs ...
+ */
+#define CMOS_READ(addr) ({ \
+outb_p((addr),RTC_PORT(0)); \
+inb_p(RTC_PORT(1)); \
+})
+#define CMOS_WRITE(val, addr) ({ \
+outb_p((addr),RTC_PORT(0)); \
+outb_p((val),RTC_PORT(1)); \
+})
+
+#endif /* _ASM_MC146818RTC_H */
index 729c11e7709d637bdb89eba58bcad5c638ef473b..e1ee66d0333fdef4f177217870fcf1d2606ea35d 100644 (file)
@@ -244,7 +244,7 @@ extern unsigned int mca_pentium_flag;
 #define IO_BITMAP_OFFSET offsetof(struct tss_struct,io_bitmap)
 #define INVALID_IO_BITMAP_OFFSET 0x8000
 
-#ifndef CONFIG_X86_FX
+#ifndef CONFIG_X86_FXSR
 
 #define i387_save_hard(x) \
        __asm__("fnsave %0\n\tfwait": :"m" (x))
index 827c5319217f00320dc998ca1463b9cf8fe07045..9088efe2c4eb7f6585109a44fedfe0d0caa9789a 100644 (file)
@@ -3,6 +3,8 @@
 
 #include <linux/linkage.h>
 
+#ifdef __KERNEL__
+
 /*
  * SMP- and interrupt-safe semaphores..
  *
@@ -373,3 +375,4 @@ extern inline void up_write(struct rw_semaphore *sem)
 }
 
 #endif
+#endif
index bb66dbe4922748c04112d6164a19d7af733bea4c..ce6710293190caa15af70340c4f2887f3e5c70d4 100644 (file)
@@ -25,7 +25,7 @@ struct _fpstate {
                        datasel;
        struct _fpreg   _st[8];
        unsigned long   status;
-#ifdef CONFIG_X86_FX
+#ifdef CONFIG_X86_FXSR
        unsigned long   mxcsr;
        unsigned long   _xmm[4*22];
 #endif
index 5bfc099711235a8d2bd4152d7d902f4c8e7cd545..b547eeca1476dde99f1f08305f7c6a15511770d8 100644 (file)
 
 #define SO_PEERNAME            28
 
+/* Nast libc5 fixup - bletch */
+#if defined(__KERNEL__)
+/* Socket types. */
+#define SOCK_STREAM    1               /* stream (connection) socket   */
+#define SOCK_DGRAM     2               /* datagram (conn.less) socket  */
+#define SOCK_RAW       3               /* raw socket                   */
+#define SOCK_RDM       4               /* reliably-delivered message   */
+#define SOCK_SEQPACKET 5               /* sequential packet socket     */
+#define SOCK_PACKET    10              /* linux specific way of        */
+                                       /* getting packets at the dev   */
+                                       /* level.  For writing rarp and */
+                                       /* other similar things on the  */
+                                       /* user level.                  */
+#endif
+
 #endif /* _ASM_SOCKET_H */
index 69e4c877481cdcaf9c61341209d7408d49778050..877ed2eecb443aa69a4bf98ce9b53f40c83bcd2e 100644 (file)
 
 #define SO_PEERNAME             28
 
+/* Nast libc5 fixup - bletch */
+#if defined(__KERNEL__)
+/* Socket types. */
+#define SOCK_STREAM    1               /* stream (connection) socket   */
+#define SOCK_DGRAM     2               /* datagram (conn.less) socket  */
+#define SOCK_RAW       3               /* raw socket                   */
+#define SOCK_RDM       4               /* reliably-delivered message   */
+#define SOCK_SEQPACKET 5               /* sequential packet socket     */
+#define SOCK_PACKET    10              /* linux specific way of        */
+                                       /* getting packets at the dev   */
+                                       /* level.  For writing rarp and */
+                                       /* other similar things on the  */
+                                       /* user level.                  */
+#endif
+
 #endif /* _ASM_IA64_SOCKET_H */
index 53ce7e6746080bc044a5f0da94c67ae39f86ae57..35bc3e18ed63a4931e14c1269aefb38ab9d0fdf3 100644 (file)
@@ -113,6 +113,8 @@ struct irq_server {
 extern void amiga_do_irq(int irq, struct pt_regs *fp);
 extern void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server);
 
+extern unsigned short amiga_intena_vals[];
+
 /* CIA interrupt control register bits */
 
 #define CIA_ICR_TA     0x01
index 0bd5a5315ef666a11b67a74267d6888d608f757b..2d97e06d9affe8cd18801566256389931fa803cf 100644 (file)
 
 #define SO_PEERNAME             28
 
+/* Nast libc5 fixup - bletch */
+#if defined(__KERNEL__)
+/* Socket types. */
+#define SOCK_STREAM    1               /* stream (connection) socket   */
+#define SOCK_DGRAM     2               /* datagram (conn.less) socket  */
+#define SOCK_RAW       3               /* raw socket                   */
+#define SOCK_RDM       4               /* reliably-delivered message   */
+#define SOCK_SEQPACKET 5               /* sequential packet socket     */
+#define SOCK_PACKET    10              /* linux specific way of        */
+                                       /* getting packets at the dev   */
+                                       /* level.  For writing rarp and */
+                                       /* other similar things on the  */
+                                       /* user level.                  */
+#endif
+
 #endif /* _ASM_SOCKET_H */
index 5108021ba0c343db69f27a5dce7dbd998df2ac9a..b98107cfe9831a971e34d6d13e97e05c6de77a91 100644 (file)
@@ -60,19 +60,19 @@ To add: #define SO_REUSEPORT 0x0200 /* Allow local address and port reuse.  */
 
 #define SO_PEERNAME             28
 
-/* Types of sockets.  */
-#define SOCK_DGRAM 1           /* Connectionless, unreliable datagrams
-                                  of fixed maximum length.  */
-#define SOCK_STREAM 2          /* Sequenced, reliable, connection-based
-                                  byte streams.  */
-#define SOCK_RAW 3             /* Raw protocol interface.  */
-#define SOCK_RDM 4             /* Reliably-delivered messages.  */
-#define SOCK_SEQPACKET 5       /* Sequenced, reliable, connection-based,
-                                  datagrams of fixed maximum length.  */
-#define SOCK_PACKET 10         /* Linux specific way of getting packets at
-                                  the dev level.  For writing rarp and
-                                  other similar things on the user level.  */
-
-#endif /* __KERNEL__ */
+/* Nast libc5 fixup - bletch */
+#if defined(__KERNEL__)
+/* Socket types. */
+#define SOCK_DGRAM     1               /* datagram (conn.less) socket  */
+#define SOCK_STREAM    2               /* stream (connection) socket   */
+#define SOCK_RAW       3               /* raw socket                   */
+#define SOCK_RDM       4               /* reliably-delivered message   */
+#define SOCK_SEQPACKET 5               /* sequential packet socket     */
+#define SOCK_PACKET    10              /* linux specific way of        */
+                                       /* getting packets at the dev   */
+                                       /* level.  For writing rarp and */
+                                       /* other similar things on the  */
+                                       /* user level.                  */
+#endif
 
 #endif /* _ASM_SOCKET_H */
index 02be40b6b0058e6760083fc11fa25812d84efbc1..b9098caa4676145b71962b97a6f1a14ba8bdd6b1 100644 (file)
@@ -61,22 +61,21 @@ To add: #define SO_REUSEPORT 0x0200 /* Allow local address and port reuse.  */
 #define SO_ATTACH_FILTER        26
 #define SO_DETACH_FILTER        27
 
-#ifdef __KERNEL__
-
 #define SO_PEERNAME             28
 
-/* Types of sockets.  */
-#define SOCK_DGRAM 1           /* Connectionless, unreliable datagrams
-                                  of fixed maximum length.  */
-#define SOCK_STREAM 2          /* Sequenced, reliable, connection-based
-                                  byte streams.  */
-#define SOCK_RAW 3             /* Raw protocol interface.  */
-#define SOCK_RDM 4             /* Reliably-delivered messages.  */
-#define SOCK_SEQPACKET 5       /* Sequenced, reliable, connection-based,
-                                  datagrams of fixed maximum length.  */
-#define SOCK_PACKET 10         /* Linux specific way of getting packets at
-                                  the dev level.  For writing rarp and
-                                  other similar things on the user level.  */
-#endif /* __KERNEL__ */
+/* Nast libc5 fixup - bletch */
+#if defined(__KERNEL__)
+/* Socket types. */
+#define SOCK_DGRAM     1               /* datagram (conn.less) socket  */
+#define SOCK_STREAM    2               /* stream (connection) socket   */
+#define SOCK_RAW       3               /* raw socket                   */
+#define SOCK_RDM       4               /* reliably-delivered message   */
+#define SOCK_SEQPACKET 5               /* sequential packet socket     */
+#define SOCK_PACKET    10              /* linux specific way of        */
+                                       /* getting packets at the dev   */
+                                       /* level.  For writing rarp and */
+                                       /* other similar things on the  */
+                                       /* user level.                  */
+#endif
 
 #endif /* _ASM_SOCKET_H */
index 644f064b0fe2d49e06c91c0e1416f5f5f8bfaff6..387ee177481cd9e0943651df28e493e6244e7786 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: socket.h,v 1.6 2000/02/27 19:47:58 davem Exp $ */
+/* $Id: socket.h,v 1.7 2000/06/09 07:35:28 davem Exp $ */
 #ifndef _ASM_SOCKET_H
 #define _ASM_SOCKET_H
 
 #define SO_SECURITY_ENCRYPTION_TRANSPORT       0x5002
 #define SO_SECURITY_ENCRYPTION_NETWORK         0x5004
 
+/* Nast libc5 fixup - bletch */
+#if defined(__KERNEL__)
+/* Socket types. */
+#define SOCK_STREAM    1               /* stream (connection) socket   */
+#define SOCK_DGRAM     2               /* datagram (conn.less) socket  */
+#define SOCK_RAW       3               /* raw socket                   */
+#define SOCK_RDM       4               /* reliably-delivered message   */
+#define SOCK_SEQPACKET 5               /* sequential packet socket     */
+#define SOCK_PACKET    10              /* linux specific way of        */
+                                       /* getting packets at the dev   */
+                                       /* level.  For writing rarp and */
+                                       /* other similar things on the  */
+                                       /* user level.                  */
+#endif
+
 #endif /* _ASM_SOCKET_H */
index 9ca80334f968c7318f91a7ff99c62bbcdbae8d56..da0e27de752c45ade3645d06bdae6cbf233cd645 100644 (file)
@@ -173,10 +173,10 @@ typedef struct _awe_voice_info {
 
        short root;                     /* midi root key */
        short tune;                     /* pitch tuning (in cents) */
-       char low, high;                 /* key note range */
-       char vellow, velhigh;           /* velocity range */
-       char fixkey, fixvel;            /* fixed key, velocity */
-       char pan, fixpan;               /* panning, fixed panning */
+       signed char low, high;          /* key note range */
+       signed char vellow, velhigh;    /* velocity range */
+       signed char fixkey, fixvel;     /* fixed key, velocity */
+       signed char pan, fixpan;        /* panning, fixed panning */
        short exclusiveClass;           /* exclusive class (0 = none) */
        unsigned char amplitude;        /* sample volume (127 max) */
        unsigned char attenuation;      /* attenuation (0.375dB) */
index ddb84dd6283ca1379a06163aabbf92f5457e3d97..b155b779696bd8904cd4d1963fb5b4299dd6cb63 100644 (file)
@@ -8,7 +8,7 @@
  * differs in spirit from the above ffz (man ffs).
  */
 
-extern __inline__ int generic_ffs(int x)
+static inline int generic_ffs(int x)
 {
        int r = 1;
 
@@ -42,7 +42,7 @@ extern __inline__ int generic_ffs(int x)
  * of bits set) of a N-bit word
  */
 
-extern __inline__ unsigned int generic_hweight32(unsigned int w)
+static inline unsigned int generic_hweight32(unsigned int w)
 {
         unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
         res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
@@ -51,7 +51,7 @@ extern __inline__ unsigned int generic_hweight32(unsigned int w)
         return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
 }
 
-extern __inline__ unsigned int generic_hweight16(unsigned int w)
+static inline unsigned int generic_hweight16(unsigned int w)
 {
         unsigned int res = (w & 0x5555) + ((w >> 1) & 0x5555);
         res = (res & 0x3333) + ((res >> 2) & 0x3333);
@@ -59,7 +59,7 @@ extern __inline__ unsigned int generic_hweight16(unsigned int w)
         return (res & 0x00FF) + ((res >> 8) & 0x00FF);
 }
 
-extern __inline__ unsigned int generic_hweight8(unsigned int w)
+static inline unsigned int generic_hweight8(unsigned int w)
 {
         unsigned int res = (w & 0x55) + ((w >> 1) & 0x55);
         res = (res & 0x33) + ((res >> 2) & 0x33);
index 88d3770b9ab9ba27f1e3b266a7b0a27e12c7a81a..9888625349e268b12cf84f4098179a7ecb8e123f 100644 (file)
@@ -32,7 +32,7 @@ struct elevator_s
                                                        \
        128,                    /* read_latency */      \
        8192,                   /* write_latency */     \
-       4,                      /* max_bomb_segments */ \
+       32,                     /* max_bomb_segments */ \
                                                        \
        0,                      /* nr_segments */       \
        0,                      /* read_pendings */     \
index 2995d563d28004fc8c172c717cbda98e3282eb63..8eb171810f43eba8313713a2e24db849c7e0a710 100644 (file)
@@ -85,14 +85,14 @@ struct softirq_action
 asmlinkage void do_softirq(void);
 extern void open_softirq(int nr, void (*action)(struct softirq_action*), void *data);
 
-extern __inline__ void __cpu_raise_softirq(int cpu, int nr)
+static inline void __cpu_raise_softirq(int cpu, int nr)
 {
        softirq_state[cpu].active |= (1<<nr);
 }
 
 
 /* I do not want to use atomic variables now, so that cli/sti */
-extern __inline__ void raise_softirq(int nr)
+static inline void raise_softirq(int nr)
 {
        unsigned long flags;
 
@@ -165,7 +165,7 @@ extern struct tasklet_head tasklet_hi_vec[NR_CPUS];
 #define tasklet_unlock(t) do { } while (0)
 #endif
 
-extern __inline__ void tasklet_schedule(struct tasklet_struct *t)
+static inline void tasklet_schedule(struct tasklet_struct *t)
 {
        if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
                int cpu = smp_processor_id();
@@ -179,7 +179,7 @@ extern __inline__ void tasklet_schedule(struct tasklet_struct *t)
        }
 }
 
-extern __inline__ void tasklet_hi_schedule(struct tasklet_struct *t)
+static inline void tasklet_hi_schedule(struct tasklet_struct *t)
 {
        if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
                int cpu = smp_processor_id();
@@ -194,18 +194,18 @@ extern __inline__ void tasklet_hi_schedule(struct tasklet_struct *t)
 }
 
 
-extern __inline__ void tasklet_disable_nosync(struct tasklet_struct *t)
+static inline void tasklet_disable_nosync(struct tasklet_struct *t)
 {
        atomic_inc(&t->count);
 }
 
-extern __inline__ void tasklet_disable(struct tasklet_struct *t)
+static inline void tasklet_disable(struct tasklet_struct *t)
 {
        tasklet_disable_nosync(t);
        tasklet_unlock_wait(t);
 }
 
-extern __inline__ void tasklet_enable(struct tasklet_struct *t)
+static inline void tasklet_enable(struct tasklet_struct *t)
 {
        atomic_dec(&t->count);
 }
@@ -240,7 +240,7 @@ extern struct tasklet_struct bh_task_vec[];
 /* It is exported _ONLY_ for wait_on_irq(). */
 extern spinlock_t global_bh_lock;
 
-extern __inline__ void mark_bh(int nr)
+static inline void mark_bh(int nr)
 {
        tasklet_hi_schedule(bh_task_vec+nr);
 }
index a3900e53c8e042c29341736d56702cbcf1b1b91b..4fbe523ab45abf765cac55f93a9146e3fa8469ff 100644 (file)
@@ -42,16 +42,26 @@ static __inline__ void __list_add(struct list_head * new,
        prev->next = new;
 }
 
-/*
- * Insert a new entry after the specified head..
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
  */
 static __inline__ void list_add(struct list_head *new, struct list_head *head)
 {
        __list_add(new, head, head->next);
 }
 
-/*
- * Insert a new entry before the specified head..
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
  */
 static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
 {
@@ -72,18 +82,28 @@ static __inline__ void __list_del(struct list_head * prev,
        prev->next = next;
 }
 
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ */
 static __inline__ void list_del(struct list_head *entry)
 {
        __list_del(entry->prev, entry->next);
 }
 
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
 static __inline__ int list_empty(struct list_head *head)
 {
        return head->next == head;
 }
 
-/*
- * Splice in "list" into "head"
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
  */
 static __inline__ void list_splice(struct list_head *list, struct list_head *head)
 {
@@ -101,9 +121,20 @@ static __inline__ void list_splice(struct list_head *list, struct list_head *hea
        }
 }
 
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:       the &struct list_head pointer.
+ * @type:      the type of the struct this is embedded in.
+ * @member:    the name of the list_struct within the struct.
+ */
 #define list_entry(ptr, type, member) \
        ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
 
+/**
+ * list_for_each       -       iterate over a list
+ * @pos:       the &struct list_head to use as a loop counter.
+ * @head:      the head for your list.
+ */
 #define list_for_each(pos, head) \
        for (pos = (head)->next; pos != (head); pos = pos->next)
 
index 0a6e120d6623c53aa9202bff0cb4439522e3a510..17a421ab8b49a10bed25ea6ee0d22ea11c0dee0e 100644 (file)
@@ -67,6 +67,8 @@
 #define CM206_CDROM_MAJOR 32
 #define IDE2_MAJOR     33
 #define IDE3_MAJOR     34
+#define XPRAM_MAJOR     35      /* expanded storage on S/390 = "slow ram" */
+                                /* proposed by Peter                      */
 #define NETLINK_MAJOR  36
 #define PS2ESDI_MAJOR  36
 #define IDETAPE_MAJOR  37
index 9cf4b9a148a6bffd98450cb32272e35afe763a0c..f2bc32f72974b0965fe1675860ca81bda3e5e2dc 100644 (file)
@@ -20,6 +20,7 @@
 #define SUN_OPENPROM_MINOR 139
 #define NVRAM_MINOR 144
 #define I2O_MINOR 166
+#define MICROCODE_MINOR                184
 #define MISC_DYNAMIC_MINOR 255
 
 #define SGI_GRAPHICS_MINOR   146
index 39d3e5560e6d84338244ce93583d27fccd8fb998..a561f805fdded9b91c487a09189deb909c5cd7e4 100644 (file)
@@ -144,6 +144,7 @@ struct module_info
 
 /* Find a symbol exported by the kernel or another module */
 extern unsigned long get_module_symbol(char *, char *);
+extern void put_module_symbol(unsigned long);
 
 extern int try_inc_mod_count(struct module *mod);
 
index 0c2289c061cfbdfe077685f71dfba858778e03fc..084f25b4c949f07fd3414f2f570c96424054799c 100644 (file)
 
 #define PCI_VENDOR_ID_NS               0x100b
 #define PCI_DEVICE_ID_NS_87415         0x0002
+#define PCI_DEVICE_ID_NS_87560_LIO      0x000e
+#define PCI_DEVICE_ID_NS_87560_USB      0x0012
 #define PCI_DEVICE_ID_NS_87410         0xd001
 
 #define PCI_VENDOR_ID_TSENG            0x100c
 #define PCI_DEVICE_ID_AMD_LANCE_HOME   0x2001
 #define PCI_DEVICE_ID_AMD_SCSI         0x2020
 #define PCI_DEVICE_ID_AMD_FE_GATE_7006 0x7006
-#define PCI_DEVICE_ID_AMD_VIPER_7403   0x7403
+#define PCI_DEVICE_ID_AMD_COBRA_7400   0x7400
+#define PCI_DEVICE_ID_AMD_COBRA_7401   0x7401
+#define PCI_DEVICE_ID_AMD_COBRA_7403   0x7403
+#define PCI_DEVICE_ID_AMD_COBRA_7404   0x7404
 #define PCI_DEVICE_ID_AMD_VIPER_7408   0x7408
 #define PCI_DEVICE_ID_AMD_VIPER_7409   0x7409
 #define PCI_DEVICE_ID_AMD_VIPER_740B   0x740B
 #define PCI_DEVICE_ID_MOTOROLA_CPX8216 0x4806
 
 #define PCI_VENDOR_ID_PROMISE          0x105a
+#define PCI_DEVICE_ID_PROMISE_20267    0x4d30
 #define PCI_DEVICE_ID_PROMISE_20246    0x4d33
 #define PCI_DEVICE_ID_PROMISE_20262    0x4d38
 #define PCI_DEVICE_ID_PROMISE_5300     0x5300
 #define PCI_DEVICE_ID_CMD_646          0x0646
 #define PCI_DEVICE_ID_CMD_647          0x0647
 #define PCI_DEVICE_ID_CMD_648          0x0648
+#define PCI_DEVICE_ID_CMD_649          0x0649
 #define PCI_DEVICE_ID_CMD_670          0x0670
 
 #define PCI_VENDOR_ID_VISION           0x1098
 #define PCI_DEVICE_ID_DATABOOK_87144   0xb106
 
 #define PCI_VENDOR_ID_PLX              0x10b5
+#define PCI_VENDOR_ID_PLX_ROMULUS      0x106a
+#define PCI_DEVICE_ID_PLX_SPCOM800     0x1076
 #define PCI_DEVICE_ID_PLX_SPCOM200     0x1103
 #define PCI_DEVICE_ID_PLX_9050         0x9050
 #define PCI_DEVICE_ID_PLX_9060         0x9060
 #define PCI_VENDOR_ID_AFAVLAB          0x14db
 #define PCI_DEVICE_ID_AFAVLAB_TK9902   0x2120
 
+#define PCI_VENDOR_ID_MORETON          0x15aa
+#define PCI_DEVICE_ID_RASTEL_2PORT     0x2000
+
 #define PCI_VENDOR_ID_SYMPHONY         0x1c1c
 #define PCI_DEVICE_ID_SYMPHONY_101     0x0001
 
 #define PCI_DEVICE_ID_INTEL_82801AB_5  0x2425
 #define PCI_DEVICE_ID_INTEL_82801AB_6  0x2426
 #define PCI_DEVICE_ID_INTEL_82801AB_8  0x2428
+#define PCI_DEVICE_ID_INTEL_82820FW_0  0x2440
+#define PCI_DEVICE_ID_INTEL_82820FW_1  0x2442
+#define PCI_DEVICE_ID_INTEL_82820FW_2  0x2443
+#define PCI_DEVICE_ID_INTEL_82820FW_3  0x2444
+#define PCI_DEVICE_ID_INTEL_82820FW_4  0x2449
+#define PCI_DEVICE_ID_INTEL_82820FW_5  0x244b
+#define PCI_DEVICE_ID_INTEL_82820FW_6  0x244e
 #define PCI_DEVICE_ID_INTEL_82810_MC1  0x7120
 #define PCI_DEVICE_ID_INTEL_82810_IG1  0x7121
 #define PCI_DEVICE_ID_INTEL_82810_MC3  0x7122
index 20029fd6727d2832184eabd4fe1bd8298c983b36..71f8772cd89d03b2cf6bf28413f1df3c25aee835 100644 (file)
@@ -168,17 +168,8 @@ struct sk_buff {
 #include <asm/system.h>
 
 extern void                    __kfree_skb(struct sk_buff *skb);
-extern void                    skb_queue_head_init(struct sk_buff_head *list);
-extern void                    skb_queue_head(struct sk_buff_head *list,struct sk_buff *buf);
-extern void                    skb_queue_tail(struct sk_buff_head *list,struct sk_buff *buf);
-extern struct sk_buff *                skb_dequeue(struct sk_buff_head *list);
-extern void                    skb_insert(struct sk_buff *old,struct sk_buff *newsk);
-extern void                    skb_append(struct sk_buff *old,struct sk_buff *newsk);
-extern void                    skb_unlink(struct sk_buff *buf);
-extern __u32                   skb_queue_len(struct sk_buff_head *list);
 extern struct sk_buff *                skb_peek_copy(struct sk_buff_head *list);
 extern struct sk_buff *                alloc_skb(unsigned int size, int priority);
-extern struct sk_buff *                dev_alloc_skb(unsigned int size);
 extern void                    kfree_skbmem(struct sk_buff *skb);
 extern struct sk_buff *                skb_clone(struct sk_buff *skb, int priority);
 extern struct sk_buff *                skb_copy(const struct sk_buff *skb, int priority);
@@ -187,13 +178,6 @@ extern struct sk_buff *            skb_copy_expand(const struct sk_buff *skb,
                                                int newtailroom,
                                                int priority);
 #define dev_kfree_skb(a)       kfree_skb(a)
-extern unsigned char *         skb_put(struct sk_buff *skb, unsigned int len);
-extern unsigned char *         skb_push(struct sk_buff *skb, unsigned int len);
-extern unsigned char *         skb_pull(struct sk_buff *skb, unsigned int len);
-extern int                     skb_headroom(const struct sk_buff *skb);
-extern int                     skb_tailroom(const struct sk_buff *skb);
-extern void                    skb_reserve(struct sk_buff *skb, unsigned int len);
-extern void                    skb_trim(struct sk_buff *skb, unsigned int len);
 extern void    skb_over_panic(struct sk_buff *skb, int len, void *here);
 extern void    skb_under_panic(struct sk_buff *skb, int len, void *here);
 
@@ -201,7 +185,7 @@ extern void skb_under_panic(struct sk_buff *skb, int len, void *here);
 #define skb_realloc_headroom(skb, nhr) skb_copy_expand(skb, nhr, skb_tailroom(skb), GFP_ATOMIC)
 
 /* Internal */
-extern __inline__ atomic_t *skb_datarefp(struct sk_buff *skb)
+static inline atomic_t *skb_datarefp(struct sk_buff *skb)
 {
        return (atomic_t *)(skb->end);
 }
@@ -213,7 +197,7 @@ extern __inline__ atomic_t *skb_datarefp(struct sk_buff *skb)
  *     Returns true if the queue is empty, false otherwise.
  */
  
-extern __inline__ int skb_queue_empty(struct sk_buff_head *list)
+static inline int skb_queue_empty(struct sk_buff_head *list)
 {
        return (list->next == (struct sk_buff *) list);
 }
@@ -226,7 +210,7 @@ extern __inline__ int skb_queue_empty(struct sk_buff_head *list)
  *     to the buffer.
  */
  
-extern __inline__ struct sk_buff *skb_get(struct sk_buff *skb)
+static inline struct sk_buff *skb_get(struct sk_buff *skb)
 {
        atomic_inc(&skb->users);
        return skb;
@@ -245,14 +229,14 @@ extern __inline__ struct sk_buff *skb_get(struct sk_buff *skb)
  *     hit zero.
  */
  
-extern __inline__ void kfree_skb(struct sk_buff *skb)
+static inline void kfree_skb(struct sk_buff *skb)
 {
        if (atomic_read(&skb->users) == 1 || atomic_dec_and_test(&skb->users))
                __kfree_skb(skb);
 }
 
 /* Use this if you didn't touch the skb state [for fast switching] */
-extern __inline__ void kfree_skb_fast(struct sk_buff *skb)
+static inline void kfree_skb_fast(struct sk_buff *skb)
 {
        if (atomic_read(&skb->users) == 1 || atomic_dec_and_test(&skb->users))
                kfree_skbmem(skb);      
@@ -267,7 +251,7 @@ extern __inline__ void kfree_skb_fast(struct sk_buff *skb)
  *     shared data so must not be written to under normal circumstances.
  */
 
-extern __inline__ int skb_cloned(struct sk_buff *skb)
+static inline int skb_cloned(struct sk_buff *skb)
 {
        return skb->cloned && atomic_read(skb_datarefp(skb)) != 1;
 }
@@ -280,7 +264,7 @@ extern __inline__ int skb_cloned(struct sk_buff *skb)
  *     buffer.
  */
  
-extern __inline__ int skb_shared(struct sk_buff *skb)
+static inline int skb_shared(struct sk_buff *skb)
 {
        return (atomic_read(&skb->users) != 1);
 }
@@ -299,7 +283,7 @@ extern __inline__ int skb_shared(struct sk_buff *skb)
  *     NULL is returned on a memory allocation failure.
  */
  
-extern __inline__ struct sk_buff *skb_share_check(struct sk_buff *skb, int pri)
+static inline struct sk_buff *skb_share_check(struct sk_buff *skb, int pri)
 {
        if (skb_shared(skb)) {
                struct sk_buff *nskb;
@@ -332,7 +316,7 @@ extern __inline__ struct sk_buff *skb_share_check(struct sk_buff *skb, int pri)
  *     %NULL is returned on a memory allocation failure.
  */
  
-extern __inline__ struct sk_buff *skb_unshare(struct sk_buff *skb, int pri)
+static inline struct sk_buff *skb_unshare(struct sk_buff *skb, int pri)
 {
        struct sk_buff *nskb;
        if(!skb_cloned(skb))
@@ -356,7 +340,7 @@ extern __inline__ struct sk_buff *skb_unshare(struct sk_buff *skb, int pri)
  *     volatile. Use with caution.
  */
  
-extern __inline__ struct sk_buff *skb_peek(struct sk_buff_head *list_)
+static inline struct sk_buff *skb_peek(struct sk_buff_head *list_)
 {
        struct sk_buff *list = ((struct sk_buff *)list_)->next;
        if (list == (struct sk_buff *)list_)
@@ -378,7 +362,7 @@ extern __inline__ struct sk_buff *skb_peek(struct sk_buff_head *list_)
  *     volatile. Use with caution.
  */
 
-extern __inline__ struct sk_buff *skb_peek_tail(struct sk_buff_head *list_)
+static inline struct sk_buff *skb_peek_tail(struct sk_buff_head *list_)
 {
        struct sk_buff *list = ((struct sk_buff *)list_)->prev;
        if (list == (struct sk_buff *)list_)
@@ -393,12 +377,12 @@ extern __inline__ struct sk_buff *skb_peek_tail(struct sk_buff_head *list_)
  *     Return the length of an &sk_buff queue. 
  */
  
-extern __inline__ __u32 skb_queue_len(struct sk_buff_head *list_)
+static inline __u32 skb_queue_len(struct sk_buff_head *list_)
 {
        return(list_->qlen);
 }
 
-extern __inline__ void skb_queue_head_init(struct sk_buff_head *list)
+static inline void skb_queue_head_init(struct sk_buff_head *list)
 {
        spin_lock_init(&list->lock);
        list->prev = (struct sk_buff *)list;
@@ -424,7 +408,7 @@ extern __inline__ void skb_queue_head_init(struct sk_buff_head *list)
  *     A buffer cannot be placed on two lists at the same time.
  */    
  
-extern __inline__ void __skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk)
+static inline void __skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk)
 {
        struct sk_buff *prev, *next;
 
@@ -451,7 +435,7 @@ extern __inline__ void __skb_queue_head(struct sk_buff_head *list, struct sk_buf
  *     A buffer cannot be placed on two lists at the same time.
  */    
 
-extern __inline__ void skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk)
+static inline void skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk)
 {
        unsigned long flags;
 
@@ -472,7 +456,7 @@ extern __inline__ void skb_queue_head(struct sk_buff_head *list, struct sk_buff
  */    
  
 
-extern __inline__ void __skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk)
+static inline void __skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk)
 {
        struct sk_buff *prev, *next;
 
@@ -498,7 +482,7 @@ extern __inline__ void __skb_queue_tail(struct sk_buff_head *list, struct sk_buf
  *     A buffer cannot be placed on two lists at the same time.
  */    
 
-extern __inline__ void skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk)
+static inline void skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk)
 {
        unsigned long flags;
 
@@ -516,7 +500,7 @@ extern __inline__ void skb_queue_tail(struct sk_buff_head *list, struct sk_buff
  *     returned or %NULL if the list is empty.
  */
 
-extern __inline__ struct sk_buff *__skb_dequeue(struct sk_buff_head *list)
+static inline struct sk_buff *__skb_dequeue(struct sk_buff_head *list)
 {
        struct sk_buff *next, *prev, *result;
 
@@ -545,7 +529,7 @@ extern __inline__ struct sk_buff *__skb_dequeue(struct sk_buff_head *list)
  *     returned or %NULL if the list is empty.
  */
 
-extern __inline__ struct sk_buff *skb_dequeue(struct sk_buff_head *list)
+static inline struct sk_buff *skb_dequeue(struct sk_buff_head *list)
 {
        long flags;
        struct sk_buff *result;
@@ -560,7 +544,7 @@ extern __inline__ struct sk_buff *skb_dequeue(struct sk_buff_head *list)
  *     Insert a packet on a list.
  */
 
-extern __inline__ void __skb_insert(struct sk_buff *newsk,
+static inline void __skb_insert(struct sk_buff *newsk,
        struct sk_buff * prev, struct sk_buff *next,
        struct sk_buff_head * list)
 {
@@ -582,7 +566,7 @@ extern __inline__ void __skb_insert(struct sk_buff *newsk,
  *     A buffer cannot be placed on two lists at the same time.
  */
 
-extern __inline__ void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
+static inline void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
 {
        unsigned long flags;
 
@@ -595,7 +579,7 @@ extern __inline__ void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
  *     Place a packet after a given packet in a list.
  */
 
-extern __inline__ void __skb_append(struct sk_buff *old, struct sk_buff *newsk)
+static inline void __skb_append(struct sk_buff *old, struct sk_buff *newsk)
 {
        __skb_insert(newsk, old, old->next, old->list);
 }
@@ -611,7 +595,7 @@ extern __inline__ void __skb_append(struct sk_buff *old, struct sk_buff *newsk)
  */
 
 
-extern __inline__ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
+static inline void skb_append(struct sk_buff *old, struct sk_buff *newsk)
 {
        unsigned long flags;
 
@@ -625,7 +609,7 @@ extern __inline__ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
  * the list known..
  */
  
-extern __inline__ void __skb_unlink(struct sk_buff *skb, struct sk_buff_head *list)
+static inline void __skb_unlink(struct sk_buff *skb, struct sk_buff_head *list)
 {
        struct sk_buff * next, * prev;
 
@@ -652,7 +636,7 @@ extern __inline__ void __skb_unlink(struct sk_buff *skb, struct sk_buff_head *li
  *     destroyed.
  */
 
-extern __inline__ void skb_unlink(struct sk_buff *skb)
+static inline void skb_unlink(struct sk_buff *skb)
 {
        struct sk_buff_head *list = skb->list;
 
@@ -677,7 +661,7 @@ extern __inline__ void skb_unlink(struct sk_buff *skb)
  *     returned or %NULL if the list is empty.
  */
 
-extern __inline__ struct sk_buff *__skb_dequeue_tail(struct sk_buff_head *list)
+static inline struct sk_buff *__skb_dequeue_tail(struct sk_buff_head *list)
 {
        struct sk_buff *skb = skb_peek_tail(list); 
        if (skb)
@@ -694,7 +678,7 @@ extern __inline__ struct sk_buff *__skb_dequeue_tail(struct sk_buff_head *list)
  *     returned or %NULL if the list is empty.
  */
 
-extern __inline__ struct sk_buff *skb_dequeue_tail(struct sk_buff_head *list)
+static inline struct sk_buff *skb_dequeue_tail(struct sk_buff_head *list)
 {
        long flags;
        struct sk_buff *result;
@@ -709,7 +693,7 @@ extern __inline__ struct sk_buff *skb_dequeue_tail(struct sk_buff_head *list)
  *     Add data to an sk_buff
  */
  
-extern __inline__ unsigned char *__skb_put(struct sk_buff *skb, unsigned int len)
+static inline unsigned char *__skb_put(struct sk_buff *skb, unsigned int len)
 {
        unsigned char *tmp=skb->tail;
        skb->tail+=len;
@@ -727,7 +711,7 @@ extern __inline__ unsigned char *__skb_put(struct sk_buff *skb, unsigned int len
  *     first byte of the extra data is returned.
  */
  
-extern __inline__ unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
+static inline unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
 {
        unsigned char *tmp=skb->tail;
        skb->tail+=len;
@@ -738,7 +722,7 @@ extern __inline__ unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
        return tmp;
 }
 
-extern __inline__ unsigned char *__skb_push(struct sk_buff *skb, unsigned int len)
+static inline unsigned char *__skb_push(struct sk_buff *skb, unsigned int len)
 {
        skb->data-=len;
        skb->len+=len;
@@ -755,7 +739,7 @@ extern __inline__ unsigned char *__skb_push(struct sk_buff *skb, unsigned int le
  *     panic. A pointer to the first byte of the extra data is returned.
  */
 
-extern __inline__ unsigned char *skb_push(struct sk_buff *skb, unsigned int len)
+static inline unsigned char *skb_push(struct sk_buff *skb, unsigned int len)
 {
        skb->data-=len;
        skb->len+=len;
@@ -765,7 +749,7 @@ extern __inline__ unsigned char *skb_push(struct sk_buff *skb, unsigned int len)
        return skb->data;
 }
 
-extern __inline__ char *__skb_pull(struct sk_buff *skb, unsigned int len)
+static inline char *__skb_pull(struct sk_buff *skb, unsigned int len)
 {
        skb->len-=len;
        return  skb->data+=len;
@@ -782,7 +766,7 @@ extern __inline__ char *__skb_pull(struct sk_buff *skb, unsigned int len)
  *     the old data.
  */
 
-extern __inline__ unsigned char * skb_pull(struct sk_buff *skb, unsigned int len)
+static inline unsigned char * skb_pull(struct sk_buff *skb, unsigned int len)
 {      
        if (len > skb->len)
                return NULL;
@@ -796,7 +780,7 @@ extern __inline__ unsigned char * skb_pull(struct sk_buff *skb, unsigned int len
  *     Return the number of bytes of free space at the head of an &sk_buff.
  */
  
-extern __inline__ int skb_headroom(const struct sk_buff *skb)
+static inline int skb_headroom(const struct sk_buff *skb)
 {
        return skb->data-skb->head;
 }
@@ -808,7 +792,7 @@ extern __inline__ int skb_headroom(const struct sk_buff *skb)
  *     Return the number of bytes of free space at the tail of an sk_buff
  */
 
-extern __inline__ int skb_tailroom(const struct sk_buff *skb)
+static inline int skb_tailroom(const struct sk_buff *skb)
 {
        return skb->end-skb->tail;
 }
@@ -822,14 +806,14 @@ extern __inline__ int skb_tailroom(const struct sk_buff *skb)
  *     room. This is only allowed for an empty buffer.
  */
 
-extern __inline__ void skb_reserve(struct sk_buff *skb, unsigned int len)
+static inline void skb_reserve(struct sk_buff *skb, unsigned int len)
 {
        skb->data+=len;
        skb->tail+=len;
 }
 
 
-extern __inline__ void __skb_trim(struct sk_buff *skb, unsigned int len)
+static inline void __skb_trim(struct sk_buff *skb, unsigned int len)
 {
        skb->len = len;
        skb->tail = skb->data+len;
@@ -844,7 +828,7 @@ extern __inline__ void __skb_trim(struct sk_buff *skb, unsigned int len)
  *     the buffer is already under the length specified it is not modified.
  */
 
-extern __inline__ void skb_trim(struct sk_buff *skb, unsigned int len)
+static inline void skb_trim(struct sk_buff *skb, unsigned int len)
 {
        if (skb->len > len) {
                __skb_trim(skb, len);
@@ -861,7 +845,7 @@ extern __inline__ void skb_trim(struct sk_buff *skb, unsigned int len)
  */
 
 
-extern __inline__ void skb_orphan(struct sk_buff *skb)
+static inline void skb_orphan(struct sk_buff *skb)
 {
        if (skb->destructor)
                skb->destructor(skb);
@@ -879,7 +863,7 @@ extern __inline__ void skb_orphan(struct sk_buff *skb)
  */
 
 
-extern __inline__ void skb_queue_purge(struct sk_buff_head *list)
+static inline void skb_queue_purge(struct sk_buff_head *list)
 {
        struct sk_buff *skb;
        while ((skb=skb_dequeue(list))!=NULL)
@@ -896,7 +880,7 @@ extern __inline__ void skb_queue_purge(struct sk_buff_head *list)
  */
 
 
-extern __inline__ void __skb_queue_purge(struct sk_buff_head *list)
+static inline void __skb_queue_purge(struct sk_buff_head *list)
 {
        struct sk_buff *skb;
        while ((skb=__skb_dequeue(list))!=NULL)
@@ -916,7 +900,7 @@ extern __inline__ void __skb_queue_purge(struct sk_buff_head *list)
  *     allocates memory it can be called from an interrupt.
  */
  
-extern __inline__ struct sk_buff *dev_alloc_skb(unsigned int length)
+static inline struct sk_buff *dev_alloc_skb(unsigned int length)
 {
        struct sk_buff *skb;
 
@@ -942,7 +926,7 @@ extern __inline__ struct sk_buff *dev_alloc_skb(unsigned int length)
  */
  
 
-extern __inline__ struct sk_buff *
+static inline struct sk_buff *
 skb_cow(struct sk_buff *skb, unsigned int headroom)
 {
        headroom = (headroom+15)&~15;
@@ -965,13 +949,13 @@ extern void skb_init(void);
 extern void skb_add_mtu(int mtu);
 
 #ifdef CONFIG_NETFILTER
-extern __inline__ void
+static inline void
 nf_conntrack_put(struct nf_ct_info *nfct)
 {
        if (nfct && atomic_dec_and_test(&nfct->master->use))
                nfct->master->destroy(nfct->master);
 }
-extern __inline__ void
+static inline void
 nf_conntrack_get(struct nf_ct_info *nfct)
 {
        if (nfct)
index d766bea0305fba0e57ea4387ebd76f9f2b33fb17..f3b8eefcc74fb4e595c8c194cf79886db9f8ebf4 100644 (file)
@@ -76,7 +76,7 @@ struct cmsghdr {
  */
  
 #ifdef __KERNEL__
-#define __KINLINE extern __inline__
+#define __KINLINE static inline
 #elif  defined(__GNUC__) 
 #define __KINLINE static __inline__
 #elif defined(__cplusplus)
index 923a7a111558be5aeb6bf4c35fb0c55efd8f4313..b374bb9c6b4851d7d5d1c791855f3ba7c67c0de0 100644 (file)
@@ -545,8 +545,11 @@ enum {
 /* /proc/sys/dev/parport/parport n */
 enum {
        DEV_PARPORT_SPINTIME=1,
-       DEV_PARPORT_HARDWARE=2,
-       DEV_PARPORT_DEVICES=3,
+       DEV_PARPORT_BASE_ADDR=2,
+       DEV_PARPORT_IRQ=3,
+       DEV_PARPORT_DMA=4,
+       DEV_PARPORT_MODES=5,
+       DEV_PARPORT_DEVICES=6,
        DEV_PARPORT_AUTOPROBE=16
 };
 
index 934850f26154d7faec8d496a86ab2f71ea13de50..85517135d38060f0a86c4e7d3379c79edd9aded8 100644 (file)
@@ -80,7 +80,7 @@ extern spinlock_t tqueue_lock;
 /*
  * queue_task
  */
-extern __inline__ void queue_task(struct tq_struct *bh_pointer,
+static inline void queue_task(struct tq_struct *bh_pointer,
                           task_queue *bh_list)
 {
        if (!test_and_set_bit(0,&bh_pointer->sync)) {
@@ -95,7 +95,7 @@ extern __inline__ void queue_task(struct tq_struct *bh_pointer,
 /*
  * Call all "bottom halfs" on a given list.
  */
-extern __inline__ void run_task_queue(task_queue *list)
+static inline void run_task_queue(task_queue *list)
 {
        if (*list) {
                unsigned long flags;
index a7c8fb324922a22faa1f14ee75dade782a4e45ec..1b1d3f902c7f10c51d9472e39387d15a4f1053be 100644 (file)
@@ -307,6 +307,10 @@ struct usb_driver {
 
        struct file_operations *fops;
        int minor;
+
+       struct semaphore serialize;
+
+       int (*ioctl)(struct usb_device *dev, unsigned int code, void *buf);
 };
 
 /*
@@ -331,6 +335,9 @@ typedef int (*usb_device_irq)(int, void *, int, void *);
  * New USB Structures                                                         *
  *----------------------------------------------------------------------------*/
 
+/*
+ * urb->transfer_flags:
+ */
 #define USB_DISABLE_SPD         0x0001
 #define USB_ISO_ASAP            0x0002
 #define USB_URB_EARLY_COMPLETE  0x0004
@@ -362,10 +369,11 @@ typedef struct urb
        void *transfer_buffer;          // associated data buffer
        int transfer_buffer_length;     // data buffer length
        int actual_length;              // actual data buffer length    
+       int bandwidth;                  // bandwidth for this transfer request (INT or ISO)
        unsigned char *setup_packet;    // setup packet (control only)
        //
        int start_frame;                // start frame (iso/irq only)
-       int number_of_packets;          // number of packets in this request (iso/irq only)
+       int number_of_packets;          // number of packets in this request (iso)
        int interval;                   // polling interval (irq only)
        int error_count;                // number of errors in this transfer (iso only)
        int timeout;                    // timeout (in jiffies)
@@ -483,7 +491,7 @@ struct usb_bus {
        struct list_head bus_list;
        void *hcpriv;                   /* Host Controller private data */
 
-       unsigned int bandwidth_allocated; /* on this Host Controller; */
+       int bandwidth_allocated;        /* on this Host Controller; */
                                          /* applies to Int. and Isoc. pipes; */
                                          /* measured in microseconds/frame; */
                                          /* range is 0..900, where 900 = */
@@ -492,7 +500,7 @@ struct usb_bus {
        int bandwidth_isoc_reqs;        /* number of Isoc. requesters */
 
        /* usbdevfs inode list */
-        struct list_head inodes;
+       struct list_head inodes;
 };
 
 #define USB_MAXCHILDREN (8)    /* This is arbitrary */
@@ -506,7 +514,6 @@ struct usb_device {
        unsigned int toggle[2];         /* one bit for each endpoint ([0] = IN, [1] = OUT) */
        unsigned int halted[2];         /* endpoint halts; one bit per endpoint # & direction; */
                                        /* [0] = IN, [1] = OUT */
-       struct usb_config_descriptor *actconfig;/* the active configuration */
        int epmaxpacketin[16];          /* INput endpoint specific maximums */
        int epmaxpacketout[16];         /* OUTput endpoint specific maximums */
 
@@ -515,6 +522,9 @@ struct usb_device {
 
        struct usb_device_descriptor descriptor;/* Descriptor */
        struct usb_config_descriptor *config;   /* All of the configs */
+       struct usb_config_descriptor *actconfig;/* the active configuration */
+
+       char **rawdescriptors;          /* Raw descriptors for each config */
 
        int have_langid;                /* whether string_langid is valid yet */
        int string_langid;              /* language ID for strings */
@@ -522,8 +532,8 @@ struct usb_device {
        void *hcpriv;                   /* Host Controller private data */
        
         /* usbdevfs inode list */
-        struct list_head inodes;
-        struct list_head filelist;
+       struct list_head inodes;
+       struct list_head filelist;
 
        /*
         * Child devices - these can be either new devices
@@ -537,6 +547,8 @@ struct usb_device {
        struct usb_device *children[USB_MAXCHILDREN];
 };
 
+extern struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum);
+
 extern int usb_register(struct usb_driver *);
 extern void usb_deregister(struct usb_driver *);
 
@@ -554,7 +566,10 @@ extern struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bu
 extern void usb_free_dev(struct usb_device *);
 extern void usb_inc_dev_use(struct usb_device *);
 #define usb_dec_dev_use usb_free_dev
-extern void usb_release_bandwidth(struct usb_device *, int);
+
+extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb);
+extern void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc);
+extern void usb_release_bandwidth(struct usb_device *dev, struct urb *urb, int isoc);
 
 extern int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout);
 
@@ -671,6 +686,7 @@ int usb_get_class_descriptor(struct usb_device *dev, int ifnum, unsigned char de
 int usb_get_device_descriptor(struct usb_device *dev);
 int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, void **ptr);
 int usb_get_status(struct usb_device *dev, int type, int target, void *data);
+int usb_get_configuration(struct usb_device *dev);
 int usb_get_protocol(struct usb_device *dev, int ifnum);
 int usb_set_protocol(struct usb_device *dev, int ifnum, int protocol);
 int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);
@@ -682,6 +698,7 @@ int usb_set_report(struct usb_device *dev, int ifnum, unsigned char type,
        unsigned char id, void *buf, int size);
 int usb_string(struct usb_device *dev, int index, char *buf, size_t size);
 int usb_clear_halt(struct usb_device *dev, int pipe);
+void usb_set_maxpacket(struct usb_device *dev);
 
 #define usb_get_extra_descriptor(ifpoint,type,ptr)\
        __usb_get_extra_descriptor((ifpoint)->extra,(ifpoint)->extralen,type,(void**)ptr)
index 7fa98fcb5a9dda7ccfd802b5ec5173e662d40d45..0bf8d308722d0e7e9c0d6b1b81577a53d529db07 100644 (file)
@@ -66,6 +66,18 @@ struct usbdevfs_disconnectsignal {
        void *context;
 };
 
+#define USBDEVFS_MAXDRIVERNAME 255
+
+struct usbdevfs_getdriver {
+       unsigned int interface;
+       char driver[USBDEVFS_MAXDRIVERNAME + 1];
+};
+
+struct usbdevfs_connectinfo {
+       unsigned int devnum;
+       unsigned char slow;
+};
+
 #define USBDEVFS_URB_DISABLE_SPD           1
 #define USBDEVFS_URB_ISO_ASAP              2
 
@@ -96,11 +108,27 @@ struct usbdevfs_urb {
        struct usbdevfs_iso_packet_desc iso_frame_desc[0];
 };
 
+/* ioctls for talking to drivers in the usbcore module: */
+struct usbdevfs_ioctl {
+       int     ifno;           /* interface 0..N ; negative numbers reserved */
+       int     ioctl_code;     /* MUST encode size + direction of data so the
+                                * macros in <asm/ioctl.h> give correct values */
+       void    *data;          /* param buffer (in, or out) */
+};
+
+/* You can do most things with hubs just through control messages,
+ * except find out what device connects to what port. */
+struct usbdevfs_hub_portinfo {
+       char nports;            /* number of downstream ports in this hub */
+       char port [127];        /* e.g. port 3 connects to device 27 */
+};
+
 #define USBDEVFS_CONTROL           _IOWR('U', 0, struct usbdevfs_ctrltransfer)
 #define USBDEVFS_BULK              _IOWR('U', 2, struct usbdevfs_bulktransfer)
 #define USBDEVFS_RESETEP           _IOR('U', 3, unsigned int)
 #define USBDEVFS_SETINTERFACE      _IOR('U', 4, struct usbdevfs_setinterface)
 #define USBDEVFS_SETCONFIGURATION  _IOR('U', 5, unsigned int)
+#define USBDEVFS_GETDRIVER         _IOW('U', 8, struct usbdevfs_getdriver)
 #define USBDEVFS_SUBMITURB         _IOR('U', 10, struct usbdevfs_urb)
 #define USBDEVFS_DISCARDURB        _IO('U', 11)
 #define USBDEVFS_REAPURB           _IOW('U', 12, void *)
@@ -108,6 +136,10 @@ struct usbdevfs_urb {
 #define USBDEVFS_DISCSIGNAL        _IOR('U', 14, struct usbdevfs_disconnectsignal)
 #define USBDEVFS_CLAIMINTERFACE    _IOR('U', 15, unsigned int)
 #define USBDEVFS_RELEASEINTERFACE  _IOR('U', 16, unsigned int)
+#define USBDEVFS_CONNECTINFO       _IOW('U', 17, struct usbdevfs_connectinfo)
+#define USBDEVFS_IOCTL             _IOWR('U', 18, struct usbdevfs_ioctl)
+#define USBDEVFS_HUB_PORTINFO      _IOR('U', 19, struct usbdevfs_hub_portinfo)
+#define USBDEVFS_RESET             _IO('U', 20)
 
 /* --------------------------------------------------------------------- */
 
@@ -165,7 +197,6 @@ extern struct inode_operations usbdevfs_bus_inode_operations;
 extern struct file_operations usbdevfs_bus_file_operations;
 extern void usbdevfs_conn_disc_event(void);
 
-
 #endif /* __KERNEL__ */
 
 /* --------------------------------------------------------------------- */
index 65fb19289600090a2f3a0656a5798b9c4b21f69c..7df8458954f01d2a903c8c2297757296b240726c 100644 (file)
@@ -337,16 +337,24 @@ static __inline__ int tcp_sk_listen_hashfn(struct sock *sk)
    so that we select tick to get range about 4 seconds.
  */
 
-#if HZ == 20
+#if HZ <= 16 || HZ > 4096
+# error Unsupported: HZ <= 16 or HZ > 4096
+#elif HZ <= 32
 # define TCP_TW_RECYCLE_TICK (5+2-TCP_TW_RECYCLE_SLOTS_LOG)
-#elif HZ == 64
+#elif HZ <= 64
 # define TCP_TW_RECYCLE_TICK (6+2-TCP_TW_RECYCLE_SLOTS_LOG)
-#elif HZ == 100 || HZ == 128
+#elif HZ <= 128
 # define TCP_TW_RECYCLE_TICK (7+2-TCP_TW_RECYCLE_SLOTS_LOG)
-#elif HZ == 1024 || HZ == 1000
+#elif HZ <= 256
+# define TCP_TW_RECYCLE_TICK (8+2-TCP_TW_RECYCLE_SLOTS_LOG)
+#elif HZ <= 512
+# define TCP_TW_RECYCLE_TICK (9+2-TCP_TW_RECYCLE_SLOTS_LOG)
+#elif HZ <= 1024
 # define TCP_TW_RECYCLE_TICK (10+2-TCP_TW_RECYCLE_SLOTS_LOG)
+#elif HZ <= 2048
+# define TCP_TW_RECYCLE_TICK (11+2-TCP_TW_RECYCLE_SLOTS_LOG)
 #else
-# error HZ != 20 && HZ != 64 && HZ != 100 && HZ != 1000 && HZ != 1024
+# define TCP_TW_RECYCLE_TICK (12+2-TCP_TW_RECYCLE_SLOTS_LOG)
 #endif
 
 /*
index 29819efbb021d1cd8bed2b735b6ff55bfa2a956a..cd9e8ac7d286f3c9fd20884145048d7c02d66c35 100644 (file)
 
 #include "util.h"
 
+/**
+ *     ipc_init        -       initialise IPC subsystem
+ *
+ *     The various system5 IPC resources (semaphores, messages and shared
+ *     memory are initialised
+ */
 void __init ipc_init (void)
 {
        sem_init();
@@ -32,6 +39,16 @@ void __init ipc_init (void)
        return;
 }
 
+/**
+ *     ipc_init_ids            -       initialise IPC identifiers
+ *     @ids: Identifier set
+ *     @size: Number of identifiers
+ *
+ *     Given a size for the ipc identifier range (limited below IPCMNI)
+ *     set up the sequence range to use then allocate and initialise the
+ *     array itself. 
+ */
 void __init ipc_init_ids(struct ipc_ids* ids, int size)
 {
        int i;
@@ -62,6 +79,14 @@ void __init ipc_init_ids(struct ipc_ids* ids, int size)
                ids->entries[i].p = NULL;
 }
 
+/**
+ *     ipc_findkey     -       find a key in an ipc identifier set     
+ *     @ids: Identifier set
+ *     @key: The key to find
+ *
+ *     Returns the identifier if found or -1 if not.
+ */
 int ipc_findkey(struct ipc_ids* ids, key_t key)
 {
        int id;
@@ -106,6 +131,18 @@ static int grow_ary(struct ipc_ids* ids, int newsize)
        return ids->size;
 }
 
+/**
+ *     ipc_addid       -       add an IPC identifier
+ *     @ids: IPC identifier set
+ *     @new: new IPC permission set
+ *     @size: new size limit for the id array
+ *
+ *     Add an entry 'new' to the IPC arrays. The permissions object is
+ *     initialised and the first free entry is set up and the id assigned
+ *     is returned. The list is returned in a locked state on success.
+ *     On failure the list is not locked and -1 is returned.
+ */
 int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
 {
        int id;
@@ -133,6 +170,17 @@ found:
        return id;
 }
 
+/**
+ *     ipc_rmid        -       remove an IPC identifier
+ *     @ids: identifier set
+ *     @id: Identifier to remove
+ *
+ *     The identifier must be valid, and in use. The kernel will panic if
+ *     fed an invalid identifier. The entry is removed and internal
+ *     variables recomputed. The object associated with the identifier
+ *     is returned.
+ */
 struct kern_ipc_perm* ipc_rmid(struct ipc_ids* ids, int id)
 {
        struct kern_ipc_perm* p;
@@ -156,6 +204,14 @@ struct kern_ipc_perm* ipc_rmid(struct ipc_ids* ids, int id)
        return p;
 }
 
+/**
+ *     ipc_alloc       -       allocate ipc space
+ *     @size: size desired
+ *
+ *     Allocate memory from the appropriate pools and return a pointer to it.
+ *     NULL is returned if the allocation fails
+ */
 void* ipc_alloc(int size)
 {
        void* out;
@@ -166,6 +222,15 @@ void* ipc_alloc(int size)
        return out;
 }
 
+/**
+ *     ipc_free        -       free ipc space
+ *     @ptr: pointer returned by ipc_alloc
+ *     @size: size of block
+ *
+ *     Free a block created with ipc_alloc. The caller must know the size
+ *     used in the allocation call.
+ */
 void ipc_free(void* ptr, int size)
 {
        if(size > PAGE_SIZE)
@@ -174,10 +239,15 @@ void ipc_free(void* ptr, int size)
                kfree(ptr);
 }
 
-/* 
- * Check user, group, other permissions for access
- * to ipc resources. return 0 if allowed
+/**
+ *     ipcperms        -       check IPC permissions
+ *     @ipcp: IPC permission set
+ *     @flag: desired permission set.
+ *
+ *     Check user, group, other permissions for access
+ *     to ipc resources. return 0 if allowed
  */
 int ipcperms (struct kern_ipc_perm *ipcp, short flag)
 {      /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */
        int requested_mode, granted_mode;
@@ -201,6 +271,16 @@ int ipcperms (struct kern_ipc_perm *ipcp, short flag)
  * old/new ipc_perm structures
  */
 
+/**
+ *     kernel_to_ipc64_perm    -       convert kernel ipc permissions to user
+ *     @in: kernel permissions
+ *     @out: new style IPC permissions
+ *
+ *     Turn the kernel object 'in' into a set of permissions descriptions
+ *     for returning to userspace (out).
+ */
+
 void kernel_to_ipc64_perm (struct kern_ipc_perm *in, struct ipc64_perm *out)
 {
        out->key        = in->key;
@@ -212,6 +292,15 @@ void kernel_to_ipc64_perm (struct kern_ipc_perm *in, struct ipc64_perm *out)
        out->seq        = in->seq;
 }
 
+/**
+ *     ipc64_perm_to_ipc_perm  -       convert old ipc permissions to new
+ *     @in: new style IPC permissions
+ *     @out: old style IPC permissions
+ *
+ *     Turn the new style permissions object in into a compatibility
+ *     object and store it into the 'out' pointer.
+ */
 void ipc64_perm_to_ipc_perm (struct ipc64_perm *in, struct ipc_perm *out)
 {
        out->key        = in->key;
@@ -223,6 +312,15 @@ void ipc64_perm_to_ipc_perm (struct ipc64_perm *in, struct ipc_perm *out)
        out->seq        = in->seq;
 }
 
+/**
+ *     ipc_parse_version       -       IPC call version
+ *     @cmd: pointer to command
+ *
+ *     Return IPC_64 for new style IPC and IPC_OLD for old style IPC. 
+ *     The cmd value is turned from an encoding command and version into
+ *     just the command code.
+ */
 int ipc_parse_version (int *cmd)
 {
        if (*cmd & IPC_64) {
index cef9aca85ee881e196d2437a3eb89d5d9d099a2b..eeab054d0cb0fc0458125dd7b0ce736aa6f886c2 100644 (file)
  *  one race (and leak) in BSD implementation.
  *  OK, that's better. ANOTHER race and leak in BSD variant. There always
  *  is one more bug... 10/11/98, AV.
+ *
+ *     Oh, fsck... Oopsable SMP race in do_process_acct() - we must hold
+ * ->mmap_sem to walk the vma list of current->mm. Nasty, since it leaks
+ * a struct file opened for write. Fixed. 2/6/2000, AV.
  */
 
 #include <linux/config.h>
@@ -66,7 +70,6 @@ int acct_parm[3] = {4, 2, 30};
 /*
  * External references and all of the globals.
  */
-void acct_timeout(unsigned long);
 
 static volatile int acct_active;
 static volatile int acct_needcheck;
@@ -77,7 +80,7 @@ static int do_acct_process(long, struct file *);
 /*
  * Called whenever the timer says to check the free space.
  */
-void acct_timeout(unsigned long unused)
+static void acct_timeout(unsigned long unused)
 {
        acct_needcheck = 1;
 }
@@ -303,11 +306,14 @@ static int do_acct_process(long exitcode, struct file *file)
 
        vsize = 0;
        if (current->mm) {
-               struct vm_area_struct *vma = current->mm->mmap;
+               struct vm_area_struct *vma;
+               down(&current->mm->mmap_sem);
+               vma = current->mm->mmap;
                while (vma) {
                        vsize += vma->vm_end - vma->vm_start;
                        vma = vma->vm_next;
                }
+               up(&current->mm->mmap_sem);
        }
        vsize = vsize / 1024;
        ac.ac_mem = encode_comp_t(vsize);
index 6e3534a15506f0118b71c1be3f0fced2da34b2bd..c0c5c9053fa5ddcdea487ccc3f469d6e081fc397 100644 (file)
@@ -973,7 +973,9 @@ leave_the_loop:
  * Gets the address for a symbol in the given module.  If modname is
  * NULL, it looks for the name in any registered symbol table.  If the
  * modname is an empty string, it looks for the symbol in kernel exported
- * symbol tables.
+ * symbol tables. Increase the usage count of the module in which the
+ * symbol was found - it's the only way we can guarantee that it's still
+ * there by the time our caller actually uses it.
  */
 unsigned long
 get_module_symbol(char *modname, char *symname)
@@ -982,6 +984,7 @@ get_module_symbol(char *modname, char *symname)
        struct module_symbol *sym;
        int i;
 
+       spin_lock(&unload_lock);
        for (mp = module_list; mp; mp = mp->next) {
                if (((modname == NULL) || (strcmp(mp->name, modname) == 0)) &&
                        MOD_CAN_QUERY(mp) &&
@@ -990,14 +993,34 @@ get_module_symbol(char *modname, char *symname)
                                i > 0; --i, ++sym) {
 
                                if (strcmp(sym->name, symname) == 0) {
+                                       __MOD_INC_USE_COUNT(mp);
+                                       spin_unlock(&unload_lock);
                                        return sym->value;
                                }
                        }
                }
        }
+       spin_unlock(&unload_lock);
        return 0;
 }
 
+/* Decrease the use count of the module containing a symbol with the 
+ * address passed.
+ */
+void put_module_symbol(unsigned long addr)
+{
+       struct module *mp;
+
+       for (mp = module_list; mp; mp = mp->next) {
+               if (MOD_CAN_QUERY(mp) &&
+                   addr >= (unsigned long)mp &&
+                   addr < (unsigned long)mp + mp->size) {
+                       __MOD_DEC_USE_COUNT(mp);
+                       return;
+               }
+       }
+}
+
 #else          /* CONFIG_MODULES */
 
 /* Dummy syscalls for people who don't want modules */
index 0404dd795b0456685a44eae0ff4293625aec3131..a481251780034159264a363dc1a043f523a5dbef 100644 (file)
@@ -144,7 +144,7 @@ static inline unsigned long move_vma(struct vm_area_struct * vma,
                        vmlist_modify_lock(current->mm);
                        insert_vm_struct(current->mm, new_vma);
                        merge_segments(current->mm, new_vma->vm_start, new_vma->vm_end);
-                       vmlist_modify_unlock(vma->vm_mm);
+                       vmlist_modify_unlock(current->mm);
                        do_munmap(current->mm, addr, old_len);
                        current->mm->total_vm += new_len >> PAGE_SHIFT;
                        if (new_vma->vm_flags & VM_LOCKED) {
index f3d04da8e5b3767574f84968703bbb6891ae4799..cccc16c58cfcdb0f252607e6c01df4497759f04c 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -666,9 +666,33 @@ kmem_cache_cal_waste(unsigned long gfporder, size_t size, size_t extra,
        return (wastage + gfporder + (extra * *num));
 }
 
-/* Create a cache:
+/**
+ * kmem_cache_create - Create a cache.
+ * @name: A string which is used in /proc/slabinfo to identify this cache.
+ * @size: The size of objects to be created in this cache.
+ * @offset: The offset to use within the page.  
+ * @flags: SLAB flags
+ * @ctor: A constructor for the objects.
+ * @dtor: A destructor for the objects.
+ *
  * Returns a ptr to the cache on success, NULL on failure.
  * Cannot be called within a int, but can be interrupted.
+ * The @ctor is run when new pages are allocated by the cache
+ * and the @dtor is run before the pages are handed back.
+ * The flags are
+ *
+ * %SLAB_POISON - Poison the slab with a known test pattern (a5a5a5a5)
+ * to catch references to uninitialised memory.
+ *
+ * %SLAB_RED_ZONE - Insert `Red' zones around the allocated memory to check
+ * for buffer overruns.
+ *
+ * %SLAB_NO_REAP - Don't automatically reap this cache when we're under
+ * memory pressure.
+ *
+ * %SLAB_HWCACHE_ALIGN - Align the objects in this cache to a hardware
+ * cacheline.  This can be beneficial if you're counting cycles as closely
+ * as davem.
  */
 kmem_cache_t *
 kmem_cache_create(const char *name, size_t size, size_t offset,
@@ -1044,7 +1068,11 @@ static int __kmem_cache_shrink(kmem_cache_t *cachep)
        return ret;
 }
 
-/* Shrink a cache.  Releases as many slabs as possible for a cache.
+/**
+ * kmem_cache_shrink - Shrink a cache.
+ * @cachep: The cache to shrink.
+ *
+ * Releases as many slabs as possible for a cache.
  * To help debugging, a zero exit status indicates all slabs were released.
  */
 int
@@ -1060,9 +1088,12 @@ kmem_cache_shrink(kmem_cache_t *cachep)
        return __kmem_cache_shrink(cachep);
 }
 
-/*
- * Remove a kmem_cache_t object from the slab cache. When returns 0 it
- * completed succesfully. -arca
+/**
+ * kmem_cache_destroy - delete a cache
+ * @cachep: the cache to destroy
+ *
+ * Remove a kmem_cache_t object from the slab cache.
+ * Returns 0 on success.
  *
  * It is expected this function will be called by a module when it is
  * unloaded.  This will remove the cache completely, and avoid a duplicate
@@ -1670,18 +1701,55 @@ null_addr:
        return;
 }
 
+/**
+ * kmem_cache_alloc - Allocate an object
+ * @cachep: The cache to allocate from.
+ * @flags: See kmalloc().
+ *
+ * Allocate an object from this cache.  The flags are only relevant
+ * if the cache has no available objects.
+ */
 void *
 kmem_cache_alloc(kmem_cache_t *cachep, int flags)
 {
        return __kmem_cache_alloc(cachep, flags);
 }
 
+/**
+ * kmem_cache_free - Deallocate an object
+ * @cachep: The cache the allocation was from.
+ * @objp: The previously allocated object.
+ *
+ * Free an object which was previously allocated from this
+ * cache.
+ */
 void
 kmem_cache_free(kmem_cache_t *cachep, void *objp)
 {
        __kmem_cache_free(cachep, objp);
 }
 
+/**
+ * kmalloc - allocate memory
+ * @size: how many bytes of memory are required.
+ * @flags: the type of memory to allocate.
+ *
+ * kmalloc is the normal method of allocating memory
+ * in the kernel.  The @flags argument may be one of:
+ * 
+ * %GFP_BUFFER - XXX
+ *
+ * %GFP_ATOMIC - allocation will not sleep.  Use inside interrupt handlers.
+ *
+ * %GFP_USER - allocate memory on behalf of user.  May sleep.
+ *
+ * %GFP_KERNEL - allocate normal kernel ram.  May sleep.
+ *
+ * %GFP_NFS - has a slightly lower probability of sleeping than %GFP_KERNEL.
+ * Don't use unless you're in the NFS code.
+ *
+ * %GFP_KSWAPD - Don't use unless you're modifying kswapd.
+ */
 void *
 kmalloc(size_t size, int flags)
 {
@@ -1696,6 +1764,13 @@ kmalloc(size_t size, int flags)
        return NULL;
 }
 
+/**
+ * kfree - free previously allocated memory
+ * @objp: pointer returned by kmalloc.
+ *
+ * Don't free memory not originally allocated by kmalloc()
+ * or you will run into trouble.
+ */
 void
 kfree(const void *objp)
 {
@@ -1741,6 +1816,17 @@ null_ptr:
        return;
 }
 
+/**
+ * kfree_s - free previously allocated memory
+ * @objp: pointer returned by kmalloc.
+ * @size: size of object which is being freed.
+ *
+ * This function performs the same task as kfree() except
+ * that it can use the extra information to speed up deallocation
+ * or perform additional tests.
+ * Don't free memory not originally allocated by kmalloc()
+ * or allocated with a different size, or you will run into trouble.
+ */
 void
 kfree_s(const void *objp, size_t size)
 {
@@ -1788,7 +1874,11 @@ kmem_find_general_cachep(size_t size)
 }
 
 
-/* Called from try_to_free_page().
+/**
+ * kmem_cache_reap - Reclaim memory from caches.
+ * @gfp_mask: the type of memory required.
+ *
+ * Called from try_to_free_page().
  * This function _cannot_ be called within a int, but it
  * can be interrupted.
  */
@@ -1951,8 +2041,17 @@ kmem_self_test(void)
 #endif /* SLAB_SELFTEST */
 
 #if    defined(CONFIG_PROC_FS)
-/* /proc/slabinfo
- * cache-name num-active-objs total-objs num-active-slabs total-slabs num-pages-per-slab
+/**
+ * get_slabinfo - generates /proc/slabinfo
+ * @buf: the buffer to write it into
+ *
+ * The contents of the buffer are
+ * cache-name
+ * num-active-objs
+ * total-objs
+ * num-active-slabs
+ * total-slabs
+ * num-pages-per-slab
  */
 int
 get_slabinfo(char *buf)
index 624885478fa26d62f7a338401357b8de8db01b7e..f383bbbd2a015c2c814be59c90c5124ea0d708e2 100644 (file)
@@ -58,10 +58,10 @@ tristate 'DECnet Support' CONFIG_DECNET
 if [ "$CONFIG_DECNET" != "n" ]; then
    source net/decnet/Config.in
 fi
+tristate '802.1d Ethernet Bridging' CONFIG_BRIDGE
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25
    tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB
-   tristate '802.1d Ethernet Bridging' CONFIG_BRIDGE
    bool '802.2 LLC (EXPERIMENTAL)' CONFIG_LLC
 #   if [ "$CONFIG_LLC" = "y" ]; then
 #      bool '  Netbeui (EXPERIMENTAL)' CONFIG_NETBEUI
index e2012cbb330a315e916db6da15acba39395df102..896bc9384991e4d295a722bbb328cfdacdb833f9 100644 (file)
@@ -1607,8 +1607,12 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_
                 * Note. ddp-> becomes invalid at the realloc.
                 */
                if (skb_headroom(skb) < 22)
+               {
+                       struct sk_buff *newskb;
                        /* 22 bytes - 12 ether, 2 len, 3 802.2 5 snap */
-                       skb = skb_realloc_headroom(skb, 32);
+                       newskb = skb_realloc_headroom(skb, 32);
+                       kfree(skb);
+               }
                else
                        skb = skb_unshare(skb, GFP_ATOMIC);
                
index bbbd53a60d521a2d0e1fa0a078c7db69a458a4b1..a569c0c97975e5d36987d9f99e6a59ac18ca7bdb 100644 (file)
@@ -5,7 +5,7 @@
  *     Authors:
  *     Lennert Buytenhek               <buytenh@gnu.org>
  *
- *     $Id: br.c,v 1.42 2000/04/14 10:10:34 davem Exp $
+ *     $Id: br.c,v 1.43 2000/05/25 02:21:36 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License
@@ -38,7 +38,7 @@ void br_inc_use_count()
        MOD_INC_USE_COUNT;
 }
 
-static int __init br_init(void)
+int __init br_init(void)
 {
        printk(KERN_INFO "NET4: Ethernet Bridge 008 for NET4.0\n");
 
index ccc4be7905d804d8eb78bd684441686d155632e1..8625038e15580fa131fb76e665126f4d4b6b412d 100644 (file)
@@ -5,7 +5,7 @@
  *     Authors:
  *     Lennert Buytenhek               <buytenh@gnu.org>
  *
- *     $Id: br_stp.c,v 1.3 2000/05/05 02:17:17 davem Exp $
+ *     $Id: br_stp.c,v 1.4 2000/06/19 10:13:35 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License
@@ -292,18 +292,19 @@ static void br_topology_change_acknowledged(struct net_bridge *br)
 /* called under bridge lock */
 void br_topology_change_detection(struct net_bridge *br)
 {
-       printk(KERN_INFO "%s: topology change detected", br->dev.name);
+       printk(KERN_INFO "%s: topology change detected", br->dev.name);
 
        if (br_is_root_bridge(br)) {
-               printk("propagating\n");
+               printk(", propagating");
                br->topology_change = 1;
                br_timer_set(&br->topology_change_timer, jiffies);
        } else if (!br->topology_change_detected) {
-               printk("sending tcn bpdu\n");
+               printk(", sending tcn bpdu");
                br_transmit_tcn(br);
                br_timer_set(&br->tcn_timer, jiffies);
        }
 
+       printk("\n");
        br->topology_change_detected = 1;
 }
 
index 569b53dd20a83af76e462de2d36c738814573684..f5b9c59b68a2835d9ee537c5a552e3162ba8a07d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  $Id: ipconfig.c,v 1.31 2000/05/03 06:37:06 davem Exp $
+ *  $Id: ipconfig.c,v 1.32 2000/06/19 06:24:59 davem Exp $
  *
  *  Automatic Configuration of IP -- use BOOTP or RARP or user-supplied
  *  information to configure own IP address and routes.
@@ -40,7 +40,6 @@
 #include <net/ip.h>
 #include <net/ipconfig.h>
 
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <asm/checksum.h>
 
index e4c1785605280005353344ee1b1f872e00829b46..3f475bac8acac96f9c9807de5bb4d824082f08cd 100644 (file)
@@ -600,8 +600,7 @@ static struct sk_buff *ipxitf_adjust_skbuff(ipx_interface *intrfc, struct sk_buf
                memcpy(skb2->h.raw, skb->h.raw, skb->len);
        }
        kfree_skb(skb);
-
-       return (NULL);
+       return (skb2);
 }
 
 static int ipxitf_send(ipx_interface *intrfc, struct sk_buff *skb, char *node)
index a29ad21f54df97d4e6d5bec9eca1300585bf08a3..de849d3f4e25eebd261e54e95f7ecf190850564a 100644 (file)
@@ -198,6 +198,17 @@ static union {
                                           the AF_UNIX size (see net/unix/af_unix.c
                                           :unix_mkname()).  
                                         */
+                                        
+/**
+ *     move_addr_to_kernel     -       copy a socket address into kernel space
+ *     @uaddr: Address in user space
+ *     @kaddr: Address in kernel space
+ *     @ulen: Length in user space
+ *
+ *     The address is copied into kernel space. If the provided address is
+ *     too long an error code of -EINVAL is returned. If the copy gives
+ *     invalid addresses -EFAULT is returned. On a success 0 is returned.
+ */
 
 int move_addr_to_kernel(void *uaddr, int ulen, void *kaddr)
 {
@@ -210,6 +221,23 @@ int move_addr_to_kernel(void *uaddr, int ulen, void *kaddr)
        return 0;
 }
 
+/**
+ *     move_addr_to_user       -       copy an address to user space
+ *     @kaddr: kernel space address
+ *     @klen: length of address in kernel
+ *     @uaddr: user space address
+ *     @ulen: pointer to user length field
+ *
+ *     The value pointed to by ulen on entry is the buffer length available.
+ *     This is overwritten with the buffer space used. -EINVAL is returned
+ *     if an overlong buffer is specified or a negative buffer size. -EFAULT
+ *     is returned if either the buffer or the length field are not
+ *     accessible.
+ *     After copying the data up to the limit the user specifies, the true
+ *     length of the data is written over the length limit the user
+ *     specified. Zero is returned for a success.
+ */
 int move_addr_to_user(void *kaddr, int klen, void *uaddr, int *ulen)
 {
        int err;
@@ -295,11 +323,20 @@ extern __inline__ struct socket *socki_lookup(struct inode *inode)
        return &inode->u.socket_i;
 }
 
-/*
- *     Go from a file number to its socket slot.
+/**
+ *     sockfd_lookup   -       Go from a file number to its socket slot
+ *     @fd: file handle
+ *     @err: pointer to an error code return
+ *
+ *     The file handle passed in is locked and the socket it is bound
+ *     too is returned. If an error occurs the err pointer is overwritten
+ *     with a negative errno code and NULL is returned. The function checks
+ *     for both invalid handles and passing a handle which is not a socket.
+ *
+ *     On a success the socket object pointer is returned.
  */
 
-extern struct socket *sockfd_lookup(int fd, int *err)
+struct socket *sockfd_lookup(int fd, int *err)
 {
        struct file *file;
        struct inode *inode;
@@ -331,8 +368,12 @@ extern __inline__ void sockfd_put(struct socket *sock)
        fput(sock->file);
 }
 
-/*
- *     Allocate a socket.
+/**
+ *     sock_alloc      -       allocate a socket
+ *     
+ *     Allocate a new inode and socket object. The two are bound together
+ *     and initialised. The socket is then returned. If we are out of inodes
+ *     NULL is returned.
  */
 
 struct socket *sock_alloc(void)
@@ -375,6 +416,15 @@ static int sock_no_open(struct inode *irrelevant, struct file *dontcare)
        return -ENXIO;
 }
 
+/**
+ *     sock_release    -       close a socket
+ *     @sock: socket to close
+ *
+ *     The socket is released from the protocol stack if it has a release
+ *     callback, and the inode is then released if the socket is bound to
+ *     an inode not a file. 
+ */
 void sock_release(struct socket *sock)
 {
        if (sock->ops) 
@@ -1548,6 +1598,11 @@ void __init proto_init(void)
 }
 
 extern void sk_init(void);
+
+#ifdef CONFIG_BRIDGE
+extern int br_init(void);
+#endif
+
 #ifdef CONFIG_WAN_ROUTER
 extern void wanrouter_init(void);
 #endif
@@ -1579,6 +1634,13 @@ void __init sock_init(void)
        skb_init();
 #endif
 
+       /*
+        *      Ethernet bridge layer.
+        */
+
+#ifdef CONFIG_BRIDGE
+       br_init();
+#endif
 
        /*
         *      Wan router layer. 
index c41dfc1eb44d2b63a783d776ca2a4a0f539918cf..475cc4229c04a3e749c31efdbbfd9268c4244e13 100644 (file)
@@ -22,7 +22,6 @@
  */
 
 #include <asm/system.h>
-#include <asm/segment.h>
 
 #include <linux/types.h>
 #include <linux/mm.h>
index 86d9c09b278f058c8c954e41ee00819d93479861..0eec0f93d3e3ae14b7e667953ea73dfc121514e5 100644 (file)
@@ -539,7 +539,7 @@ if [ -f $DEFAULTS ]; then
   echo "# Using defaults found in" $DEFAULTS
   echo "#"
   . $DEFAULTS
-  sed -e 's/# \(.*\) is not.*/\1=n/' < $DEFAULTS > .config-is-not.$$
+  sed -e 's/# \(CONFIG_[^ ]*\) is not.*/\1=n/' <$DEFAULTS >.config-is-not.$$
   . .config-is-not.$$
   rm .config-is-not.$$
 else
index 3e0da2a9f1b5d0f630fcc348a20d288cbf2502f2..c59053f1ffbda76dd7f31fadee104379e97096ec 100644 (file)
@@ -545,7 +545,7 @@ function l_int () {
 
                        # Semantics of + and ? in GNU expr changed, so
                        # we avoid them:
-                       if expr "$answer" : '0$\|-[1-9][0-9]*$\|[1-9][0-9]*$' >/dev/null
+                       if expr "$answer" : '0$' '|' "$answer" : '[1-9][0-9]*$' '|' "$answer" : '-[1-9][0-9]*$' >/dev/null
                        then
                                eval $2="$answer"
                        else
index 36b12df49aeda925402cedecf5d6d213c2060701..878e12b32427677ba3804420a8ae294a68372efb 100644 (file)
@@ -93,7 +93,7 @@ static int find_identical_file(struct entry *orig,struct entry *newfile)
         if(!orig) return 0;
         if(orig->size==newfile->size && orig->uncompressed && !memcmp(orig->uncompressed,newfile->uncompressed,orig->size)) {
                 newfile->same=orig;
-                return 0;
+                return 1;
         }
         return find_identical_file(orig->child,newfile) ||
                    find_identical_file(orig->next,newfile);
@@ -441,9 +441,9 @@ static unsigned int do_compress(char *base, unsigned int offset, char const *nam
                size -= input;
                if (!is_zero (uncompressed, input)) {
                        compress(base + curr, &len, uncompressed, input);
-                       uncompressed += input;
                        curr += len;
                }
+               uncompressed += input;
 
                if (len > blksize*2) {
                        /* (I don't think this can happen with zlib.) */
index f2189e239925190749d53038a85c7f59a5405d2a..94963425a9a59760547417e3e753db0d96066c4c 100644 (file)
@@ -110,6 +110,8 @@ proc load_configfile { w title func } {
        wm geometry $w +$winx+$winy
 }
 
+bind all <Alt-q> {maybe_exit .maybe}
+
 proc maybe_exit { w } {
        catch {destroy $w}
        toplevel $w -class Dialog
@@ -128,6 +130,8 @@ proc maybe_exit { w } {
                -width 20 -command "destroy $w; focus $oldFocus"
        pack $w.f.back $w.f.canc -side left -pady 10 -padx 45
        pack $w.f -pady 10 -side bottom -padx 10 -anchor w
+       bind $w <Return> "exit"
+       bind $w <Escape> "destroy $w; focus $oldFocus"
        focus $w
        global winx; global winy
        set winx [expr [winfo x .]+30]; set winy [expr [winfo y .]+30]
@@ -402,6 +406,7 @@ proc minimenu { w mnum line text variable helpidx } {
 
 proc menusplit {w m n} {
        if { $n > 2 } then {
+               update idletasks
                set menuoptsize [expr [$m yposition 2] - [$m yposition 1]]   
                set maxsize [winfo screenheight $w]
                set splitpoint [expr $maxsize * 4 / 5 / $menuoptsize - 1]
@@ -411,6 +416,10 @@ proc menusplit {w m n} {
        }
 }
 
+proc menutitle {text menu w} {
+       wm title $w "$text"
+}
+
 proc submenu { w mnum line text subnum } {
        frame $w.x$line
        button $w.x$line.l -text "" -width 15 -relief groove
@@ -531,6 +540,9 @@ ${var}:\\
        wm maxsize $w [winfo width $w] $sizy
 }
 
+bind all <Alt-s> { catch {exec cp -f .config .config.old}; \
+               writeconfig .config include/linux/autoconf.h; wrapup .wrap }
+
 proc wrapup {w }  {
        catch {destroy $w}
        toplevel $w -class Dialog
@@ -554,6 +566,7 @@ proc wrapup {w }  {
        pack $w.f.back -side bottom -pady 10 -anchor s
        pack $w.f -pady 10 -side top -padx 10 -anchor s
        focus $w
+        bind $w <Return> "exit"
        global winx; global winy
        set winx [expr [winfo x .]+30]; set winy [expr [winfo y .]+30]
        wm geometry $w +$winx+$winy
index 2bad7a12fee1a570f9100ede028ab029d94e350f..ed8d17c37823123137b5a46f9dae170f4b30ffd2 100644 (file)
@@ -1,20 +1,16 @@
-CC = $(HOSTCC)
-CPP = $(HOSTCC) -E
-
-CFLAGS = $(HOSTCFLAGS) -DLOCALE 
-LDFLAGS = -s -L .
-LDLIBS = -lncurses
+HOSTCFLAGS += -DLOCALE 
+LIBS = -lncurses
 
 ifeq (/usr/include/ncurses/ncurses.h, $(wildcard /usr/include/ncurses/ncurses.h))
-        CFLAGS += -I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"
+        HOSTCFLAGS += -I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"
 else
 ifeq (/usr/include/ncurses/curses.h, $(wildcard /usr/include/ncurses/curses.h))
-        CFLAGS += -I/usr/include/ncurses -DCURSES_LOC="<ncurses/curses.h>"
+        HOSTCFLAGS += -I/usr/include/ncurses -DCURSES_LOC="<ncurses/curses.h>"
 else
 ifeq (/usr/include/ncurses.h, $(wildcard /usr/include/ncurses.h))
-        CFLAGS += -DCURSES_LOC="<ncurses.h>"
+        HOSTCFLAGS += -DCURSES_LOC="<ncurses.h>"
 else
-       CFLAGS += -DCURSES_LOC="<curses.h>"
+       HOSTCFLAGS += -DCURSES_LOC="<curses.h>"
 endif
 endif
 endif
@@ -22,16 +18,18 @@ endif
 
 OBJS = checklist.o menubox.o textbox.o yesno.o inputbox.o \
        util.o lxdialog.o msgbox.o
-SRCS = $(OBJS:.o=.c)
 
+%.o: %.c
+       $(HOSTCC) $(HOSTCFLAGS) -c -o $@ $<
 
 all: ncurses lxdialog
 
 lxdialog: $(OBJS)
+       $(HOSTCC) -o lxdialog $(OBJS) $(LIBS)
 
 ncurses:
        @echo "main() {}" > lxtemp.c
-       @if $(CC) -lncurses lxtemp.c ; then \
+       @if $(HOSTCC) -lncurses lxtemp.c ; then \
                rm -f lxtemp.c a.out; \
        else \
                rm -f lxtemp.c; \
index 3627424519e04b7b44e308ff482fd9b9733b5d29..49d7aa37a3247efd22a71930b1c3210b7b2f9be3 100644 (file)
@@ -32,11 +32,11 @@ if { [file readable .config] == 1} then {
 update_define 1 $total_menus 0
 update_mainmenu
 
-button .f0.right.save -anchor w -text "Save and Exit" \
+button .f0.right.save -anchor w -text "Save and Exit" -underline 0\
     -command { catch {exec cp -f .config .config.old}; \
                writeconfig .config include/linux/autoconf.h; wrapup .wrap }
 
-button .f0.right.quit -anchor w -text "Quit Without Saving" \
+button .f0.right.quit -anchor w -text "Quit Without Saving" -underline 0\
     -command { maybe_exit .maybe }
 
 button .f0.right.load -anchor w -text "Load Configuration from File" \
index 18d968eff8c86191febd793dbc46cd11296a6e30..9faede6102dede1ecdf5a9c75724300697c877f3 100644 (file)
@@ -149,18 +149,10 @@ static void start_proc( char * label, int menu_num, int toplevel )
     printf( "\tpack $w.m -pady 10 -side top -padx 10\n" );
     printf( "\twm title $w \"%s\" \n\n", label );
 
-    /*
-     * Attach the "Prev", "Next" and "OK" buttons at the end of the window.
-     */
-    printf( "\tframe $w.f\n" );
-    if ( toplevel )
-       printf( "\tbutton $w.f.back -text \"Main Menu\" \\\n" );
-    else
-       printf( "\tbutton $w.f.back -text \"OK\" \\\n" );
-    printf( "\t\t-width 15 -command \"catch {focus $oldFocus}; destroy $w; unregister_active %d\"\n",
-       menu_num );
-    printf( "\tbutton $w.f.next -text \"Next\" \\\n" );
-    printf( "\t\t-width 15 -command \"catch {focus $oldFocus}; " );
+    printf( "\tbind $w <Escape> \"catch {focus $oldFocus}; destroy $w; unregister_active %d; break\"\n", menu_num);
+
+    printf("\tset nextscript ");
+    printf("\"catch {focus $oldFocus}; " );
     /* 
      * We are checking which windows should be destroyed and which are 
      * common parrents with the next one. Remember that menu_num field
@@ -182,13 +174,48 @@ static void start_proc( char * label, int menu_num, int toplevel )
     }
     printf( "menu%d .menu%d \\\"$title\\\"\"\n",
        menu_num+1, menu_num+1 );
-    if ( menu_num == tot_menu_num )
-       printf( "\t$w.f.next configure -state disabled\n" );
-    printf( "\tbutton $w.f.prev -text \"Prev\" \\\n" );
+
+    /*
+     * Attach the "Prev", "Next" and "OK" buttons at the end of the window.
+     */
+    printf( "\tframe $w.f\n" );
+    if ( toplevel )
+       printf( "\tbutton $w.f.back -text \"Main Menu\" \\\n" );
+    else
+       printf( "\tbutton $w.f.back -text \"OK\" \\\n" );
+    printf( "\t\t-width 15 -command \"catch {focus $oldFocus}; destroy $w; unregister_active %d\"\n",
+       menu_num );
+    printf( "\tbutton $w.f.next -text \"Next\" -underline 0\\\n" );
+    printf( "\t\t-width 15 -command $nextscript\n");
+
+    if ( menu_num == tot_menu_num ) {
+      printf( "\t$w.f.next configure -state disabled\n" );
+        /* 
+         *  this is a bit hackish but Alt-n must be rebound
+         *  otherwise if the user press Alt-n on the last menu
+         *  it will give him/her the next menu of one of the 
+         *  previous options
+         */
+        printf( "\tbind all <Alt-n> \"puts \\\"no more menus\\\" \"\n");
+    }
+    else
+    {
+        /*
+         * I should be binding to $w not all - but if I do nehat I get the error "unknown path"
+         */
+        printf( "\tbind all <Alt-n> $nextscript\n");
+    }
+    printf( "\tbutton $w.f.prev -text \"Prev\" -underline 0\\\n" );
     printf( "\t\t-width 15 -command \"catch {focus $oldFocus}; destroy $w; unregister_active %d; menu%d .menu%d \\\"$title\\\"\"\n",
        menu_num, menu_num-1, menu_num-1 );
-    if ( menu_num == 1 )
+    if ( menu_num == 1 ) {
        printf( "\t$w.f.prev configure -state disabled\n" );
+    }
+    else
+    {
+        printf( "\tbind $w <Alt-p> \"catch {focus $oldFocus}; destroy $w; unregister_active %d; menu%d .menu%d \\\"$title\\\";break\"\n",
+            menu_num, menu_num-1, menu_num-1 );
+    }  
     printf( "\tpack $w.f.back $w.f.next $w.f.prev -side left -expand on\n" );
     printf( "\tpack $w.f -pady 10 -side bottom -anchor w -fill x\n" );
 
@@ -215,6 +242,12 @@ static void start_proc( char * label, int menu_num, int toplevel )
     printf( "\t\t-relief flat -borderwidth 0 -yscrollcommand \"$w.config.vscroll set\" \\\n" );
     printf( "\t\t-width [expr [winfo screenwidth .] * 1 / 2] \n" );
     printf( "\tframe $w.config.f\n" );
+    printf( "\tbind $w <Key-Down> \"$w.config.canvas yview scroll  1 unit;break;\"\n");
+    printf( "\tbind $w <Key-Up> \"$w.config.canvas yview scroll  -1 unit;break;\"\n");
+    printf( "\tbind $w <Key-Next> \"$w.config.canvas yview scroll  1 page;break;\"\n");
+    printf( "\tbind $w <Key-Prior> \"$w.config.canvas yview scroll  -1 page;break;\"\n");
+    printf( "\tbind $w <Key-Home> \"$w.config.canvas yview moveto 0;break;\"\n");
+    printf( "\tbind $w <Key-End> \"$w.config.canvas yview moveto 1 ;break;\"\n");
     printf( "\tpack $w.config.canvas -side right -fill y\n" );
     printf("\n\n");
 }
@@ -974,7 +1007,7 @@ static void end_proc( struct kconfig * scfg, int menu_num )
     }
     else
        printf( "\tset winx [expr [winfo x .]+30]; set winy [expr [winfo y .]+30]\n" );
-    printf( "\twm geometry $w +$winx+$winy\n" );
+    printf( "\tif {[winfo exists $w]} then {wm geometry $w +$winx+$winy}\n" );
 
     /*
      * Now that the whole window is in place, we need to wait for an "update"
@@ -987,7 +1020,7 @@ static void end_proc( struct kconfig * scfg, int menu_num )
      * around frames.  Sigh.
      */
     printf( "\tupdate idletasks\n" );
-    printf( "\t$w.config.canvas create window 0 0 -anchor nw -window $w.config.f\n\n" );
+    printf( "\tif {[winfo exists $w]} then  {$w.config.canvas create window 0 0 -anchor nw -window $w.config.f\n\n" );
     printf( "\t$w.config.canvas configure \\\n" );
     printf( "\t\t-width [expr [winfo reqwidth $w.config.f] + 1]\\\n" );
     printf( "\t\t-scrollregion \"-1 -1 [expr [winfo reqwidth $w.config.f] + 1] \\\n" );
@@ -1005,17 +1038,17 @@ static void end_proc( struct kconfig * scfg, int menu_num )
     printf( "\t\t$w.config.canvas configure -height $canvtotal\n" );
     printf( "\t} else {\n" );
     printf( "\t\t$w.config.canvas configure -height [expr $scry - $winy]\n" );
-    printf( "\t}\n" );
+    printf( "\t\t}\n\t}\n" );
 
     /*
      * Limit the min/max window size.  Height can vary, but not width,
      * because of the limitations of canvas and our laziness.
      */
     printf( "\tupdate idletasks\n" );
-    printf( "\twm maxsize $w [winfo width $w] [winfo screenheight $w]\n" );
+    printf( "\tif {[winfo exists $w]} then {\n\twm maxsize $w [winfo width $w] [winfo screenheight $w]\n" );
     printf( "\twm minsize $w [winfo width $w] 100\n\n" );
     printf( "\twm deiconify $w\n" );
-    printf( "}\n\n\n" );
+    printf( "}\n}\n\n" );
 
     /*
      * Now we generate the companion procedure for the menu we just
@@ -1248,7 +1281,7 @@ void dump_tk_script( struct kconfig * scfg )
                printf( "\tminimenu $w.config.f %d %d \"%s\" tmpvar_%d %s\n",
                    cfg->menu_number, cfg->menu_line, cfg->label,
                    -(cfg->nameindex), vartable[cfg->next->nameindex].name );
-               printf( "\tmenu $w.config.f.x%d.x.menu -title \"%s\"\n",
+               printf( "\tmenu $w.config.f.x%d.x.menu -tearoffcommand \"menutitle \\\"%s\\\"\"\n",
                    cfg->menu_line, cfg->label );
                cfg1 = cfg;
                opt_count = 0;
index e17f109a49d29e95aa7f9ec5fd9c06d0513afd76..abf5ad8b080dc649d13655e6bb89654e3a86c404 100644 (file)
@@ -172,6 +172,28 @@ static const char * get_qstring( const char * pnt, char ** label )
 
 
 
+/*
+ * Get a quoted or unquoted string. It is recognized by the first 
+ * non-white character. '"' and '"' are not allowed inside the string.
+ */
+static const char * get_qnqstring( const char * pnt, char ** label )
+{
+    char quote_char;
+
+    while ( *pnt == ' ' || *pnt == '\t' )
+       pnt++;
+
+    if ( *pnt == '\0' )
+       return pnt;
+    quote_char = *pnt;
+    if ( quote_char == '"' || quote_char == '\'' )
+       return get_qstring( pnt, label );
+    else
+       return get_string( pnt, label );
+}
+
+
+
 /*
  * Tokenize an 'if' statement condition.
  */
@@ -505,6 +527,8 @@ static void tokenize_line( const char * pnt )
        if ( last_menuoption != NULL )
        {
            pnt = get_qstring(pnt, &cfg->label);
+           if (cfg->label == NULL)
+               syntax_error( "missing comment text" );
            last_menuoption->label = cfg->label;
            last_menuoption = NULL;
        }
@@ -546,7 +570,9 @@ static void tokenize_line( const char * pnt )
     case token_define_string:
        pnt = get_string( pnt, &buffer );
        cfg->nameindex = get_varnum( buffer );
-       pnt = get_qstring( pnt, &cfg->value );
+       pnt = get_qnqstring( pnt, &cfg->value );
+       if (cfg->value == NULL)
+           syntax_error( "missing value" );
        break;
 
     case token_dep_bool:
@@ -659,7 +685,9 @@ static void tokenize_line( const char * pnt )
        pnt = get_qstring ( pnt, &cfg->label );
        pnt = get_string  ( pnt, &buffer );
        cfg->nameindex = get_varnum( buffer );
-       pnt = get_qstring  ( pnt, &cfg->value );
+       pnt = get_qnqstring  ( pnt, &cfg->value );
+       if (cfg->value == NULL)
+           syntax_error( "missing initial value" );
        break;
 
     case token_if: