diff -Nru a/CREDITS b/CREDITS --- a/CREDITS Tue Feb 26 11:57:57 2002 +++ b/CREDITS Tue Feb 26 11:57:57 2002 @@ -1219,10 +1219,10 @@ S: Germany N: Christoph Hellwig -E: hch@caldera.de E: hch@infradead.org D: misc driver & makefile hacking D: freevxfs driver +D: sysvfs maintainer S: Triftstraße 26 S: 38644 Goslar S: Germany @@ -2672,6 +2672,16 @@ D: Linux-Support, -Mailbox, -Stammtisch D: several improvements to system programs S: Oldenburg +S: Germany + +N: Robert Schwebel +E: robert@schwebel.de +W: http://www.schwebel.de +D: Embedded hacker and book author, +D: AMD Elan support for Linux +S: Pengutronix +S: Braunschweiger Strasse 79 +S: 31134 Hildesheim S: Germany N: Darren Senn diff -Nru a/Documentation/arm/mem_alignment b/Documentation/arm/mem_alignment --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/arm/mem_alignment Tue Feb 26 11:58:00 2002 @@ -0,0 +1,58 @@ +Too many problems poped up because of unnoticed misaligned memory access in +kernel code lately. Therefore the alignment fixup is now unconditionally +configured in for SA11x0 based targets. According to Alan Cox, this is a +bad idea to configure it out, but Russell King has some good reasons for +doing so on some f***ed up ARM architectures like the EBSA110. However +this is not the case on many design I'm aware of, like all SA11x0 based +ones. + +Of course this is a bad idea to rely on the alignment trap to perform +unaligned memory access in general. If those access are predictable, you +are better to use the macros provided by include/asm/unaligned.h. The +alignment trap can fixup misaligned access for the exception cases, but at +a high performance cost. It better be rare. + +Now for user space applications, it is possible to configure the alignment +trap to SIGBUS any code performing unaligned access (good for debugging bad +code), or even fixup the access by software like for kernel code. The later +mode isn't recommended for performance reasons (just think about the +floating point emulation that works about the same way). Fix your code +instead! + +Please note that randomly changing the behaviour without good thought is +real bad - it changes the behaviour of all unaligned instructions in user +space, and might cause programs to fail unexpectedly. + +To change the alignment trap behavior, simply echo a number into +/proc/sys/debug/alignment. The number is made up from various bits: + +bit behavior when set +--- ----------------- + +0 A user process performing an unaligned memory access + will cause the kernel to print a message indicating + process name, pid, pc, instruction, address, and the + fault code. + +1 The kernel will attempt to fix up the user process + performing the unaligned access. This is of course + slow (think about the floating point emulator) and + not recommended for production use. + +2 The kernel will send a SIGBUS signal to the user process + performing the unaligned access. + +Note that not all combinations are supported - only values 0 through 5. +(6 and 7 don't make sense). + +For example, the following will turn on the warnings, but without +fixing up or sending SIGBUS signals: + + echo 1 > /proc/sys/debug/alignment + +You can also read the content of the same file to get statistical +information on unaligned access occurences plus the current mode of +operation for user space code. + + +Nicolas Pitre, Mar 13, 2001. Modified Russell King, Nov 30, 2001. diff -Nru a/Documentation/filesystems/porting b/Documentation/filesystems/porting --- a/Documentation/filesystems/porting Tue Feb 26 11:57:58 2002 +++ b/Documentation/filesystems/porting Tue Feb 26 11:57:58 2002 @@ -81,11 +81,12 @@ [mandatory] ->lookup(), ->truncate(), ->create(), ->unlink(), ->mknod(), ->mkdir(), -->rmdir(), ->link(), ->symlink() and ->rename() are called without BKL now. -Grab it on the entry, drop upon return - that will guarantee the same -locking you used to have. If your method or its parts do not need BKL - -better yet, now you can shift lock_kernel() / unlock_kernel() so that -they would protect exactly what needs to be protected. +->rmdir(), ->link(), ->lseek(), ->symlink() and ->rename() are called +without BKL now. Grab it on the entry, drop upon return - that will +guarantee the same locking you used to have. If your method or its +parts do not need BKL - better yet, now you can shift lock_kernel() and +unlock_kernel() so that they would protect exactly what needs to be +protected. --- [informational] diff -Nru a/Documentation/kbuild/config-language.txt b/Documentation/kbuild/config-language.txt --- a/Documentation/kbuild/config-language.txt Tue Feb 26 11:57:59 2002 +++ b/Documentation/kbuild/config-language.txt Tue Feb 26 11:57:59 2002 @@ -30,7 +30,7 @@ scripts/Configure make config, make oldconfig scripts/Menuconfig make menuconfig scripts/tkparse make xconfig - mconfig (in development) + mconfig ftp.kernel.org/pub/linux/kernel/people/hch/mconfig/ 'Configure' is a bash script which interprets Config.in files by sourcing them. Some of the Config Language commands are native bash commands; @@ -52,9 +52,6 @@ into an internal syntax tree and then hands the syntax tree to one of several user-interface front ends. -This document describes the behaviour of all four interpreters, even though -mconfig has not been released at the time of writing. - === Statements @@ -489,7 +486,7 @@ Configure: implemented Menuconfig: implemented XConfig: implemented -mconfig: not implemented +mconfig: implemented Example: diff -Nru a/Documentation/networking/3c359.txt b/Documentation/networking/3c359.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/networking/3c359.txt Tue Feb 26 11:58:00 2002 @@ -0,0 +1,58 @@ + +3COM PCI TOKEN LINK VELOCITY XL TOKEN RING CARDS README + +Release 0.9.0 - Release + Jul 17th 2000 Mike Phillips + + 1.2.0 - Final + Feb 17th 2002 Mike Phillips + Updated for submission to the 2.4.x kernel. + +Thanks: + Terry Murphy from 3Com for tech docs and support, + Adam D. Ligas for testing the driver. + +Note: + This driver will NOT work with the 3C339 Token Ring cards, you need +to use the tms380 driver instead. + +Options: + +The driver accepts three options: ringspeed, pkt_buf_sz and message_level. + +These options can be specified differently for each card found. + +ringspeed: Has one of three settings 0 (default), 4 or 16. 0 will +make the card autosense the ringspeed and join at the appropriate speed, +this will be the default option for most people. 4 or 16 allow you to +explicitly force the card to operate at a certain speed. The card will fail +if you try to insert it at the wrong speed. (Although some hubs will allow +this so be *very* careful). The main purpose for explicitly setting the ring +speed is for when the card is first on the ring. In autosense mode, if the card +cannot detect any active monitors on the ring it will open at the same speed as +its last opening. This can be hazardous if this speed does not match the speed +you want the ring to operate at. + +pkt_buf_sz: This is this initial receive buffer allocation size. This will +default to 4096 if no value is entered. You may increase performance of the +driver by setting this to a value larger than the network packet size, although +the driver now re-sizes buffers based on MTU settings as well. + +message_level: Controls level of messages created by the driver. Defaults to 0: +which only displays start-up and critical messages. Presently any non-zero +value will display all soft messages as well. NB This does not turn +debuging messages on, that must be done by modified the source code. + +Variable MTU size: + +The driver can handle a MTU size upto either 4500 or 18000 depending upon +ring speed. The driver also changes the size of the receive buffers as part +of the mtu re-sizing, so if you set mtu = 18000, you will need to be able +to allocate 16 * (sk_buff with 18000 buffer size) call it 18500 bytes per ring +position = 296,000 bytes of memory space, plus of course anything +necessary for the tx sk_buff's. Remember this is per card, so if you are +building routers, gateway's etc, you could start to use a lot of memory +real fast. + +2/17/02 Mike Phillips + diff -Nru a/Documentation/networking/e1000.txt b/Documentation/networking/e1000.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/networking/e1000.txt Tue Feb 26 11:58:00 2002 @@ -0,0 +1,245 @@ +Linux* Base Driver for the Intel(R) PRO/1000 Family of Adapters +=============================================================== + +February 5, 2002 + + +Contents +======== + +- In This Release +- Supported Adapters +- Command Line Parameters +- Speed and Duplex Configuration +- Known Issues +- Support + + +In This Release +=============== + +This file describes the Linux* Base Driver for the Intel(R) PRO/1000 Family +of Adapters, version 4.2.x. +This driver includes support for Itanium(TM)-based systems. + +This release version includes the following: + + - support for the ethtool 1.4 interface. A third-party application can use + the ethtool interface to get and set driver parameters. + + - the zero copy feature. Zero copy provides faster information throughput. + By default, this feature is enabled if using a kernel that supports it. + Zero copy is not supported on the original PWLA8490 (plain) adapter. + + +Supported Adapters +================== + +The following Intel network adapters are compatible with the drivers in this +release: + + Controller Adapter Name Board IDs + ---------- ------------ --------- + + 82542 PRO/1000 Gigabit Server Adapter 700262-xxx, 717037-xxx + + 82543 PRO/1000 F Server Adapter 738640-xxx, A38888-xxx, + A06512-xxx + + 82543 PRO/1000 T Server Adapter A19845-xxx, A33948-xxx + + 82544 PRO/1000 XT Server Adapter A51580-xxx + + 82544 PRO/1000 XF Server Adapter A50484-xxx + + 82544 PRO/1000 T Desktop Adapter A62947-xxx + + +To verify your Intel adapter is supported, find the board ID number on the +adapter. Look for a label that has a barcode and a number in the format of +123456-001 (six digits hyphen three digits). Match this to the list of +numbers above. + +For more information on how to identify your adapter, go to the Adapter & +Driver ID Guide at: + + http://support.intel.com/support/network/adapter/pro100/21397.htm + +For the latest Intel network drivers for Linux, go to: + + http://appsr.intel.com/scripts-df/support_intel.asp + + +Command Line Parameters +======================= + +If the driver is built as a module, the following parameters are used by +entering them on the command line with the modprobe or insmod command. +For example, with two PRO/1000 PCI adapters, entering: + + insmod e1000 TxDescriptors=80,128 + +loads the e1000 driver with 80 TX resources for the first adapter and 128 TX +resources for the second adapter. + +For more information about the AutoNeg, Duplex, and Speed parameters, see the +"Speed and Duplex Configuration" section in this document. + + +AutoNeg (Intel PRO/1000 T and PRO/1000 XT server adapters only) +Valid Range: 0-0x0F, 0x20-0x2F +Default Value: 0x2F + This parameter is a bit mask that specifies which speed and duplex + settings the board advertises. When this parameter is used, the Speed and + Duplex parameters must not be specified. + +Duplex (Intel PRO/1000 T and PRO/1000 XT server adapters only) +Valid Range: 0-2 (0=auto-negotiate, 1=half, 2=full) +Default Value: 0 + Defines the direction in which data is allowed to flow. Can by either one + or two-directional. If both Duplex and the link partner are set to auto- + negotiate, the board auto-detects the correct duplex. If the link partner + is forced (either full or half), Duplex defaults to half-duplex. + +FlowControl +Valid Range: 0-3 (0=none, 1=Rx only, 2=Tx only, 3=Rx&Tx) +Default: Read flow control settings from the EEPROM + This parameter controls the automatic generation(Tx) and response(Rx) to + Ethernet PAUSE frames. + +RxDescriptors +Valid Range: 80-256 for 82542 and 82543-based adapters + 80-4096 for 82544-based adapters +Default Value: 256 + This value is the number of receive descriptors allocated by the driver. + Increasing this value allows the driver to buffer more incoming packets. + Each descriptor is 16 bytes. A receive buffer is also allocated for each + descriptor and can be either 2048, 4096, 8192, or 16384 bytes, depending + on the MTU setting. + +RxIntDelay +Valid Range: 0-65535 (0=off) +Default Value: 64 + This value delays the generation of receive interrupts in units of 1.024 + microseconds. Receive interrupt reduction can improve CPU efficiency if + properly tuned for specific network traffic. Increasing this value adds + extra latency to frame reception and can end up decreasing the throughput + of TCP traffic. If the system is reporting dropped receives, this value + may be set too high, causing the driver to run out of available receive + descriptors. + +Speed (Intel PRO/1000 T and PRO/1000 XT server adapters only) +Valid Settings: 0, 10, 100, 1000 +Default Value: 0 (auto-negotiate at all supported speeds) + Speed forces the line speed to the specified value in megabits per second + (Mbps). If this parameter is not specified or is set to 0 and the link + partner is set to auto-negotiate, the board will auto-detect the correct + speed. Duplex must also be set when Speed is set to either 10 or 100. + +TxDescriptors +Valid Range: 80-256 for 82542 and 82543-based adapters + 80-4096 for 82544-based adapters +Default Value: 256 + This value is the number of transmit descriptors allocated by the driver. + Increasing this value allows the driver to queue more transmits. Each + descriptor is 16 bytes. + +TxIntDelay +Valid Range: 0-65535 (0=off) +Default Value: 64 + This value delays the generation of transmit interrupts in units of 1.024 + microseconds. Transmit interrupt reduction can improve CPU efficiency if + properly tuned for specific network traffic. If the system is reporting + dropped transmits, this value may be set too high causing the driver to + run out of available transmit descriptors. + +XsumRX (not available on the PRO/1000 Gigabit Server Adapter) +Valid Range: 0-1 +Default Value: 1 + A value of '1' indicates that the driver should enable IP checksum + offload for received packets (both UDP and TCP) to the adapter hardware. + + +Speed and Duplex Configuration +============================== + +Three keywords are used to control the speed and duplex configuration of the +PRO/1000 T and PRO/1000 XT server adapters. These keywords are Speed, Duplex, +and AutoNeg. + +If the board uses a fiber interface, these keywords are ignored, and the +fiber interface board only links at 1000 Mbps full-duplex. + +For copper-based boards, the keywords interact as follows: + + The default operation is auto-negotiate. The board advertises all supported + speed and duplex combinations, and it links at the highest common speed and + duplex mode IF the link partner is set to auto-negotiate. + + If Speed = 1000, limited auto-negotiation is enabled and only 1000 Mbps is + advertised (The 1000BaseT spec requires auto-negotiation.) + + If Speed = 10 or 100, then both Speed and Duplex must be set. Auto- + negotiation is disabled, and the AutoNeg parameter is ignored. Partner MUST + also be forced. + +The AutoNeg parameter is used when more control is required over the auto- +negotiation process. When this parameter is used, Speed and Duplex must not +be specified. This parameter is a bitmap that specifies which speed and +duplex settings are advertised to the link partner. + +Bit 7 6 5 4 3 2 1 0 +Speed (Mbps) N/A N/A 1000 N/A 100 100 10 10 +Duplex Full Full Half Full Half + +Note that setting AutoNeg does not guarantee that the board will link at the +highest specified speed or duplex mode, but the board will link at the +highest possible speed/duplex of the link partner IF the link partner is also +set to auto-negotiate. If the link partner is forced speed/duplex, the +adapter MUST be forced to the same speed/duplex. + + +Known Issues +============ + + Driver Hangs Under Heavy Traffic Loads + -------------------------------------- + + Intel is aware that previously released e1000 drivers may hang under very + specific types of heavy traffic loads. This version includes a workaround + that resets the adapter automatically if a hang condition is detected. This + workaround ensures network traffic flow is not affected when a hang occurs. + + Jumbo Frames System Requirement + ------------------------------- + + Memory allocation failures have been observed on Linux systems with 64 MB + of RAM or less that are running Jumbo Frames. If you are using Jumbo + Frames, your system may require more than the advertised minimum + requirement of 64 MB of system memory. + + +Support +======= + +For general information and support, go to the Intel support website at: + + http://support.intel.com + +If an issue is identified with the released source code on the supported +kernel with a supported adapter, email the specific information related to +the issue to linux.nics@intel.com. + + +License +======= + +This software program is released under the terms of a license agreement +between you ('Licensee') and Intel. Do not use or load this software or any +associated materials (collectively, the 'Software') until you have carefully +read the full terms and conditions of the LICENSE located in this software +package. By loading or using the Software, you agree to the terms of this +Agreement. If you do not agree with the terms of this Agreement, do not +install or use the Software. + +* Other names and brands may be claimed as the property of others. diff -Nru a/Documentation/sound/AD1816 b/Documentation/sound/AD1816 --- a/Documentation/sound/AD1816 Tue Feb 26 11:57:57 2002 +++ b/Documentation/sound/AD1816 Tue Feb 26 11:57:57 2002 @@ -80,5 +80,5 @@ tek@rbg.informatik.tu-darmstadt.de Thorsten Knabe -Christoph Hellwig +Christoph Hellwig Last modified: 2000/09/20 diff -Nru a/Documentation/sound/NEWS b/Documentation/sound/NEWS --- a/Documentation/sound/NEWS Tue Feb 26 11:58:00 2002 +++ b/Documentation/sound/NEWS Tue Feb 26 11:58:00 2002 @@ -1,6 +1,6 @@ Linux 2.4 Sound Changes 2000-September-25 -Christoph Hellwig, +Christoph Hellwig, diff -Nru a/MAINTAINERS b/MAINTAINERS --- a/MAINTAINERS Tue Feb 26 11:57:56 2002 +++ b/MAINTAINERS Tue Feb 26 11:57:56 2002 @@ -69,6 +69,14 @@ it has been replaced by a better system and you should be using that. +3C359 NETWORK DRIVER +P: Mike Phillips +M: mikep@linuxtr.net +L: linux-net@vger.rutgers.edu +L: linux-tr@linuxtr.net +W: http://www.linuxtr.net +S: Maintained + 3C501 NETWORK DRIVER P: Alan Cox M: alan@the.3c501.cabal.tm @@ -118,11 +126,11 @@ S: Maintained A2232 SERIAL BOARD DRIVER -P: Enver Haase -M: ehaase@inf.fu-berlin.de -M: A2232@gmx.net -L: linux-m68k@lists.linux-m68k.org -S: Maintained +P: Enver Haase +M: ehaase@inf.fu-berlin.de +M: A2232@gmx.net +L: linux-m68k@lists.linux-m68k.org +S: Maintained ACENIC DRIVER P: Jes Sorensen @@ -145,6 +153,14 @@ W: http://www.ibm.com/linux/ltc/ S: Supported +AACRAID SCSI RAID DRIVER +P: Adaptec OEM Raid Solutions +M: linux-aacraid-devel@dell.com +L: linux-aacraid-devel@dell.com +L: linux-aacraid-announce@dell.com +W: http://domsch.com/linux +S: Supported + ACPI P: Andy Grover M: andrew.grover@intel.com @@ -290,11 +306,11 @@ S: Maintained COMPAQ FIBRE CHANNEL 64-bit/66MHz PCI non-intelligent HBA -P: Amy Vanzant-Hodge -M: Amy Vanzant-Hodge (fibrechannel@compaq.com) +P: Amy Vanzant-Hodge +M: Amy Vanzant-Hodge (fibrechannel@compaq.com) L: compaqandlinux@cpqlin.van-dijk.net W: ftp.compaq.com/pub/products/drivers/linux -S: Supported +S: Supported COMPAQ SMART2 RAID DRIVER P: Charles White @@ -311,12 +327,12 @@ S: Supported COMPUTONE INTELLIPORT MULTIPORT CARD -P: Michael H. Warfield -M: Michael H. Warfield -W: http://www.computone.com/ -W: http://www.wittsend.com/computone.html -L: linux-computone@lazuli.wittsend.com -S: Supported +P: Michael H. Warfield +M: Michael H. Warfield +W: http://www.computone.com/ +W: http://www.wittsend.com/computone.html +L: linux-computone@lazuli.wittsend.com +S: Supported COMX/MULTIGATE SYNC SERIAL DRIVERS P: Gergely Madarasz @@ -330,15 +346,6 @@ W: http://kbuild.sourceforge.net S: Maintained -CONFIGURE.HELP -P: Steven P. Cole -M: Steven P. Cole -P: Eric S. Raymond -M: Eric S. Raymond -L: kbuild-devel@lists.sourceforge.net -W: http://kbuild.sourceforge.net -S: Maintained - COSA/SRP SYNC SERIAL DRIVER P: Jan "Yenya" Kasprzak M: kas@fi.muni.cz @@ -428,9 +435,9 @@ DIGI INTL. EPCA DRIVER P: Chad Schwartz -M: support@dgii.com -L: digilnux@dgii.com -S: Maintained +M: support@dgii.com +L: digilnux@dgii.com +S: Maintained DIGI RIGHTSWITCH NETWORK DRIVER P: Rick Richardson @@ -452,12 +459,12 @@ S: Supported DISK GEOMETRY AND PARTITION HANDLING -P: Andries Brouwer -M: aeb@cwi.nl -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 +P: Andries Brouwer +M: aeb@cwi.nl +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 @@ -532,9 +539,9 @@ S: Maintained ETHERTEAM 16I DRIVER -P: Mika Kuoppala -M: miku@iki.fi -S: Maintained +P: Mika Kuoppala +M: miku@iki.fi +S: Maintained EXT2 FILE SYSTEM P: Remy Card @@ -575,7 +582,7 @@ FREEVXFS FILESYSTEM P: Christoph Hellwig -M: hch@caldera.de +M: hch@infradead.org W: ftp://ftp.openlinux.org/pub/people/hch/vxfs S: Maintained @@ -613,10 +620,10 @@ S: Maintained HFS FILESYSTEM -P: Adrian Sun -M: asun@cobaltnet.com -L: linux-kernel@vger.kernel.org -S: Maintained +P: Adrian Sun +M: asun@cobaltnet.com +L: linux-kernel@vger.kernel.org +S: Maintained HGA FRAMEBUFFER DRIVER P: Ferenc Bakonyi @@ -649,6 +656,11 @@ W: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi S: Maintained +HPUSBSCSI +P: Oliver Neukum +M: drivers@neukum.org +S: Maintained + I2C DRIVERS P: Simon Vogl M: simon@tk.uni-linz.ac.at @@ -691,10 +703,10 @@ S: Maintained IBM ServeRAID RAID DRIVER -P: Keith Mitchell -M: ipslinux@us.ibm.com -W: http://www.developer.ibm.com/welcome/netfinity/serveraid.html -S: Supported +P: Keith Mitchell +M: ipslinux@us.ibm.com +W: http://www.developer.ibm.com/welcome/netfinity/serveraid.html +S: Supported IDE DRIVER [GENERAL] P: Andre Hedrick @@ -777,12 +789,19 @@ M: tigran@veritas.com S: Maintained +INTEL PRO/1000 GIGABIT ETHERNET SUPPORT +P: Chris Leech +M: christopher.leech@intel.com +P: Scott Feldman +M: scott.feldman@intel.com +S: Supported + INTERMEZZO FILE SYSTEM P: Peter J. Braam -M: braam@clusterfs.com -W: http://www.inter-mezzo.org/ -L: intermezzo-discuss@lists.sourceforge.net -S: Maintained +M: braam@clusterfs.com +W: http://www.inter-mezzo.org/ +L: intermezzo-discuss@lists.sourceforge.net +S: Maintained IP MASQUERADING: P: Juanjo Ciarlante @@ -796,11 +815,11 @@ S: Maintained IRDA SUBSYSTEM -P: Dag Brattli -M: Dag Brattli -L: linux-irda@pasta.cs.uit.no -W: http://irda.sourceforge.net/ -S: Maintained +P: Dag Brattli +M: Dag Brattli +L: linux-irda@pasta.cs.uit.no +W: http://irda.sourceforge.net/ +S: Maintained ISAPNP P: Jaroslav Kysela @@ -875,10 +894,10 @@ S: Maintained LANMEDIA WAN CARD DRIVER -P: Andrew Stanley-Jones -M: asj@lanmedia.com -W: http://www.lanmedia.com/ -S: Supported +P: Andrew Stanley-Jones +M: asj@lanmedia.com +W: http://www.lanmedia.com/ +S: Supported LAPB module P: Henner Eisen @@ -919,10 +938,10 @@ S: Maintained LOGICAL VOLUME MANAGER -P: Heinz Mauelshagen -L: linux-LVM@sistina.com -W: http://www.sistina.com/lvm -S: Maintained +P: Heinz Mauelshagen +L: linux-LVM@sistina.com +W: http://www.sistina.com/lvm +S: Maintained LSILOGIC/SYMBIOS/NCR 53C8XX and 53C1010 PCI-SCSI drivers P: Gerard Roudier @@ -969,10 +988,9 @@ S: Maintained MICROTEK X6 SCANNER -P: Oliver Neukum -M: drivers@neukum.org -W: http://fachschaft.cup.uni-muenchen.de/~neukum/scanner.html -S: Maintained +P: Oliver Neukum +M: drivers@neukum.org +S: Maintained MIPS P: Ralf Baechle @@ -1015,9 +1033,9 @@ S: Maintained NATSEMI ETHERNET DRIVER (DP8381x) -P: Tim Hockin -M: thockin@hockin.org -S: Maintained +P: Tim Hockin +M: thockin@hockin.org +S: Maintained NCP FILESYSTEM P: Petr Vandrovec @@ -1088,17 +1106,17 @@ S: Maintained NFS CLIENT -P: Trond Myklebust -M: trond.myklebust@fys.uio.no -L: linux-kernel@vger.kernel.org -S: Maintained +P: Trond Myklebust +M: trond.myklebust@fys.uio.no +L: linux-kernel@vger.kernel.org +S: Maintained NI5010 NETWORK DRIVER -P: Jan-Pascal van Best and Andreas Mohr -M: Jan-Pascal van Best -M: Andreas Mohr <100.30936@germany.net> -L: linux-net@vger.kernel.org -S: Maintained +P: Jan-Pascal van Best and Andreas Mohr +M: Jan-Pascal van Best +M: Andreas Mohr <100.30936@germany.net> +L: linux-net@vger.kernel.org +S: Maintained NINJA SCSI-3 / NINJA SCSI-32Bi PCMCIA SCSI HOST ADAPTER DRIVER P: YOKOTA Hiroshi @@ -1127,7 +1145,7 @@ OLYMPIC NETWORK DRIVER P: Peter De Shrijver -M: p2@ace.ulyssis.student.ac.be +M: p2@ace.ulyssis.student.kuleuven.ac.be P: Mike Phillips M: mikep@linuxtr.net L: linux-net@vger.kernel.org @@ -1170,9 +1188,9 @@ PERSONALITY HANDLING P: Christoph Hellwig -M: hch@caldera.de +M: hch@infradead.org L: linux-abi-devel@lists.sourceforge.net -S: Supported +S: Maintained PCI ID DATABASE P: Jens Maurer @@ -1261,6 +1279,12 @@ W: http://www.alarsen.net/linux/qnx4fs/ S: Maintained +RADEON FRAMEBUFFER DISPLAY DRIVER +P: Ani Joshi +M: ajoshi@shell.unixbox.com +L: linux-fbdev-devel@lists.sourceforge.net +S: Maintained + RAGE128 FRAMEBUFFER DISPLAY DRIVER P: Ani Joshi M: ajoshi@shell.unixbox.com @@ -1280,11 +1304,11 @@ S: Maintained REISERFS FILE SYSTEM -P: Hans Reiser -M: reiserfs-dev@namesys.com -L: reiserfs-list@namesys.com -W: http://www.namesys.com -S: Supported +P: Hans Reiser +M: reiserfs-dev@namesys.com +L: reiserfs-list@namesys.com +W: http://www.namesys.com +S: Supported ROSE NETWORK LAYER P: Jean-Paul Roubelat @@ -1470,7 +1494,7 @@ SYSV FILESYSTEM P: Christoph Hellwig -M: hch@caldera.de +M: hch@infradead.org S: Maintained TLAN NETWORK DRIVER @@ -1498,10 +1522,10 @@ S: Maintained TRIDENT 4DWAVE/SIS 7018 PCI AUDIO CORE -P: Ollie Lho -M: ollie@sis.com.tw +P: Ollie Lho +M: ollie@sis.com.tw L: linux-kernel@vger.kernel.org -S: Supported +S: Supported TMS380 TOKEN-RING NETWORK DRIVER P: Adam Fritzler @@ -1613,12 +1637,12 @@ S: Maintained USB OV511 DRIVER -P: Mark McClelland -M: mmcclell@bigfoot.com -L: linux-usb-users@lists.sourceforge.net -L: linux-usb-devel@lists.sourceforge.net -W: http://alpha.dyndns.org/ov511/ -S: Maintained +P: Mark McClelland +M: mmcclell@bigfoot.com +L: linux-usb-users@lists.sourceforge.net +L: linux-usb-devel@lists.sourceforge.net +W: http://alpha.dyndns.org/ov511/ +S: Maintained USB PEGASUS DRIVER P: Petko Manolov @@ -1734,11 +1758,11 @@ S: Maintained for 2.2 only WAN ROUTER & SANGOMA WANPIPE DRIVERS & API (X.25, FRAME RELAY, PPP, CISCO HDLC) -P: Nenad Corbic -M: ncorbic@sangoma.com -M: dm@sangoma.com -W: http://www.sangoma.com -S: Supported +P: Nenad Corbic +M: ncorbic@sangoma.com +M: dm@sangoma.com +W: http://www.sangoma.com +S: Supported WAVELAN NETWORK DRIVER & WIRELESS EXTENSIONS P: Jean Tourrilhes diff -Nru a/Makefile b/Makefile --- a/Makefile Tue Feb 26 11:57:57 2002 +++ b/Makefile Tue Feb 26 11:57:57 2002 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 5 -SUBLEVEL = 5 -EXTRAVERSION = +SUBLEVEL = 6 +EXTRAVERSION =-pre1 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -Nru a/arch/alpha/Makefile b/arch/alpha/Makefile --- a/arch/alpha/Makefile Tue Feb 26 11:57:56 2002 +++ b/arch/alpha/Makefile Tue Feb 26 11:57:56 2002 @@ -25,6 +25,11 @@ have_mcpu_ev67 := $(shell if $(CC) -mcpu=ev67 -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo y; else echo n; fi) +have_msmall_data := $(shell if $(CC) -msmall-data -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo y; else echo n; fi) +ifeq ($(have_msmall_data),y) + CFLAGS := $(CFLAGS) -msmall-data +endif + # Turn on the proper cpu optimizations. ifeq ($(have_mcpu),y) # If GENERIC, make sure to turn off any instruction set extensions that diff -Nru a/arch/alpha/kernel/core_titan.c b/arch/alpha/kernel/core_titan.c --- a/arch/alpha/kernel/core_titan.c Tue Feb 26 11:57:58 2002 +++ b/arch/alpha/kernel/core_titan.c Tue Feb 26 11:57:58 2002 @@ -279,7 +279,6 @@ titan_init_one_pachip_port(titan_pachip_port *port, int index) { struct pci_controller *hose; - unsigned long sg_size; hose = alloc_pci_controller(); if (index == 0) diff -Nru a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S --- a/arch/alpha/kernel/entry.S Tue Feb 26 11:57:56 2002 +++ b/arch/alpha/kernel/entry.S Tue Feb 26 11:57:56 2002 @@ -489,22 +489,22 @@ .prologue 0 bsr $1,do_switch_stack call_pal PAL_swpctx - unop - bsr $1,undo_switch_stack lda $8,0x3fff - mov $17,$0 + bsr $1,undo_switch_stack bic $30,$8,$8 ret $31,($26),1 .end alpha_switch_to +#ifdef CONFIG_SMP .globl ret_from_fork .align 3 .ent ret_from_fork ret_from_fork: lda $26,ret_from_sys_call - mov $0,$16 + mov $17,$16 jmp $31,schedule_tail .end ret_from_fork +#endif /* * Oh, well.. Disassembling OSF/1 binaries to find out how the diff -Nru a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c --- a/arch/alpha/kernel/process.c Tue Feb 26 11:57:58 2002 +++ b/arch/alpha/kernel/process.c Tue Feb 26 11:57:58 2002 @@ -283,6 +283,7 @@ unsigned long unused, struct task_struct * p, struct pt_regs * regs) { + extern void ret_from_sys_call(void); extern void ret_from_fork(void); struct thread_info *childti = p->thread_info; @@ -304,7 +305,11 @@ stack = ((struct switch_stack *) regs) - 1; childstack = ((struct switch_stack *) childregs) - 1; *childstack = *stack; +#ifdef CONFIG_SMP childstack->r26 = (unsigned long) ret_from_fork; +#else + childstack->r26 = (unsigned long) ret_from_sys_call; +#endif childti->pcb.usp = usp; childti->pcb.ksp = (unsigned long) childstack; childti->pcb.flags = 1; /* set FEN, clear everything else */ diff -Nru a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h --- a/arch/alpha/kernel/proto.h Tue Feb 26 11:57:57 2002 +++ b/arch/alpha/kernel/proto.h Tue Feb 26 11:57:57 2002 @@ -162,9 +162,9 @@ unsigned char extra; } __mcheck_info; -#define mcheck_expected(cpu) (__mcheck_info.expected) -#define mcheck_taken(cpu) (__mcheck_info.taken) -#define mcheck_extra(cpu) (__mcheck_info.extra) +#define mcheck_expected(cpu) ((void)(cpu), __mcheck_info.expected) +#define mcheck_taken(cpu) ((void)(cpu), __mcheck_info.taken) +#define mcheck_extra(cpu) ((void)(cpu), __mcheck_info.extra) #endif #define DEBUG_MCHECK 0 /* 0 = minimal, 1 = debug, 2 = debug+dump. */ diff -Nru a/arch/alpha/kernel/sys_titan.c b/arch/alpha/kernel/sys_titan.c --- a/arch/alpha/kernel/sys_titan.c Tue Feb 26 11:58:00 2002 +++ b/arch/alpha/kernel/sys_titan.c Tue Feb 26 11:58:00 2002 @@ -84,8 +84,8 @@ *dim3; #else volatile unsigned long *dimB; - if (bcpu == 0) dimB = &cchip->dim0.csr; - else if (bcpu == 1) dimB = &cchip->dim1.csr; + dimB = &cchip->dim0.csr; + if (bcpu == 1) dimB = &cchip->dim1.csr; else if (bcpu == 2) dimB = &cchip->dim2.csr; else if (bcpu == 3) dimB = &cchip->dim3.csr; @@ -190,9 +190,6 @@ static void __init privateer_init_irq(void) { - extern asmlinkage void entInt(void); - int cpu; - outb(0, DMA1_RESET_REG); outb(0, DMA2_RESET_REG); outb(DMA_MODE_CASCADE, DMA2_MODE_REG); diff -Nru a/arch/arm/Config.help b/arch/arm/Config.help --- a/arch/arm/Config.help Tue Feb 26 11:57:56 2002 +++ b/arch/arm/Config.help Tue Feb 26 11:57:56 2002 @@ -116,6 +116,16 @@ information about which PCI hardware does work under Linux and which doesn't. +CONFIG_PREEMPT + This option reduces the latency of the kernel when reacting to + real-time or interactive events by allowing a low priority process to + be preempted even if it is in kernel mode executing a system call. + This allows applications to run more reliably even when the system is + under load. + + Say Y here if you are building a kernel for a desktop, embedded + or real-time system. Say N if you are unsure. + CONFIG_MCA MicroChannel Architecture is found in some IBM PS/2 machines and laptops. It is a bus system similar to PCI or ISA. See @@ -521,6 +531,10 @@ Saying N will reduce the size of the Footbridge kernel. +CONFIG_ARCH_IQ80310 + Say Y here if you want to run your kernel on the Intel IQ80310 + evaluation kit for the IOP310 chipset. + CONFIG_ARCH_L7200 Say Y here if you intend to run this kernel on a LinkUp Systems L7200 Software Development Board which uses an ARM720T processor. @@ -558,6 +572,13 @@ If you have any questions or comments about the Compaq Personal Server, send e-mail to skiff@crl.dec.com. +CONFIG_PLD_HOTSWAP + This enables support for the dynamic loading and configuration of + compatible drivers when the contents of the PLD are changed. This + is still experimental and requires configuration tools which are + not yet generally available. Say N here. You must enable the kernel + module loader for this feature to work. + CONFIG_SA1100_ASSABET Say Y here if you are using the Intel(R) StrongARM(R) SA-1110 Microprocessor Development Board (also known as the Assabet). @@ -567,28 +588,14 @@ Microprocessor Development Board (Assabet) with the SA-1111 Development Board (Nepon). -CONFIG_SA1100_H3600 - Say Y here if you intend to run this kernel on the Compaq iPAQ - H3600 handheld computer. Information about this machine and the - Linux port to this machine can be found at: - - - +CONFIG_SA1100_BADGE4 + Say Y here if you want to build a kernel for the HP Laboratories + BadgePAD 4. CONFIG_SA1100_BRUTUS Say Y here if you are using the Intel(R) StrongARM(R) SA-1100 Microprocessor Development Board (also known as the Brutus). -CONFIG_SA1100_LART - Say Y here if you are using the Linux Advanced Radio Terminal - (also known as the LART). See for - information on the LART. - -CONFIG_SA1100_GRAPHICSCLIENT - Say Y here if you are using an Applied Data Systems Intel(R) - StrongARM(R) SA-1100 based Graphics Client SBC. See - for information on this system. - CONFIG_SA1100_CERF The Intrinsyc CerfBoard is based on the StrongARM 1110. More information is available at: @@ -602,6 +609,24 @@ handheld instruments. Information about this machine can be found at: . +CONFIG_SA1100_GRAPHICSCLIENT + Say Y here if you are using an Applied Data Systems Intel(R) + StrongARM(R) SA-1100 based Graphics Client SBC. See + for information on this system. + +CONFIG_SA1100_H3600 + Say Y here if you intend to run this kernel on the Compaq iPAQ + H3600 handheld computer. Information about this machine and the + Linux port to this machine can be found at: + + + + +CONFIG_SA1100_LART + Say Y here if you are using the Linux Advanced Radio Terminal + (also known as the LART). See for + information on the LART. + CONFIG_SA1100_NANOENGINE The nanoEngine is a StrongARM 1110-based single board computer from Bright Star Engineering. More information is available at: @@ -619,6 +644,19 @@ Say Y if configuring for a Pangolin. Say N otherwise. +CONFIG_SA1100_PFS168 + The Radisys Corp. PFS-168 (aka Tulsa) is an Intel® StrongArm® SA-1110 based + computer which includes the SA-1111 Microprocessor Companion Chip and other + custom I/O designed to add connectivity and multimedia features for vending + and business machine applications. Say Y here if you require support for + this target. + +CONFIG_SA1100_SHANNON + The Shannon (also known as a Tuxscreen, and also as a IS2630) was a + limited edition webphone produced by Philips. The Shannon is a SA1100 + platform with a 640x480 LCD, touchscreen, CIR keyboard, PCMCIA slots, + and a telco interface. + CONFIG_SA1100_VICTOR Say Y here if you are using a Visu Aide Intel(R) StrongARM(R) SA-1100 based Victor Digital Talking Book Reader. See @@ -656,6 +694,31 @@ Say Y if you want support for the ARM920T processor. Otherwise, say N. +CONFIG_CPU_ARM922T + The ARM922T is a version of the ARM920T, but with smaller + instruction and data caches. It is used in Altera's + Excalibur XA device family. + + Say Y if you want support for the ARM922T processor. + Otherwise, say N. + +CONFIG_CPU_ARM922_CPU_IDLE + Saying Y here will allow the processor to enter a low power + mode whilst waiting for an interrupt in idle. If you're unsure + say Y. + +CONFIG_CPU_ARM922_I_CACHE_ON + Say Y here to enable the processor instruction cache. Unless + you have a reason not to, say Y. + +CONFIG_CPU_ARM922_D_CACHE_ON + Say Y here to enable the processor data cache. Unless + you have a reason not to, say Y. + +CONFIG_CPU_ARM922_WRITETHROUGH + Say Y here to use the data cache in writethough mode. Unless you + specifically require this, say N. + CONFIG_CPU_ARM1020 The ARM1020 is the cached version of the ARM10 processor, with an addition of a floating-point unit. @@ -688,16 +751,14 @@ CONFIG_FPE_FASTFPE Say Y here to include the FAST floating point emulator in the kernel. - This is an experimental much faster emulator which has only 32 bit + This is an experimental much faster emulator which now also has full precision for the mantissa. It does not support any exceptions. - This makes it very simple, it is approximately 4-8 times faster than - NWFPE. + It is very simple, and approximately 3-6 times faster than NWFPE. - It should be sufficient for most programs. It is definitely not - suitable if you do scientific calculations that need double - precision for iteration formulas that sum up lots of very small - numbers. If you do not feel you need a faster FP emulation you - should better choose NWFPE. + It should be sufficient for most programs. It may be not suitable + for scientific calculations, but you have to check this for yourself. + If you do not feel you need a faster FP emulation you should better + choose NWFPE. It is also possible to say M to build the emulator as a module (fastfpe.o). But keep in mind that you should only load the FP diff -Nru a/arch/arm/boot/compressed/ofw-shark.c b/arch/arm/boot/compressed/ofw-shark.c --- a/arch/arm/boot/compressed/ofw-shark.c Tue Feb 26 11:57:59 2002 +++ b/arch/arm/boot/compressed/ofw-shark.c Tue Feb 26 11:57:59 2002 @@ -19,7 +19,7 @@ asmlinkage void create_params (unsigned long *buffer) { - /* Is there a better address? Also change in mach-shark/arch.c */ + /* Is there a better address? Also change in mach-shark/core.c */ struct tag *tag = (struct tag *) 0x08003000; int j,i,m,k,nr_banks,size; unsigned char *c; diff -Nru a/arch/arm/config.in b/arch/arm/config.in --- a/arch/arm/config.in Tue Feb 26 11:57:57 2002 +++ b/arch/arm/config.in Tue Feb 26 11:57:57 2002 @@ -464,6 +464,7 @@ tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC bool 'Power Management support' CONFIG_PM +dep_bool 'Preemptible Kernel (experimental)' CONFIG_PREEMPT $CONFIG_CPU_32 $CONFIG_EXPERIMENTAL dep_tristate 'Advanced Power Management Emulation' CONFIG_APM $CONFIG_PM dep_tristate 'RISC OS personality' CONFIG_ARTHUR $CONFIG_CPU_32 diff -Nru a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c --- a/arch/arm/kernel/armksyms.c Tue Feb 26 11:57:58 2002 +++ b/arch/arm/kernel/armksyms.c Tue Feb 26 11:57:58 2002 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -273,3 +274,7 @@ EXPORT_SYMBOL_NOVERS(__up_wakeup); EXPORT_SYMBOL(get_wchan); + +#ifdef CONFIG_PREEMPT +EXPORT_SYMBOL(kernel_flag); +#endif diff -Nru a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S --- a/arch/arm/kernel/calls.S Tue Feb 26 11:57:59 2002 +++ b/arch/arm/kernel/calls.S Tue Feb 26 11:57:59 2002 @@ -21,13 +21,13 @@ .long SYMBOL_NAME(sys_write) /* 5 */ .long SYMBOL_NAME(sys_open) .long SYMBOL_NAME(sys_close) - .long SYMBOL_NAME(sys_waitpid) + .long SYMBOL_NAME(sys_ni_syscall) /* was sys_waitpid */ .long SYMBOL_NAME(sys_creat) .long SYMBOL_NAME(sys_link) /* 10 */ .long SYMBOL_NAME(sys_unlink) .long SYMBOL_NAME(sys_execve_wrapper) .long SYMBOL_NAME(sys_chdir) - .long SYMBOL_NAME(sys_time) + .long SYMBOL_NAME(sys_time) /* used by libc4 */ .long SYMBOL_NAME(sys_mknod) /* 15 */ .long SYMBOL_NAME(sys_chmod) .long SYMBOL_NAME(sys_lchown16) @@ -36,15 +36,15 @@ .long SYMBOL_NAME(sys_lseek) /* 20 */ .long SYMBOL_NAME(sys_getpid) .long SYMBOL_NAME(sys_mount) - .long SYMBOL_NAME(sys_oldumount) + .long SYMBOL_NAME(sys_oldumount) /* used by libc4 */ .long SYMBOL_NAME(sys_setuid16) .long SYMBOL_NAME(sys_getuid16) /* 25 */ .long SYMBOL_NAME(sys_stime) .long SYMBOL_NAME(sys_ptrace) - .long SYMBOL_NAME(sys_alarm) + .long SYMBOL_NAME(sys_alarm) /* used by libc4 */ .long SYMBOL_NAME(sys_ni_syscall) /* was sys_fstat */ .long SYMBOL_NAME(sys_pause) -/* 30 */ .long SYMBOL_NAME(sys_utime) +/* 30 */ .long SYMBOL_NAME(sys_utime) /* used by libc4 */ .long SYMBOL_NAME(sys_ni_syscall) /* was sys_stty */ .long SYMBOL_NAME(sys_ni_syscall) /* was sys_getty */ .long SYMBOL_NAME(sys_access) @@ -62,7 +62,7 @@ /* 45 */ .long SYMBOL_NAME(sys_brk) .long SYMBOL_NAME(sys_setgid16) .long SYMBOL_NAME(sys_getgid16) - .long SYMBOL_NAME(sys_signal) + .long SYMBOL_NAME(sys_ni_syscall) /* was sys_signal */ .long SYMBOL_NAME(sys_geteuid16) /* 50 */ .long SYMBOL_NAME(sys_getegid16) .long SYMBOL_NAME(sys_acct) @@ -82,29 +82,29 @@ /* 65 */ .long SYMBOL_NAME(sys_getpgrp) .long SYMBOL_NAME(sys_setsid) .long SYMBOL_NAME(sys_sigaction) - .long SYMBOL_NAME(sys_sgetmask) - .long SYMBOL_NAME(sys_ssetmask) + .long SYMBOL_NAME(sys_ni_syscall) /* was sys_sgetmask */ + .long SYMBOL_NAME(sys_ni_syscall) /* was sys_ssetmask */ /* 70 */ .long SYMBOL_NAME(sys_setreuid16) .long SYMBOL_NAME(sys_setregid16) .long SYMBOL_NAME(sys_sigsuspend_wrapper) .long SYMBOL_NAME(sys_sigpending) .long SYMBOL_NAME(sys_sethostname) /* 75 */ .long SYMBOL_NAME(sys_setrlimit) - .long SYMBOL_NAME(sys_old_getrlimit) + .long SYMBOL_NAME(sys_old_getrlimit) /* used by libc4 */ .long SYMBOL_NAME(sys_getrusage) .long SYMBOL_NAME(sys_gettimeofday) .long SYMBOL_NAME(sys_settimeofday) /* 80 */ .long SYMBOL_NAME(sys_getgroups16) .long SYMBOL_NAME(sys_setgroups16) - .long SYMBOL_NAME(old_select) + .long SYMBOL_NAME(old_select) /* used by libc4 */ .long SYMBOL_NAME(sys_symlink) .long SYMBOL_NAME(sys_ni_syscall) /* was sys_lstat */ /* 85 */ .long SYMBOL_NAME(sys_readlink) .long SYMBOL_NAME(sys_uselib) .long SYMBOL_NAME(sys_swapon) .long SYMBOL_NAME(sys_reboot) - .long SYMBOL_NAME(old_readdir) -/* 90 */ .long SYMBOL_NAME(old_mmap) + .long SYMBOL_NAME(old_readdir) /* used by libc4 */ +/* 90 */ .long SYMBOL_NAME(old_mmap) /* used by libc4 */ .long SYMBOL_NAME(sys_munmap) .long SYMBOL_NAME(sys_truncate) .long SYMBOL_NAME(sys_ftruncate) @@ -236,7 +236,22 @@ .long SYMBOL_NAME(sys_mincore) /* 220 */ .long SYMBOL_NAME(sys_madvise) .long SYMBOL_NAME(sys_fcntl64) + .long SYMBOL_NAME(sys_ni_syscall) /* TUX */ + .long SYMBOL_NAME(sys_ni_syscall) /* Security */ .long SYMBOL_NAME(sys_gettid) +/* 225 */ .long SYMBOL_NAME(sys_readahead) + .long SYMBOL_NAME(sys_setxattr) + .long SYMBOL_NAME(sys_lsetxattr) + .long SYMBOL_NAME(sys_fsetxattr) + .long SYMBOL_NAME(sys_getxattr) +/* 230 */ .long SYMBOL_NAME(sys_lgetxattr) + .long SYMBOL_NAME(sys_fgetxattr) + .long SYMBOL_NAME(sys_listxattr) + .long SYMBOL_NAME(sys_llistxattr) + .long SYMBOL_NAME(sys_flistxattr) +/* 235 */ .long SYMBOL_NAME(sys_removexattr) + .long SYMBOL_NAME(sys_lremovexattr) + .long SYMBOL_NAME(sys_fremovexattr) .long SYMBOL_NAME(sys_tkill) __syscall_end: diff -Nru a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S --- a/arch/arm/kernel/entry-armv.S Tue Feb 26 11:57:58 2002 +++ b/arch/arm/kernel/entry-armv.S Tue Feb 26 11:57:58 2002 @@ -15,6 +15,7 @@ */ #include #include "entry-header.S" +#include #ifdef IOC_BASE @@ -690,8 +691,7 @@ msr cpsr_c, r9 mov r2, sp bl SYMBOL_NAME(do_DataAbort) - mov r0, #PSR_I_BIT | MODE_SVC - msr cpsr_c, r0 + set_cpsr_c r0, #PSR_I_BIT | MODE_SVC ldr r0, [sp, #S_PSR] msr spsr, r0 ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr @@ -705,17 +705,50 @@ add r4, sp, #S_SP mov r6, lr stmia r4, {r5, r6, r7, r8, r9} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro +#ifdef CONFIG_PREEMPT + get_thread_info r8 + ldr r9, [r8, #TI_PREEMPT] @ get preempt count + add r7, r9, #1 @ increment it + str r7, [r8, #TI_PREEMPT] +#endif 1: get_irqnr_and_base r0, r6, r5, lr movne r1, sp @ @ routine called with r0 = irq number, r1 = struct pt_regs * @ adrsvc ne, lr, 1b - bne do_IRQ + bne asm_do_IRQ +#ifdef CONFIG_PREEMPT + ldr r0, [r8, #TI_FLAGS] @ get flags + tst r0, #_TIF_NEED_RESCHED + ldrne r6, .LCirq_stat + blne svc_preempt +preempt_return: + ldr r0, [r8, #TI_PREEMPT] @ read preempt value + teq r0, r7 + strne r0, [r0, -r0] @ bug() + str r9, [r8, #TI_PREEMPT] @ restore preempt count +#endif ldr r0, [sp, #S_PSR] @ irqs are already disabled msr spsr, r0 ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr +#ifdef CONFIG_PREEMPT +svc_preempt: teq r9, #0 + movne pc, lr + ldr r0, [r6, #4] @ local_irq_count + ldr r1, [r6, #8] @ local_b_count + adds r0, r0, r1 + movne pc, lr +1: set_cpsr_c r0, #MODE_SVC @ enable IRQs + bl SYMBOL_NAME(preempt_schedule) + set_cpsr_c r0, #PSR_I_BIT | MODE_SVC @ disable IRQs + ldr r0, [r8, #TI_FLAGS] + tst r0, #_TIF_NEED_RESCHED + bne 1b + b preempt_return +#endif + .align 5 __und_svc: sub sp, sp, #S_FRAME_SIZE stmia sp, {r0 - r12} @ save r0 - r12 @@ -733,8 +766,7 @@ mov r1, sp @ struct pt_regs *regs bl SYMBOL_NAME(do_undefinstr) -1: mov r0, #PSR_I_BIT | MODE_SVC - msr cpsr_c, r0 +1: set_cpsr_c r0, #PSR_I_BIT | MODE_SVC ldr lr, [sp, #S_PSR] @ Get SVC cpsr msr spsr, lr ldmia sp, {r0 - pc}^ @ Restore SVC registers @@ -755,8 +787,7 @@ mov r0, r2 @ address (pc) mov r1, sp @ regs bl SYMBOL_NAME(do_PrefetchAbort) @ call abort handler - mov r0, #PSR_I_BIT | MODE_SVC - msr cpsr_c, r0 + set_cpsr_c r0, #PSR_I_BIT | MODE_SVC ldr r0, [sp, #S_PSR] msr spsr, r0 ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr @@ -769,6 +800,9 @@ .LCprocfns: .word SYMBOL_NAME(processor) #endif .LCfp: .word SYMBOL_NAME(fp_enter) +#ifdef CONFIG_PREEMPT +.LCirq_stat: .word SYMBOL_NAME(irq_stat) +#endif irq_prio_table @@ -793,8 +827,7 @@ #else bl cpu_data_abort #endif - mov r2, #MODE_SVC - msr cpsr_c, r2 @ Enable interrupts + set_cpsr_c r2, #MODE_SVC @ Enable interrupts mov r2, sp adrsvc al, lr, ret_from_exception b SYMBOL_NAME(do_DataAbort) @@ -809,15 +842,29 @@ stmdb r8, {sp, lr}^ alignment_trap r4, r7, __temp_irq zero_fp +#ifdef CONFIG_PREEMPT + get_thread_info r8 + ldr r9, [r8, #TI_PREEMPT] @ get preempt count + add r7, r9, #1 @ increment it + str r7, [r8, #TI_PREEMPT] +#endif 1: get_irqnr_and_base r0, r6, r5, lr movne r1, sp adrsvc ne, lr, 1b @ @ routine called with r0 = irq number, r1 = struct pt_regs * @ - bne do_IRQ + bne asm_do_IRQ +#ifdef CONFIG_PREEMPT + ldr r0, [r8, #TI_PREEMPT] + teq r0, r7 + strne r0, [r0, -r0] + str r9, [r8, #TI_PREEMPT] + mov tsk, r8 +#else + get_thread_info tsk +#endif mov why, #0 - get_current_task tsk b ret_to_user .align 5 @@ -833,15 +880,15 @@ adrsvc al, r9, ret_from_exception @ r9 = normal FP return adrsvc al, lr, fpundefinstr @ lr = undefined instr return -call_fpe: get_current_task r10 +call_fpe: get_thread_info r10 @ get current thread + ldr r4, [r10, #TI_TASK] @ get current task mov r8, #1 - strb r8, [r10, #TSK_USED_MATH] @ set current->used_math + strb r8, [r4, #TSK_USED_MATH] @ set current->used_math ldr r4, .LCfp - add r10, r10, #TSS_FPESAVE @ r10 = workspace + add r10, r10, #TI_FPSTATE @ r10 = workspace ldr pc, [r4] @ Call FP module USR entry point -fpundefinstr: mov r0, #MODE_SVC - msr cpsr_c, r0 @ Enable interrupts +fpundefinstr: set_cpsr_c r0, #MODE_SVC @ Enable interrupts mov r0, lr mov r1, sp adrsvc al, lr, ret_from_exception @@ -857,8 +904,7 @@ stmdb r8, {sp, lr}^ @ Save sp_usr lr_usr alignment_trap r4, r7, __temp_abt zero_fp - mov r0, #MODE_SVC - msr cpsr_c, r0 @ Enable interrupts + set_cpsr_c r0, #MODE_SVC @ Enable interrupts mov r0, r5 @ address (pc) mov r1, sp @ regs bl SYMBOL_NAME(do_PrefetchAbort) @ call abort handler @@ -867,7 +913,7 @@ * This is the return code to user mode for abort handlers */ ENTRY(ret_from_exception) - get_current_task tsk + get_thread_info tsk mov why, #0 b ret_to_user @@ -877,16 +923,16 @@ .text /* * Register switch for ARMv3 and ARMv4 processors - * r0 = previous, r1 = next, return previous. + * r0 = previous thread_info, r1 = next thread_info, return previous. * previous and next are guaranteed not to be the same. */ ENTRY(__switch_to) stmfd sp!, {r4 - sl, fp, lr} @ Store most regs on stack mrs ip, cpsr str ip, [sp, #-4]! @ Save cpsr_SVC - str sp, [r0, #TSS_SAVE] @ Save sp_SVC - ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC - ldr r2, [r1, #TSS_DOMAIN] + str sp, [r0, #TI_CPU_SAVE] @ Save sp_SVC + ldr sp, [r1, #TI_CPU_SAVE] @ Get saved sp_SVC + ldr r2, [r1, #TI_CPU_DOMAIN] ldr ip, [sp], #4 mcr p15, 0, r2, c3, c0 @ Set domain register msr spsr, ip @ Save tasks CPSR into SPSR for this return diff -Nru a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S --- a/arch/arm/kernel/entry-common.S Tue Feb 26 11:57:56 2002 +++ b/arch/arm/kernel/entry-common.S Tue Feb 26 11:57:56 2002 @@ -9,6 +9,7 @@ */ #include #include "entry-header.S" +#include /* * We rely on the fact that R0 is at the bottom of the stack (due to @@ -34,39 +35,42 @@ * stack. */ ret_fast_syscall: -#error ldr r1, [tsk, #TSK_NEED_RESCHED] -#error ldr r2, [tsk, #TSK_SIGPENDING] - teq r1, #0 @ need_resched || sigpending - teqeq r2, #0 - bne slow + set_cpsr_c r1, #PSR_I_BIT | MODE_SVC @ disable interrupts + ldr r1, [tsk, #TI_FLAGS] + tst r1, #_TIF_WORK_MASK + bne ret_fast_work fast_restore_user_regs /* * Ok, we need to do extra processing, enter the slow path. */ -slow: str r0, [sp, #S_R0+S_OFF]! @ returned r0 - b 1f +ret_fast_work: + str r0, [sp, #S_R0+S_OFF]! @ returned r0 + b work_pending +work_resched: + bl SYMBOL_NAME(schedule) /* * "slow" syscall return path. "why" tells us if this was a real syscall. */ -reschedule: - bl SYMBOL_NAME(schedule) ENTRY(ret_to_user) ret_slow_syscall: -#error ldr r1, [tsk, #TSK_NEED_RESCHED] -#error ldr r2, [tsk, #TSK_SIGPENDING] -1: teq r1, #0 @ need_resched => schedule() - bne reschedule - teq r2, #0 @ sigpending => do_signal() - blne __do_signal + set_cpsr_c r1, #PSR_I_BIT | MODE_SVC + ldr r1, [tsk, #TI_FLAGS] + tst r1, #_TIF_WORK_MASK + beq no_work_pending +work_pending: + tst r1, #_TIF_NEED_RESCHED + bne work_resched + tst r1, #_TIF_NOTIFY_RESUME | _TIF_SIGPENDING + blne __do_notify_resume +no_work_pending: restore_user_regs -__do_signal: - mov r0, #0 @ NULL 'oldset' - mov r1, sp @ 'regs' +__do_notify_resume: + mov r0, sp @ 'regs' mov r2, why @ 'syscall' -#error b SYMBOL_NAME(do_signal) @ note the bl above sets lr + b SYMBOL_NAME(do_notify_resume) @ note the bl above sets lr /* * This is how we return from a fork. __switch_to will be calling us @@ -75,14 +79,14 @@ */ ENTRY(ret_from_fork) bl SYMBOL_NAME(schedule_tail) - get_current_task tsk - ldr ip, [tsk, #TSK_PTRACE] @ check for syscall tracing + get_thread_info tsk + ldr ip, [tsk, #TI_FLAGS] @ check for syscall tracing mov why, #1 - tst ip, #PT_TRACESYS @ are we tracing syscalls? + tst ip, #_TIF_SYSCALL_TRACE @ are we tracing syscalls? beq ret_slow_syscall mov r1, sp mov r0, #1 @ trace exit [IP = 1] -#error bl SYMBOL_NAME(syscall_trace) + bl SYMBOL_NAME(syscall_trace) b ret_slow_syscall @@ -134,12 +138,12 @@ str r4, [sp, #-S_OFF]! @ push fifth arg - get_current_task tsk - ldr ip, [tsk, #TSK_PTRACE] @ check for syscall tracing + get_thread_info tsk + ldr ip, [tsk, #TI_FLAGS] @ check for syscall tracing bic scno, scno, #0xff000000 @ mask off SWI op-code eor scno, scno, #OS_NUMBER << 20 @ check OS number adr tbl, sys_call_table @ load syscall table pointer - tst ip, #PT_TRACESYS @ are we tracing syscalls? + tst ip, #_TIF_SYSCALL_TRACE @ are we tracing syscalls? bne __sys_trace adrsvc al, lr, ret_fast_syscall @ return address @@ -160,7 +164,7 @@ __sys_trace: add r1, sp, #S_OFF mov r0, #0 @ trace entry [IP = 0] -#error bl SYMBOL_NAME(syscall_trace) + bl SYMBOL_NAME(syscall_trace) adrsvc al, lr, __sys_trace_return @ return address add r1, sp, #S_R0 + S_OFF @ pointer to regs @@ -173,7 +177,7 @@ str r0, [sp, #S_R0 + S_OFF]! @ save returned r0 mov r1, sp mov r0, #1 @ trace exit [IP = 1] -#error bl SYMBOL_NAME(syscall_trace) + bl SYMBOL_NAME(syscall_trace) b ret_slow_syscall .align 5 diff -Nru a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S --- a/arch/arm/kernel/entry-header.S Tue Feb 26 11:57:59 2002 +++ b/arch/arm/kernel/entry-header.S Tue Feb 26 11:57:59 2002 @@ -113,7 +113,7 @@ msr cpsr_c, \temp .endm - .macro get_current_task, rd + .macro get_thread_info, rd mov \rd, sp, lsr #13 mov \rd, \rd, lsl #13 .endm @@ -171,7 +171,7 @@ .macro initialise_traps_extra .endm - .macro get_current_task, rd + .macro get_thread_info, rd mov \rd, sp, lsr #13 mov \rd, \rd, lsl #13 .endm @@ -197,10 +197,10 @@ * * We must set at least "tsk" and "why" when calling ret_with_reschedule. */ -scno .req r7 @ syscall number -tbl .req r8 @ syscall table pointer -why .req r8 @ Linux syscall (!= 0) -tsk .req r9 @ current task +scno .req r7 @ syscall number +tbl .req r8 @ syscall table pointer +why .req r8 @ Linux syscall (!= 0) +tsk .req r9 @ current thread_info /* * Get the system call number. @@ -214,6 +214,15 @@ #else mask_pc lr, lr ldr scno, [lr, #-4] @ get SWI instruction +#endif + .endm + + .macro set_cpsr_c, reg, mode +#if 1 + mov \reg, \mode + msr cpsr_c, \reg +#else + msr cpsr_c, \mode #endif .endm diff -Nru a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S --- a/arch/arm/kernel/head.S Tue Feb 26 11:57:56 2002 +++ b/arch/arm/kernel/head.S Tue Feb 26 11:57:56 2002 @@ -149,7 +149,7 @@ .long SYMBOL_NAME(processor_id) .long SYMBOL_NAME(__machine_arch_type) .long SYMBOL_NAME(cr_alignment) - .long SYMBOL_NAME(init_task_union)+8192 + .long SYMBOL_NAME(init_thread_union)+8192 .type __ret, %function __ret: ldr lr, __switch_data diff -Nru a/arch/arm/kernel/init_task.c b/arch/arm/kernel/init_task.c --- a/arch/arm/kernel/init_task.c Tue Feb 26 11:58:00 2002 +++ b/arch/arm/kernel/init_task.c Tue Feb 26 11:58:00 2002 @@ -16,7 +16,7 @@ struct mm_struct init_mm = INIT_MM(init_mm); /* - * Initial task structure. + * Initial thread structure. * * We need to make sure that this is 8192-byte aligned due to the * way process stacks are handled. This is done by making sure @@ -25,5 +25,13 @@ * * The things we do for performance.. */ -union task_union init_task_union __attribute__((__section__(".init.task"))) = - { INIT_TASK(init_task_union.task) }; +union thread_union init_thread_union + __attribute__((__section__(".init.task"))) = + { INIT_THREAD_INFO(init_task) }; + +/* + * Initial task structure. + * + * All other task structs will be allocated on slabs in fork.c + */ +struct task_struct init_task = INIT_TASK(init_task); diff -Nru a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c --- a/arch/arm/kernel/process.c Tue Feb 26 11:57:58 2002 +++ b/arch/arm/kernel/process.c Tue Feb 26 11:57:58 2002 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,7 @@ #include #include #include +#include #include /* @@ -83,9 +85,7 @@ void cpu_idle(void) { /* endless idle loop with no priority at all */ - init_idle(); - current->nice = 20; - + preempt_disable(); while (1) { void (*idle)(void) = pm_idle; if (!idle) @@ -228,51 +228,61 @@ /* * Task structure and kernel stack allocation. */ -static struct task_struct *task_struct_head; -static unsigned int nr_task_struct; +static unsigned long *thread_info_head; +static unsigned int nr_thread_info; #ifdef CONFIG_CPU_32 #define EXTRA_TASK_STRUCT 4 +#define ll_alloc_task_struct() ((struct thread_info *) __get_free_pages(GFP_KERNEL,1)) +#define ll_free_task_struct(p) free_pages((unsigned long)(p),1) #else +extern unsigned long get_page_8k(int priority); +extern void free_page_8k(unsigned long page); + #define EXTRA_TASK_STRUCT 0 +#define ll_alloc_task_struct() ((struct task_struct *)get_page_8k(GFP_KERNEL)) +#define ll_free_task_struct(p) free_page_8k((unsigned long)(p)) #endif -struct task_struct *alloc_task_struct(void) +struct thread_info *alloc_thread_info(void) { - struct task_struct *tsk; + struct thread_info *thread = NULL; - if (EXTRA_TASK_STRUCT) - tsk = task_struct_head; - else - tsk = NULL; - - if (tsk) { - task_struct_head = tsk->next_task; - nr_task_struct -= 1; - } else - tsk = ll_alloc_task_struct(); + if (EXTRA_TASK_STRUCT) { + unsigned long *p = thread_info_head; + + if (p) { + thread_info_head = (unsigned long *)p[0]; + nr_thread_info -= 1; + } + thread = (struct thread_info *)p; + } + + if (!thread) + thread = ll_alloc_task_struct(); #ifdef CONFIG_SYSRQ /* * The stack must be cleared if you want SYSRQ-T to * give sensible stack usage information */ - if (tsk) { - char *p = (char *)tsk; + if (thread) { + char *p = (char *)thread; memzero(p+KERNEL_STACK_SIZE, KERNEL_STACK_SIZE); } #endif - return tsk; + return thread; } -void __free_task_struct(struct task_struct *p) +void free_thread_info(struct thread_info *thread) { - if (EXTRA_TASK_STRUCT && nr_task_struct < EXTRA_TASK_STRUCT) { - p->next_task = task_struct_head; - task_struct_head = p; - nr_task_struct += 1; + if (EXTRA_TASK_STRUCT && nr_thread_info < EXTRA_TASK_STRUCT) { + unsigned long *p = (unsigned long *)thread; + p[0] = (unsigned long)thread_info_head; + thread_info_head = p; + nr_thread_info += 1; } else - ll_free_task_struct(p); + ll_free_task_struct(thread); } /* @@ -284,10 +294,13 @@ void flush_thread(void) { - memset(¤t->thread.debug, 0, sizeof(struct debug_info)); - memset(¤t->thread.fpstate, 0, sizeof(union fp_state)); + struct thread_info *thread = current_thread_info(); + struct task_struct *tsk = current; + + memset(&tsk->thread.debug, 0, sizeof(struct debug_info)); + memset(&thread->fpstate, 0, sizeof(union fp_state)); + current->used_math = 0; - current->flags &= ~PF_USEDFPU; } void release_thread(struct task_struct *dead_task) @@ -300,21 +313,19 @@ unsigned long unused, struct task_struct * p, struct pt_regs * regs) { - struct pt_regs * childregs; - struct context_save_struct * save; - - atomic_set(&p->thread.refcount, 1); + struct pt_regs *childregs; + struct cpu_context_save *save; - childregs = ((struct pt_regs *)((unsigned long)p + 8192)) - 1; + childregs = ((struct pt_regs *)((unsigned long)p->thread_info + THREAD_SIZE)) - 1; *childregs = *regs; childregs->ARM_r0 = 0; childregs->ARM_sp = esp; - save = ((struct context_save_struct *)(childregs)) - 1; + save = ((struct cpu_context_save *)(childregs)) - 1; *save = INIT_CSS; save->pc |= (unsigned long)ret_from_fork; - p->thread.save = save; + p->thread_info->cpu_context = save; return 0; } @@ -324,10 +335,13 @@ */ int dump_fpu (struct pt_regs *regs, struct user_fp *fp) { - if (current->used_math) - memcpy(fp, ¤t->thread.fpstate.soft, sizeof (*fp)); + struct thread_info *thread = current_thread_info(); + int used_math = current->used_math; + + if (used_math) + memcpy(fp, &thread->fpstate.soft, sizeof (*fp)); - return current->used_math; + return used_math; } /* @@ -405,7 +419,7 @@ return 0; stack_page = 4096 + (unsigned long)p; - fp = get_css_fp(&p->thread); + fp = thread_saved_fp(p); do { if (fp < stack_page || fp > 4092+stack_page) return 0; diff -Nru a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c --- a/arch/arm/kernel/ptrace.c Tue Feb 26 11:57:57 2002 +++ b/arch/arm/kernel/ptrace.c Tue Feb 26 11:57:57 2002 @@ -9,6 +9,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include #include #include #include @@ -72,7 +73,7 @@ newregs = *regs; newregs.uregs[offset] = data; - + if (valid_user_regs(&newregs)) { regs->uregs[offset] = data; ret = 0; @@ -455,9 +456,9 @@ if ((unsigned long) data > _NSIG) break; if (request == PTRACE_SYSCALL) - child->ptrace |= PT_TRACESYS; + set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); else - child->ptrace &= ~PT_TRACESYS; + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); child->exit_code = data; /* make sure single-step breakpoint is gone. */ __ptrace_cancel_bpt(child); @@ -490,7 +491,7 @@ if ((unsigned long) data > _NSIG) break; child->thread.debug.nsaved = -1; - child->ptrace &= ~PT_TRACESYS; + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); child->exit_code = data; /* give it a chance to run. */ wake_up_process(child); @@ -547,7 +548,7 @@ break; /* we should check child->used_math here */ - ret = __copy_to_user((void *)data, &child->thread.fpstate, + ret = __copy_to_user((void *)data, &child->thread_info->fpstate, sizeof(struct user_fp)) ? -EFAULT : 0; break; @@ -560,7 +561,7 @@ break; child->used_math = 1; - ret = __copy_from_user(&child->thread.fpstate, (void *)data, + ret = __copy_from_user(&child->thread_info->fpstate, (void *)data, sizeof(struct user_fp)) ? -EFAULT : 0; break; @@ -616,7 +617,7 @@ ret = do_ptrace(request, child, addr, data); out_tsk: - free_task_struct(child); + put_task_struct(child); out: unlock_kernel(); return ret; @@ -626,8 +627,9 @@ { unsigned long ip; - if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) - != (PT_PTRACED|PT_TRACESYS)) + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + return; + if (!(current->ptrace & PT_PTRACED)) return; /* diff -Nru a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c --- a/arch/arm/kernel/setup.c Tue Feb 26 11:57:56 2002 +++ b/arch/arm/kernel/setup.c Tue Feb 26 11:57:56 2002 @@ -38,6 +38,10 @@ #define CONFIG_CMDLINE "" #endif +#ifdef CONFIG_PREEMPT +spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; +#endif + #if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE) char fpe_type[8]; diff -Nru a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c --- a/arch/arm/kernel/signal.c Tue Feb 26 11:57:56 2002 +++ b/arch/arm/kernel/signal.c Tue Feb 26 11:57:56 2002 @@ -480,6 +480,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs * regs) { + struct thread_info *thread = current_thread_info(); struct task_struct *tsk = current; int usig = sig; int ret; @@ -487,8 +488,8 @@ /* * translate the signal */ - if (usig < 32 && tsk->exec_domain && tsk->exec_domain->signal_invmap) - usig = tsk->exec_domain->signal_invmap[usig]; + if (usig < 32 && thread->exec_domain && thread->exec_domain->signal_invmap) + usig = thread->exec_domain->signal_invmap[usig]; /* * Set up the stack frame @@ -532,7 +533,7 @@ * the kernel can handle, and then we build all the user-level signal handling * stack-frames in one go after that. */ -asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) +int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) { struct k_sigaction *ka; siginfo_t info; @@ -677,4 +678,11 @@ if (single_stepping) ptrace_set_bpt(current); return 0; +} + +asmlinkage void +do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall) +{ + if (thread_flags & _TIF_SIGPENDING) + do_signal(NULL, regs, syscall); } diff -Nru a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c --- a/arch/arm/kernel/traps.c Tue Feb 26 11:57:59 2002 +++ b/arch/arm/kernel/traps.c Tue Feb 26 11:57:59 2002 @@ -115,7 +115,7 @@ static void dump_stack(struct task_struct *tsk, unsigned long sp) { - dump_mem("Stack: ", sp - 16, 8192+(unsigned long)tsk); + dump_mem("Stack: ", sp - 16, 8192+(unsigned long)tsk->thread_info); } static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) @@ -146,7 +146,7 @@ void show_trace_task(struct task_struct *tsk) { if (tsk != current) { - unsigned int fp = tsk->thread.save->fp; + unsigned int fp = thread_saved_fp(tsk); c_backtrace(fp, 0x10); } } @@ -304,16 +304,17 @@ static int bad_syscall(int n, struct pt_regs *regs) { + struct thread_info *thread = current_thread_info(); siginfo_t info; /* You might think just testing `handler' would be enough, but PER_LINUX * points it to no_lcall7 to catch undercover SVr4 binaries. Gutted. */ - if (current->personality != PER_LINUX && current->exec_domain->handler) { + if (current->personality != PER_LINUX && thread->exec_domain->handler) { /* Hand it off to iBCS. The extra parameter and consequent type * forcing is necessary because of the weird ARM calling convention. */ - current->exec_domain->handler(n, regs); + thread->exec_domain->handler(n, regs); return regs->ARM_r0; } diff -Nru a/arch/arm/lib/csumpartial.S b/arch/arm/lib/csumpartial.S --- a/arch/arm/lib/csumpartial.S Tue Feb 26 11:57:59 2002 +++ b/arch/arm/lib/csumpartial.S Tue Feb 26 11:57:59 2002 @@ -41,7 +41,7 @@ tst buf, #1 @ odd address? ldrneb td0, [buf], #1 subne len, len, #1 - adcnes sum, sum, td0, lsl #8 + adcnes sum, sum, td0, lsl #byte(1) .less4: tst len, #6 beq .less8_byte @@ -56,7 +56,11 @@ ldrb td0, [buf], #1 ldrb td3, [buf], #1 sub len, len, #2 +#ifndef __ARMEB__ orr td0, td0, td3, lsl #8 +#else + orr td0, td3, td0, lsl #8 +#endif #endif adcs sum, sum, td0 tst len, #6 @@ -64,7 +68,7 @@ .less8_byte: tst len, #1 @ odd number of bytes ldrneb td0, [buf], #1 @ include last byte - adcnes sum, sum, td0 @ update checksum + adcnes sum, sum, td0, lsl #byte(0) @ update checksum .done: adc r0, sum, #0 @ collect up the last carry ldr td0, [sp], #4 @@ -76,7 +80,7 @@ .not_aligned: tst buf, #1 @ odd address ldrneb td0, [buf], #1 @ make even subne len, len, #1 - adcnes sum, sum, td0, lsl #8 @ update checksum + adcnes sum, sum, td0, lsl #byte(1) @ update checksum tst buf, #2 @ 32-bit aligned? #ifdef __ARM_ARCH_4__ @@ -86,7 +90,11 @@ ldrneb td0, [buf], #1 ldrneb ip, [buf], #1 subne len, len, #2 +#ifndef __ARMEB__ orrne td0, td0, ip, lsl #8 +#else + orrne td0, ip, td0, lsl #8 +#endif #endif adcnes sum, sum, td0 @ update checksum mov pc, lr diff -Nru a/arch/arm/lib/csumpartialcopygeneric.S b/arch/arm/lib/csumpartialcopygeneric.S --- a/arch/arm/lib/csumpartialcopygeneric.S Tue Feb 26 11:57:57 2002 +++ b/arch/arm/lib/csumpartialcopygeneric.S Tue Feb 26 11:57:57 2002 @@ -36,16 +36,16 @@ load1b ip sub len, len, #1 - adcs sum, sum, ip, lsl #8 @ update checksum + adcs sum, sum, ip, lsl #byte(1) @ update checksum strb ip, [dst], #1 tst dst, #2 moveq pc, lr @ dst is now 32bit aligned .dst_16bit: load2b r8, ip sub len, len, #2 - adcs sum, sum, r8 + adcs sum, sum, r8, lsl #byte(0) strb r8, [dst], #1 - adcs sum, sum, ip, lsl #8 + adcs sum, sum, ip, lsl #byte(1) strb ip, [dst], #1 mov pc, lr @ dst is now 32bit aligned @@ -63,16 +63,16 @@ /* Align dst */ load1b ip sub len, len, #1 - adcs sum, sum, ip, lsl #8 @ update checksum + adcs sum, sum, ip, lsl #byte(1) @ update checksum strb ip, [dst], #1 tst len, #6 beq .less8_byteonly 1: load2b r8, ip sub len, len, #2 - adcs sum, sum, r8 + adcs sum, sum, r8, lsl #byte(0) strb r8, [dst], #1 - adcs sum, sum, ip, lsl #8 + adcs sum, sum, ip, lsl #byte(1) strb ip, [dst], #1 .less8_aligned: tst len, #6 bne 1b @@ -80,7 +80,7 @@ tst len, #1 beq .done load1b r8 - adcs sum, sum, r8 @ update checksum + adcs sum, sum, r8, lsl #byte(0) @ update checksum strb r8, [dst], #1 b .done @@ -137,18 +137,19 @@ 4: ands len, len, #3 beq .done - load1l r4 + load1l r5 tst len, #2 + mov r4, r5, lsr #byte(0) beq .exit - adcs sum, sum, r4, lsl #16 + adcs sum, sum, r5, push #16 strb r4, [dst], #1 - mov r4, r4, lsr #8 + mov r4, r5, lsr #byte(1) strb r4, [dst], #1 - mov r4, r4, lsr #8 + mov r4, r5, lsr #byte(2) .exit: tst len, #1 strneb r4, [dst], #1 andne r4, r4, #255 - adcnes sum, sum, r4 + adcnes sum, sum, r4, lsl #byte(0) /* * If the dst pointer was not 16-bit aligned, we @@ -167,27 +168,27 @@ adc sum, sum, #0 @ include C from dst alignment and ip, src, #3 bic src, src, #3 - load1l r4 + load1l r5 cmp ip, #2 beq .src2_aligned bhi .src3_aligned - mov r4, r4, lsr #8 @ C = 0 + mov r4, r5, pull #8 @ C = 0 bics ip, len, #15 beq 2f 1: load4l r5, r6, r7, r8 - orr r4, r4, r5, lsl #24 - mov r5, r5, lsr #8 - orr r5, r5, r6, lsl #24 - mov r6, r6, lsr #8 - orr r6, r6, r7, lsl #24 - mov r7, r7, lsr #8 - orr r7, r7, r8, lsl #24 + orr r4, r4, r5, push #24 + mov r5, r5, pull #8 + orr r5, r5, r6, push #24 + mov r6, r6, pull #8 + orr r6, r6, r7, push #24 + mov r7, r7, pull #8 + orr r7, r7, r8, push #24 stmia dst!, {r4, r5, r6, r7} adcs sum, sum, r4 adcs sum, sum, r5 adcs sum, sum, r6 adcs sum, sum, r7 - mov r4, r8, lsr #8 + mov r4, r8, pull #8 sub ip, ip, #16 teq ip, #0 bne 1b @@ -196,49 +197,50 @@ tst ip, #8 beq 3f load2l r5, r6 - orr r4, r4, r5, lsl #24 - mov r5, r5, lsr #8 - orr r5, r5, r6, lsl #24 + orr r4, r4, r5, push #24 + mov r5, r5, pull #8 + orr r5, r5, r6, push #24 stmia dst!, {r4, r5} adcs sum, sum, r4 adcs sum, sum, r5 - mov r4, r6, lsr #8 + mov r4, r6, pull #8 tst ip, #4 beq 4f 3: load1l r5 - orr r4, r4, r5, lsl #24 + orr r4, r4, r5, push #24 str r4, [dst], #4 adcs sum, sum, r4 - mov r4, r5, lsr #8 4: ands len, len, #3 beq .done + mov r4, r5, lsr #byte(1) tst len, #2 beq .exit - adcs sum, sum, r4, lsl #16 + bic r5, r5, #0xff << byte(0) + adcs sum, sum, r5, push #8 strb r4, [dst], #1 - mov r4, r4, lsr #8 + mov r4, r5, lsr #byte(2) strb r4, [dst], #1 - mov r4, r4, lsr #8 + mov r4, r5, lsr #byte(3) b .exit -.src2_aligned: mov r4, r4, lsr #16 +.src2_aligned: mov r4, r5, pull #16 adds sum, sum, #0 bics ip, len, #15 beq 2f 1: load4l r5, r6, r7, r8 - orr r4, r4, r5, lsl #16 - mov r5, r5, lsr #16 - orr r5, r5, r6, lsl #16 - mov r6, r6, lsr #16 - orr r6, r6, r7, lsl #16 - mov r7, r7, lsr #16 - orr r7, r7, r8, lsl #16 + orr r4, r4, r5, push #16 + mov r5, r5, pull #16 + orr r5, r5, r6, push #16 + mov r6, r6, pull #16 + orr r6, r6, r7, push #16 + mov r7, r7, pull #16 + orr r7, r7, r8, push #16 stmia dst!, {r4, r5, r6, r7} adcs sum, sum, r4 adcs sum, sum, r5 adcs sum, sum, r6 adcs sum, sum, r7 - mov r4, r8, lsr #16 + mov r4, r8, pull #16 sub ip, ip, #16 teq ip, #0 bne 1b @@ -247,51 +249,51 @@ tst ip, #8 beq 3f load2l r5, r6 - orr r4, r4, r5, lsl #16 - mov r5, r5, lsr #16 - orr r5, r5, r6, lsl #16 + orr r4, r4, r5, push #16 + mov r5, r5, pull #16 + orr r5, r5, r6, push #16 stmia dst!, {r4, r5} adcs sum, sum, r4 adcs sum, sum, r5 - mov r4, r6, lsr #16 + mov r4, r6, pull #16 tst ip, #4 beq 4f 3: load1l r5 - orr r4, r4, r5, lsl #16 + orr r4, r4, r5, push #16 str r4, [dst], #4 adcs sum, sum, r4 - mov r4, r5, lsr #16 4: ands len, len, #3 beq .done + mov r4, r5, lsr #byte(2) tst len, #2 beq .exit - adcs sum, sum, r4, lsl #16 + adcs sum, sum, r5, pull #16 strb r4, [dst], #1 - mov r4, r4, lsr #8 + mov r4, r5, lsr #byte(3) strb r4, [dst], #1 tst len, #1 beq .done load1b r4 b .exit -.src3_aligned: mov r4, r4, lsr #24 +.src3_aligned: mov r4, r5, pull #24 adds sum, sum, #0 bics ip, len, #15 beq 2f 1: load4l r5, r6, r7, r8 - orr r4, r4, r5, lsl #8 - mov r5, r5, lsr #24 - orr r5, r5, r6, lsl #8 - mov r6, r6, lsr #24 - orr r6, r6, r7, lsl #8 - mov r7, r7, lsr #24 - orr r7, r7, r8, lsl #8 + orr r4, r4, r5, push #8 + mov r5, r5, pull #24 + orr r5, r5, r6, push #8 + mov r6, r6, pull #24 + orr r6, r6, r7, push #8 + mov r7, r7, pull #24 + orr r7, r7, r8, push #8 stmia dst!, {r4, r5, r6, r7} adcs sum, sum, r4 adcs sum, sum, r5 adcs sum, sum, r6 adcs sum, sum, r7 - mov r4, r8, lsr #24 + mov r4, r8, pull #24 sub ip, ip, #16 teq ip, #0 bne 1b @@ -300,28 +302,29 @@ tst ip, #8 beq 3f load2l r5, r6 - orr r4, r4, r5, lsl #8 - mov r5, r5, lsr #24 - orr r5, r5, r6, lsl #8 + orr r4, r4, r5, push #8 + mov r5, r5, pull #24 + orr r5, r5, r6, push #8 stmia dst!, {r4, r5} adcs sum, sum, r4 adcs sum, sum, r5 - mov r4, r6, lsr #24 + mov r4, r6, pull #24 tst ip, #4 beq 4f 3: load1l r5 - orr r4, r4, r5, lsl #8 + orr r4, r4, r5, push #8 str r4, [dst], #4 adcs sum, sum, r4 - mov r4, r5, lsr #24 4: ands len, len, #3 beq .done + mov r4, r5, lsr #byte(3) tst len, #2 beq .exit - adcs sum, sum, r4, lsl #16 + adcs sum, sum, r5, pull #24 strb r4, [dst], #1 - load1l r4 + load1l r5 + mov r4, r5, lsr #byte(0) strb r4, [dst], #1 - adcs sum, sum, r4, lsl #24 - mov r4, r4, lsr #8 + adcs sum, sum, r4, push #24 + mov r4, r5, lsr #byte(1) b .exit diff -Nru a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S --- a/arch/arm/lib/getuser.S Tue Feb 26 11:57:59 2002 +++ b/arch/arm/lib/getuser.S Tue Feb 26 11:57:59 2002 @@ -27,12 +27,13 @@ * Note also that it is intended that __get_user_bad is not global. */ #include +#include .global __get_user_1 __get_user_1: bic r1, sp, #0x1f00 bic r1, r1, #0x00ff - ldr r1, [r1, #TSK_ADDR_LIMIT] + ldr r1, [r1, #TI_ADDR_LIMIT] sub r1, r1, #1 cmp r0, r1 1: ldrlsbt r1, [r0] @@ -44,7 +45,7 @@ __get_user_2: bic r2, sp, #0x1f00 bic r2, r2, #0x00ff - ldr r2, [r2, #TSK_ADDR_LIMIT] + ldr r2, [r2, #TI_ADDR_LIMIT] sub r2, r2, #2 cmp r0, r2 2: ldrlsbt r1, [r0], #1 @@ -62,7 +63,7 @@ __get_user_4: bic r1, sp, #0x1f00 bic r1, r1, #0x00ff - ldr r1, [r1, #TSK_ADDR_LIMIT] + ldr r1, [r1, #TI_ADDR_LIMIT] sub r1, r1, #4 cmp r0, r1 4: ldrlst r1, [r0] @@ -74,7 +75,7 @@ __get_user_8: bic r2, sp, #0x1f00 bic r2, r2, #0x00ff - ldr r2, [r2, #TSK_ADDR_LIMIT] + ldr r2, [r2, #TI_ADDR_LIMIT] sub r2, r2, #8 cmp r0, r2 5: ldrlst r1, [r0], #4 diff -Nru a/arch/arm/lib/putuser.S b/arch/arm/lib/putuser.S --- a/arch/arm/lib/putuser.S Tue Feb 26 11:58:00 2002 +++ b/arch/arm/lib/putuser.S Tue Feb 26 11:58:00 2002 @@ -27,12 +27,13 @@ * Note also that it is intended that __put_user_bad is not global. */ #include +#include .global __put_user_1 __put_user_1: bic r2, sp, #0x1f00 bic r2, r2, #0x00ff - ldr r2, [r2, #TSK_ADDR_LIMIT] + ldr r2, [r2, #TI_ADDR_LIMIT] sub r2, r2, #1 cmp r0, r2 1: strlsbt r1, [r0] @@ -44,7 +45,7 @@ __put_user_2: bic r2, sp, #0x1f00 bic r2, r2, #0x00ff - ldr r2, [r2, #TSK_ADDR_LIMIT] + ldr r2, [r2, #TI_ADDR_LIMIT] sub r2, r2, #2 cmp r0, r2 movls r2, r1, lsr #8 @@ -63,7 +64,7 @@ __put_user_4: bic r2, sp, #0x1f00 bic r2, r2, #0x00ff - ldr r2, [r2, #TSK_ADDR_LIMIT] + ldr r2, [r2, #TI_ADDR_LIMIT] sub r2, r2, #4 cmp r0, r2 4: strlst r1, [r0] @@ -75,7 +76,7 @@ __put_user_8: bic ip, sp, #0x1f00 bic ip, ip, #0x00ff - ldr ip, [ip, #TSK_ADDR_LIMIT] + ldr ip, [ip, #TI_ADDR_LIMIT] sub ip, ip, #8 cmp r0, ip 5: strlst r1, [r0], #4 diff -Nru a/arch/arm/lib/strrchr.S b/arch/arm/lib/strrchr.S --- a/arch/arm/lib/strrchr.S Tue Feb 26 11:57:59 2002 +++ b/arch/arm/lib/strrchr.S Tue Feb 26 11:57:59 2002 @@ -18,7 +18,7 @@ mov r3, #0 1: ldrb r2, [r0], #1 teq r2, r1 - moveq r3, r0 + subeq r3, r0, #1 teq r2, #0 bne 1b mov r0, r3 diff -Nru a/arch/arm/mach-adifcc/arch.c b/arch/arm/mach-adifcc/arch.c --- a/arch/arm/mach-adifcc/arch.c Tue Feb 26 11:58:00 2002 +++ b/arch/arm/mach-adifcc/arch.c Tue Feb 26 11:58:00 2002 @@ -7,7 +7,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - +#include #include #include #include @@ -33,7 +33,7 @@ setup_ramdisk( 1, 0, 0, 8192 ); setup_initrd( 0xc0800000, 3*1024*1024 ); - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); #endif } diff -Nru a/arch/arm/mach-adifcc/irq.c b/arch/arm/mach-adifcc/irq.c --- a/arch/arm/mach-adifcc/irq.c Tue Feb 26 11:57:59 2002 +++ b/arch/arm/mach-adifcc/irq.c Tue Feb 26 11:57:59 2002 @@ -12,8 +12,6 @@ * 80200 on chip interrupts. That'll change once the hardware adds * support for PCI though. */ - -#include #include #include #include diff -Nru a/arch/arm/mach-anakin/arch.c b/arch/arm/mach-anakin/arch.c --- a/arch/arm/mach-anakin/arch.c Tue Feb 26 11:57:56 2002 +++ b/arch/arm/mach-anakin/arch.c Tue Feb 26 11:57:56 2002 @@ -30,7 +30,7 @@ fixup_anakin(struct machine_desc *desc, struct param_struct *unused, char **cmdline, struct meminfo *mi) { - ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR, 0); setup_ramdisk(1, 0, 0, CONFIG_BLK_DEV_RAM_SIZE); setup_initrd(0xc0800000, 4 * 1024 * 1024); } diff -Nru a/arch/arm/mach-arc/arch.c b/arch/arm/mach-arc/arch.c --- a/arch/arm/mach-arc/arch.c Tue Feb 26 11:57:57 2002 +++ b/arch/arm/mach-arc/arch.c Tue Feb 26 11:57:57 2002 @@ -9,6 +9,7 @@ * * Architecture specific fixups. */ +#include #include #include diff -Nru a/arch/arm/mach-clps711x/cdb89712.c b/arch/arm/mach-clps711x/cdb89712.c --- a/arch/arm/mach-clps711x/cdb89712.c Tue Feb 26 11:57:56 2002 +++ b/arch/arm/mach-clps711x/cdb89712.c Tue Feb 26 11:57:56 2002 @@ -17,7 +17,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include diff -Nru a/arch/arm/mach-epxa10db/arch.c b/arch/arm/mach-epxa10db/arch.c --- a/arch/arm/mach-epxa10db/arch.c Tue Feb 26 11:57:59 2002 +++ b/arch/arm/mach-epxa10db/arch.c Tue Feb 26 11:57:59 2002 @@ -18,7 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include @@ -46,7 +45,7 @@ mi->bank[0].node = 0; /* - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, 8192 ); setup_initrd(0xc0200000, 6*1024*1024); */ diff -Nru a/arch/arm/mach-ftvpci/core.c b/arch/arm/mach-ftvpci/core.c --- a/arch/arm/mach-ftvpci/core.c Tue Feb 26 11:57:58 2002 +++ b/arch/arm/mach-ftvpci/core.c Tue Feb 26 11:57:58 2002 @@ -8,7 +8,6 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ -#include #include #include #include diff -Nru a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c --- a/arch/arm/mach-integrator/pci_v3.c Tue Feb 26 11:57:57 2002 +++ b/arch/arm/mach-integrator/pci_v3.c Tue Feb 26 11:57:57 2002 @@ -20,6 +20,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include #include #include diff -Nru a/arch/arm/mach-iop310/arch.c b/arch/arm/mach-iop310/arch.c --- a/arch/arm/mach-iop310/arch.c Tue Feb 26 11:57:59 2002 +++ b/arch/arm/mach-iop310/arch.c Tue Feb 26 11:57:59 2002 @@ -9,7 +9,7 @@ * published by the Free Software Foundation. * */ - +#include #include #include #include @@ -44,7 +44,7 @@ #elif defined(CONFIG_BLK_DEV_INITRD) setup_ramdisk( 1, 0, 0, CONFIG_BLK_DEV_RAM_SIZE ); setup_initrd( 0xc0800000, 4*1024*1024 ); - ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); /* /dev/ram */ + ROOT_DEV = mk_kdev(RAMDISK_MAJOR, 0); /* /dev/ram */ #endif } diff -Nru a/arch/arm/mach-iop310/iop310-irq.c b/arch/arm/mach-iop310/iop310-irq.c --- a/arch/arm/mach-iop310/iop310-irq.c Tue Feb 26 11:58:00 2002 +++ b/arch/arm/mach-iop310/iop310-irq.c Tue Feb 26 11:58:00 2002 @@ -13,8 +13,6 @@ * Added IOP310 chipset and IQ80310 board demuxing, masking code. - DS * */ - -#include #include #include #include diff -Nru a/arch/arm/mach-iop310/iq80310-irq.c b/arch/arm/mach-iop310/iq80310-irq.c --- a/arch/arm/mach-iop310/iq80310-irq.c Tue Feb 26 11:57:57 2002 +++ b/arch/arm/mach-iop310/iq80310-irq.c Tue Feb 26 11:57:57 2002 @@ -14,8 +14,6 @@ * Moved demux from asm to C - DS * Fixes for various revision boards - DS */ - -#include #include #include #include diff -Nru a/arch/arm/mach-iop310/mm.c b/arch/arm/mach-iop310/mm.c --- a/arch/arm/mach-iop310/mm.c Tue Feb 26 11:57:57 2002 +++ b/arch/arm/mach-iop310/mm.c Tue Feb 26 11:57:57 2002 @@ -13,7 +13,7 @@ * option) any later version. * */ - +#include #include #include diff -Nru a/arch/arm/mach-iop310/xs80200-irq.c b/arch/arm/mach-iop310/xs80200-irq.c --- a/arch/arm/mach-iop310/xs80200-irq.c Tue Feb 26 11:57:59 2002 +++ b/arch/arm/mach-iop310/xs80200-irq.c Tue Feb 26 11:57:59 2002 @@ -10,8 +10,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - -#include #include #include #include diff -Nru a/arch/arm/mach-l7200/core.c b/arch/arm/mach-l7200/core.c --- a/arch/arm/mach-l7200/core.c Tue Feb 26 11:57:57 2002 +++ b/arch/arm/mach-l7200/core.c Tue Feb 26 11:57:57 2002 @@ -5,6 +5,7 @@ * * Extra MM routines for L7200 architecture */ +#include #include #include @@ -90,7 +91,7 @@ mi->bank[0].size = (32*1024*1024); mi->bank[0].node = 0; - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, CONFIG_BLK_DEV_RAM_SIZE); setup_initrd( __phys_to_virt(0xf1000000), 0x005dac7b); diff -Nru a/arch/arm/mach-sa1100/adsbitsy.c b/arch/arm/mach-sa1100/adsbitsy.c --- a/arch/arm/mach-sa1100/adsbitsy.c Tue Feb 26 11:57:56 2002 +++ b/arch/arm/mach-sa1100/adsbitsy.c Tue Feb 26 11:57:56 2002 @@ -26,8 +26,6 @@ #include #include -#include - #include "generic.h" #include "sa1111.h" @@ -120,7 +118,7 @@ SET_BANK( 0, 0xc0000000, 32*1024*1024 ); mi->nr_banks = 1; - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, 8192 ); setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 ); } diff -Nru a/arch/arm/mach-sa1100/brutus.c b/arch/arm/mach-sa1100/brutus.c --- a/arch/arm/mach-sa1100/brutus.c Tue Feb 26 11:57:58 2002 +++ b/arch/arm/mach-sa1100/brutus.c Tue Feb 26 11:57:58 2002 @@ -32,7 +32,7 @@ SET_BANK( 3, 0xd8000000, 4*1024*1024 ); mi->nr_banks = 4; - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, 8192 ); setup_initrd( __phys_to_virt(0xd8000000), 3*1024*1024 ); } diff -Nru a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c --- a/arch/arm/mach-sa1100/cerf.c Tue Feb 26 11:57:59 2002 +++ b/arch/arm/mach-sa1100/cerf.c Tue Feb 26 11:57:59 2002 @@ -1,7 +1,7 @@ /* * linux/arch/arm/mach-sa1100/cerf.c */ - +#include #include #include #include @@ -55,7 +55,7 @@ #error "Undefined memory size for Cerfboard." #endif -// ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); +// ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); // setup_ramdisk(1, 0, 0, 8192); // // Save 2Meg for RAMDisk // setup_initrd(0xc0500000, 3*1024*1024); diff -Nru a/arch/arm/mach-sa1100/empeg.c b/arch/arm/mach-sa1100/empeg.c --- a/arch/arm/mach-sa1100/empeg.c Tue Feb 26 11:58:00 2002 +++ b/arch/arm/mach-sa1100/empeg.c Tue Feb 26 11:58:00 2002 @@ -24,7 +24,7 @@ SET_BANK( 1, 0xc8000000, 4*1024*1024 ); mi->nr_banks = 2; - ROOT_DEV = MKDEV( 3, 1 ); /* /dev/hda1 */ + ROOT_DEV = mk_kdev( 3, 1 ); /* /dev/hda1 */ setup_ramdisk( 1, 0, 0, 4096 ); setup_initrd( 0xd0000000+((1024-320)*1024), (320*1024) ); } diff -Nru a/arch/arm/mach-sa1100/flexanet.c b/arch/arm/mach-sa1100/flexanet.c --- a/arch/arm/mach-sa1100/flexanet.c Tue Feb 26 11:57:59 2002 +++ b/arch/arm/mach-sa1100/flexanet.c Tue Feb 26 11:57:59 2002 @@ -9,8 +9,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - -#include #include #include #include @@ -113,7 +111,6 @@ * * get_mctrl : set state of modem control lines * set_mctrl : set the modem control lines - * enable_ms : enable modem-status interrupts * pm : power-management. Turn device on/off. * */ @@ -121,7 +118,6 @@ { set_mctrl : flexanet_set_mctrl, get_mctrl : flexanet_get_mctrl, - enable_ms : NULL, pm : NULL, }; @@ -168,7 +164,7 @@ mi->nr_banks = 1; /* setup ramdisk */ - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, 8192 ); setup_initrd( 0xc0800000, 3*1024*1024 ); } diff -Nru a/arch/arm/mach-sa1100/freebird.c b/arch/arm/mach-sa1100/freebird.c --- a/arch/arm/mach-sa1100/freebird.c Tue Feb 26 11:57:57 2002 +++ b/arch/arm/mach-sa1100/freebird.c Tue Feb 26 11:57:57 2002 @@ -58,7 +58,7 @@ #ifdef CONFIG_SA1100_FREEBIRD_OLD SET_BANK( 0, 0xc0000000, 32*1024*1024 ); mi->nr_banks = 1; - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0 ,0 , 8192 ); setup_initrd( 0xc0800000, 3*1024*1024 ); #endif diff -Nru a/arch/arm/mach-sa1100/graphicsclient.c b/arch/arm/mach-sa1100/graphicsclient.c --- a/arch/arm/mach-sa1100/graphicsclient.c Tue Feb 26 11:58:00 2002 +++ b/arch/arm/mach-sa1100/graphicsclient.c Tue Feb 26 11:58:00 2002 @@ -130,7 +130,7 @@ SET_BANK( 1, 0xc8000000, 16*1024*1024 ); mi->nr_banks = 2; - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, 8192 ); setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 ); } diff -Nru a/arch/arm/mach-sa1100/graphicsmaster.c b/arch/arm/mach-sa1100/graphicsmaster.c --- a/arch/arm/mach-sa1100/graphicsmaster.c Tue Feb 26 11:57:59 2002 +++ b/arch/arm/mach-sa1100/graphicsmaster.c Tue Feb 26 11:57:59 2002 @@ -193,7 +193,7 @@ SET_BANK( 1, 0xc8000000, 16*1024*1024 ); mi->nr_banks = 2; - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, 8192 ); setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 ); } diff -Nru a/arch/arm/mach-sa1100/h3600.c b/arch/arm/mach-sa1100/h3600.c --- a/arch/arm/mach-sa1100/h3600.c Tue Feb 26 11:57:57 2002 +++ b/arch/arm/mach-sa1100/h3600.c Tue Feb 26 11:57:57 2002 @@ -19,8 +19,6 @@ * and abstracted EGPIO interface. * */ - -#include #include #include #include diff -Nru a/arch/arm/mach-sa1100/huw_webpanel.c b/arch/arm/mach-sa1100/huw_webpanel.c --- a/arch/arm/mach-sa1100/huw_webpanel.c Tue Feb 26 11:57:59 2002 +++ b/arch/arm/mach-sa1100/huw_webpanel.c Tue Feb 26 11:57:59 2002 @@ -2,8 +2,6 @@ * linux/arch/arm/mach-sa1100/huw_webpanel.c * */ - -#include #include #include #include @@ -66,7 +64,7 @@ **/ SET_BANK( 0, 0xc0000000, ((32*1024 - (256 + 32)) * 1024)); mi->nr_banks = 1; - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, 8192 ); setup_initrd( __phys_to_virt(0xc0800000), 8*1024*1024 ); } diff -Nru a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c --- a/arch/arm/mach-sa1100/irq.c Tue Feb 26 11:58:00 2002 +++ b/arch/arm/mach-sa1100/irq.c Tue Feb 26 11:58:00 2002 @@ -9,8 +9,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - -#include #include #include #include diff -Nru a/arch/arm/mach-sa1100/leds-adsbitsy.c b/arch/arm/mach-sa1100/leds-adsbitsy.c --- a/arch/arm/mach-sa1100/leds-adsbitsy.c Tue Feb 26 11:57:58 2002 +++ b/arch/arm/mach-sa1100/leds-adsbitsy.c Tue Feb 26 11:57:58 2002 @@ -28,7 +28,7 @@ { unsigned long flags; - save_flags_cli(flags); + local_irq_save(flags); switch (evt) { case led_start: @@ -92,5 +92,5 @@ GPCR = hw_led_state ^ LED_MASK; } - restore_flags(flags); + local_irq_restore(flags); } diff -Nru a/arch/arm/mach-sa1100/leds-graphicsclient.c b/arch/arm/mach-sa1100/leds-graphicsclient.c --- a/arch/arm/mach-sa1100/leds-graphicsclient.c Tue Feb 26 11:57:56 2002 +++ b/arch/arm/mach-sa1100/leds-graphicsclient.c Tue Feb 26 11:57:56 2002 @@ -30,7 +30,7 @@ { unsigned long flags; - save_flags_cli(flags); + local_irq_save(flags); switch (evt) { case led_start: @@ -100,5 +100,5 @@ GPCR = hw_led_state ^ LED_MASK; } - restore_flags(flags); + local_irq_restore(flags); } diff -Nru a/arch/arm/mach-sa1100/leds-graphicsmaster.c b/arch/arm/mach-sa1100/leds-graphicsmaster.c --- a/arch/arm/mach-sa1100/leds-graphicsmaster.c Tue Feb 26 11:57:56 2002 +++ b/arch/arm/mach-sa1100/leds-graphicsmaster.c Tue Feb 26 11:57:56 2002 @@ -30,7 +30,7 @@ { unsigned long flags; - save_flags_cli(flags); + local_irq_save(flags); switch (evt) { case led_start: @@ -100,5 +100,5 @@ GPCR = hw_led_state ^ LED_MASK; } - restore_flags(flags); + local_irq_restore(flags); } diff -Nru a/arch/arm/mach-sa1100/leds-system3.c b/arch/arm/mach-sa1100/leds-system3.c --- a/arch/arm/mach-sa1100/leds-system3.c Tue Feb 26 11:57:59 2002 +++ b/arch/arm/mach-sa1100/leds-system3.c Tue Feb 26 11:57:59 2002 @@ -26,7 +26,6 @@ * * */ -#include #include #include diff -Nru a/arch/arm/mach-sa1100/leds.c b/arch/arm/mach-sa1100/leds.c --- a/arch/arm/mach-sa1100/leds.c Tue Feb 26 11:57:57 2002 +++ b/arch/arm/mach-sa1100/leds.c Tue Feb 26 11:57:57 2002 @@ -5,7 +5,6 @@ * * Copyright (C) 2001 Nicolas Pitre */ -#include #include #include diff -Nru a/arch/arm/mach-sa1100/nanoengine.c b/arch/arm/mach-sa1100/nanoengine.c --- a/arch/arm/mach-sa1100/nanoengine.c Tue Feb 26 11:57:56 2002 +++ b/arch/arm/mach-sa1100/nanoengine.c Tue Feb 26 11:57:56 2002 @@ -23,7 +23,7 @@ SET_BANK( 0, 0xc0000000, 32*1024*1024 ); mi->nr_banks = 1; - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, 8192 ); setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 ); diff -Nru a/arch/arm/mach-sa1100/omnimeter.c b/arch/arm/mach-sa1100/omnimeter.c --- a/arch/arm/mach-sa1100/omnimeter.c Tue Feb 26 11:57:56 2002 +++ b/arch/arm/mach-sa1100/omnimeter.c Tue Feb 26 11:57:56 2002 @@ -47,7 +47,7 @@ SET_BANK( 0, 0xc0000000, 16*1024*1024 ); mi->nr_banks = 1; - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, 8192 ); setup_initrd( __phys_to_virt(0xd0000000), 0x00400000 ); } diff -Nru a/arch/arm/mach-sa1100/pangolin.c b/arch/arm/mach-sa1100/pangolin.c --- a/arch/arm/mach-sa1100/pangolin.c Tue Feb 26 11:58:00 2002 +++ b/arch/arm/mach-sa1100/pangolin.c Tue Feb 26 11:58:00 2002 @@ -1,7 +1,7 @@ /* * linux/arch/arm/mach-sa1100/pangolin.c */ - +#include #include #include #include @@ -23,7 +23,7 @@ SET_BANK( 0, 0xc0000000, 128*1024*1024 ); mi->nr_banks = 1; - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, 16384 ); setup_initrd( 0xc0800000, 3*1024*1024 ); } diff -Nru a/arch/arm/mach-sa1100/pfs168.c b/arch/arm/mach-sa1100/pfs168.c --- a/arch/arm/mach-sa1100/pfs168.c Tue Feb 26 11:57:56 2002 +++ b/arch/arm/mach-sa1100/pfs168.c Tue Feb 26 11:57:56 2002 @@ -1,7 +1,7 @@ /* * linux/arch/arm/mach-sa1100/pfs168.c */ - +#include #include #include #include @@ -96,7 +96,7 @@ SET_BANK( 0, 0xc0000000, 16*1024*1024 ); mi->nr_banks = 1; - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, 8192 ); setup_initrd( 0xc0800000, 3*1024*1024 ); } diff -Nru a/arch/arm/mach-sa1100/pleb.c b/arch/arm/mach-sa1100/pleb.c --- a/arch/arm/mach-sa1100/pleb.c Tue Feb 26 11:57:58 2002 +++ b/arch/arm/mach-sa1100/pleb.c Tue Feb 26 11:57:58 2002 @@ -28,7 +28,7 @@ /* make it 1 if a 16MB memory card is used */ mi->nr_banks = 2; /* Default 32MB */ - ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR, 0); setup_ramdisk(1, 0, 0, 8192); setup_initrd(0xc0400000, 4*1024*1024); } diff -Nru a/arch/arm/mach-sa1100/sa1111-pcibuf.c b/arch/arm/mach-sa1100/sa1111-pcibuf.c --- a/arch/arm/mach-sa1100/sa1111-pcibuf.c Tue Feb 26 11:57:56 2002 +++ b/arch/arm/mach-sa1100/sa1111-pcibuf.c Tue Feb 26 11:57:56 2002 @@ -13,7 +13,6 @@ * * 06/13/2001 - created. */ -#include #include #include #include diff -Nru a/arch/arm/mach-sa1100/sherman.c b/arch/arm/mach-sa1100/sherman.c --- a/arch/arm/mach-sa1100/sherman.c Tue Feb 26 11:57:56 2002 +++ b/arch/arm/mach-sa1100/sherman.c Tue Feb 26 11:57:56 2002 @@ -24,7 +24,7 @@ SET_BANK( 1, 0xc8000000, 64*1024*1024 ); mi->nr_banks = 2; - ROOT_DEV = MKDEV( 60, 2 ); + ROOT_DEV = mk_kdev( 60, 2 ); setup_ramdisk( 1, 0, 0, 8192 ); // setup_initrd( 0xc0400000, 8*1024*1024 ); } diff -Nru a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c --- a/arch/arm/mach-sa1100/simpad.c Tue Feb 26 11:57:56 2002 +++ b/arch/arm/mach-sa1100/simpad.c Tue Feb 26 11:57:56 2002 @@ -50,7 +50,7 @@ SET_BANK( 0, 0xc0000000, 32*1024*1024 ); #endif mi->nr_banks = 1; - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, 8192 ); setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 ); } diff -Nru a/arch/arm/mach-sa1100/system3.c b/arch/arm/mach-sa1100/system3.c --- a/arch/arm/mach-sa1100/system3.c Tue Feb 26 11:57:58 2002 +++ b/arch/arm/mach-sa1100/system3.c Tue Feb 26 11:57:58 2002 @@ -54,8 +54,6 @@ #include #include -#include - #include #include "generic.h" @@ -227,7 +225,7 @@ { DPRINTK( "%s\n", "START" ); - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, 8192 ); setup_initrd( 0xc0800000, 8*1024*1024 ); } diff -Nru a/arch/arm/mach-sa1100/victor.c b/arch/arm/mach-sa1100/victor.c --- a/arch/arm/mach-sa1100/victor.c Tue Feb 26 11:57:56 2002 +++ b/arch/arm/mach-sa1100/victor.c Tue Feb 26 11:57:56 2002 @@ -48,7 +48,7 @@ SET_BANK( 0, 0xc0000000, 4*1024*1024 ); mi->nr_banks = 1; - ROOT_DEV = MKDEV( 60, 2 ); + ROOT_DEV = mk_kdev( 60, 2 ); /* Get command line parameters passed from the loader (if any) */ if( *((char*)0xc0000000) ) diff -Nru a/arch/arm/mach-sa1100/yopy.c b/arch/arm/mach-sa1100/yopy.c --- a/arch/arm/mach-sa1100/yopy.c Tue Feb 26 11:57:57 2002 +++ b/arch/arm/mach-sa1100/yopy.c Tue Feb 26 11:57:57 2002 @@ -1,8 +1,6 @@ /* * linux/arch/arm/mach-sa1100/yopy.c */ - -#include #include #include #include diff -Nru a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c --- a/arch/arm/mm/alignment.c Tue Feb 26 11:57:57 2002 +++ b/arch/arm/mm/alignment.c Tue Feb 26 11:57:57 2002 @@ -30,6 +30,10 @@ #include #include +extern void +do_bad_area(struct task_struct *tsk, struct mm_struct *mm, unsigned long addr, + int error_code, struct pt_regs *regs); + /* * 32-bit misaligned trap handler (c) 1998 San Mehat (CCC) -July 1998 * /proc/sys/debug/alignment, modified and integrated into @@ -163,9 +167,9 @@ #define TYPE_LDST 2 #define TYPE_DONE 3 -#define get8_unaligned_check(val,addr,err) \ +#define __get8_unaligned_check(ins,val,addr,err) \ __asm__( \ - "1: ldrb %1, [%2], #1\n" \ + "1: "ins" %1, [%2], #1\n" \ "2:\n" \ " .section .fixup,\"ax\"\n" \ " .align 2\n" \ @@ -179,39 +183,49 @@ : "=r" (err), "=&r" (val), "=r" (addr) \ : "0" (err), "2" (addr)) -#define get8t_unaligned_check(val,addr,err) \ - __asm__( \ - "1: ldrbt %1, [%2], #1\n" \ - "2:\n" \ - " .section .fixup,\"ax\"\n" \ - " .align 2\n" \ - "3: mov %0, #1\n" \ - " b 2b\n" \ - " .previous\n" \ - " .section __ex_table,\"a\"\n" \ - " .align 3\n" \ - " .long 1b, 3b\n" \ - " .previous\n" \ - : "=r" (err), "=&r" (val), "=r" (addr) \ - : "0" (err), "2" (addr)) +#define __get16_unaligned_check(ins,val,addr) \ + do { \ + unsigned int err = 0, v, a = addr; \ + __get8_unaligned_check(ins,val,a,err); \ + __get8_unaligned_check(ins,v,a,err); \ + val |= v << 8; \ + if (err) \ + goto fault; \ + } while (0) + +#define get16_unaligned_check(val,addr) \ + __get16_unaligned_check("ldrb",val,addr) + +#define get16t_unaligned_check(val,addr) \ + __get16_unaligned_check("ldrbt",val,addr) -#define get16_unaligned_check(val,addr) \ +#define __get32_unaligned_check(ins,val,addr) \ do { \ unsigned int err = 0, v, a = addr; \ - get8_unaligned_check(val,a,err); \ - get8_unaligned_check(v,a,err); \ + __get8_unaligned_check(ins,val,a,err); \ + __get8_unaligned_check(ins,v,a,err); \ val |= v << 8; \ + __get8_unaligned_check(ins,v,a,err); \ + val |= v << 16; \ + __get8_unaligned_check(ins,v,a,err); \ + val |= v << 24; \ if (err) \ goto fault; \ } while (0) -#define put16_unaligned_check(val,addr) \ +#define get32_unaligned_check(val,addr) \ + __get32_unaligned_check("ldrb",val,addr) + +#define get32t_unaligned_check(val,addr) \ + __get32_unaligned_check("ldrbt",val,addr) + +#define __put16_unaligned_check(ins,val,addr) \ do { \ unsigned int err = 0, v = val, a = addr; \ __asm__( \ - "1: strb %1, [%2], #1\n" \ + "1: "ins" %1, [%2], #1\n" \ " mov %1, %1, lsr #8\n" \ - "2: strb %1, [%2]\n" \ + "2: "ins" %1, [%2]\n" \ "3:\n" \ " .section .fixup,\"ax\"\n" \ " .align 2\n" \ @@ -229,6 +243,12 @@ goto fault; \ } while (0) +#define put16_unaligned_check(val,addr) \ + __put16_unaligned_check("strb",val,addr) + +#define put16t_unaligned_check(val,addr) \ + __put16_unaligned_check("strbt",val,addr) + #define __put32_unaligned_check(ins,val,addr) \ do { \ unsigned int err = 0, v = val, a = addr; \ @@ -259,37 +279,9 @@ goto fault; \ } while (0) -#define get32_unaligned_check(val,addr) \ - do { \ - unsigned int err = 0, v, a = addr; \ - get8_unaligned_check(val,a,err); \ - get8_unaligned_check(v,a,err); \ - val |= v << 8; \ - get8_unaligned_check(v,a,err); \ - val |= v << 16; \ - get8_unaligned_check(v,a,err); \ - val |= v << 24; \ - if (err) \ - goto fault; \ - } while (0) - #define put32_unaligned_check(val,addr) \ __put32_unaligned_check("strb", val, addr) -#define get32t_unaligned_check(val,addr) \ - do { \ - unsigned int err = 0, v, a = addr; \ - get8t_unaligned_check(val,a,err); \ - get8t_unaligned_check(v,a,err); \ - val |= v << 8; \ - get8t_unaligned_check(v,a,err); \ - val |= v << 16; \ - get8t_unaligned_check(v,a,err); \ - val |= v << 24; \ - if (err) \ - goto fault; \ - } while (0) - #define put32t_unaligned_check(val,addr) \ __put32_unaligned_check("strbt", val, addr) @@ -319,6 +311,9 @@ ai_half += 1; + if (user_mode(regs)) + goto user; + if (LDST_L_BIT(instr)) { unsigned long val; get16_unaligned_check(val, addr); @@ -333,12 +328,27 @@ return TYPE_LDST; -swp: + user: + if (LDST_L_BIT(instr)) { + unsigned long val; + get16t_unaligned_check(val, addr); + + /* signed half-word? */ + if (instr & 0x40) + val = (signed long)((signed short) val); + + regs->uregs[rd] = val; + } else + put16t_unaligned_check(regs->uregs[rd], addr); + + return TYPE_LDST; + + swp: printk(KERN_ERR "Alignment trap: not handling swp instruction\n"); -bad: + bad: return TYPE_ERROR; -fault: + fault: return TYPE_FAULT; } @@ -349,23 +359,27 @@ ai_word += 1; - if (!LDST_P_BIT(instr) && LDST_W_BIT(instr)) + if ((!LDST_P_BIT(instr) && LDST_W_BIT(instr)) || user_mode(regs)) goto trans; - if (LDST_L_BIT(instr)) - get32_unaligned_check(regs->uregs[rd], addr); - else + if (LDST_L_BIT(instr)) { + unsigned int val; + get32_unaligned_check(val, addr); + regs->uregs[rd] = val; + } else put32_unaligned_check(regs->uregs[rd], addr); return TYPE_LDST; -trans: - if (LDST_L_BIT(instr)) - get32t_unaligned_check(regs->uregs[rd], addr); - else + trans: + if (LDST_L_BIT(instr)) { + unsigned int val; + get32t_unaligned_check(val, addr); + regs->uregs[rd] = val; + } else put32t_unaligned_check(regs->uregs[rd], addr); return TYPE_LDST; -fault: + fault: return TYPE_FAULT; } @@ -431,14 +445,31 @@ } #endif - for (regbits = REGMASK_BITS(instr), rd = 0; regbits; regbits >>= 1, rd += 1) - if (regbits & 1) { - if (LDST_L_BIT(instr)) - get32_unaligned_check(regs->uregs[rd], eaddr); - else - put32_unaligned_check(regs->uregs[rd], eaddr); - eaddr += 4; - } + if (user_mode(regs)) { + for (regbits = REGMASK_BITS(instr), rd = 0; regbits; + regbits >>= 1, rd += 1) + if (regbits & 1) { + if (LDST_L_BIT(instr)) { + unsigned int val; + get32t_unaligned_check(val, eaddr); + regs->uregs[rd] = val; + } else + put32t_unaligned_check(regs->uregs[rd], eaddr); + eaddr += 4; + } + } else { + for (regbits = REGMASK_BITS(instr), rd = 0; regbits; + regbits >>= 1, rd += 1) + if (regbits & 1) { + if (LDST_L_BIT(instr)) { + unsigned int val; + get32_unaligned_check(val, eaddr); + regs->uregs[rd] = val; + } else + put32_unaligned_check(regs->uregs[rd], eaddr); + eaddr += 4; + } + } if (LDST_W_BIT(instr)) regs->uregs[rn] = newaddr; @@ -539,7 +570,7 @@ return 0; -bad_or_fault: + bad_or_fault: if (type == TYPE_ERROR) goto bad; regs->ARM_pc -= 4; @@ -549,7 +580,7 @@ do_bad_area(current, current->mm, addr, error_code, regs); return 0; -bad: + bad: /* * Oops, we didn't handle the instruction. */ diff -Nru a/arch/arm/tools/getconstants.c b/arch/arm/tools/getconstants.c --- a/arch/arm/tools/getconstants.c Tue Feb 26 11:57:58 2002 +++ b/arch/arm/tools/getconstants.c Tue Feb 26 11:57:58 2002 @@ -32,23 +32,21 @@ #endif #define OFF_TSK(n) (unsigned long)&(((struct task_struct *)0)->n) +#define OFF_VMA(n) (unsigned long)&(((struct vm_area_struct *)0)->n) #define DEFN(name,off) asm("\n#define "name" %0" :: "I" (off)) void func(void) { -#error DEFN("TSK_SIGPENDING", OFF_TSK(sigpending)); -DEFN("TSK_ADDR_LIMIT", OFF_TSK(addr_limit)); -#error DEFN("TSK_NEED_RESCHED", OFF_TSK(need_resched)); -#error DEFN("TSK_PTRACE", OFF_TSK(ptrace)); DEFN("TSK_USED_MATH", OFF_TSK(used_math)); +DEFN("TSK_ACTIVE_MM", OFF_TSK(active_mm)); -DEFN("TSS_SAVE", OFF_TSK(thread.save)); -DEFN("TSS_FPESAVE", OFF_TSK(thread.fpstate.soft.save)); +DEFN("VMA_VM_MM", OFF_VMA(vm_mm)); +DEFN("VMA_VM_FLAGS", OFF_VMA(vm_flags)); -#ifdef CONFIG_CPU_32 -DEFN("TSS_DOMAIN", OFF_TSK(thread.domain)); +DEFN("VM_EXEC", VM_EXEC); +#ifdef CONFIG_CPU_32 DEFN("HPTE_TYPE_SMALL", PTE_TYPE_SMALL); DEFN("HPTE_AP_READ", PTE_AP_READ); DEFN("HPTE_AP_WRITE", PTE_AP_WRITE); diff -Nru a/arch/i386/defconfig b/arch/i386/defconfig --- a/arch/i386/defconfig Tue Feb 26 11:57:57 2002 +++ b/arch/i386/defconfig Tue Feb 26 11:57:57 2002 @@ -121,7 +121,18 @@ # # Parallel port support # -# CONFIG_PARPORT is not set +CONFIG_PARPORT=y +CONFIG_PARPORT_PC=y +CONFIG_PARPORT_PC_CML1=y +# CONFIG_PARPORT_SERIAL is not set +# CONFIG_PARPORT_PC_PCMCIA is not set +# CONFIG_PARPORT_AMIGA is not set +# CONFIG_PARPORT_MFC3 is not set +# CONFIG_PARPORT_ATARI is not set +# CONFIG_PARPORT_GSC is not set +# CONFIG_PARPORT_SUNBPP is not set +# CONFIG_PARPORT_OTHER is not set +CONFIG_PARPORT_1284=y # # Plug and Play configuration @@ -333,6 +344,8 @@ # CONFIG_SCSI_IPS is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_PPA is not set +# CONFIG_SCSI_IMM is not set # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_SYM53C8XX_2 is not set @@ -454,6 +467,7 @@ # # CONFIG_ACENIC is not set # CONFIG_DL2K is not set +# CONFIG_E1000 is not set # CONFIG_MYRI_SBUS is not set # CONFIG_NS83820 is not set # CONFIG_HAMACHI is not set @@ -550,6 +564,9 @@ # CONFIG_SERIAL_NONSTANDARD is not set CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 +CONFIG_PRINTER=y +# CONFIG_LP_CONSOLE is not set +# CONFIG_PPDEV is not set # # I2C support @@ -718,11 +735,19 @@ CONFIG_SND_PCM_OSS=y CONFIG_SND_SEQUENCER_OSS=y # CONFIG_SND_DEBUG is not set + +# +# Generic devices +# # CONFIG_SND_DUMMY is not set # CONFIG_SND_VIRMIDI is not set # CONFIG_SND_MTPAV is not set # CONFIG_SND_SERIAL_U16550 is not set # CONFIG_SND_MPU401 is not set + +# +# ISA devices +# # CONFIG_SND_AD1816A is not set # CONFIG_SND_AD1848 is not set # CONFIG_SND_CS4231 is not set @@ -749,6 +774,10 @@ # CONFIG_SND_DT0197H is not set # CONFIG_SND_OPL3SA2 is not set # CONFIG_SND_SGALAXY is not set + +# +# PCI devices +# # CONFIG_SND_ALI5451 is not set # CONFIG_SND_CS46XX is not set # CONFIG_SND_EMU10K1 is not set diff -Nru a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c --- a/arch/i386/kernel/apic.c Tue Feb 26 11:57:59 2002 +++ b/arch/i386/kernel/apic.c Tue Feb 26 11:57:59 2002 @@ -582,12 +582,17 @@ * Detect and enable local APICs on non-SMP boards. * Original code written by Keir Fraser. */ +int dont_enable_local_apic __initdata = 0; static int __init detect_init_APIC (void) { u32 h, l, features; extern void get_cpu_vendor(struct cpuinfo_x86*); + /* Disabled by DMI scan or kernel option? */ + if (dont_enable_local_apic) + return -1; + /* Workaround for us being called before identify_cpu(). */ get_cpu_vendor(&boot_cpu_data); @@ -903,8 +908,14 @@ static unsigned int calibration_result; +int dont_use_local_apic_timer __initdata = 0; + void __init setup_APIC_clocks (void) { + /* Disabled by DMI scan or kernel option? */ + if (dont_use_local_apic_timer) + return; + printk("Using local APIC timer interrupts.\n"); using_apic_timer = 1; diff -Nru a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c --- a/arch/i386/kernel/dmi_scan.c Tue Feb 26 11:57:59 2002 +++ b/arch/i386/kernel/dmi_scan.c Tue Feb 26 11:57:59 2002 @@ -9,6 +9,7 @@ #include #include #include +#include unsigned long dmi_broken; int is_sony_vaio_laptop; @@ -51,7 +52,7 @@ u8 *data; int i=1; - buf = ioremap(base, len); + buf = bt_ioremap(base, len); if(buf==NULL) return -1; @@ -83,7 +84,7 @@ data+=2; i++; } - iounmap(buf); + bt_iounmap(buf, len); return 0; } @@ -155,7 +156,7 @@ return; if (dmi_ident[slot]) return; - dmi_ident[slot] = kmalloc(strlen(p)+1, GFP_KERNEL); + dmi_ident[slot] = alloc_bootmem(strlen(p)+1); if(dmi_ident[slot]) strcpy(dmi_ident[slot], p); else @@ -416,6 +417,43 @@ return 0; } +/* + * Some machines, usually laptops, can't handle an enabled local APIC. + * The symptoms include hangs or reboots when suspending or resuming, + * attaching or detaching the power cord, or entering BIOS setup screens + * through magic key sequences. + */ +static int __init local_apic_kills_bios(struct dmi_blacklist *d) +{ +#ifdef CONFIG_X86_LOCAL_APIC + extern int dont_enable_local_apic; + if (!dont_enable_local_apic) { + dont_enable_local_apic = 1; + printk(KERN_WARNING "%s with broken BIOS detected. " + "Refusing to enable the local APIC.\n", + d->ident); + } +#endif + return 0; +} + +/* + * The Intel AL440LX mainboard will hang randomly if the local APIC + * timer is running and the APM BIOS hasn't been disabled. + */ +static int __init apm_kills_local_apic_timer(struct dmi_blacklist *d) +{ +#ifdef CONFIG_X86_LOCAL_APIC + extern int dont_use_local_apic_timer; + if (apm_info.bios.version && !dont_use_local_apic_timer) { + dont_use_local_apic_timer = 1; + printk(KERN_WARNING "%s with broken BIOS detected. " + "The local APIC timer will not be used.\n", + d->ident); + } +#endif + return 0; +} /* * Simple "print if true" callback @@ -560,6 +598,25 @@ MATCH(DMI_BIOS_DATE, "09/12/00"), NO_MATCH } }, + /* Machines which have problems handling enabled local APICs */ + + { local_apic_kills_bios, "Dell Inspiron", { + MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), + MATCH(DMI_PRODUCT_NAME, "Inspiron"), + NO_MATCH, NO_MATCH + } }, + + { local_apic_kills_bios, "Dell Latitude", { + MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), + MATCH(DMI_PRODUCT_NAME, "Latitude"), + NO_MATCH, NO_MATCH + } }, + + { apm_kills_local_apic_timer, "Intel AL440LX", { + MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), + MATCH(DMI_BOARD_NAME, "AL440LX"), + NO_MATCH, NO_MATCH } }, + /* Problem Intel 440GX bioses */ { broken_pirq, "SABR1 Bios", { /* Bad $PIR */ @@ -588,7 +645,7 @@ NO_MATCH, NO_MATCH } }, - /* Intel in disgiuse - In this case they can't hide and they don't run + /* Intel in disguise - In this case they can't hide and they don't run too well either... */ { broken_pirq, "Dell PowerEdge 8450", { /* Bad $PIR */ MATCH(DMI_PRODUCT_NAME, "Dell PowerEdge 8450"), @@ -728,12 +785,9 @@ } } -static int __init dmi_scan_machine(void) +void __init dmi_scan_machine(void) { int err = dmi_iterate(dmi_decode); if(err == 0) dmi_check_blacklist(); - return err; } - -module_init(dmi_scan_machine); diff -Nru a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c --- a/arch/i386/kernel/i8259.c Tue Feb 26 11:58:00 2002 +++ b/arch/i386/kernel/i8259.c Tue Feb 26 11:58:00 2002 @@ -79,7 +79,6 @@ * through the ICC by us (IPIs) */ #ifdef CONFIG_SMP -BUILD_SMP_INTERRUPT(task_migration_interrupt,TASK_MIGRATION_VECTOR) BUILD_SMP_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR) BUILD_SMP_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR) BUILD_SMP_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR) @@ -473,9 +472,6 @@ * IPI, driven by wakeup. */ set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt); - - /* IPI for task migration */ - set_intr_gate(TASK_MIGRATION_VECTOR, task_migration_interrupt); /* IPI for invalidation */ set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt); diff -Nru a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c --- a/arch/i386/kernel/setup.c Tue Feb 26 11:57:59 2002 +++ b/arch/i386/kernel/setup.c Tue Feb 26 11:57:59 2002 @@ -99,8 +99,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -113,6 +113,7 @@ #include #include #include + /* * Machine setup.. */ @@ -158,6 +159,7 @@ unsigned char aux_device_present; extern void mcheck_init(struct cpuinfo_x86 *c); +extern void dmi_scan_machine(void); extern int root_mountflags; extern char _text, _etext, _edata, _end; extern int blk_nohighio; @@ -907,7 +909,6 @@ */ if (smp_found_config) get_smp_config(); - init_apic_mappings(); #endif @@ -959,6 +960,7 @@ conswitchp = &dummy_con; #endif #endif + dmi_scan_machine(); } static int cachesize_override __initdata = -1; diff -Nru a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c --- a/arch/i386/kernel/smp.c Tue Feb 26 11:57:56 2002 +++ b/arch/i386/kernel/smp.c Tue Feb 26 11:57:56 2002 @@ -485,35 +485,6 @@ do_flush_tlb_all_local(); } -static spinlock_t migration_lock = SPIN_LOCK_UNLOCKED; -static task_t *new_task; - -/* - * This function sends a 'task migration' IPI to another CPU. - * Must be called from syscall contexts, with interrupts *enabled*. - */ -void smp_migrate_task(int cpu, task_t *p) -{ - /* - * The target CPU will unlock the migration spinlock: - */ - _raw_spin_lock(&migration_lock); - new_task = p; - send_IPI_mask(1 << cpu, TASK_MIGRATION_VECTOR); -} - -/* - * Task migration callback. - */ -asmlinkage void smp_task_migration_interrupt(void) -{ - task_t *p; - - ack_APIC_irq(); - p = new_task; - _raw_spin_unlock(&migration_lock); - sched_task_migrated(p); -} /* * this function sends a 'reschedule' IPI to another CPU. * it goes straight through and wastes no time serializing diff -Nru a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c --- a/arch/i386/kernel/traps.c Tue Feb 26 11:57:57 2002 +++ b/arch/i386/kernel/traps.c Tue Feb 26 11:57:57 2002 @@ -974,6 +974,10 @@ EISA_bus = 1; #endif +#ifdef CONFIG_X86_LOCAL_APIC + init_apic_mappings(); +#endif + set_trap_gate(0,÷_error); set_trap_gate(1,&debug); set_intr_gate(2,&nmi); diff -Nru a/arch/i386/mm/init.c b/arch/i386/mm/init.c --- a/arch/i386/mm/init.c Tue Feb 26 11:57:58 2002 +++ b/arch/i386/mm/init.c Tue Feb 26 11:57:58 2002 @@ -105,7 +105,6 @@ static inline void set_pte_phys (unsigned long vaddr, unsigned long phys, pgprot_t flags) { - pgprot_t prot; pgd_t *pgd; pmd_t *pmd; pte_t *pte; @@ -121,10 +120,8 @@ return; } pte = pte_offset_kernel(pmd, vaddr); - if (pte_val(*pte)) - pte_ERROR(*pte); - pgprot_val(prot) = pgprot_val(PAGE_KERNEL) | pgprot_val(flags); - set_pte(pte, mk_pte_phys(phys, prot)); + /* stored as-is, to permit clearing entries */ + set_pte(pte, mk_pte_phys(phys, flags)); /* * It's enough to flush this one mapping. diff -Nru a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c --- a/arch/i386/mm/ioremap.c Tue Feb 26 11:57:58 2002 +++ b/arch/i386/mm/ioremap.c Tue Feb 26 11:57:58 2002 @@ -161,3 +161,69 @@ if (addr > high_memory) return vfree((void *) (PAGE_MASK & (unsigned long) addr)); } + +#include +void __init *bt_ioremap(unsigned long phys_addr, unsigned long size) +{ + unsigned long offset, last_addr; + unsigned int nrpages; + enum fixed_addresses idx; + + /* Don't allow wraparound or zero size */ + last_addr = phys_addr + size - 1; + if (!size || last_addr < phys_addr) + return NULL; + + /* + * Don't remap the low PCI/ISA area, it's always mapped.. + */ + if (phys_addr >= 0xA0000 && last_addr < 0x100000) + return phys_to_virt(phys_addr); + + /* + * Mappings have to be page-aligned + */ + offset = phys_addr & ~PAGE_MASK; + phys_addr &= PAGE_MASK; + size = PAGE_ALIGN(last_addr) - phys_addr; + + /* + * Mappings have to fit in the FIX_BTMAP area. + */ + nrpages = size >> PAGE_SHIFT; + if (nrpages > NR_FIX_BTMAPS) + return NULL; + + /* + * Ok, go for it.. + */ + idx = FIX_BTMAP_BEGIN; + while (nrpages > 0) { + set_fixmap(idx, phys_addr); + phys_addr += PAGE_SIZE; + --idx; + --nrpages; + } + return (void*) (offset + fix_to_virt(FIX_BTMAP_BEGIN)); +} + +void __init bt_iounmap(void *addr, unsigned long size) +{ + unsigned long virt_addr; + unsigned long offset; + unsigned int nrpages; + enum fixed_addresses idx; + + virt_addr = (unsigned long)addr; + if (virt_addr < fix_to_virt(FIX_BTMAP_BEGIN)) + return; + offset = virt_addr & ~PAGE_MASK; + nrpages = PAGE_ALIGN(offset + size - 1) >> PAGE_SHIFT; + + idx = FIX_BTMAP_BEGIN; + while (nrpages > 0) { + __set_fixmap(idx, 0, __pgprot(0)); + --idx; + --nrpages; + } +} diff -Nru a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c --- a/arch/ia64/kernel/perfmon.c Tue Feb 26 11:57:59 2002 +++ b/arch/ia64/kernel/perfmon.c Tue Feb 26 11:57:59 2002 @@ -332,35 +332,8 @@ return ia64_get_itc(); } -/* Given PGD from the address space's page table, return the kernel - * virtual mapping of the physical memory mapped at ADR. - */ -static inline unsigned long -uvirt_to_kva(pgd_t *pgd, unsigned long adr) -{ - unsigned long ret = 0UL; - pmd_t *pmd; - pte_t *ptep, pte; - - if (!pgd_none(*pgd)) { - pmd = pmd_offset(pgd, adr); - if (!pmd_none(*pmd)) { - ptep = pte_offset(pmd, adr); - pte = *ptep; - if (pte_present(pte)) { - ret = (unsigned long) page_address(pte_page(pte)); - ret |= (adr & (PAGE_SIZE - 1)); - } - } - } - DBprintk(("uv2kva(%lx-->%lx)\n", adr, ret)); - return ret; -} - - /* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa(unsigned long adr) @@ -374,19 +347,15 @@ rvmalloc(unsigned long size) { void *mem; - unsigned long adr, page; + unsigned long adr; - /* XXX: may have to revisit this part because - * vmalloc() does not necessarily return a page-aligned buffer. - * This maybe a security problem when mapped at user level - */ + size=PAGE_ALIGN(size); mem=vmalloc(size); if (mem) { memset(mem, 0, size); /* Clear the ram out, no junk to the user */ adr=(unsigned long) mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -397,13 +366,12 @@ static void rvfree(void *mem, unsigned long size) { - unsigned long adr, page; + unsigned long adr; if (mem) { adr=(unsigned long) mem; - while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -515,7 +483,6 @@ vma->vm_file = NULL; vma->vm_raend = 0; - /* XXX: see rvmalloc() for page alignment problem */ smpl_buf = rvmalloc(size); if (smpl_buf == NULL) goto no_buffer; diff -Nru a/drivers/Makefile b/drivers/Makefile --- a/drivers/Makefile Tue Feb 26 11:57:58 2002 +++ b/drivers/Makefile Tue Feb 26 11:57:58 2002 @@ -1,7 +1,7 @@ # # Makefile for the Linux kernel device drivers. # -# 15 Sep 2000, Christoph Hellwig +# 15 Sep 2000, Christoph Hellwig # Rewritten to use lists instead of if-statements. # diff -Nru a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c --- a/drivers/acorn/block/mfmhd.c Tue Feb 26 11:57:57 2002 +++ b/drivers/acorn/block/mfmhd.c Tue Feb 26 11:57:57 2002 @@ -321,14 +321,14 @@ unsigned long flags; va_list ap; - save_flags_cli(flags); + local_irq_save(flags); va_start(ap, fmt); vsprintf(buffer, fmt, ap); console_print(buffer); va_end(fmt); - restore_flags(flags); + local_irq_restore(flags); }; /* console_printf */ #define DBG(x...) console_printf(x) @@ -746,7 +746,7 @@ /* Yep - a partial access */ /* and issue the remainder */ - issue_request(MINOR(CURRENT->rq_dev), PartFragRead_RestartBlock, PartFragRead_SectorsLeft, CURRENT); + issue_request(minor(CURRENT->rq_dev), PartFragRead_RestartBlock, PartFragRead_SectorsLeft, CURRENT); return; } @@ -929,7 +929,7 @@ DBG("mfm_request: before arg extraction\n"); - dev = MINOR(CURRENT->rq_dev); + dev = minor(CURRENT->rq_dev); block = CURRENT->sector; nsect = CURRENT->nr_sectors; #ifdef DEBUG @@ -1187,10 +1187,10 @@ if (!inode || !(dev = inode->i_rdev)) return -EINVAL; - major = MAJOR(dev); - minor = MINOR(dev); + major = major(dev); + minor = minor(dev); - device = DEVICE_NR(MINOR(inode->i_rdev)), err; + device = DEVICE_NR(minor(inode->i_rdev)), err; if (device >= mfm_drives) return -EINVAL; @@ -1231,7 +1231,7 @@ static int mfm_open(struct inode *inode, struct file *file) { - int dev = DEVICE_NR(MINOR(inode->i_rdev)); + int dev = DEVICE_NR(minor(inode->i_rdev)); if (dev >= mfm_drives) return -ENODEV; @@ -1249,7 +1249,7 @@ */ static int mfm_release(struct inode *inode, struct file *file) { - mfm_info[DEVICE_NR(MINOR(inode->i_rdev))].access_count--; + mfm_info[DEVICE_NR(minor(inode->i_rdev))].access_count--; return 0; } @@ -1270,7 +1270,7 @@ void xd_set_geometry(kdev_t dev, unsigned char secsptrack, unsigned char heads, unsigned long discsize, unsigned int secsize) { - int drive = MINOR(dev) >> 6; + int drive = minor(dev) >> 6; if (mfm_info[drive].cylinders == 1) { mfm_info[drive].sectors = secsptrack; @@ -1338,7 +1338,7 @@ for (i = 0; i < mfm_drives; i++) { mfm_geometry (i); - register_disk(&mfm_gendisk, MKDEV(MAJOR_NR,i<<6), 1<<6, + register_disk(&mfm_gendisk, mk_kdev(MAJOR_NR,i<<6), 1<<6, &mfm_fops, mfm_info[i].cylinders * mfm_info[i].heads * mfm_info[i].sectors / 2); @@ -1448,23 +1448,23 @@ */ static int mfm_reread_partitions(kdev_t dev) { - unsigned int start, i, maxp, target = DEVICE_NR(MINOR(dev)); + unsigned int start, i, maxp, target = DEVICE_NR(minor(dev)); unsigned long flags; - save_flags_cli(flags); + local_irq_save(flags); if (mfm_info[target].busy || mfm_info[target].access_count > 1) { - restore_flags (flags); + local_irq_restore (flags); return -EBUSY; } mfm_info[target].busy = 1; - restore_flags (flags); + local_irq_restore (flags); maxp = 1 << mfm_gendisk.minor_shift; start = target << mfm_gendisk.minor_shift; for (i = maxp - 1; i >= 0; i--) { int minor = start + i; - invalidate_device (MKDEV(MAJOR_NR, minor), 1); + invalidate_device (mk_kdev(MAJOR_NR, minor), 1); mfm_gendisk.part[minor].start_sect = 0; mfm_gendisk.part[minor].nr_sects = 0; } diff -Nru a/drivers/acorn/char/mouse_ps2.c b/drivers/acorn/char/mouse_ps2.c --- a/drivers/acorn/char/mouse_ps2.c Tue Feb 26 11:57:58 2002 +++ b/drivers/acorn/char/mouse_ps2.c Tue Feb 26 11:57:58 2002 @@ -1,8 +1,6 @@ /* * Driver for PS/2 mouse on IOMD interface */ - -#include #include #include #include diff -Nru a/drivers/acorn/net/ether1.c b/drivers/acorn/net/ether1.c --- a/drivers/acorn/net/ether1.c Tue Feb 26 11:57:56 2002 +++ b/drivers/acorn/net/ether1.c Tue Feb 26 11:57:56 2002 @@ -99,13 +99,13 @@ unsigned long flags; unsigned short ret; - if (svflgs) { - save_flags_cli (flags); - } + if (svflgs) + local_irq_save (flags); + outb (addr >> 12, REG_PAGE); ret = inw (ETHER1_RAM + ((addr & 4095) >> 1)); if (svflgs) - restore_flags (flags); + local_irq_restore (flags); return ret; } @@ -114,13 +114,13 @@ { unsigned long flags; - if (svflgs) { - save_flags_cli (flags); - } + if (svflgs) + local_irq_save (flags); + outb (addr >> 12, REG_PAGE); outw (val, ETHER1_RAM + ((addr & 4095) >> 1)); if (svflgs) - restore_flags (flags); + local_irq_restore (flags); } /* @@ -722,7 +722,7 @@ nop.nop_command = CMD_NOP; nop.nop_link = nopaddr; - save_flags_cli(flags); + local_irq_save(flags); ether1_writebuffer (dev, &tx, txaddr, TX_SIZE); ether1_writebuffer (dev, &tbd, tbdaddr, TBD_SIZE); ether1_writebuffer (dev, skb->data, dataddr, len); @@ -733,7 +733,7 @@ /* now reset the previous nop pointer */ ether1_outw (dev, txaddr, tmp, nop_t, nop_link, NORMALIRQS); - restore_flags(flags); + local_irq_restore(flags); /* handle transmit */ dev->trans_start = jiffies; diff -Nru a/drivers/acorn/net/ether3.c b/drivers/acorn/net/ether3.c --- a/drivers/acorn/net/ether3.c Tue Feb 26 11:57:59 2002 +++ b/drivers/acorn/net/ether3.c Tue Feb 26 11:57:59 2002 @@ -491,7 +491,7 @@ del_timer(&priv->timer); - save_flags_cli(flags); + local_irq_save(flags); printk(KERN_ERR "%s: transmit timed out, network cable problem?\n", dev->name); printk(KERN_ERR "%s: state: { status=%04X cfg1=%04X cfg2=%04X }\n", dev->name, ether3_inw(REG_STATUS), ether3_inw(REG_CONFIG1), ether3_inw(REG_CONFIG2)); @@ -501,7 +501,7 @@ priv->tx_head, priv->tx_tail); ether3_setbuffer(dev, buffer_read, priv->tx_tail); printk(KERN_ERR "%s: packet status = %08X\n", dev->name, ether3_readlong(dev)); - restore_flags(flags); + local_irq_restore(flags); priv->regs.config2 |= CFG2_CTRLO; priv->stats.tx_errors += 1; @@ -533,10 +533,10 @@ next_ptr = (priv->tx_head + 1) & 15; - save_flags_cli(flags); + local_irq_save(flags); if (priv->tx_tail == next_ptr) { - restore_flags(flags); + local_irq_restore(flags); return 1; /* unable to queue */ } @@ -565,7 +565,7 @@ } next_ptr = (priv->tx_head + 1) & 15; - restore_flags(flags); + local_irq_restore(flags); dev_kfree_skb(skb); diff -Nru a/drivers/atm/eni.c b/drivers/atm/eni.c --- a/drivers/atm/eni.c Tue Feb 26 11:57:58 2002 +++ b/drivers/atm/eni.c Tue Feb 26 11:57:58 2002 @@ -2310,7 +2310,7 @@ name: DEV_LABEL, id_table: eni_pci_tbl, probe: eni_init_one, - remove: eni_remove_one, + remove: __devexit_p(eni_remove_one), }; diff -Nru a/drivers/atm/firestream.c b/drivers/atm/firestream.c --- a/drivers/atm/firestream.c Tue Feb 26 11:57:57 2002 +++ b/drivers/atm/firestream.c Tue Feb 26 11:57:57 2002 @@ -1530,7 +1530,7 @@ fs_dprintk (FS_DEBUG_QUEUE, "Added %d entries. \n", n); } -static void __exit free_queue (struct fs_dev *dev, struct queue *txq) +static void __devexit free_queue (struct fs_dev *dev, struct queue *txq) { func_enter (); @@ -1546,7 +1546,7 @@ func_exit (); } -static void __exit free_freepool (struct fs_dev *dev, struct freepool *fp) +static void __devexit free_freepool (struct fs_dev *dev, struct freepool *fp) { func_enter (); @@ -2088,7 +2088,7 @@ #endif */ -const static struct pci_device_id firestream_pci_tbl[] __devinitdata = { +static struct pci_device_id firestream_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_FUJITSU_ME, PCI_DEVICE_ID_FUJITSU_FS50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FS_IS50}, { PCI_VENDOR_ID_FUJITSU_ME, PCI_DEVICE_ID_FUJITSU_FS155, @@ -2102,7 +2102,7 @@ name: "firestream", id_table: firestream_pci_tbl, probe: firestream_init_one, - remove: firestream_remove_one, + remove: __devexit_p(firestream_remove_one), }; static int __init firestream_init_module (void) diff -Nru a/drivers/block/DAC960.h b/drivers/block/DAC960.h --- a/drivers/block/DAC960.h Tue Feb 26 11:58:00 2002 +++ b/drivers/block/DAC960.h Tue Feb 26 11:58:00 2002 @@ -2074,7 +2074,7 @@ #define DAC960_KernelDevice(ControllerNumber, \ LogicalDriveNumber, \ PartitionNumber) \ - MKDEV(DAC960_MajorNumber(ControllerNumber), \ + mk_kdev(DAC960_MajorNumber(ControllerNumber), \ DAC960_MinorNumber(LogicalDriveNumber, PartitionNumber)) diff -Nru a/drivers/block/Makefile b/drivers/block/Makefile --- a/drivers/block/Makefile Tue Feb 26 11:58:00 2002 +++ b/drivers/block/Makefile Tue Feb 26 11:58:00 2002 @@ -1,7 +1,7 @@ # # Makefile for the kernel block device drivers. # -# 12 June 2000, Christoph Hellwig +# 12 June 2000, Christoph Hellwig # Rewritten to use lists instead of if-statements. # # Note : at this point, these files are compiled on all systems. diff -Nru a/drivers/block/acsi.c b/drivers/block/acsi.c --- a/drivers/block/acsi.c Tue Feb 26 11:57:59 2002 +++ b/drivers/block/acsi.c Tue Feb 26 11:57:59 2002 @@ -784,7 +784,7 @@ status = acsi_getstatus(); if (status != 0) { - int dev = DEVICE_NR(MINOR(CURRENT->rq_dev)); + int dev = DEVICE_NR(minor(CURRENT->rq_dev)); printk( KERN_ERR "ad%c: ", dev+'a' ); if (!acsi_reqsense( acsi_buffer, acsi_info[dev].target, acsi_info[dev].lun)) @@ -815,7 +815,7 @@ status = acsi_getstatus(); if (status != 0) { - int dev = DEVICE_NR(MINOR(CURRENT->rq_dev)); + int dev = DEVICE_NR(minor(CURRENT->rq_dev)); printk( KERN_ERR "ad%c: ", dev+'a' ); if (!acsi_reqsense( acsi_buffer, acsi_info[dev].target, acsi_info[dev].lun)) @@ -993,7 +993,7 @@ panic(DEVICE_NAME ": block not locked"); } - dev = MINOR(CURRENT->rq_dev); + dev = minor(CURRENT->rq_dev); block = CURRENT->sector; if (DEVICE_NR(dev) >= NDevices || block+CURRENT->nr_sectors >= acsi_part[dev].nr_sects) { @@ -1111,7 +1111,7 @@ if (!inode) return -EINVAL; - dev = DEVICE_NR(MINOR(inode->i_rdev)); + dev = DEVICE_NR(minor(inode->i_rdev)); if (dev >= NDevices) return -EINVAL; switch (cmd) { @@ -1174,7 +1174,7 @@ int device; struct acsi_info_struct *aip; - device = DEVICE_NR(MINOR(inode->i_rdev)); + device = DEVICE_NR(minor(inode->i_rdev)); if (device >= NDevices) return -ENXIO; aip = &acsi_info[device]; @@ -1212,7 +1212,7 @@ static int acsi_release( struct inode * inode, struct file * file ) { - int device = DEVICE_NR(MINOR(inode->i_rdev)); + int device = DEVICE_NR(minor(inode->i_rdev)); if (--access_count[device] == 0 && acsi_info[device].removable) acsi_prevent_removal(device, 0); return( 0 ); @@ -1240,7 +1240,7 @@ static int acsi_media_change (dev_t dev) { - int device = DEVICE_NR(MINOR(dev)); + int device = DEVICE_NR(minor(dev)); struct acsi_info_struct *aip; aip = &acsi_info[device]; @@ -1742,7 +1742,7 @@ acsi_blocksizes[i] = 1024; blksize_size[MAJOR_NR] = acsi_blocksizes; for( i = 0; i < NDevices; ++i ) - register_disk(&acsi_gendisk, MKDEV(MAJOR_NR,i<<4), + register_disk(&acsi_gendisk, mk_kdev(MAJOR_NR,i<<4), (acsi_info[i].type==HARDDISK)?1<<4:1, &acsi_fops, acsi_info[i].size); @@ -1853,7 +1853,7 @@ int res; struct acsi_info_struct *aip; - device = DEVICE_NR(MINOR(dev)); + device = DEVICE_NR(minor(dev)); aip = &acsi_info[device]; gdev = &GENDISK_STRUCT; diff -Nru a/drivers/block/ataflop.c b/drivers/block/ataflop.c --- a/drivers/block/ataflop.c Tue Feb 26 11:57:57 2002 +++ b/drivers/block/ataflop.c Tue Feb 26 11:57:57 2002 @@ -659,7 +659,7 @@ unsigned char *p; int sect, nsect; unsigned long flags; - int type, drive = MINOR(device) & 3; + int type, drive = minor(device) & 3; DPRINT(("do_format( dr=%d tr=%d he=%d offs=%d )\n", drive, desc->track, desc->head, desc->sect_offset )); @@ -672,7 +672,7 @@ atari_turnon_irq( IRQ_MFP_FDC ); /* should be already, just to be sure */ restore_flags(flags); - type = MINOR(device) >> 2; + type = minor(device) >> 2; if (type) { if (--type >= NUM_DISK_MINORS || minor2disktype[type].drive_types > DriveType) { @@ -1367,9 +1367,9 @@ static int check_floppy_change (kdev_t dev) { - unsigned int drive = MINOR(dev) & 0x03; + unsigned int drive = minor(dev) & 0x03; - if (MAJOR(dev) != MAJOR_NR) { + if (major(dev) != MAJOR_NR) { printk(KERN_ERR "floppy_changed: not a floppy\n"); return 0; } @@ -1394,7 +1394,7 @@ static int floppy_revalidate (kdev_t dev) { - int drive = MINOR(dev) & 3; + int drive = minor(dev) & 3; if (test_bit(drive, &changed_floppies) || test_bit(drive, &fake_change) || @@ -1466,13 +1466,13 @@ if (QUEUE_EMPTY) goto the_end; - if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) + if (major(CURRENT->rq_dev) != MAJOR_NR) panic(DEVICE_NAME ": request list destroyed"); if (CURRENT->bh && !buffer_locked(CURRENT->bh)) panic(DEVICE_NAME ": block not locked"); - device = MINOR(CURRENT_DEVICE); + device = minor(CURRENT_DEVICE); drive = device & 3; type = device >> 2; @@ -1553,7 +1553,7 @@ { /* invalidate the buffer track to force a reread */ BufferDrive = -1; - set_bit(MINOR(rdev) & 3, &fake_change); + set_bit(minor(rdev) & 3, &fake_change); check_disk_change(rdev); return 0; } @@ -1576,7 +1576,7 @@ case BLKFLSBUF: return blk_ioctl(device, cmd, param); } - drive = MINOR (device); + drive = minor (device); type = drive >> 2; drive &= 3; switch (cmd) { @@ -1896,15 +1896,15 @@ return -EIO; } - drive = MINOR(inode->i_rdev) & 3; - type = MINOR(inode->i_rdev) >> 2; + drive = minor(inode->i_rdev) & 3; + type = minor(inode->i_rdev) >> 2; DPRINT(("fd_open: type=%d\n",type)); if (drive >= FD_MAX_UNITS || type > NUM_DISK_MINORS) return -ENXIO; old_dev = fd_device[drive]; - if (fd_ref[drive] && old_dev != MINOR(inode->i_rdev)) + if (fd_ref[drive] && old_dev != minor(inode->i_rdev)) return -EBUSY; if (fd_ref[drive] == -1 || (fd_ref[drive] && filp->f_flags & O_EXCL)) @@ -1915,10 +1915,10 @@ else fd_ref[drive]++; - fd_device[drive] = MINOR(inode->i_rdev); + fd_device[drive] = minor(inode->i_rdev); - if (old_dev && old_dev != MINOR(inode->i_rdev)) - invalidate_buffers(MKDEV(FLOPPY_MAJOR, old_dev)); + if (old_dev && old_dev != minor(inode->i_rdev)) + invalidate_buffers(mk_kdev(FLOPPY_MAJOR, old_dev)); if (filp->f_flags & O_NDELAY) return 0; @@ -1939,7 +1939,7 @@ static int floppy_release( struct inode * inode, struct file * filp ) { - int drive = MINOR(inode->i_rdev) & 3; + int drive = minor(inode->i_rdev) & 3; if (fd_ref[drive] < 0) fd_ref[drive] = 0; diff -Nru a/drivers/block/cciss.c b/drivers/block/cciss.c --- a/drivers/block/cciss.c Tue Feb 26 11:58:00 2002 +++ b/drivers/block/cciss.c Tue Feb 26 11:58:00 2002 @@ -2617,7 +2617,7 @@ static struct pci_driver cciss_pci_driver = { name: "cciss", probe: cciss_init_one, - remove: cciss_remove_one, + remove: __devexit_p(cciss_remove_one), id_table: cciss_pci_device_id, /* id_table */ }; diff -Nru a/drivers/block/rd.c b/drivers/block/rd.c --- a/drivers/block/rd.c Tue Feb 26 11:57:56 2002 +++ b/drivers/block/rd.c Tue Feb 26 11:57:56 2002 @@ -268,7 +268,7 @@ goto fail; set_bit(BIO_UPTODATE, &sbh->bi_flags); - sbh->bi_end_io(sbh, len >> 9); + sbh->bi_end_io(sbh); return 0; fail: bio_io_error(sbh); diff -Nru a/drivers/char/Makefile b/drivers/char/Makefile --- a/drivers/char/Makefile Tue Feb 26 11:57:59 2002 +++ b/drivers/char/Makefile Tue Feb 26 11:57:59 2002 @@ -23,7 +23,7 @@ export-objs := busmouse.o console.o keyboard.o sysrq.o \ misc.o pty.o random.o selection.o serial.o \ - sonypi.o tty_io.o tty_ioctl.o generic_serial.o + sonypi.o tty_io.o tty_ioctl.o generic_serial.o rtc.o mod-subdirs := ftape drm pcmcia diff -Nru a/drivers/char/drm/drm_scatter.h b/drivers/char/drm/drm_scatter.h --- a/drivers/char/drm/drm_scatter.h Tue Feb 26 11:57:56 2002 +++ b/drivers/char/drm/drm_scatter.h Tue Feb 26 11:57:56 2002 @@ -66,9 +66,6 @@ drm_scatter_gather_t request; drm_sg_mem_t *entry; unsigned long pages, i, j; - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte, pte_entry; DRM_DEBUG( "%s\n", __FUNCTION__ ); @@ -135,25 +132,9 @@ DRM_DEBUG( "sg alloc virtual = %p\n", entry->virtual ); for ( i = entry->handle, j = 0 ; j < pages ; i += PAGE_SIZE, j++ ) { - pgd = pgd_offset_k( i ); - if ( !pgd_present( *pgd ) ) + entry->pagelist[j] = vmalloc_to_page((void *)i); + if (!entry->pagelist[j]) goto failed; - - pmd = pmd_offset( pgd, i ); - if ( !pmd_present( *pmd ) ) - goto failed; - - preempt_disable(); - pte = pte_offset_map(pmd, i); - pte_entry = *pte; - pte_unmap(pte); - preempt_enable(); - - if (!pte_present(pte_entry)) - goto failed; - - entry->pagelist[j] = pte_page(pte_entry); - SetPageReserved(entry->pagelist[j]); } diff -Nru a/drivers/char/drm/drm_vm.h b/drivers/char/drm/drm_vm.h --- a/drivers/char/drm/drm_vm.h Tue Feb 26 11:57:59 2002 +++ b/drivers/char/drm/drm_vm.h Tue Feb 26 11:57:59 2002 @@ -152,9 +152,6 @@ #endif unsigned long offset; unsigned long i; - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte, entry; struct page *page; if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */ @@ -162,26 +159,9 @@ offset = address - vma->vm_start; i = (unsigned long)map->handle + offset; - /* We have to walk page tables here because we need large SAREA's, and - * they need to be virtually contiguous in kernel space. - */ - pgd = pgd_offset_k( i ); - if (!pgd_present(*pgd)) - goto oom; - pmd = pmd_offset( pgd, i ); - if (!pmd_present(*pmd)) - goto oom; - - preempt_disable(); - pte = pte_offset_map(pmd, i); - entry = *pte; - pte_unmap(pte); - preempt_enable(); - - if (!pte_present(entry)) - goto oom; - - page = pte_page(entry); + page = vmalloc_to_page((void *)i); + if (!page) + return NOPAGE_OOM; get_page(page); DRM_DEBUG("shm_nopage 0x%lx\n", address); @@ -190,8 +170,6 @@ #else return page; #endif -oom: - return NOPAGE_OOM; } /* Special close routine which deletes map information if we are the last diff -Nru a/drivers/char/mem.c b/drivers/char/mem.c --- a/drivers/char/mem.c Tue Feb 26 11:57:59 2002 +++ b/drivers/char/mem.c Tue Feb 26 11:57:59 2002 @@ -273,6 +273,8 @@ return virtr + read; } +extern long vwrite(char *buf, char *addr, unsigned long count); + /* * This function writes to the *virtual* memory as seen by the kernel. */ @@ -280,12 +282,46 @@ size_t count, loff_t *ppos) { unsigned long p = *ppos; + ssize_t wrote = 0; + ssize_t virtr = 0; + char * kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */ + + if (p < (unsigned long) high_memory) { + wrote = count; + if (count > (unsigned long) high_memory - p) + wrote = (unsigned long) high_memory - p; + + wrote = do_write_mem(file, (void*)p, p, buf, wrote, ppos); + + p += wrote; + buf += wrote; + count -= wrote; + } + + if (count > 0) { + kbuf = (char *)__get_free_page(GFP_KERNEL); + if (!kbuf) + return -ENOMEM; + while (count > 0) { + int len = count; + + if (len > PAGE_SIZE) + len = PAGE_SIZE; + if (len && copy_from_user(kbuf, buf, len)) { + free_page((unsigned long)kbuf); + return -EFAULT; + } + len = vwrite(kbuf, (char *)p, len); + count -= len; + buf += len; + virtr += len; + p += len; + } + free_page((unsigned long)kbuf); + } - if (p >= (unsigned long) high_memory) - return 0; - if (count > (unsigned long) high_memory - p) - count = (unsigned long) high_memory - p; - return do_write_mem(file, (void*)p, p, buf, count, ppos); + *ppos = p; + return virtr + wrote; } #if !defined(__mc68000__) diff -Nru a/drivers/char/mwave/mwavedd.c b/drivers/char/mwave/mwavedd.c --- a/drivers/char/mwave/mwavedd.c Tue Feb 26 11:57:58 2002 +++ b/drivers/char/mwave/mwavedd.c Tue Feb 26 11:57:58 2002 @@ -461,7 +461,7 @@ * mwave_exit is called on module unload * mwave_exit is also used to clean up after an aborted mwave_init */ -static void __exit mwave_exit(void) +static void mwave_exit(void) { pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd; diff -Nru a/drivers/char/rtc.c b/drivers/char/rtc.c --- a/drivers/char/rtc.c Tue Feb 26 11:57:59 2002 +++ b/drivers/char/rtc.c Tue Feb 26 11:57:59 2002 @@ -41,9 +41,11 @@ * 1.10c Cesar Barros: SMP locking fixes and cleanup * 1.10d Paul Gortmaker: delete paranoia check in rtc_exit * 1.10e Maciej W. Rozycki: Handle DECstation's year weirdness. + * 1.11 Takashi Iwai: Kernel access functions + * rtc_register/rtc_unregister/rtc_control */ -#define RTC_VERSION "1.10e" +#define RTC_VERSION "1.11" #define RTC_IO_EXTENT 0x10 /* Only really two ports, but... */ @@ -139,6 +141,11 @@ static unsigned long rtc_freq = 0; /* Current periodic IRQ rate */ static unsigned long rtc_irq_data = 0; /* our output to the world */ +#if RTC_IRQ +static spinlock_t rtc_task_lock = SPIN_LOCK_UNLOCKED; +static rtc_task_t *rtc_callback = NULL; +#endif + /* * If this driver ever becomes modularised, it will be really nice * to make the epoch retain its value across module reload... @@ -180,6 +187,10 @@ spin_unlock (&rtc_lock); /* Now do the rest of the actions */ + spin_lock(&rtc_task_lock); + if (rtc_callback) + rtc_callback->func(rtc_callback->private_data); + spin_unlock(&rtc_task_lock); wake_up_interruptible(&rtc_wait); kill_fasync (&rtc_async_queue, SIGIO, POLL_IN); @@ -244,8 +255,7 @@ #endif } -static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) +static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) { struct rtc_time wtime; @@ -295,7 +305,7 @@ * We don't really want Joe User enabling more * than 64Hz of interrupts on a multi-user machine. */ - if ((rtc_freq > 64) && (!capable(CAP_SYS_RESOURCE))) + if (!kernel && (rtc_freq > 64) && (!capable(CAP_SYS_RESOURCE))) return -EACCES; if (!(rtc_status & RTC_TIMER_ON)) { @@ -493,7 +503,7 @@ * We don't really want Joe User generating more * than 64Hz of interrupts on a multi-user machine. */ - if ((arg > 64) && (!capable(CAP_SYS_RESOURCE))) + if (!kernel && (arg > 64) && (!capable(CAP_SYS_RESOURCE))) return -EACCES; while (arg > (1<func == NULL) + return -EINVAL; + spin_lock_irq(&rtc_lock); + if (rtc_status & RTC_IS_OPEN) { + spin_unlock_irq(&rtc_lock); + return -EBUSY; + } + spin_lock(&rtc_task_lock); + if (rtc_callback) { + spin_unlock(&rtc_task_lock); + spin_unlock_irq(&rtc_lock); + return -EBUSY; + } + rtc_status |= RTC_IS_OPEN; + rtc_callback = task; + spin_unlock(&rtc_task_lock); + spin_unlock_irq(&rtc_lock); + return 0; +#endif +} + +int rtc_unregister(rtc_task_t *task) +{ +#if !RTC_IRQ + return -EIO; +#else + unsigned char tmp; + + spin_lock_irq(&rtc_task_lock); + if (rtc_callback != task) { + spin_unlock_irq(&rtc_task_lock); + return -ENXIO; + } + rtc_callback = NULL; + spin_lock(&rtc_lock); + /* disable controls */ + tmp = CMOS_READ(RTC_CONTROL); + tmp &= ~RTC_PIE; + tmp &= ~RTC_AIE; + tmp &= ~RTC_UIE; + CMOS_WRITE(tmp, RTC_CONTROL); + CMOS_READ(RTC_INTR_FLAGS); + if (rtc_status & RTC_TIMER_ON) { + rtc_status &= ~RTC_TIMER_ON; + del_timer(&rtc_irq_timer); + } + rtc_status &= ~RTC_IS_OPEN; + spin_unlock(&rtc_lock); + spin_unlock_irq(&rtc_task_lock); + return 0; +#endif +} + +int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg) +{ +#if !RTC_IRQ + return -EIO; +#else + spin_lock_irq(&rtc_task_lock); + if (rtc_callback != task) { + spin_unlock_irq(&rtc_task_lock); + return -ENXIO; + } + spin_unlock_irq(&rtc_task_lock); + return rtc_do_ioctl(cmd, arg, 1); +#endif +} + + +/* * The various file operations we support. */ @@ -822,7 +917,6 @@ module_init(rtc_init); module_exit(rtc_exit); -EXPORT_NO_SYMBOLS; #if RTC_IRQ /* diff -Nru a/drivers/char/synclink.c b/drivers/char/synclink.c --- a/drivers/char/synclink.c Tue Feb 26 11:57:58 2002 +++ b/drivers/char/synclink.c Tue Feb 26 11:57:58 2002 @@ -941,7 +941,7 @@ name: "synclink", id_table: synclink_pci_tbl, probe: synclink_init_one, - remove: synclink_remove_one, + remove: __devexit_p(synclink_remove_one), }; static struct tty_driver serial_driver, callout_driver; @@ -8220,7 +8220,7 @@ return 0; } -static void __exit synclink_remove_one (struct pci_dev *dev) +static void __devexit synclink_remove_one (struct pci_dev *dev) { } diff -Nru a/drivers/char/wdt_pci.c b/drivers/char/wdt_pci.c --- a/drivers/char/wdt_pci.c Tue Feb 26 11:57:56 2002 +++ b/drivers/char/wdt_pci.c Tue Feb 26 11:57:56 2002 @@ -558,7 +558,7 @@ } -static void __exit wdtpci_remove_one (struct pci_dev *pdev) +static void __devexit wdtpci_remove_one (struct pci_dev *pdev) { /* here we assume only one device will ever have * been picked up and registered by probe function */ @@ -583,7 +583,7 @@ name: "wdt-pci", id_table: wdtpci_pci_tbl, probe: wdtpci_init_one, - remove: wdtpci_remove_one, + remove: __devexit_p(wdtpci_remove_one), }; diff -Nru a/drivers/ide/ataraid.c b/drivers/ide/ataraid.c --- a/drivers/ide/ataraid.c Tue Feb 26 11:57:59 2002 +++ b/drivers/ide/ataraid.c Tue Feb 26 11:57:59 2002 @@ -70,7 +70,7 @@ static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int minor; - minor = MINOR(inode->i_rdev)>>SHIFT; + minor = minor(inode->i_rdev)>>SHIFT; if ((ataraid_ops[minor])&&(ataraid_ops[minor]->ioctl)) return (ataraid_ops[minor]->ioctl)(inode,file,cmd,arg); @@ -80,7 +80,7 @@ static int ataraid_open(struct inode * inode, struct file * filp) { int minor; - minor = MINOR(inode->i_rdev)>>SHIFT; + minor = minor(inode->i_rdev)>>SHIFT; if ((ataraid_ops[minor])&&(ataraid_ops[minor]->open)) return (ataraid_ops[minor]->open)(inode,filp); @@ -91,7 +91,7 @@ static int ataraid_release(struct inode * inode, struct file * filp) { int minor; - minor = MINOR(inode->i_rdev)>>SHIFT; + minor = minor(inode->i_rdev)>>SHIFT; if ((ataraid_ops[minor])&&(ataraid_ops[minor]->release)) return (ataraid_ops[minor]->release)(inode,filp); @@ -102,7 +102,7 @@ { int minor; int retval; - minor = MINOR(bh->b_rdev)>>SHIFT; + minor = minor(bh->b_rdev)>>SHIFT; if ((ataraid_ops[minor])&&(ataraid_ops[minor]->make_request)) { @@ -229,7 +229,7 @@ void ataraid_register_disk(int device,long size) { - register_disk(&ataraid_gendisk, MKDEV(ATAMAJOR,16*device),16, + register_disk(&ataraid_gendisk, mk_kdev(ATAMAJOR,16*device),16, &ataraid_fops,size); } diff -Nru a/drivers/ide/hd.c b/drivers/ide/hd.c --- a/drivers/ide/hd.c Tue Feb 26 11:57:57 2002 +++ b/drivers/ide/hd.c Tue Feb 26 11:57:57 2002 @@ -558,7 +558,7 @@ reset_hd(); return; } - dev = MINOR(CURRENT->rq_dev); + dev = minor(CURRENT->rq_dev); block = CURRENT->sector; nsect = CURRENT->nr_sectors; if (dev >= (NR_HD<<6) || (dev & 0x3f) || @@ -568,7 +568,7 @@ kdevname(CURRENT->rq_dev)); else printk("hd%c: bad access: block=%d, count=%d\n", - (MINOR(CURRENT->rq_dev)>>6)+'a', block, nsect); + (minor(CURRENT->rq_dev)>>6)+'a', block, nsect); end_request(0); goto repeat; } @@ -626,7 +626,7 @@ struct hd_geometry *loc = (struct hd_geometry *) arg; int dev; - if ((!inode) || !(inode->i_rdev)) + if ((!inode) || kdev_none(inode->i_rdev)) return -EINVAL; dev = DEVICE_NR(inode->i_rdev); if (dev >= NR_HD) @@ -822,7 +822,7 @@ hd_gendisk.nr_real = NR_HD; for(drive=0; drive < NR_HD; drive++) - register_disk(&hd_gendisk, MKDEV(MAJOR_NR,drive<<6), 1<<6, + register_disk(&hd_gendisk, mk_kdev(MAJOR_NR,drive<<6), 1<<6, &hd_fops, hd_info[drive].head * hd_info[drive].sect * hd_info[drive].cyl); } diff -Nru a/drivers/ide/hptraid.c b/drivers/ide/hptraid.c --- a/drivers/ide/hptraid.c Tue Feb 26 11:57:59 2002 +++ b/drivers/ide/hptraid.c Tue Feb 26 11:57:59 2002 @@ -75,16 +75,16 @@ unsigned char val; unsigned long sectors; - if (!inode || !inode->i_rdev) + if (!inode || kdev_none(inode->i_rdev)) return -EINVAL; - minor = MINOR(inode->i_rdev)>>SHIFT; + minor = minor(inode->i_rdev)>>SHIFT; switch (cmd) { case BLKGETSIZE: /* Return device size */ if (!arg) return -EINVAL; - sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects; - if (MINOR(inode->i_rdev)&15) + sectors = ataraid_gendisk.part[minor(inode->i_rdev)].nr_sects; + if (minor(inode->i_rdev)&15) return put_user(sectors, (unsigned long *) arg); return put_user(raid[minor].sectors , (unsigned long *) arg); break; @@ -102,7 +102,7 @@ if (put_user(val, (byte *) &loc->sectors)) return -EFAULT; bios_cyl = raid[minor].sectors/63/255; if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT; - if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect, + if (put_user((unsigned)ataraid_gendisk.part[minor(inode->i_rdev)].start_sect, (unsigned long *) &loc->start)) return -EFAULT; return 0; } @@ -118,7 +118,7 @@ if (put_user(val, (byte *) &loc->sectors)) return -EFAULT; bios_cyl = raid[minor].sectors/63/255; if (put_user(bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT; - if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect, + if (put_user((unsigned)ataraid_gendisk.part[minor(inode->i_rdev)].start_sect, (unsigned long *) &loc->start)) return -EFAULT; return 0; } @@ -167,7 +167,7 @@ /* Partitions need adding of the start sector of the partition to the requested sector */ - rsect += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect; + rsect += ataraid_gendisk.part[minor(bh->b_rdev)].start_sect; /* Woops we need to split the request to avoid crossing a stride barrier */ if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) { @@ -248,7 +248,7 @@ kdev_t dev; ide_drive_t *ideinfo; - dev = MKDEV(major,minor); + dev = mk_kdev(major,minor); ideinfo = get_info_ptr (dev); if (ideinfo==NULL) return 0; @@ -268,7 +268,7 @@ static void __init probedisk(int major, int minor,int device) { int i; - struct block_device *bdev = bdget(MKDEV(major,minor)); + struct block_device *bdev = bdget(mk_kdev(major,minor)); struct gendisk *gd; if (!bdev) @@ -301,14 +301,14 @@ /* now blank the /proc/partitions table for the wrong partition table, so that scripts don't accidentally mount it and crash the kernel */ /* XXX: the 0 is an utter hack --hch */ - gd=get_gendisk(MKDEV(major, 0)); + gd=get_gendisk(mk_kdev(major, 0)); if (gd!=NULL) { int j; for (j=1+(minor<minor_shift);j<((minor+1)<minor_shift);j++) gd->part[j].nr_sects=0; } - raid[device].disk[i].device = MKDEV(major,minor); + raid[device].disk[i].device = mk_kdev(major,minor); raid[device].disk[i].sectors = maxsectors(major,minor); raid[device].stride = (1<i_rdev) + if (!inode || kdev_none(inode->i_rdev)) return -EINVAL; - minor = MINOR(inode->i_rdev)>>SHIFT; + minor = minor(inode->i_rdev)>>SHIFT; switch (cmd) { case BLKGETSIZE: /* Return device size */ if (!arg) return -EINVAL; - sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects; - if (MINOR(inode->i_rdev)&15) + sectors = ataraid_gendisk.part[minor(inode->i_rdev)].nr_sects; + if (minor(inode->i_rdev)&15) return put_user(sectors, (unsigned long *) arg); return put_user(raid[minor].sectors , (unsigned long *) arg); break; @@ -127,7 +127,7 @@ if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT; if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT; if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT; - if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect, + if (put_user((unsigned)ataraid_gendisk.part[minor(inode->i_rdev)].start_sect, (unsigned long *) &loc->start)) return -EFAULT; return 0; } @@ -139,7 +139,7 @@ if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT; if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT; if (put_user(raid[minor].geom.cylinders, (unsigned int *) &loc->cylinders)) return -EFAULT; - if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect, + if (put_user((unsigned)ataraid_gendisk.part[minor(inode->i_rdev)].start_sect, (unsigned long *) &loc->start)) return -EFAULT; return 0; } @@ -463,7 +463,7 @@ major = devlist[devindex].major; minor = devlist[devindex].minor; - bdev = bdget(MKDEV(major,minor)); + bdev = bdget(mk_kdev(major,minor)); if (!bdev) return; @@ -491,7 +491,7 @@ (prom.raid.disk[i].device == prom.raid.device) ) { raid[device].disk[i].bdev = bdev; - raid[device].disk[i].device = MKDEV(major,minor); + raid[device].disk[i].device = mk_kdev(major,minor); raid[device].disk[i].sectors = prom.raid.disk_secs; raid[device].stride = (1< #include #include #include diff -Nru a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c --- a/drivers/ieee1394/dv1394.c Tue Feb 26 11:57:57 2002 +++ b/drivers/ieee1394/dv1394.c Tue Feb 26 11:57:57 2002 @@ -185,78 +185,19 @@ /* Memory management functions */ /*******************************/ -#define MDEBUG(x) do { } while(0) /* Debug memory management */ - -/* [DaveM] I've recoded most of this so that: - * 1) It's easier to tell what is happening - * 2) It's more portable, especially for translating things - * out of vmalloc mapped areas in the kernel. - * 3) Less unnecessary translations happen. - * - * The code used to assume that the kernel vmalloc mappings - * existed in the page tables of every process, this is simply - * not guarenteed. We now use pgd_offset_k which is the - * defined way to get at the kernel page tables. - */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) -#define page_address(x) (x) -#endif - -/* Given PGD from the address space's page table, return the kernel - * virtual mapping of the physical memory mapped at ADR. - */ -static inline struct page *uvirt_to_page(pgd_t *pgd, unsigned long adr) -{ - pmd_t *pmd; - pte_t *ptep, pte; - struct page *ret = NULL; - - if (!pgd_none(*pgd)) { - pmd = pmd_offset(pgd, adr); - if (!pmd_none(*pmd)) { - preempt_disable(); - ptep = pte_offset_map(pmd, adr); - pte = *ptep; - pte_unmap(pte); - preempt_enable(); - if(pte_present(pte)) - ret = pte_page(pte); - } - } - return ret; -} - -/* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved, and for - * handling page faults on the rvmalloc()ed buffer - */ -static inline unsigned long kvirt_to_pa(unsigned long adr) -{ - unsigned long va, kva, ret; - - va = VMALLOC_VMADDR(adr); - kva = (unsigned long) page_address(uvirt_to_page(pgd_offset_k(va), va)); - kva |= adr & (PAGE_SIZE-1); /* restore the offset */ - ret = __pa(kva); - MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); - return ret; -} - static void * rvmalloc(unsigned long size) { void * mem; - unsigned long adr, page; - + unsigned long adr; + + size=PAGE_ALIGN(size); mem=vmalloc_32(size); if (mem) { memset(mem, 0, size); /* Clear the ram out, no junk to the user */ adr=(unsigned long) mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -266,13 +207,12 @@ static void rvfree(void * mem, unsigned long size) { - unsigned long adr, page; - + unsigned long adr; + if (mem) { adr=(unsigned long) mem; - while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -1166,9 +1106,9 @@ /* fill the sglist with the kernel addresses of pages in the non-contiguous buffer */ for(i = 0; i < video->user_dma.n_pages; i++) { - unsigned long va = VMALLOC_VMADDR( (unsigned long) video->user_buf + i * PAGE_SIZE ); + unsigned long va = (unsigned long) video->user_buf + i * PAGE_SIZE; - video->user_dma.sglist[i].page = uvirt_to_page(pgd_offset_k(va), va); + video->user_dma.sglist[i].page = vmalloc_to_page((void *)va); video->user_dma.sglist[i].length = PAGE_SIZE; } @@ -1492,7 +1432,7 @@ static struct page * dv1394_nopage(struct vm_area_struct * area, unsigned long address, int write_access) { unsigned long offset; - unsigned long page, kernel_virt_addr; + unsigned long kernel_virt_addr; struct page *ret = NOPAGE_SIGBUS; struct video_card *video = (struct video_card*) area->vm_private_data; @@ -1510,10 +1450,7 @@ offset = address - area->vm_start; kernel_virt_addr = (unsigned long) video->user_buf + offset; - - page = kvirt_to_pa(kernel_virt_addr); - - ret = virt_to_page(__va(page)); + ret = vmalloc_to_page((void *)kernel_virt_addr); get_page(ret); out: diff -Nru a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c --- a/drivers/ieee1394/video1394.c Tue Feb 26 11:57:57 2002 +++ b/drivers/ieee1394/video1394.c Tue Feb 26 11:57:57 2002 @@ -159,61 +159,35 @@ /* Memory management functions */ /*******************************/ -#define MDEBUG(x) do { } while(0) /* Debug memory management */ - -/* [DaveM] I've recoded most of this so that: - * 1) It's easier to tell what is happening - * 2) It's more portable, especially for translating things - * out of vmalloc mapped areas in the kernel. - * 3) Less unnecessary translations happen. - * - * The code used to assume that the kernel vmalloc mappings - * existed in the page tables of every process, this is simply - * not guaranteed. We now use pgd_offset_k which is the - * defined way to get at the kernel page tables. - */ - -static inline unsigned long uvirt_to_bus(unsigned long adr) -{ - unsigned long kva, ret; - - kva = page_address(vmalloc_to_page(adr)); - ret = virt_to_bus((void *)kva); - MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret)); - return ret; -} - static inline unsigned long kvirt_to_bus(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = page_address(vmalloc_to_page(va)); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ ret = virt_to_bus((void *)kva); - MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret)); return ret; } /* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = page_address(vmalloc_to_page(va)); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ ret = __pa(kva); - MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); return ret; } static void * rvmalloc(unsigned long size) { void * mem; - unsigned long adr, page; - + unsigned long adr; + + size=PAGE_ALIGN(size); mem=vmalloc_32(size); if (mem) { @@ -222,8 +196,7 @@ adr=(unsigned long) mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -233,15 +206,14 @@ static void rvfree(void * mem, unsigned long size) { - unsigned long adr, page; - + unsigned long adr; + if (mem) { adr=(unsigned long) mem; - while (size > 0) + while ((long) size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -1381,7 +1353,7 @@ if (video->current_ctx == NULL) { PRINT(KERN_ERR, ohci->id, "Current iso context not set"); } else - res = do_iso_mmap(ohci, video->current_ctx, + res = do_iso_mmap(vma, ohci, video->current_ctx, (char *)vma->vm_start, (unsigned long)(vma->vm_end-vma->vm_start)); unlock_kernel(); diff -Nru a/drivers/input/gameport/cs461x.c b/drivers/input/gameport/cs461x.c --- a/drivers/input/gameport/cs461x.c Tue Feb 26 11:57:56 2002 +++ b/drivers/input/gameport/cs461x.c Tue Feb 26 11:57:56 2002 @@ -313,7 +313,7 @@ name: "PCI Gameport", id_table: cs461x_pci_tbl, probe: cs461x_pci_probe, - remove: cs461x_pci_remove, + remove: __devexit_p(cs461x_pci_remove), }; int __init js_cs461x_init(void) diff -Nru a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c --- a/drivers/input/gameport/emu10k1-gp.c Tue Feb 26 11:57:59 2002 +++ b/drivers/input/gameport/emu10k1-gp.c Tue Feb 26 11:57:59 2002 @@ -108,7 +108,7 @@ name: "Emu10k1 Gameport", id_table: emu_tbl, probe: emu_probe, - remove: emu_remove, + remove: __devexit_p(emu_remove), }; int __init emu_init(void) diff -Nru a/drivers/input/gameport/pcigame.c b/drivers/input/gameport/pcigame.c --- a/drivers/input/gameport/pcigame.c Tue Feb 26 11:57:57 2002 +++ b/drivers/input/gameport/pcigame.c Tue Feb 26 11:57:57 2002 @@ -180,7 +180,7 @@ name: "pcigame", id_table: pcigame_id_table, probe: pcigame_probe, - remove: pcigame_remove, + remove: __devexit_p(pcigame_remove), }; int __init pcigame_init(void) diff -Nru a/drivers/isdn/Config.help b/drivers/isdn/Config.help --- a/drivers/isdn/Config.help Tue Feb 26 11:57:59 2002 +++ b/drivers/isdn/Config.help Tue Feb 26 11:57:59 2002 @@ -161,6 +161,10 @@ Enable this if you like to use ISDN in US on a NI1 basic rate interface. +CONFIG_HISAX_MAX_CARDS + This option allows you to specify the maximum number of cards which + the HiSax driver will be able to handle. + CONFIG_HISAX_16_0 This enables HiSax support for the Teles ISDN-cards S0-16.0, S0-8 and many compatibles. diff -Nru a/drivers/isdn/Config.in b/drivers/isdn/Config.in --- a/drivers/isdn/Config.in Tue Feb 26 11:57:59 2002 +++ b/drivers/isdn/Config.in Tue Feb 26 11:57:59 2002 @@ -84,6 +84,7 @@ dep_tristate 'ST5481 USB ISDN modem (EXPERIMENTAL)' CONFIG_HISAX_ST5481 $CONFIG_HISAX $CONFIG_USB $CONFIG_EXPERIMENTAL dep_tristate 'AVM Fritz!Card PCI/PCIv2/PnP support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_PCIPNP $CONFIG_HISAX $CONFIG_EXPERIMENTAL dep_tristate 'AVM Fritz!Card classic support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_CLASSIC $CONFIG_HISAX $CONFIG_EXPERIMENTAL + dep_tristate 'HFC PCI support (EXPERIMENTAL)' CONFIG_HISAX_HFCPCI $CONFIG_HISAX $CONFIG_EXPERIMENTAL fi endmenu diff -Nru a/drivers/isdn/avmb1/capi.c b/drivers/isdn/avmb1/capi.c --- a/drivers/isdn/avmb1/capi.c Tue Feb 26 11:58:00 2002 +++ b/drivers/isdn/avmb1/capi.c Tue Feb 26 11:58:00 2002 @@ -1535,7 +1535,7 @@ /* -------- init function and module interface ---------------------- */ -static void __exit alloc_exit(void) +static void alloc_exit(void) { if (capidev_cachep) { (void)kmem_cache_destroy(capidev_cachep); diff -Nru a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile --- a/drivers/isdn/hisax/Makefile Tue Feb 26 11:57:59 2002 +++ b/drivers/isdn/hisax/Makefile Tue Feb 26 11:57:59 2002 @@ -64,6 +64,7 @@ obj-$(CONFIG_HISAX_ST5481) += hisax_st5481.o obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_isac.o hisax_fcpcipnp.o obj-$(CONFIG_HISAX_FRITZ_CLASSIC) += hisax_isac.o hisax_hscx.o hisax_fcclassic.o +obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_hfcpci.o CERT := $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?) CFLAGS_cert.o := -DCERTIFICATION=$(CERT) diff -Nru a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c --- a/drivers/isdn/hisax/hisax_fcpcipnp.c Tue Feb 26 11:57:57 2002 +++ b/drivers/isdn/hisax/hisax_fcpcipnp.c Tue Feb 26 11:57:57 2002 @@ -945,14 +945,14 @@ static struct pci_driver fcpci_driver = { name: "fcpci", probe: fcpci_probe, - remove: fcpci_remove, + remove: __devexit_p(fcpci_remove), id_table: fcpci_ids, }; static struct isapnp_driver fcpnp_driver = { name: "fcpnp", probe: fcpnp_probe, - remove: fcpnp_remove, + remove: __devexit_p(fcpnp_remove), id_table: fcpnp_ids, }; diff -Nru a/drivers/isdn/hisax/hisax_hfcpci.c b/drivers/isdn/hisax/hisax_hfcpci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/isdn/hisax/hisax_hfcpci.c Tue Feb 26 11:58:00 2002 @@ -0,0 +1,1646 @@ +/* + * Driver for HFC PCI based cards + * + * Author Kai Germaschewski + * Copyright 2002 by Kai Germaschewski + * 2000 by Karsten Keil + * 2000 by Werner Cornelius + * + * based upon Werner Cornelius's original hfc_pci.c driver + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + */ + +// XXX timer3 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hisax_hfcpci.h" + +// debugging cruft +#define __debug_variable debug +#include "hisax_debug.h" + +#ifdef CONFIG_HISAX_DEBUG +static int debug = 0; +MODULE_PARM(debug, "i"); +#endif + +MODULE_AUTHOR("Kai Germaschewski /Werner Cornelius "); +MODULE_DESCRIPTION("HFC PCI ISDN driver"); + +#define ID(ven, dev, name) \ + { vendor: PCI_VENDOR_ID_##ven, \ + device: PCI_DEVICE_ID_##dev, \ + subvendor: PCI_ANY_ID, \ + subdevice: PCI_ANY_ID, \ + class: 0, \ + class_mask: 0, \ + driver_data: (unsigned long) name } + +static struct pci_device_id hfcpci_ids[] __devinitdata = { + ID(CCD, CCD_2BD0, "CCD/Billion/Asuscom 2BD0"), + ID(CCD, CCD_B000, "Billion B000"), + ID(CCD, CCD_B006, "Billion B006"), + ID(CCD, CCD_B007, "Billion B007"), + ID(CCD, CCD_B008, "Billion B008"), + ID(CCD, CCD_B009, "Billion B009"), + ID(CCD, CCD_B00A, "Billion B00A"), + ID(CCD, CCD_B00B, "Billion B00B"), + ID(CCD, CCD_B00C, "Billion B00C"), + ID(CCD, CCD_B100, "Seyeon"), + ID(ABOCOM, ABOCOM_2BD1, "Abocom/Magitek"), + ID(ASUSTEK, ASUSTEK_0675, "Asuscom/Askey"), + ID(BERKOM, BERKOM_T_CONCEPT, "German Telekom T-Concept"), + ID(BERKOM, BERKOM_A1T, "German Telekom A1T"), + ID(ANIGMA, ANIGMA_MC145575, "Motorola MC145575"), + ID(ZOLTRIX, ZOLTRIX_2BD0, "Zoltrix 2BD0"), + ID(DIGI, DIGI_DF_M_IOM2_E, "Digi DataFire Micro V IOM2 (Europe)"), + ID(DIGI, DIGI_DF_M_E, "Digi DataFire Micro V (Europe)"), + ID(DIGI, DIGI_DF_M_IOM2_A, "Digi DataFire Micro V IOM2 (America)"), + ID(DIGI, DIGI_DF_M_A, "Digi DataFire Micro V (America)"), + { } +}; +MODULE_DEVICE_TABLE(pci, hfcpci_ids); + +#undef ID + +static int protocol = 2; /* EURO-ISDN Default */ +MODULE_PARM(protocol, "i"); + +// ---------------------------------------------------------------------- +// + +#define DBG_WARN 0x0001 +#define DBG_INFO 0x0002 +#define DBG_IRQ 0x0010 +#define DBG_L1M 0x0020 +#define DBG_PR 0x0040 +#define DBG_D_XMIT 0x0100 +#define DBG_D_RECV 0x0200 +#define DBG_B_XMIT 0x1000 +#define DBG_B_RECV 0x2000 + +/* memory window base address offset (in config space) */ + +#define HFCPCI_MWBA 0x80 + +/* GCI/IOM bus monitor registers */ + +#define HCFPCI_C_I 0x08 +#define HFCPCI_TRxR 0x0C +#define HFCPCI_MON1_D 0x28 +#define HFCPCI_MON2_D 0x2C + + +/* GCI/IOM bus timeslot registers */ + +#define HFCPCI_B1_SSL 0x80 +#define HFCPCI_B2_SSL 0x84 +#define HFCPCI_AUX1_SSL 0x88 +#define HFCPCI_AUX2_SSL 0x8C +#define HFCPCI_B1_RSL 0x90 +#define HFCPCI_B2_RSL 0x94 +#define HFCPCI_AUX1_RSL 0x98 +#define HFCPCI_AUX2_RSL 0x9C + +/* GCI/IOM bus data registers */ + +#define HFCPCI_B1_D 0xA0 +#define HFCPCI_B2_D 0xA4 +#define HFCPCI_AUX1_D 0xA8 +#define HFCPCI_AUX2_D 0xAC + +/* GCI/IOM bus configuration registers */ + +#define HFCPCI_MST_EMOD 0xB4 +#define HFCPCI_MST_MODE 0xB8 +#define HFCPCI_CONNECT 0xBC + + +/* Interrupt and status registers */ + +#define HFCPCI_FIFO_EN 0x44 +#define HFCPCI_TRM 0x48 +#define HFCPCI_B_MODE 0x4C +#define HFCPCI_CHIP_ID 0x58 +#define HFCPCI_CIRM 0x60 +#define HFCPCI_CTMT 0x64 +#define HFCPCI_INT_M1 0x68 +#define HFCPCI_INT_M2 0x6C +#define HFCPCI_INT_S1 0x78 +#define HFCPCI_INT_S2 0x7C +#define HFCPCI_STATUS 0x70 + +/* S/T section registers */ + +#define HFCPCI_STATES 0xC0 +#define HFCPCI_SCTRL 0xC4 +#define HFCPCI_SCTRL_E 0xC8 +#define HFCPCI_SCTRL_R 0xCC +#define HFCPCI_SQ 0xD0 +#define HFCPCI_CLKDEL 0xDC +#define HFCPCI_B1_REC 0xF0 +#define HFCPCI_B1_SEND 0xF0 +#define HFCPCI_B2_REC 0xF4 +#define HFCPCI_B2_SEND 0xF4 +#define HFCPCI_D_REC 0xF8 +#define HFCPCI_D_SEND 0xF8 +#define HFCPCI_E_REC 0xFC + + +/* bits in status register (READ) */ +#define HFCPCI_PCI_PROC 0x02 +#define HFCPCI_NBUSY 0x04 +#define HFCPCI_TIMER_ELAP 0x10 +#define HFCPCI_STATINT 0x20 +#define HFCPCI_FRAMEINT 0x40 +#define HFCPCI_ANYINT 0x80 + +/* bits in CTMT (Write) */ +#define HFCPCI_CLTIMER 0x80 +#define HFCPCI_TIM3_125 0x04 +#define HFCPCI_TIM25 0x10 +#define HFCPCI_TIM50 0x14 +#define HFCPCI_TIM400 0x18 +#define HFCPCI_TIM800 0x1C +#define HFCPCI_AUTO_TIMER 0x20 +#define HFCPCI_TRANSB2 0x02 +#define HFCPCI_TRANSB1 0x01 + +/* bits in CIRM (Write) */ +#define HFCPCI_AUX_MSK 0x07 +#define HFCPCI_RESET 0x08 +#define HFCPCI_B1_REV 0x40 +#define HFCPCI_B2_REV 0x80 + +/* bits in INT_M1 and INT_S1 */ +#define HFCPCI_INTS_B1TRANS 0x01 +#define HFCPCI_INTS_B2TRANS 0x02 +#define HFCPCI_INTS_DTRANS 0x04 +#define HFCPCI_INTS_B1REC 0x08 +#define HFCPCI_INTS_B2REC 0x10 +#define HFCPCI_INTS_DREC 0x20 +#define HFCPCI_INTS_L1STATE 0x40 +#define HFCPCI_INTS_TIMER 0x80 + +/* bits in INT_M2 */ +#define HFCPCI_PROC_TRANS 0x01 +#define HFCPCI_GCI_I_CHG 0x02 +#define HFCPCI_GCI_MON_REC 0x04 +#define HFCPCI_IRQ_ENABLE 0x08 +#define HFCPCI_PMESEL 0x80 + +/* bits in STATES */ +#define HFCPCI_STATE_MSK 0x0F +#define HFCPCI_LOAD_STATE 0x10 +#define HFCPCI_ACTIVATE 0x20 +#define HFCPCI_DO_ACTION 0x40 +#define HFCPCI_NT_G2_G3 0x80 + +/* bits in HFCD_MST_MODE */ +#define HFCPCI_MASTER 0x01 +#define HFCPCI_SLAVE 0x00 +/* remaining bits are for codecs control */ + +/* bits in HFCD_SCTRL */ +#define SCTRL_B1_ENA 0x01 +#define SCTRL_B2_ENA 0x02 +#define SCTRL_MODE_TE 0x00 +#define SCTRL_MODE_NT 0x04 +#define SCTRL_LOW_PRIO 0x08 +#define SCTRL_SQ_ENA 0x10 +#define SCTRL_TEST 0x20 +#define SCTRL_NONE_CAP 0x40 +#define SCTRL_PWR_DOWN 0x80 + +/* bits in SCTRL_E */ +#define HFCPCI_AUTO_AWAKE 0x01 +#define HFCPCI_DBIT_1 0x04 +#define HFCPCI_IGNORE_COL 0x08 +#define HFCPCI_CHG_B1_B2 0x80 + +/* bits in FIFO_EN register */ +#define HFCPCI_FIFOEN_B1 0x03 +#define HFCPCI_FIFOEN_B2 0x0C +#define HFCPCI_FIFOEN_DTX 0x10 +#define HFCPCI_FIFOEN_DRX 0x20 +#define HFCPCI_FIFOEN_B1TX 0x01 +#define HFCPCI_FIFOEN_B1RX 0x02 +#define HFCPCI_FIFOEN_B2TX 0x04 +#define HFCPCI_FIFOEN_B2RX 0x08 + +/* + * thresholds for transparent B-channel mode + * change mask and threshold simultaneously + */ +#define HFCPCI_BTRANS_THRESHOLD 128 +#define HFCPCI_BTRANS_THRESMASK 0x00 + +#define CLKDEL_TE 0x0e /* CLKDEL in TE mode */ +#define CLKDEL_NT 0x6c /* CLKDEL in NT mode */ + +#define MAX_D_FRAMES 0x10 +#define MAX_B_FRAMES 0x20 +#define B_FIFO_START 0x0200 +#define B_FIFO_END 0x2000 +#define B_FIFO_SIZE (B_FIFO_END - B_FIFO_START) +#define D_FIFO_START 0x0000 +#define D_FIFO_END 0x0200 +#define D_FIFO_SIZE (D_FIFO_END - D_FIFO_START) + +// ---------------------------------------------------------------------- +// push messages to the upper layers + +static inline void D_L1L2(struct hfcpci_adapter *adapter, int pr, void *arg) +{ + struct hisax_if *ifc = (struct hisax_if *) &adapter->d_if; + + DBG(DBG_PR, "pr %#x", pr); + ifc->l1l2(ifc, pr, arg); +} + +static inline void B_L1L2(struct hfcpci_bcs *bcs, int pr, void *arg) +{ + struct hisax_if *ifc = (struct hisax_if *) &bcs->b_if; + + DBG(DBG_PR, "pr %#x", pr); + ifc->l1l2(ifc, pr, arg); +} + +// ---------------------------------------------------------------------- +// MMIO + +static inline void +hfcpci_writeb(struct hfcpci_adapter *adapter, u8 b, unsigned char offset) +{ + writeb(b, adapter->mmio + offset); +} + +static inline u8 +hfcpci_readb(struct hfcpci_adapter *adapter, unsigned char offset) +{ + return readb(adapter->mmio + offset); +} + +// ---------------------------------------------------------------------- +// magic to define the various F/Z counter accesses + +#define DECL_B_F(r, f) \ +static inline u8 \ +get_b_##r##_##f (struct hfcpci_bcs *bcs) \ +{ \ + u16 off = bcs->channel ? OFF_B2_##r##_##f : OFF_B1_##r##_##f; \ + \ + return *(bcs->adapter->fifo + off); \ +} \ + \ +static inline void \ +set_b_##r##_##f (struct hfcpci_bcs *bcs, u8 f) \ +{ \ + u16 off = bcs->channel ? OFF_B2_##r##_##f : OFF_B1_##r##_##f; \ + \ + *(bcs->adapter->fifo + off) = f; \ +} + +#define OFF_B1_rx_f1 0x6080 +#define OFF_B2_rx_f1 0x6180 +#define OFF_B1_rx_f2 0x6081 +#define OFF_B2_rx_f2 0x6181 + +#define OFF_B1_tx_f1 0x2080 +#define OFF_B2_tx_f1 0x2180 +#define OFF_B1_tx_f2 0x2081 +#define OFF_B2_tx_f2 0x2181 + +DECL_B_F(rx, f1) +DECL_B_F(rx, f2) +DECL_B_F(tx, f1) +DECL_B_F(tx, f2) + +#undef DECL_B_F + +#define DECL_B_Z(r, z) \ +static inline u16 \ +get_b_##r##_##z (struct hfcpci_bcs *bcs, u8 f) \ +{ \ + u16 off = bcs->channel ? OFF_B2_##r##_##z : OFF_B1_##r##_##z; \ + \ + return le16_to_cpu(*((u16 *) (bcs->adapter->fifo + off + f * 4))); \ +} \ + \ +static inline void \ +set_b_##r##_##z(struct hfcpci_bcs *bcs, u8 f, u16 z) \ +{ \ + u16 off = bcs->channel ? OFF_B2_##r##_##z : OFF_B1_##r##_##z; \ + \ + *((u16 *) (bcs->adapter->fifo + off + f * 4)) = cpu_to_le16(z); \ +} + +#define OFF_B1_rx_z1 0x6000 +#define OFF_B2_rx_z1 0x6100 +#define OFF_B1_rx_z2 0x6002 +#define OFF_B2_rx_z2 0x6102 + +#define OFF_B1_tx_z1 0x2000 +#define OFF_B2_tx_z1 0x2100 +#define OFF_B1_tx_z2 0x2002 +#define OFF_B2_tx_z2 0x2102 + +DECL_B_Z(rx, z1) +DECL_B_Z(rx, z2) +DECL_B_Z(tx, z1) +DECL_B_Z(tx, z2) + +#undef DECL_B_Z + +#define DECL_D_F(r, f) \ +static inline u8 \ +get_d_##r##_##f (struct hfcpci_adapter *adapter) \ +{ \ + u16 off = OFF_D_##r##_##f; \ + \ + return *(adapter->fifo + off) & 0xf; \ +} \ + \ +static inline void \ +set_d_##r##_##f (struct hfcpci_adapter *adapter, u8 f) \ +{ \ + u16 off = OFF_D_##r##_##f; \ + \ + *(adapter->fifo + off) = f | 0x10; \ +} + +#define OFF_D_rx_f1 0x60a0 +#define OFF_D_rx_f2 0x60a1 + +#define OFF_D_tx_f1 0x20a0 +#define OFF_D_tx_f2 0x20a1 + +DECL_D_F(rx, f1) +DECL_D_F(rx, f2) +DECL_D_F(tx, f1) +DECL_D_F(tx, f2) + +#undef DECL_D_F + +#define DECL_D_Z(r, z) \ +static inline u16 \ +get_d_##r##_##z (struct hfcpci_adapter *adapter, u8 f) \ +{ \ + u16 off = OFF_D_##r##_##z; \ + \ + return le16_to_cpu(*((u16 *) (adapter->fifo + off + (f | 0x10) * 4)));\ +} \ + \ +static inline void \ +set_d_##r##_##z(struct hfcpci_adapter *adapter, u8 f, u16 z) \ +{ \ + u16 off = OFF_D_##r##_##z; \ + \ + *((u16 *) (adapter->fifo + off + (f | 0x10) * 4)) = cpu_to_le16(z); \ +} + +#define OFF_D_rx_z1 0x6080 +#define OFF_D_rx_z2 0x6082 + +#define OFF_D_tx_z1 0x2080 +#define OFF_D_tx_z2 0x2082 + +DECL_D_Z(rx, z1) +DECL_D_Z(rx, z2) +DECL_D_Z(tx, z1) +DECL_D_Z(tx, z2) + +#undef DECL_B_Z + +// ---------------------------------------------------------------------- +// fill b / d fifos + +static inline void +hfcpci_fill_d_fifo(struct hfcpci_adapter *adapter) +{ + u8 f1, f2; + u16 z1, z2; + int cnt, fcnt; + char *fifo_adr = adapter->fifo; + struct sk_buff *tx_skb = adapter->tx_skb; + + f1 = get_d_tx_f1(adapter); + f2 = get_d_tx_f2(adapter); + DBG(DBG_D_XMIT, "f1 %#x f2 %#x", f1, f2); + + fcnt = f1 - f2; + if (fcnt < 0) + fcnt += MAX_D_FRAMES; + + if (fcnt) { + printk("BUG\n"); + return; + } + + z1 = get_d_tx_z1(adapter, f1); + z2 = get_d_tx_z2(adapter, f1); //XXX + DBG(DBG_D_XMIT, "z1 %#x z2 %#x", z1, z2); + + cnt = z2 - z1; + if (cnt <= 0) + cnt += D_FIFO_SIZE; + + if (tx_skb->len > cnt) { + printk("BUG\n"); + return; + } + + cnt = tx_skb->len; + if (z1 + cnt <= D_FIFO_END) { + memcpy(fifo_adr + z1, tx_skb->data, cnt); + } else { + memcpy(fifo_adr + z1, tx_skb->data, D_FIFO_END - z1); + memcpy(fifo_adr + D_FIFO_START, + tx_skb->data + (D_FIFO_END - z1), + cnt - (D_FIFO_END - z1)); + } + z1 += cnt; + if (z1 >= D_FIFO_END) + z1 -= D_FIFO_SIZE; + + f1 = (f1 + 1) & (MAX_D_FRAMES - 1); + mb(); + set_d_tx_z1(adapter, f1, z1); + mb(); + set_d_tx_f1(adapter, f1); +} + +static inline void +hfcpci_fill_b_fifo_hdlc(struct hfcpci_bcs *bcs) +{ + u8 f1, f2; + u16 z1, z2; + int cnt, fcnt; + char *fifo_adr = bcs->adapter->fifo + (bcs->channel ? 0x2000 : 0x0000); + struct sk_buff *tx_skb = bcs->tx_skb; + + f1 = get_b_tx_f1(bcs); + f2 = get_b_tx_f2(bcs); + DBG(DBG_B_XMIT, "f1 %#x f2 %#x", f1, f2); + + fcnt = f1 - f2; + if (fcnt < 0) + fcnt += MAX_B_FRAMES; + + if (fcnt) { + printk("BUG\n"); + return; + } + + z1 = get_b_tx_z1(bcs, f1); + z2 = get_b_tx_z2(bcs, f1); //XXX + DBG(DBG_B_XMIT, "z1 %#x z2 %#x", z1, z2); + + cnt = z2 - z1; + if (cnt <= 0) + cnt += B_FIFO_SIZE; + + if (tx_skb->len > cnt) { + printk("BUG\n"); + return; + } + + cnt = tx_skb->len; + if (z1 + cnt <= B_FIFO_END) { + memcpy(fifo_adr + z1, tx_skb->data, cnt); + } else { + memcpy(fifo_adr + z1, tx_skb->data, B_FIFO_END - z1); + memcpy(fifo_adr + B_FIFO_START, + tx_skb->data + (B_FIFO_END - z1), + cnt - (B_FIFO_END - z1)); + } + z1 += cnt; + if (z1 >= B_FIFO_END) + z1 -= B_FIFO_SIZE; + + f1 = (f1 + 1) & (MAX_B_FRAMES - 1); + mb(); + set_b_tx_z1(bcs, f1, z1); + mb(); + set_b_tx_f1(bcs, f1); +} + +static inline void +hfcpci_fill_b_fifo_trans(struct hfcpci_bcs *bcs) +{ + int cnt; + char *fifo_adr = bcs->adapter->fifo + (bcs->channel ? 0x2000 : 0x0000); + struct sk_buff *tx_skb = bcs->tx_skb; + u8 f1, f2; + u16 z1, z2; + + f1 = get_b_tx_f1(bcs); + f2 = get_b_tx_f2(bcs); + + if (f1 != f2) + BUG(); + + z1 = get_b_tx_z1(bcs, f1); + z2 = get_b_tx_z2(bcs, f1); + + cnt = z2 - z1; + if (cnt <= 0) + cnt += B_FIFO_SIZE; + + if (tx_skb->len > cnt) + BUG(); + + if (z1 + cnt <= B_FIFO_END) { + memcpy(fifo_adr + z1, tx_skb->data, cnt); + } else { + memcpy(fifo_adr + z1, tx_skb->data, B_FIFO_END - z1); + memcpy(fifo_adr + B_FIFO_START, + tx_skb->data + (B_FIFO_END - z1), + cnt - (B_FIFO_END - z1)); + } + z1 += cnt; + if (z1 >= B_FIFO_END) + z1 -= B_FIFO_SIZE; + + mb(); + set_b_tx_z1(bcs, f1, z1); +} + +static inline void +hfcpci_fill_b_fifo(struct hfcpci_bcs *bcs) +{ + if (!bcs->tx_skb) { + DBG(DBG_WARN, "?"); + return; + } + + switch (bcs->mode) { + case L1_MODE_TRANS: + hfcpci_fill_b_fifo_trans(bcs); + break; + case L1_MODE_HDLC: + hfcpci_fill_b_fifo_hdlc(bcs); + break; + default: + DBG(DBG_WARN, "?"); + } +} + +static void hfcpci_clear_b_rx_fifo(struct hfcpci_bcs *bcs); +static void hfcpci_clear_b_tx_fifo(struct hfcpci_bcs *bcs); + +static void +hfcpci_b_mode(struct hfcpci_bcs *bcs, int mode) +{ + struct hfcpci_adapter *adapter = bcs->adapter; + + DBG(DBG_B_XMIT, "B%d mode %d --> %d", + bcs->channel + 1, bcs->mode, mode); + + if (bcs->mode == mode) + return; + + switch (mode) { + case L1_MODE_NULL: + if (bcs->channel == 0) { + adapter->sctrl &= ~SCTRL_B1_ENA; + adapter->sctrl_r &= ~SCTRL_B1_ENA; + adapter->fifo_en &= ~HFCPCI_FIFOEN_B1; + adapter->int_m1 &= ~(HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC); + } else { + adapter->sctrl &= ~SCTRL_B2_ENA; + adapter->sctrl_r &= ~SCTRL_B2_ENA; + adapter->fifo_en &= ~HFCPCI_FIFOEN_B2; + adapter->int_m1 &= ~(HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC); + } + break; + case L1_MODE_TRANS: + case L1_MODE_HDLC: + hfcpci_clear_b_rx_fifo(bcs); + hfcpci_clear_b_tx_fifo(bcs); + if (bcs->channel == 0) { + adapter->sctrl |= SCTRL_B1_ENA; + adapter->sctrl_r |= SCTRL_B1_ENA; + adapter->fifo_en |= HFCPCI_FIFOEN_B1; + adapter->int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC); + + if (mode == L1_MODE_TRANS) + adapter->ctmt |= 1; + else + adapter->ctmt &= ~1; + + } else { + adapter->sctrl |= SCTRL_B2_ENA; + adapter->sctrl_r |= SCTRL_B2_ENA; + adapter->fifo_en |= HFCPCI_FIFOEN_B2; + adapter->int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC); + + if (mode == L1_MODE_TRANS) + adapter->ctmt |= 2; + else + adapter->ctmt &= ~2; + + } + break; + } + hfcpci_writeb(adapter, adapter->int_m1, HFCPCI_INT_M1); + hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN); + hfcpci_writeb(adapter, adapter->sctrl, HFCPCI_SCTRL); + hfcpci_writeb(adapter, adapter->sctrl_r, HFCPCI_SCTRL_R); + hfcpci_writeb(adapter, adapter->ctmt, HFCPCI_CTMT); + hfcpci_writeb(adapter, adapter->conn, HFCPCI_CONNECT); + + bcs->mode = mode; +} + +// ---------------------------------------------------------------------- +// Layer 1 state machine + +static struct Fsm l1fsm; + +enum { + ST_L1_F0, + ST_L1_F2, + ST_L1_F3, + ST_L1_F4, + ST_L1_F5, + ST_L1_F6, + ST_L1_F7, + ST_L1_F8, +}; + +#define L1_STATE_COUNT (ST_L1_F8+1) + +static char *strL1State[] = +{ + "ST_L1_F0", + "ST_L1_F2", + "ST_L1_F3", + "ST_L1_F4", + "ST_L1_F5", + "ST_L1_F6", + "ST_L1_F7", + "ST_L1_F8", +}; + +enum { + EV_PH_F0, + EV_PH_1, + EV_PH_F2, + EV_PH_F3, + EV_PH_F4, + EV_PH_F5, + EV_PH_F6, + EV_PH_F7, + EV_PH_F8, + EV_PH_ACTIVATE_REQ, + EV_PH_DEACTIVATE_REQ, + EV_TIMER3, +}; + +#define L1_EVENT_COUNT (EV_TIMER3 + 1) + +static char *strL1Event[] = +{ + "EV_PH_F0", + "EV_PH_1", + "EV_PH_F2", + "EV_PH_F3", + "EV_PH_F4", + "EV_PH_F5", + "EV_PH_F6", + "EV_PH_F7", + "EV_PH_F8", + "EV_PH_ACTIVATE_REQ", + "EV_PH_DEACTIVATE_REQ", + "EV_TIMER3", +}; + +static void l1_ignore(struct FsmInst *fi, int event, void *arg) +{ +} + +static void l1_go_f3(struct FsmInst *fi, int event, void *arg) +{ + FsmChangeState(fi, ST_L1_F3); +} + +static void l1_go_f3_deact_ind(struct FsmInst *fi, int event, void *arg) +{ + struct hfcpci_adapter *adapter = fi->userdata; + + FsmChangeState(fi, ST_L1_F3); + D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL); +} + +static void l1_go_f4(struct FsmInst *fi, int event, void *arg) +{ + FsmChangeState(fi, ST_L1_F3); +} + +static void l1_go_f5(struct FsmInst *fi, int event, void *arg) +{ + FsmChangeState(fi, ST_L1_F3); +} + +static void l1_go_f6(struct FsmInst *fi, int event, void *arg) +{ + FsmChangeState(fi, ST_L1_F6); +} + +static void l1_go_f6_deact_ind(struct FsmInst *fi, int event, void *arg) +{ + struct hfcpci_adapter *adapter = fi->userdata; + + FsmChangeState(fi, ST_L1_F6); + D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL); +} + +static void l1_go_f7(struct FsmInst *fi, int event, void *arg) +{ + FsmChangeState(fi, ST_L1_F7); +} + +static void l1_go_f7_act_ind(struct FsmInst *fi, int event, void *arg) +{ + struct hfcpci_adapter *adapter = fi->userdata; + + FsmChangeState(fi, ST_L1_F7); + D_L1L2(adapter, PH_ACTIVATE | INDICATION, NULL); +} + +static void l1_go_f8(struct FsmInst *fi, int event, void *arg) +{ + FsmChangeState(fi, ST_L1_F8); +} + +static void l1_go_f8_deact_ind(struct FsmInst *fi, int event, void *arg) +{ + struct hfcpci_adapter *adapter = fi->userdata; + + FsmChangeState(fi, ST_L1_F8); + D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL); +} + +static void l1_act_req(struct FsmInst *fi, int event, void *arg) +{ + struct hfcpci_adapter *adapter = fi->userdata; + + hfcpci_writeb(adapter, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION, HFCPCI_STATES); +} + +static struct FsmNode L1FnList[] __initdata = +{ + {ST_L1_F2, EV_PH_F3, l1_go_f3}, + {ST_L1_F2, EV_PH_F6, l1_go_f6}, + {ST_L1_F2, EV_PH_F7, l1_go_f7_act_ind}, + + {ST_L1_F3, EV_PH_F3, l1_ignore}, + {ST_L1_F3, EV_PH_F4, l1_go_f4}, + {ST_L1_F3, EV_PH_F5, l1_go_f5}, + {ST_L1_F3, EV_PH_F6, l1_go_f6}, + {ST_L1_F3, EV_PH_F7, l1_go_f7_act_ind}, + {ST_L1_F3, EV_PH_ACTIVATE_REQ, l1_act_req}, + + {ST_L1_F4, EV_PH_F7, l1_ignore}, + {ST_L1_F4, EV_PH_F3, l1_go_f3}, + {ST_L1_F4, EV_PH_F5, l1_go_f5}, + {ST_L1_F4, EV_PH_F6, l1_go_f6}, + {ST_L1_F4, EV_PH_F7, l1_go_f7}, + + {ST_L1_F5, EV_PH_F7, l1_ignore}, + {ST_L1_F5, EV_PH_F3, l1_go_f3}, + {ST_L1_F5, EV_PH_F6, l1_go_f6}, + {ST_L1_F5, EV_PH_F7, l1_go_f7}, + + {ST_L1_F6, EV_PH_F7, l1_ignore}, + {ST_L1_F6, EV_PH_F3, l1_go_f3}, + {ST_L1_F6, EV_PH_F7, l1_go_f7_act_ind}, + {ST_L1_F6, EV_PH_F8, l1_go_f8}, + + {ST_L1_F7, EV_PH_F7, l1_ignore}, + {ST_L1_F7, EV_PH_F3, l1_go_f3_deact_ind}, + {ST_L1_F7, EV_PH_F6, l1_go_f6_deact_ind}, + {ST_L1_F7, EV_PH_F8, l1_go_f8_deact_ind}, + + {ST_L1_F8, EV_PH_F7, l1_ignore}, + {ST_L1_F8, EV_PH_F3, l1_go_f3}, + {ST_L1_F8, EV_PH_F6, l1_go_f6}, + {ST_L1_F8, EV_PH_F7, l1_go_f7_act_ind}, + +}; + +static void l1m_debug(struct FsmInst *fi, char *fmt, ...) +{ + va_list args; + char buf[256]; + + va_start(args, fmt); + vsprintf(buf, fmt, args); + DBG(DBG_L1M, "%s", buf); + va_end(args); +} + +// ---------------------------------------------------------------------- +// clear FIFOs + +static void +hfcpci_clear_d_rx_fifo(struct hfcpci_adapter *adapter) +{ + u8 fifo_state; + + DBG(DBG_D_RECV, ""); + + fifo_state = adapter->fifo_en & HFCPCI_FIFOEN_DRX; + + if (fifo_state) { // enabled + // XXX locking + adapter->fifo_en &= ~fifo_state; + hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN); + } + + adapter->last_fcnt = 0; + + set_d_rx_z1(adapter, MAX_D_FRAMES - 1, D_FIFO_END - 1); + set_d_rx_z2(adapter, MAX_D_FRAMES - 1, D_FIFO_END - 1); + mb(); + set_d_rx_f1(adapter, MAX_D_FRAMES - 1); + set_d_rx_f2(adapter, MAX_D_FRAMES - 1); + mb(); + + if (fifo_state) { + adapter->fifo_en |= fifo_state; + hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN); + } +} + +static void +hfcpci_clear_b_rx_fifo(struct hfcpci_bcs *bcs) +{ + struct hfcpci_adapter *adapter = bcs->adapter; + int nr = bcs->channel; + u8 fifo_state; + + DBG(DBG_B_RECV, ""); + + fifo_state = adapter->fifo_en & + (nr ? HFCPCI_FIFOEN_B2RX : HFCPCI_FIFOEN_B1RX); + + if (fifo_state) { // enabled + adapter->fifo_en &= ~fifo_state; + hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN); + } + + bcs->last_fcnt = 0; + + set_b_rx_z1(bcs, MAX_B_FRAMES - 1, B_FIFO_END - 1); + set_b_rx_z2(bcs, MAX_B_FRAMES - 1, B_FIFO_END - 1); + mb(); + set_b_rx_f1(bcs, MAX_B_FRAMES - 1); + set_b_rx_f2(bcs, MAX_B_FRAMES - 1); + mb(); + + if (fifo_state) { + adapter->fifo_en |= fifo_state; + hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN); + } +} + +// XXX clear d_tx_fifo? + +static void +hfcpci_clear_b_tx_fifo(struct hfcpci_bcs *bcs) +{ + struct hfcpci_adapter *adapter = bcs->adapter; + int nr = bcs->channel; + u8 fifo_state; + + fifo_state = adapter->fifo_en & + (nr ? HFCPCI_FIFOEN_B2TX : HFCPCI_FIFOEN_B1TX); + + if (fifo_state) { // enabled + adapter->fifo_en &= ~fifo_state; + hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN); + } + + bcs->last_fcnt = 0; + + set_b_rx_z1(bcs, MAX_B_FRAMES - 1, B_FIFO_END - 1); + set_b_rx_z2(bcs, MAX_B_FRAMES - 1, B_FIFO_END - 1); + mb(); + set_b_rx_f1(bcs, MAX_B_FRAMES - 1); + set_b_rx_f2(bcs, MAX_B_FRAMES - 1); + mb(); + + if (fifo_state) { + adapter->fifo_en |= fifo_state; + hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN); + } +} + +// ---------------------------------------------------------------------- +// receive messages from upper layers + +static void +hfcpci_d_l2l1(struct hisax_if *ifc, int pr, void *arg) +{ + struct hfcpci_adapter *adapter = ifc->priv; + struct sk_buff *skb = arg; + + DBG(DBG_PR, "pr %#x", pr); + + switch (pr) { + case PH_ACTIVATE | REQUEST: + FsmEvent(&adapter->l1m, EV_PH_ACTIVATE_REQ, NULL); + break; + case PH_DEACTIVATE | REQUEST: + FsmEvent(&adapter->l1m, EV_PH_DEACTIVATE_REQ, NULL); + break; + case PH_DATA | REQUEST: + DBG(DBG_PR, "PH_DATA REQUEST len %d", skb->len); + DBG_SKB(DBG_D_XMIT, skb); + if (adapter->l1m.state != ST_L1_F7) { + DBG(DBG_WARN, "L1 wrong state %d", adapter->l1m.state); + break; + } + if (adapter->tx_skb) + BUG(); + + adapter->tx_skb = skb; + hfcpci_fill_d_fifo(adapter); + break; + } +} + +static void +hfcpci_b_l2l1(struct hisax_if *ifc, int pr, void *arg) +{ + struct hfcpci_bcs *bcs = ifc->priv; + struct sk_buff *skb = arg; + int mode; + + DBG(DBG_PR, "pr %#x", pr); + + switch (pr) { + case PH_DATA | REQUEST: + if (bcs->tx_skb) + BUG(); + + bcs->tx_skb = skb; + DBG_SKB(DBG_B_XMIT, skb); + hfcpci_fill_b_fifo(bcs); + break; + case PH_ACTIVATE | REQUEST: + mode = (int) arg; + DBG(DBG_PR,"B%d,PH_ACTIVATE_REQUEST %d", bcs->channel + 1, mode); + hfcpci_b_mode(bcs, mode); + B_L1L2(bcs, PH_ACTIVATE | INDICATION, NULL); + break; + case PH_DEACTIVATE | REQUEST: + DBG(DBG_PR,"B%d,PH_DEACTIVATE_REQUEST", bcs->channel + 1); + hfcpci_b_mode(bcs, L1_MODE_NULL); + B_L1L2(bcs, PH_DEACTIVATE | INDICATION, NULL); + break; + } +} + +// ---------------------------------------------------------------------- +// receive IRQ + +static inline void +hfcpci_d_recv_irq(struct hfcpci_adapter *adapter) +{ + struct sk_buff *skb; + char *fifo_adr = adapter->fifo + 0x4000; + char *p; + int cnt, fcnt; + int loop = 5; + u8 f1, f2; + u16 z1, z2; + + while (loop-- > 0) { + f1 = get_d_rx_f1(adapter); + f2 = get_d_rx_f2(adapter); + DBG(DBG_D_RECV, "f1 %#x f2 %#x", f1, f2); + + fcnt = f1 - f2; + if (fcnt < 0) + fcnt += 16; + + if (!fcnt) + return; + + if (fcnt < adapter->last_fcnt) + /* overrun */ + hfcpci_clear_d_rx_fifo(adapter); + // XXX init last_fcnt + + z1 = get_d_rx_z1(adapter, f2); + z2 = get_d_rx_z2(adapter, f2); + DBG(DBG_D_RECV, "z1 %#x z2 %#x", z1, z2); + + cnt = z1 - z2; + if (cnt < 0) + cnt += D_FIFO_SIZE; + cnt++; + + if (cnt < 4) { + DBG(DBG_WARN, "frame too short"); + goto next; + } + if (fifo_adr[z1] != 0) { + DBG(DBG_WARN, "CRC error"); + goto next; + } + cnt -= 3; + skb = dev_alloc_skb(cnt); + if (!skb) { + DBG(DBG_WARN, "no mem"); + goto next; + } + p = skb_put(skb, cnt); + if (z2 + cnt <= D_FIFO_END) { + memcpy(p, fifo_adr + z2, cnt); + } else { + memcpy(p, fifo_adr + z2, D_FIFO_END - z2); + memcpy(p + (D_FIFO_END - z2), fifo_adr + D_FIFO_START, + cnt - (D_FIFO_END - z2)); + } + + DBG_SKB(DBG_D_RECV, skb); + D_L1L2(adapter, PH_DATA | INDICATION, skb); + + next: + if (++z1 >= D_FIFO_END) + z1 -= D_FIFO_START; + + f2 = (f2 + 1) & (MAX_D_FRAMES - 1); + mb(); + set_d_rx_z2(adapter, f2, z1); + mb(); + set_d_rx_f2(adapter, f2); + + adapter->last_fcnt = fcnt - 1; + } +} + +static inline void +hfcpci_b_recv_hdlc_irq(struct hfcpci_adapter *adapter, int nr) +{ + struct hfcpci_bcs *bcs = &adapter->bcs[nr]; + struct sk_buff *skb; + char *fifo_adr = adapter->fifo + (nr ? 0x6000 : 0x4000); + char *p; + int cnt, fcnt; + int loop = 5; + u8 f1, f2; + u16 z1, z2; + + while (loop-- > 0) { + f1 = get_b_rx_f1(bcs); + f2 = get_b_rx_f2(bcs); + DBG(DBG_B_RECV, "f1 %d f2 %d", f1, f2); + + fcnt = f1 - f2; + if (fcnt < 0) + fcnt += 32; + + if (!fcnt) + return; + + if (fcnt < bcs->last_fcnt) + /* overrun */ + hfcpci_clear_b_rx_fifo(bcs); + // XXX init last_fcnt + + z1 = get_b_rx_z1(bcs, f2); + z2 = get_b_rx_z2(bcs, f2); + DBG(DBG_B_RECV, "z1 %d z2 %d", z1, z2); + + cnt = z1 - z2; + if (cnt < 0) + cnt += B_FIFO_SIZE; + cnt++; + + if (cnt < 4) { + DBG(DBG_WARN, "frame too short"); + goto next; + } + if (fifo_adr[z1] != 0) { + DBG(DBG_WARN, "CRC error"); + goto next; + } + cnt -= 3; + skb = dev_alloc_skb(cnt); + if (!skb) { + DBG(DBG_WARN, "no mem"); + goto next; + } + p = skb_put(skb, cnt); + if (z2 + cnt <= B_FIFO_END) { + memcpy(p, fifo_adr + z2, cnt); + } else { + memcpy(p, fifo_adr + z2, B_FIFO_END - z2); + memcpy(p + (B_FIFO_END - z2), fifo_adr + B_FIFO_START, + cnt - (B_FIFO_END - z2)); + } + + DBG_SKB(DBG_B_RECV, skb); + B_L1L2(bcs, PH_DATA | INDICATION, skb); + + next: + if (++z1 >= B_FIFO_END) + z1 -= B_FIFO_SIZE; + + f2 = (f2 + 1) & (MAX_B_FRAMES - 1); + mb(); + set_b_rx_z2(bcs, f2, z1); + mb(); + set_b_rx_f2(bcs, f2); + + bcs->last_fcnt = fcnt - 1; + } +} + +static inline void +hfcpci_b_recv_trans_irq(struct hfcpci_adapter *adapter, int nr) +{ + struct hfcpci_bcs *bcs = &adapter->bcs[nr]; + struct sk_buff *skb; + char *fifo_adr = adapter->fifo + (nr ? 0x6000 : 0x4000); + char *p; + int cnt; + int loop = 5; + u8 f1, f2; + u16 z1, z2; + + f1 = get_b_rx_f1(bcs); + f2 = get_b_rx_f2(bcs); + + if (f1 != f2) + BUG(); + + while (loop-- > 0) { + z1 = get_b_rx_z1(bcs, f2); + z2 = get_b_rx_z2(bcs, f2); + + cnt = z1 - z2; + if (!cnt) + /* no data available */ + return; + + if (cnt < 0) + cnt += B_FIFO_SIZE; + + if (cnt > HFCPCI_BTRANS_THRESHOLD) + cnt = HFCPCI_BTRANS_THRESHOLD; + + skb = dev_alloc_skb(cnt); + if (!skb) { + DBG(DBG_WARN, "no mem"); + goto next; + } + + p = skb_put(skb, cnt); + if (z2 + cnt <= 0x2000) { + memcpy(p, fifo_adr + z2, cnt); + } else { + memcpy(p, fifo_adr + z2, 0x2000 - z2); + p += 0x2000 - z2; + memcpy(p, fifo_adr + 0x200, cnt - (0x2000 - z2)); + } + + DBG_SKB(DBG_B_RECV, skb); + B_L1L2(bcs, PH_DATA | INDICATION, skb); + + next: + z2 += cnt; + if (z2 >= 0x2000) + z2 -= B_FIFO_SIZE; + + mb(); + set_b_rx_z2(bcs, f2, z2); + // XXX always receive buffers of a given size + } +} + +static inline void +hfcpci_b_recv_irq(struct hfcpci_adapter *adapter, int nr) +{ + DBG(DBG_B_RECV, ""); + + switch (adapter->bcs[nr].mode) { + case L1_MODE_NULL: + DBG(DBG_WARN, "?"); + break; + + case L1_MODE_HDLC: + hfcpci_b_recv_hdlc_irq(adapter, nr); + break; + + case L1_MODE_TRANS: + hfcpci_b_recv_trans_irq(adapter, nr); + break; + } +} + +// ---------------------------------------------------------------------- +// transmit IRQ + +// XXX make xmit FIFO deeper than 1 + +static inline void +hfcpci_d_xmit_irq(struct hfcpci_adapter *adapter) +{ + struct sk_buff *skb; + + DBG(DBG_D_XMIT, ""); + + skb = adapter->tx_skb; + if (!skb) { + DBG(DBG_WARN, "?"); + return; + } + + adapter->tx_skb = NULL; + D_L1L2(adapter, PH_DATA | CONFIRM, (void *) skb->truesize); + dev_kfree_skb_irq(skb); +} + +static inline void +hfcpci_b_xmit_irq(struct hfcpci_adapter *adapter, int nr) +{ + struct hfcpci_bcs *bcs = &adapter->bcs[nr]; + struct sk_buff *skb; + + DBG(DBG_B_XMIT, ""); + + skb = bcs->tx_skb; + if (!skb) { + DBG(DBG_WARN, "?"); + return; + } + + bcs->tx_skb = NULL; + B_L1L2(bcs, PH_DATA | CONFIRM, (void *) skb->truesize); + dev_kfree_skb_irq(skb); +} + +// ---------------------------------------------------------------------- +// Layer 1 state change IRQ + +static inline void +hfcpci_state_irq(struct hfcpci_adapter *adapter) +{ + u8 val; + + val = hfcpci_readb(adapter, HFCPCI_STATES); + DBG(DBG_L1M, "STATES %#x", val); + FsmEvent(&adapter->l1m, val & 0xf, NULL); +} + +// ---------------------------------------------------------------------- +// Timer IRQ + +static inline void +hfcpci_timer_irq(struct hfcpci_adapter *adapter) +{ + hfcpci_writeb(adapter, adapter->ctmt | HFCPCI_CLTIMER, HFCPCI_CTMT); +} + +// ---------------------------------------------------------------------- +// IRQ handler + +static void +hfcpci_irq(int intno, void *dev, struct pt_regs *regs) +{ + struct hfcpci_adapter *adapter = dev; + int loop = 15; + u8 val, stat; + + if (!(adapter->int_m2 & 0x08)) + return; /* not initialised */ // XX + + stat = hfcpci_readb(adapter, HFCPCI_STATUS); + if (!(stat & HFCPCI_ANYINT)) + return; + + spin_lock(&adapter->hw_lock); + while (loop-- > 0) { + val = hfcpci_readb(adapter, HFCPCI_INT_S1); + DBG(DBG_IRQ, "stat %02x s1 %02x", stat, val); + val &= adapter->int_m1; + + if (!val) + break; + + if (val & 0x08) + hfcpci_b_recv_irq(adapter, 0); + + if (val & 0x10) + hfcpci_b_recv_irq(adapter, 1); + + if (val & 0x01) + hfcpci_b_xmit_irq(adapter, 0); + + if (val & 0x02) + hfcpci_b_xmit_irq(adapter, 1); + + if (val & 0x20) + hfcpci_d_recv_irq(adapter); + + if (val & 0x04) + hfcpci_d_xmit_irq(adapter); + + if (val & 0x40) + hfcpci_state_irq(adapter); + + if (val & 0x80) + hfcpci_timer_irq(adapter); + } + spin_unlock(&adapter->hw_lock); +} + +// ---------------------------------------------------------------------- +// reset hardware + +static void +hfcpci_reset(struct hfcpci_adapter *adapter) +{ + /* disable all interrupts */ + adapter->int_m1 = 0; + adapter->int_m2 = 0; + hfcpci_writeb(adapter, adapter->int_m1, HFCPCI_INT_M1); + hfcpci_writeb(adapter, adapter->int_m2, HFCPCI_INT_M2); + + /* reset */ + hfcpci_writeb(adapter, HFCPCI_RESET, HFCPCI_CIRM); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((30 * HZ) / 1000); + hfcpci_writeb(adapter, 0, HFCPCI_CIRM); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((20 * HZ) / 1000); + if (hfcpci_readb(adapter, HFCPCI_STATUS) & 2) // XX + printk(KERN_WARNING "HFC-PCI init bit busy\n"); +} + +// ---------------------------------------------------------------------- +// init hardware + +static void +hfcpci_hw_init(struct hfcpci_adapter *adapter) +{ + adapter->fifo_en = 0x30; /* only D fifos enabled */ // XX + hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN); + + /* no echo connect , threshold */ + adapter->trm = HFCPCI_BTRANS_THRESMASK; + hfcpci_writeb(adapter, adapter->trm, HFCPCI_TRM); + + /* ST-Bit delay for TE-Mode */ + hfcpci_writeb(adapter, CLKDEL_TE, HFCPCI_CLKDEL); + + /* S/T Auto awake */ + adapter->sctrl_e = HFCPCI_AUTO_AWAKE; + hfcpci_writeb(adapter, adapter->sctrl_e, HFCPCI_SCTRL_E); + + /* no exchange */ + adapter->bswapped = 0; + /* we are in TE mode */ + adapter->nt_mode = 0; + + adapter->ctmt = HFCPCI_TIM3_125 | HFCPCI_AUTO_TIMER; + hfcpci_writeb(adapter, adapter->ctmt, HFCPCI_CTMT); + + adapter->int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC | + HFCPCI_INTS_L1STATE; + hfcpci_writeb(adapter, adapter->int_m1, HFCPCI_INT_M1); + + /* clear already pending ints */ + hfcpci_readb(adapter, HFCPCI_INT_S1); + + adapter->l1m.state = 2; + hfcpci_writeb(adapter, HFCPCI_LOAD_STATE | 2, HFCPCI_STATES); // XX /* HFC ST 2 */ + udelay(10); + hfcpci_writeb(adapter, 2, HFCPCI_STATES); /* HFC ST 2 */ + + /* HFC Master Mode */ + adapter->mst_m = HFCPCI_MASTER; + hfcpci_writeb(adapter, adapter->mst_m, HFCPCI_MST_MODE); + + /* set tx_lo mode, error in datasheet ! */ + adapter->sctrl = 0x40; + hfcpci_writeb(adapter, adapter->sctrl, HFCPCI_SCTRL); + + adapter->sctrl_r = 0; + hfcpci_writeb(adapter, adapter->sctrl_r, HFCPCI_SCTRL_R); + + // XXX + /* Init GCI/IOM2 in master mode */ + /* Slots 0 and 1 are set for B-chan 1 and 2 */ + /* D- and monitor/CI channel are not enabled */ + /* STIO1 is used as output for data, B1+B2 from ST->IOM+HFC */ + /* STIO2 is used as data input, B1+B2 from IOM->ST */ + /* ST B-channel send disabled -> continous 1s */ + /* The IOM slots are always enabled */ + adapter->conn = 0; /* set data flow directions */ + hfcpci_writeb(adapter, adapter->conn, HFCPCI_CONNECT); + hfcpci_writeb(adapter, 0x80, HFCPCI_B1_SSL); /* B1-Slot 0 STIO1 out enabled */ + hfcpci_writeb(adapter, 0x81, HFCPCI_B2_SSL); /* B2-Slot 1 STIO1 out enabled */ + hfcpci_writeb(adapter, 0x80, HFCPCI_B1_RSL); /* B1-Slot 0 STIO2 in enabled */ + hfcpci_writeb(adapter, 0x81, HFCPCI_B2_RSL); /* B2-Slot 1 STIO2 in enabled */ + + /* Finally enable IRQ output */ + adapter->int_m2 = HFCPCI_IRQ_ENABLE; + hfcpci_writeb(adapter, adapter->int_m2, HFCPCI_INT_M2); + + hfcpci_readb(adapter, HFCPCI_INT_S2); +} + +// ---------------------------------------------------------------------- +// probe / remove + +static struct hfcpci_adapter * __devinit +new_adapter(struct pci_dev *pdev) +{ + struct hfcpci_adapter *adapter; + struct hisax_b_if *b_if[2]; + int i; + + adapter = kmalloc(sizeof(struct hfcpci_adapter), GFP_KERNEL); + if (!adapter) + return NULL; + + memset(adapter, 0, sizeof(struct hfcpci_adapter)); + + SET_MODULE_OWNER(&adapter->d_if); + adapter->d_if.ifc.priv = adapter; + adapter->d_if.ifc.l2l1 = hfcpci_d_l2l1; + + for (i = 0; i < 2; i++) { + adapter->bcs[i].adapter = adapter; + adapter->bcs[i].channel = i; + adapter->bcs[i].b_if.ifc.priv = &adapter->bcs[i]; + adapter->bcs[i].b_if.ifc.l2l1 = hfcpci_b_l2l1; + } + + pci_set_drvdata(pdev, adapter); + + for (i = 0; i < 2; i++) + b_if[i] = &adapter->bcs[i].b_if; + + hisax_register(&adapter->d_if, b_if, "hfcpci", protocol); + + return adapter; +} + +static void delete_adapter(struct hfcpci_adapter *adapter) +{ + hisax_unregister(&adapter->d_if); + kfree(adapter); +} + +static int __devinit hfcpci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct hfcpci_adapter *adapter; + int retval; + + DBG(DBG_INFO, ""); + retval = -ENOMEM; + adapter = new_adapter(pdev); + if (!adapter) + goto err; + + retval = pci_enable_device(pdev); + if (retval) + goto err_free; + + adapter->irq = pdev->irq; + retval = request_irq(adapter->irq, hfcpci_irq, SA_SHIRQ, + "hfcpci", adapter); + if (retval) + goto err_free; + + retval = -EBUSY; + if (!request_mem_region(pci_resource_start(pdev, 1), 256, "hfcpci")) + goto err_free_irq; + + adapter->mmio = ioremap(pci_resource_start(pdev, 1), 256); // XX pci_io + if (!adapter->mmio) + goto err_release_region; + + /* Allocate 32K for FIFOs */ + if (pci_set_dma_mask(pdev, 0xffffffff)) + goto err_unmap; + + adapter->fifo = pci_alloc_consistent(pdev, 32768, &adapter->fifo_dma); + if (!adapter->fifo) + goto err_unmap; + + pci_write_config_dword(pdev, HFCPCI_MWBA, (u32) adapter->fifo_dma); + pci_set_master(pdev); + + adapter->l1m.fsm = &l1fsm; + adapter->l1m.state = ST_L1_F0; +#ifdef CONFIG_HISAX_DEBUG + adapter->l1m.debug = 1; +#else + adapter->l1m.debug = 0; +#endif + adapter->l1m.userdata = adapter; + adapter->l1m.printdebug = l1m_debug; + FsmInitTimer(&adapter->l1m, &adapter->timer); + + hfcpci_reset(adapter); + hfcpci_hw_init(adapter); + + printk(KERN_INFO "hisax_hfcpci: found adapter %s at %s\n", + (char *) ent->driver_data, pdev->slot_name); + + return 0; + + err_unmap: + iounmap(adapter->mmio); + err_release_region: + release_mem_region(pci_resource_start(pdev, 1), 256); + err_free_irq: + free_irq(adapter->irq, adapter); + err_free: + delete_adapter(adapter); + err: + return retval; +} + +static void __devexit hfcpci_remove(struct pci_dev *pdev) +{ + struct hfcpci_adapter *adapter = pci_get_drvdata(pdev); + + hfcpci_reset(adapter); + +// del_timer(&cs->hw.hfcpci.timer); XX + + /* disable DMA */ + pci_disable_device(pdev); + pci_write_config_dword(pdev, HFCPCI_MWBA, 0); + pci_free_consistent(pdev, 32768, adapter->fifo, adapter->fifo_dma); + + iounmap(adapter->mmio); + release_mem_region(pci_resource_start(pdev, 1), 256); + free_irq(adapter->irq, adapter); + delete_adapter(adapter); +} + +static struct pci_driver hfcpci_driver = { + name: "hfcpci", + probe: hfcpci_probe, + remove: hfcpci_remove, + id_table: hfcpci_ids, +}; + +static int __init hisax_hfcpci_init(void) +{ + int retval; + + printk(KERN_INFO "hisax_hfcpcipnp: HFC PCI ISDN driver v0.0.1\n"); + + l1fsm.state_count = L1_STATE_COUNT; + l1fsm.event_count = L1_EVENT_COUNT; + l1fsm.strState = strL1State; + l1fsm.strEvent = strL1Event; + retval = FsmNew(&l1fsm, L1FnList, ARRAY_SIZE(L1FnList)); + if (retval) + goto err; + + retval = pci_module_init(&hfcpci_driver); + if (retval) + goto err_fsm; + + return 0; + + err_fsm: + FsmFree(&l1fsm); + err: + return retval; +} + +static void __exit hisax_hfcpci_exit(void) +{ + FsmFree(&l1fsm); + pci_unregister_driver(&hfcpci_driver); +} + +module_init(hisax_hfcpci_init); +module_exit(hisax_hfcpci_exit); diff -Nru a/drivers/isdn/hisax/hisax_hfcpci.h b/drivers/isdn/hisax/hisax_hfcpci.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/isdn/hisax/hisax_hfcpci.h Tue Feb 26 11:58:00 2002 @@ -0,0 +1,40 @@ +#include "hisax_if.h" +#include "hisax_isac.h" +#include + +struct hfcpci_bcs { + struct hisax_b_if b_if; + struct hfcpci_adapter *adapter; + int mode; + int channel; + int last_fcnt; + + struct sk_buff *tx_skb; +}; + +struct hfcpci_adapter { + struct hisax_d_if d_if; + spinlock_t hw_lock; + unsigned int irq; + void *mmio; + u8 *fifo; + dma_addr_t fifo_dma; + + struct FsmInst l1m; + struct FsmTimer timer; + struct sk_buff *tx_skb; + int last_fcnt; + + u8 int_m1, int_m2; + u8 fifo_en; + u8 trm; + u8 sctrl, sctrl_r, sctrl_e; + u8 nt_mode; + u8 ctmt; + u8 mst_m; + u8 conn; + u8 bswapped; + + struct hfcpci_bcs bcs[2]; +}; + diff -Nru a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c --- a/drivers/isdn/hisax/st5481_init.c Tue Feb 26 11:58:00 2002 +++ b/drivers/isdn/hisax/st5481_init.c Tue Feb 26 11:58:00 2002 @@ -178,7 +178,7 @@ static struct usb_driver st5481_usb_driver = { name: "st5481_usb", probe: probe_st5481, - disconnect: disconnect_st5481, + disconnect: __devexit_p(disconnect_st5481), id_table: st5481_ids, }; diff -Nru a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c --- a/drivers/isdn/hisax/st5481_usb.c Tue Feb 26 11:57:59 2002 +++ b/drivers/isdn/hisax/st5481_usb.c Tue Feb 26 11:57:59 2002 @@ -416,7 +416,7 @@ for (j = 0; j < 2; j++) { retval = -ENOMEM; - urb[j] = usb_alloc_urb(num_packet, GFP_KERNEL); + urb[j] = usb_alloc_urb(num_packets, GFP_KERNEL); if (!urb[j]) goto err; diff -Nru a/drivers/isdn/tpam/tpam_main.c b/drivers/isdn/tpam/tpam_main.c --- a/drivers/isdn/tpam/tpam_main.c Tue Feb 26 11:57:57 2002 +++ b/drivers/isdn/tpam/tpam_main.c Tue Feb 26 11:57:57 2002 @@ -254,7 +254,7 @@ name: "tpam", id_table: tpam_pci_tbl, probe: tpam_probe, - remove: tpam_remove, + remove: __devexit_p(tpam_remove), }; static int __init tpam_init(void) { diff -Nru a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c --- a/drivers/media/radio/radio-gemtek-pci.c Tue Feb 26 11:57:57 2002 +++ b/drivers/media/radio/radio-gemtek-pci.c Tue Feb 26 11:57:57 2002 @@ -424,7 +424,7 @@ name: "gemtek_pci", id_table: gemtek_pci_id, probe: gemtek_pci_probe, - remove: gemtek_pci_remove + remove: __devexit_p(gemtek_pci_remove) }; static int __init gemtek_pci_init_module( void ) diff -Nru a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c --- a/drivers/media/radio/radio-maxiradio.c Tue Feb 26 11:57:59 2002 +++ b/drivers/media/radio/radio-maxiradio.c Tue Feb 26 11:57:59 2002 @@ -376,7 +376,7 @@ name: "radio-maxiradio", id_table: maxiradio_pci_tbl, probe: maxiradio_init_one, - remove: maxiradio_remove_one, + remove: __devexit_p(maxiradio_remove_one), }; int __init maxiradio_radio_init(void) diff -Nru a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c --- a/drivers/media/video/bttv-driver.c Tue Feb 26 11:57:58 2002 +++ b/drivers/media/video/bttv-driver.c Tue Feb 26 11:57:58 2002 @@ -141,58 +141,63 @@ * defined way to get at the kernel page tables. */ -static inline unsigned long uvirt_to_bus(unsigned long adr) -{ - unsigned long kva, ret; - kva = page_address(vmalloc_to_page(adr)); - ret = virt_to_bus((void *)kva); - MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret)); - return ret; +/* + * Take a vmalloc address, and turn it into + * the aliased kernel virtual address.. + * + * CAREFUL! Anybody who does this gets to sit + * in their own cr*p when it comes to virtual + * cache aliases. It's _your_ problem. + * + * Also, note how it only works within one page. + * If you're doing page-crossing stuff, you're on + * your own. + * + * THIS IS BROKEN CODE! You shouldn't do things + * like this. + */ +static inline void *vmalloc_to_virt(void *addr) +{ + struct page *page = vmalloc_to_page(addr); + return page_address(page) + (~PAGE_MASK & (unsigned long)addr); } -static inline unsigned long kvirt_to_bus(unsigned long adr) +static inline unsigned long kvirt_to_bus(unsigned long addr) { - unsigned long va, kva, ret; - - va = VMALLOC_VMADDR(adr); - kva = page_address(vmalloc_to_page(va)); - ret = virt_to_bus((void *)kva); - MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret)); + unsigned long ret; + ret = virt_to_bus(vmalloc_to_virt((void *)addr)); + MDEBUG(printk("kv2b(%lx-->%lx)", addr, ret)); return ret; } /* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ -static inline unsigned long kvirt_to_pa(unsigned long adr) +static inline unsigned long kvirt_to_pa(unsigned long addr) { - unsigned long va, kva, ret; - - va = VMALLOC_VMADDR(adr); - kva = page_address(vmalloc_to_page(va)); - ret = __pa(kva); - MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); + unsigned long ret; + ret = virt_to_phys(vmalloc_to_virt((void *)addr)); + MDEBUG(printk("kv2pa(%lx-->%lx)", addr, ret)); return ret; } -static void * rvmalloc(signed long size) +static void * rvmalloc(unsigned long size) { void * mem; - unsigned long adr, page; + unsigned long adr; + size=PAGE_ALIGN(size); mem=vmalloc_32(size); if (NULL == mem) - printk(KERN_INFO "bttv: vmalloc_32(%ld) failed\n",size); + printk(KERN_INFO "bttv: vmalloc_32(%lu) failed\n",size); else { /* Clear the ram out, no junk to the user */ memset(mem, 0, size); adr=(unsigned long) mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -200,17 +205,16 @@ return mem; } -static void rvfree(void * mem, signed long size) +static void rvfree(void * mem, unsigned long size) { - unsigned long adr, page; + unsigned long adr; if (mem) { adr=(unsigned long) mem; - while (size > 0) + while ((long) size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -2794,7 +2798,8 @@ * Scan for a Bt848 card, request the irq and map the io memory */ -static void __devexit bttv_remove(struct pci_dev *pci_dev) +/* Can't be marked __devexit with a reference from bttv_probe. */ +static void bttv_remove(struct pci_dev *pci_dev) { u8 command; int j; diff -Nru a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c --- a/drivers/media/video/cpia.c Tue Feb 26 11:58:00 2002 +++ b/drivers/media/video/cpia.c Tue Feb 26 11:58:00 2002 @@ -181,15 +181,14 @@ **********************************************************************/ /* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = page_address(vmalloc_to_page(va)); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ ret = __pa(kva); return ret; } @@ -197,12 +196,9 @@ static void *rvmalloc(unsigned long size) { void *mem; - unsigned long adr, page; - - /* Round it off to PAGE_SIZE */ - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); + unsigned long adr; + size = PAGE_ALIGN(size); mem = vmalloc_32(size); if (!mem) return NULL; @@ -210,13 +206,9 @@ memset(mem, 0, size); /* Clear the ram out, no junk to the user */ adr = (unsigned long) mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } return mem; @@ -224,23 +216,16 @@ static void rvfree(void *mem, unsigned long size) { - unsigned long adr, page; + unsigned long adr; if (!mem) return; - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); - adr = (unsigned long) mem; - while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } vfree(mem); } diff -Nru a/drivers/media/video/meye.c b/drivers/media/video/meye.c --- a/drivers/media/video/meye.c Tue Feb 26 11:57:56 2002 +++ b/drivers/media/video/meye.c Tue Feb 26 11:57:56 2002 @@ -115,34 +115,29 @@ /* Memory allocation routines (stolen from bttv-driver.c) */ /****************************************************************************/ -#define MDEBUG(x) do {} while (0) -/* #define MDEBUG(x) x */ - /* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = page_address(vmalloc_to_page(va)); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ ret = __pa(kva); - MDEBUG(printk("kv2pa(%lx-->%lx)\n", adr, ret)); return ret; } -static void *rvmalloc(signed long size) { +static void *rvmalloc(unsigned long size) { void *mem; - unsigned long adr, page; + unsigned long adr; + size = PAGE_ALIGN(size); mem = vmalloc_32(size); if (mem) { memset(mem, 0, size); /* Clear the ram out, no junk to the user */ adr = (unsigned long)mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; size -= PAGE_SIZE; } @@ -150,14 +145,13 @@ return mem; } -static void rvfree(void * mem, signed long size) { - unsigned long adr, page; - +static void rvfree(void * mem, unsigned long size) { + unsigned long adr; + if (mem) { adr = (unsigned long) mem; - while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; size -= PAGE_SIZE; } @@ -1425,7 +1419,7 @@ name: "meye", id_table: meye_pci_tbl, probe: meye_probe, - remove: meye_remove, + remove: __devexit_p(meye_remove), }; static int __init meye_init_module(void) { diff -Nru a/drivers/media/video/zr36120.c b/drivers/media/video/zr36120.c --- a/drivers/media/video/zr36120.c Tue Feb 26 11:57:59 2002 +++ b/drivers/media/video/zr36120.c Tue Feb 26 11:57:59 2002 @@ -2024,7 +2024,7 @@ } static -void __exit release_zoran(int max) +void release_zoran(int max) { struct zoran *ztv; int i; diff -Nru a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c --- a/drivers/message/i2o/i2o_block.c Tue Feb 26 11:58:00 2002 +++ b/drivers/message/i2o/i2o_block.c Tue Feb 26 11:58:00 2002 @@ -116,7 +116,7 @@ #define I2O_BSA_DSC_VOLUME_CHANGED 0x000D #define I2O_BSA_DSC_TIMEOUT 0x000E -#define I2O_UNIT(dev) (i2ob_dev[MINOR((dev)) & 0xf0]) +#define I2O_UNIT(dev) (i2ob_dev[minor((dev)) & 0xf0]) #define I2O_LOCK(unit) (i2ob_dev[(unit)].req_queue->queue_lock) /* @@ -760,7 +760,7 @@ { u64 size; - if(do_i2ob_revalidate(MKDEV(MAJOR_NR, unit),0) != -EBUSY) + if(do_i2ob_revalidate(mk_kdev(MAJOR_NR, unit),0) != -EBUSY) continue; if(i2ob_query_device(&i2ob_dev[unit], 0x0004, 0, &size, 8) !=0 ) @@ -869,7 +869,7 @@ if(i2ob_backlog[c->unit] == NULL) i2ob_backlog_tail[c->unit] = NULL; - unit = MINOR(ireq->req->rq_dev); + unit = minor(ireq->req->rq_dev); i2ob_send(m, dev, ireq, i2ob[unit].start_sect, unit); } if(i2ob_backlog[c->unit]) @@ -905,7 +905,7 @@ if(req->rq_status == RQ_INACTIVE) return; - unit = MINOR(req->rq_dev); + unit = minor(req->rq_dev); dev = &i2ob_dev[(unit&0xF0)]; /* @@ -1038,7 +1038,7 @@ static int do_i2ob_revalidate(kdev_t dev, int maxu) { - int minor=MINOR(dev); + int minor=minor(dev); int i; minor&=0xF0; @@ -1053,7 +1053,7 @@ for( i = 15; i>=0 ; i--) { int m = minor+i; - invalidate_device(MKDEV(MAJOR_NR, m), 1); + invalidate_device(mk_kdev(MAJOR_NR, m), 1); i2ob_gendisk.part[m].start_sect = 0; i2ob_gendisk.part[m].nr_sects = 0; } @@ -1079,14 +1079,14 @@ if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (!inode || !inode->i_rdev) + if (!inode || kdev_none(inode->i_rdev)) return -EINVAL; switch (cmd) { case HDIO_GETGEO: { struct hd_geometry g; - int u = MINOR(inode->i_rdev) & 0xF0; + int u = minor(inode->i_rdev) & 0xF0; i2o_block_biosparam(i2ob_sizes[u]<<1, &g.cylinders, &g.heads, &g.sectors); g.start = get_start_sect(inode->i_rdev); @@ -1121,7 +1121,7 @@ struct i2ob_device *dev; int minor; - minor = MINOR(inode->i_rdev); + minor = minor(inode->i_rdev); if (minor >= (MAX_I2OB<<4)) return -ENODEV; dev = &i2ob_dev[(minor&0xF0)]; @@ -1193,7 +1193,7 @@ if (!inode) return -EINVAL; - minor = MINOR(inode->i_rdev); + minor = minor(inode->i_rdev); if (minor >= MAX_I2OB<<4) return -ENODEV; dev=&i2ob_dev[(minor&0xF0)]; @@ -1384,7 +1384,7 @@ */ dev->req_queue = &i2ob_queues[c->unit]->req_queue; - grok_partitions(MKDEV(MAJOR_NR, unit), (long)(size>>9)); + grok_partitions(mk_kdev(MAJOR_NR, unit), (long)(size>>9)); /* * Register for the events we're interested in and that the @@ -1704,7 +1704,7 @@ */ static int i2ob_media_change(kdev_t dev) { - int i=MINOR(dev); + int i=minor(dev); i>>=4; if(i2ob_media_change_flag[i]) { @@ -1883,7 +1883,7 @@ * Finally see what is actually plugged in to our controllers */ for (i = 0; i < MAX_I2OB; i++) - register_disk(&i2ob_gendisk, MKDEV(MAJOR_NR,i<<4), 1<<4, + register_disk(&i2ob_gendisk, mk_kdev(MAJOR_NR,i<<4), 1<<4, &i2ob_fops, 0); i2ob_probe(); diff -Nru a/drivers/mtd/devices/blkmtd.c b/drivers/mtd/devices/blkmtd.c --- a/drivers/mtd/devices/blkmtd.c Tue Feb 26 11:57:56 2002 +++ b/drivers/mtd/devices/blkmtd.c Tue Feb 26 11:57:56 2002 @@ -989,8 +989,8 @@ rawdevice->as.nrpages = 0; rawdevice->as.a_ops = &blkmtd_aops; rawdevice->as.host = inode; - rawdevice->as.i_mmap = NULL; - rawdevice->as.i_mmap_shared = NULL; + INIT_LIST_HEAD(&rawdevice->as.i_mmap); + INIT_LIST_HEAD(&rawdevice->as.i_mmap_shared); spin_lock_init(&rawdevice->as.i_shared_lock); rawdevice->as.gfp_mask = GFP_KERNEL; rawdevice->file = file; diff -Nru a/drivers/mtd/maps/elan-104nc.c b/drivers/mtd/maps/elan-104nc.c --- a/drivers/mtd/maps/elan-104nc.c Tue Feb 26 11:57:59 2002 +++ b/drivers/mtd/maps/elan-104nc.c Tue Feb 26 11:57:59 2002 @@ -213,7 +213,7 @@ /* MTD device for all of the flash. */ static struct mtd_info *all_mtd; -static void __exit cleanup_elan_104nc(void) +static void cleanup_elan_104nc(void) { if( all_mtd ) { del_mtd_partitions( all_mtd ); diff -Nru a/drivers/mtd/maps/sbc_gxx.c b/drivers/mtd/maps/sbc_gxx.c --- a/drivers/mtd/maps/sbc_gxx.c Tue Feb 26 11:57:59 2002 +++ b/drivers/mtd/maps/sbc_gxx.c Tue Feb 26 11:57:59 2002 @@ -221,7 +221,7 @@ /* MTD device for all of the flash. */ static struct mtd_info *all_mtd; -static void __exit cleanup_sbc_gxx(void) +static void cleanup_sbc_gxx(void) { if( all_mtd ) { del_mtd_partitions( all_mtd ); diff -Nru a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c --- a/drivers/mtd/nftlcore.c Tue Feb 26 11:57:56 2002 +++ b/drivers/mtd/nftlcore.c Tue Feb 26 11:57:56 2002 @@ -156,7 +156,7 @@ #if LINUX_VERSION_CODE < 0x20328 resetup_one_dev(&nftl_gendisk, firstfree); #else - grok_partitions(MKDEV(MAJOR_NR,firstfree<nr_sects); #endif } @@ -779,7 +779,7 @@ struct NFTLrecord *nftl; int res; - nftl = NFTLs[MINOR(inode->i_rdev) >> NFTL_PARTN_BITS]; + nftl = NFTLs[minor(inode->i_rdev) >> NFTL_PARTN_BITS]; if (!nftl) return -EINVAL; @@ -853,7 +853,7 @@ (req->cmd == READ) ? "Read " : "Write", req->sector, req->current_nr_sectors); - dev = MINOR(req->rq_dev); + dev = minor(req->rq_dev); block = req->sector; nsect = req->current_nr_sectors; buffer = req->buffer; @@ -875,7 +875,7 @@ if (block + nsect > part_table[dev].nr_sects) { /* access past the end of device */ printk("nftl%c%d: bad access: block = %d, count = %d\n", - (MINOR(req->rq_dev)>>6)+'a', dev & 0xf, block, nsect); + (minor(req->rq_dev)>>6)+'a', dev & 0xf, block, nsect); up(&nftl->mutex); res = 0; /* fail */ goto repeat; @@ -933,7 +933,7 @@ static int nftl_open(struct inode *ip, struct file *fp) { - int nftlnum = MINOR(ip->i_rdev) >> NFTL_PARTN_BITS; + int nftlnum = minor(ip->i_rdev) >> NFTL_PARTN_BITS; struct NFTLrecord *thisNFTL; thisNFTL = NFTLs[nftlnum]; @@ -947,7 +947,7 @@ #endif if (!thisNFTL) { DEBUG(MTD_DEBUG_LEVEL2,"ENODEV: thisNFTL = %d, minor = %d, ip = %p, fp = %p\n", - nftlnum, ip->i_rdev, ip, fp); + nftlnum, minor(ip->i_rdev), ip, fp); return -ENODEV; } @@ -967,7 +967,7 @@ { struct NFTLrecord *thisNFTL; - thisNFTL = NFTLs[MINOR(inode->i_rdev) / 16]; + thisNFTL = NFTLs[minor(inode->i_rdev) / 16]; DEBUG(MTD_DEBUG_LEVEL2, "NFTL_release\n"); diff -Nru a/drivers/net/3c59x.c b/drivers/net/3c59x.c --- a/drivers/net/3c59x.c Tue Feb 26 11:57:56 2002 +++ b/drivers/net/3c59x.c Tue Feb 26 11:57:56 2002 @@ -2916,7 +2916,7 @@ static struct pci_driver vortex_driver = { name: "3c59x", probe: vortex_init_one, - remove: vortex_remove_one, + remove: __devexit_p(vortex_remove_one), id_table: vortex_pci_tbl, #ifdef CONFIG_PM suspend: vortex_suspend, diff -Nru a/drivers/net/8139cp.c b/drivers/net/8139cp.c --- a/drivers/net/8139cp.c Tue Feb 26 11:57:59 2002 +++ b/drivers/net/8139cp.c Tue Feb 26 11:57:59 2002 @@ -1371,7 +1371,7 @@ name: DRV_NAME, id_table: cp_pci_tbl, probe: cp_init_one, - remove: cp_remove_one, + remove: __devexit_p(cp_remove_one), }; static int __init cp_init (void) diff -Nru a/drivers/net/8139too.c b/drivers/net/8139too.c --- a/drivers/net/8139too.c Tue Feb 26 11:57:56 2002 +++ b/drivers/net/8139too.c Tue Feb 26 11:57:56 2002 @@ -2499,7 +2499,7 @@ name: DRV_NAME, id_table: rtl8139_pci_tbl, probe: rtl8139_init_one, - remove: rtl8139_remove_one, + remove: __devexit_p(rtl8139_remove_one), #ifdef CONFIG_PM suspend: rtl8139_suspend, resume: rtl8139_resume, diff -Nru a/drivers/net/Config.help b/drivers/net/Config.help --- a/drivers/net/Config.help Tue Feb 26 11:57:56 2002 +++ b/drivers/net/Config.help Tue Feb 26 11:57:56 2002 @@ -3,6 +3,10 @@ MIPS-32-based Baget embedded system. This chipset is better known via the NE2100 cards. +CONFIG_LASI_82596 + Say Y here to support the on-board Intel 82596 ethernet controller + built into Hewlett-Packard PA-RISC machines. + CONFIG_MIPS_JAZZ_SONIC This is the driver for the onboard card of MIPS Magnum 4000, Acer PICA, Olivetti M700-10 and a few other identical OEM systems. @@ -214,6 +218,12 @@ pppd, along with binaries of a patched pppd package can be found at: . +CONFIG_PPPOATM + Support PPP (Point to Point Protocol) encapsulated in ATM frames. + This implementation does not yet comply with section 8 of RFC2364, + which can lead to bad results if the ATM peer loses state and + changes its encapsulation unilaterally. + CONFIG_NET_RADIO Support for wireless LANs and everything having to do with radio, but not with amateur radio or FM broadcasting. @@ -806,6 +816,42 @@ say M here and read . This is recommended. The module will be called dl2k.o. +CONFIG_E1000 + This driver supports Intel(R) PRO/1000 gigabit ethernet family of + adapters, which includes: + + Controller Adapter Name Board IDs + ---------- ------------ --------- + 82542 PRO/1000 Gigabit Server Adapter 700262-xxx, + 717037-xxx + 82543 PRO/1000 F Server Adapter 738640-xxx, + A38888-xxx, + A06512-xxx + 82543 PRO/1000 T Server Adapter A19845-xxx, + A33948-xxx + 82544 PRO/1000 XT Server Adapter A51580-xxx + 82544 PRO/1000 XF Server Adapter A50484-xxx + 82544 PRO/1000 T Desktop Adapter A62947-xxx + + For more information on how to identify your adapter, go to the + Adapter & Driver ID Guide at: + + + + For general information and support, go to the Intel support + website at: + + + + More specific information on configuring the driver is in + . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called e1000.o. If you want to compile it as a + module, say M here and read as well + as . + CONFIG_LANCE If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from @@ -817,6 +863,10 @@ say M here and read . This is recommended. The module will be called lance.o. +CONFIG_MIPS_AU1000_ENET + If you have an Alchemy Semi AU1000 ethernet controller + on an SGI MIPS system, say Y. Otherwise, say N. + CONFIG_SGI_IOC3_ETH If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from @@ -1290,6 +1340,24 @@ module, say M here and read as well as . +CONFIG_DE2104X + This driver is developed for the SMC EtherPower series Ethernet + cards and also works with cards based on the DECchip + 21040 (Tulip series) chips. Some LinkSys PCI cards are + of this type. (If your card is NOT SMC EtherPower 10/100 PCI + (smc9332dst), you can also try the driver for "Generic DECchip" + cards, above. However, most people with a network card of this type + will say Y here.) Do read the Ethernet-HOWTO, available from + . More specific + information is contained in + . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called tulip.o. If you want to compile it as a + module, say M here and read as well + as . + CONFIG_TULIP This driver is developed for the SMC EtherPower series Ethernet cards and also works with cards based on the DECchip @@ -1308,6 +1376,20 @@ module, say M here and read as well as . +CONFIG_TULIP_MWI + This configures your Tulip card specifically for the card and + system cache line size type you are using. + + This is experimental code, not yet tested on many boards. + + If unsure, say N. + +CONFIG_TULIP_MMIO + Use PCI shared memory for the NIC registers, rather than going through + the Tulip's PIO (programmed I/O ports). Faster, but could produce + obscure bugs if your mainboard has memory controller timing issues. + If in doubt, say N. + CONFIG_DGRS This is support for the Digi International RightSwitch series of PCI/EISA Ethernet switch cards. These include the SE-4 and the SE-6 @@ -1338,6 +1420,11 @@ cards. Specifications and data at . +CONFIG_LP486E + Say Y here to support the 82596-based on-board Ethernet controller + for the Panther motherboard, which is one of the two shipped in the + Intel Professional Workstation. + CONFIG_ETH16I If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from @@ -1376,6 +1463,16 @@ The module will be called via-rhine.o. If you want to compile it as a module, say M here and read as well as . + +CONFIG_VIA_RHINE_MMIO + This instructs the driver to use PCI shared memory (MMIO) instead of + programmed I/O ports (PIO). Enabling this gives an improvement in + processing time in parts of the driver. + + It is not known if this works reliably on all "rhine" based cards, + but it has been tested successfully on some DFE-530TX adapters. + + If unsure, say N. CONFIG_DM9102 This driver is for DM9102(A)/DM9132/DM9801 compatible PCI cards from diff -Nru a/drivers/net/Config.in b/drivers/net/Config.in --- a/drivers/net/Config.in Tue Feb 26 11:57:56 2002 +++ b/drivers/net/Config.in Tue Feb 26 11:57:56 2002 @@ -231,6 +231,7 @@ bool ' Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I fi dep_tristate 'D-Link DL2000-based Gigabit Ethernet support' CONFIG_DL2K $CONFIG_PCI +dep_tristate 'Intel(R) PRO/1000 Gigabit Ethernet support' CONFIG_E1000 $CONFIG_PCI dep_tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS $CONFIG_SBUS dep_tristate 'National Semiconduct DP83820 support' CONFIG_NS83820 $CONFIG_PCI dep_tristate 'Packet Engines Hamachi GNIC-II support' CONFIG_HAMACHI $CONFIG_PCI diff -Nru a/drivers/net/Makefile b/drivers/net/Makefile --- a/drivers/net/Makefile Tue Feb 26 11:57:58 2002 +++ b/drivers/net/Makefile Tue Feb 26 11:57:58 2002 @@ -25,6 +25,10 @@ obj-y += tulip/tulip.o endif +ifeq ($(CONFIG_E1000),y) + obj-y += e1000/e1000.o +endif + ifeq ($(CONFIG_ISDN_PPP),y) obj-$(CONFIG_ISDN) += slhc.o endif @@ -32,6 +36,7 @@ subdir-$(CONFIG_NET_PCMCIA) += pcmcia subdir-$(CONFIG_NET_WIRELESS) += wireless subdir-$(CONFIG_TULIP) += tulip +subdir-$(CONFIG_E1000) += e1000 subdir-$(CONFIG_IRDA) += irda subdir-$(CONFIG_TR) += tokenring subdir-$(CONFIG_WAN) += wan diff -Nru a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c --- a/drivers/net/arcnet/com20020-pci.c Tue Feb 26 11:57:57 2002 +++ b/drivers/net/arcnet/com20020-pci.c Tue Feb 26 11:57:57 2002 @@ -160,7 +160,7 @@ name: "com20020", id_table: com20020pci_id_table, probe: com20020pci_probe, - remove: com20020pci_remove + remove: __devexit_p(com20020pci_remove) }; static int __init com20020pci_init(void) diff -Nru a/drivers/net/defxx.c b/drivers/net/defxx.c --- a/drivers/net/defxx.c Tue Feb 26 11:57:56 2002 +++ b/drivers/net/defxx.c Tue Feb 26 11:57:56 2002 @@ -3362,7 +3362,7 @@ static struct pci_driver dfx_driver = { name: "defxx", probe: dfx_init_one, - remove: dfx_remove_one, + remove: __devexit_p(dfx_remove_one), id_table: dfx_pci_tbl, }; diff -Nru a/drivers/net/dl2k.c b/drivers/net/dl2k.c --- a/drivers/net/dl2k.c Tue Feb 26 11:57:59 2002 +++ b/drivers/net/dl2k.c Tue Feb 26 11:57:59 2002 @@ -1682,7 +1682,7 @@ name:"dl2k", id_table:rio_pci_tbl, probe:rio_probe1, - remove:rio_remove1, + remove: __devexit_p(rio_remove1), }; static int __init diff -Nru a/drivers/net/e1000/LICENSE b/drivers/net/e1000/LICENSE --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/e1000/LICENSE Tue Feb 26 11:58:00 2002 @@ -0,0 +1,69 @@ +This software program is available to you under a choice of one of two +licenses. You may choose to be licensed under either the GNU General Public +License (GPL) Version 2, June 1991, available at +http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the +text of which follows: + +Recipient has requested a license and Intel Corporation ("Intel") is willing +to grant a license for the software entitled Linux Base Driver for the +Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided +by Intel Corporation. The following definitions apply to this license: + +"Licensed Patents" means patent claims licensable by Intel Corporation which +are necessarily infringed by the use of sale of the Software alone or when +combined with the operating system referred to below. + +"Recipient" means the party to whom Intel delivers this Software. + +"Licensee" means Recipient and those third parties that receive a license to +any operating system available under the GNU Public License version 2.0 or +later. + +Copyright (c) 1999 - 2002 Intel Corporation. +All rights reserved. + +The license is provided to Recipient and Recipient's Licensees under the +following terms. + +Redistribution and use in source and binary forms of the Software, with or +without modification, are permitted provided that the following conditions +are met: + +Redistributions of source code of the Software may retain the above +copyright notice, this list of conditions and the following disclaimer. + +Redistributions in binary form of the Software may reproduce the above +copyright notice, this list of conditions and the following disclaimer in +the documentation and/or materials provided with the distribution. + +Neither the name of Intel Corporation nor the names of its contributors +shall be used to endorse or promote products derived from this Software +without specific prior written permission. + +Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, +royalty-free patent license under Licensed Patents to make, use, sell, offer +to sell, import and otherwise transfer the Software, if any, in source code +and object code form. This license shall include changes to the Software +that are error corrections or other minor changes to the Software that do +not add functionality or features when the Software is incorporated in any +version of an operating system that has been distributed under the GNU +General Public License 2.0 or later. This patent license shall apply to the +combination of the Software and any operating system licensed under the GNU +Public License version 2.0 or later if, at the time Intel provides the +Software to Recipient, such addition of the Software to the then publicly +available versions of such operating systems available under the GNU Public +License version 2.0 or later (whether in gold, beta or alpha form) causes +such combination to be covered by the Licensed Patents. The patent license +shall not apply to any other combinations which include the Software. NO +hardware per se is licensed hereunder. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED +AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff -Nru a/drivers/net/e1000/Makefile b/drivers/net/e1000/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/e1000/Makefile Tue Feb 26 11:58:00 2002 @@ -0,0 +1,16 @@ +# +# Makefile for the Intel(R) PRO/1000 ethernet driver +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +O_TARGET := e1000.o + +obj-y := e1000_main.o e1000_mac.o e1000_phy.o \ + e1000_ethtool.o e1000_param.o e1000_proc.o +obj-m := $(O_TARGET) + +include $(TOPDIR)/Rules.make diff -Nru a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/e1000/e1000.h Tue Feb 26 11:58:00 2002 @@ -0,0 +1,233 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +/* Linux PRO/1000 Ethernet Driver main header file */ + +#ifndef _E1000_H_ +#define _E1000_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct e1000_adapter; + +#include "e1000_mac.h" +#include "e1000_phy.h" + +#define BAR_0 0 + +/* Advertise that we can DMA from any address location */ +#define E1000_DMA_MASK (~0x0UL) + +#if DBG +#define E1000_DBG(args...) printk(KERN_DEBUG "e1000: " args) +#else +#define E1000_DBG(args...) +#endif + +#define E1000_ERR(args...) printk(KERN_ERR "e1000: " args) + +#ifdef CONFIG_PPC +#define E1000_MAX_INTR 1 +#else +#define E1000_MAX_INTR 10 +#endif + +/* Supported Rx Buffer Sizes */ +#define E1000_RXBUFFER_2048 2048 +#define E1000_RXBUFFER_4096 4096 +#define E1000_RXBUFFER_8192 8192 +#define E1000_RXBUFFER_16384 16384 + +/* How many Tx Descriptors do we need to call netif_wake_queue ? */ +#define E1000_TX_QUEUE_WAKE 16 + +#define E1000_JUMBO_PBA 0x00000028 +#define E1000_DEFAULT_PBA 0x00000030 + +/* only works for sizes that are powers of 2 */ +#define E1000_ROUNDUP(i, size) ((i) = (((i) + (size) - 1) & ~((size) - 1))) + +/* wrapper around a pointer to a socket buffer, + * so a DMA handle can be stored along with the buffer */ +struct e1000_buffer { + struct sk_buff *skb; + uint64_t dma; + unsigned long length; +}; + +struct e1000_desc_ring { + /* pointer to the descriptor ring memory */ + void *desc; + /* physical address of the descriptor ring */ + dma_addr_t dma; + /* length of descriptor ring in bytes */ + unsigned int size; + /* number of descriptors in the ring */ + unsigned int count; + /* (atomic) number of desc with no buffer */ + atomic_t unused; + /* number of desc with no buffer */ + unsigned int unused_count; + /* next descriptor to associate a buffer with */ + unsigned int next_to_use; + /* next descriptor to check for DD status bit */ + unsigned int next_to_clean; + /* array of buffer information structs */ + struct e1000_buffer *buffer_info; +}; + +#define E1000_RX_DESC(ring, i) \ + (&(((struct e1000_rx_desc *)((ring).desc))[i])) + +#define E1000_TX_DESC(ring, i) \ + (&(((struct e1000_tx_desc *)((ring).desc))[i])) + +#define E1000_CONTEXT_DESC(ring, i) \ + (&(((struct e1000_context_desc *)((ring).desc))[i])) + +/* board specific private data structure */ + +struct e1000_adapter { + struct timer_list watchdog_timer; + struct timer_list phy_info_timer; +#ifdef CONFIG_PROC_FS + struct list_head proc_list_head; +#endif + char *id_string; + uint32_t bd_number; + uint32_t rx_buffer_len; + uint32_t part_num; + uint32_t wol; + uint16_t link_speed; + uint16_t link_duplex; + spinlock_t stats_lock; + atomic_t irq_sem; + boolean_t rx_csum; + + /* TX */ + struct e1000_desc_ring tx_ring; + unsigned long trans_finish; + uint32_t tx_int_delay; + uint32_t txd_cmd; + + /* RX */ + struct e1000_desc_ring rx_ring; + uint64_t hw_csum_err; + uint64_t hw_csum_good; + uint32_t rx_int_delay; + + /* OS defined structs */ + struct net_device *netdev; + struct pci_dev *pdev; + struct net_device_stats net_stats; + + /* structs defined in e1000_mac.h or e1000_phy.h */ + struct e1000_shared_adapter shared; + struct e1000_shared_stats stats; + struct e1000_phy_info phy_info; + struct e1000_phy_stats phy_stats; +}; + +#endif /* _E1000_H_ */ diff -Nru a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/e1000/e1000_ethtool.c Tue Feb 26 11:58:00 2002 @@ -0,0 +1,377 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/* ethtool support for e1000 */ + +#include "e1000.h" + +#include +#include + +extern char e1000_driver_name[]; +extern char e1000_driver_version[]; + +extern int e1000_up(struct e1000_adapter *adapter); +extern void e1000_down(struct e1000_adapter *adapter); +extern void e1000_enable_WOL(struct e1000_adapter *adapter); + +static void +e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd) +{ + struct e1000_shared_adapter *shared = &adapter->shared; + + if(shared->media_type == e1000_media_type_copper) { + + ecmd->supported = (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full| + SUPPORTED_Autoneg | + SUPPORTED_TP); + + ecmd->advertising = ADVERTISED_TP; + + if(shared->autoneg == 1) { + ecmd->advertising |= ADVERTISED_Autoneg; + + /* the e1000 autoneg seems to match ethtool nicely */ + + ecmd->advertising |= shared->autoneg_advertised; + } + + ecmd->port = PORT_TP; + ecmd->phy_address = shared->phy_addr; + + if(shared->mac_type == e1000_82543) + ecmd->transceiver = XCVR_EXTERNAL; + else + ecmd->transceiver = XCVR_INTERNAL; + + } else { + ecmd->supported = (SUPPORTED_1000baseT_Full | + SUPPORTED_FIBRE | + SUPPORTED_Autoneg); + + ecmd->advertising = (SUPPORTED_1000baseT_Full | + SUPPORTED_FIBRE | + SUPPORTED_Autoneg); + + ecmd->port = PORT_FIBRE; + + ecmd->transceiver = XCVR_EXTERNAL; + } + + if(netif_carrier_ok(adapter->netdev)) { + + e1000_get_speed_and_duplex(shared, &adapter->link_speed, + &adapter->link_duplex); + ecmd->speed = adapter->link_speed; + + /* unfortunatly FULL_DUPLEX != DUPLEX_FULL + * and HALF_DUPLEX != DUPLEX_HALF */ + + if(adapter->link_duplex == FULL_DUPLEX) + ecmd->duplex = DUPLEX_FULL; + else + ecmd->duplex = DUPLEX_HALF; + } else { + ecmd->speed = -1; + ecmd->duplex = -1; + } + + ecmd->autoneg = (shared->autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE); + + return; +} + +static int +e1000_ethtool_sset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd) +{ + struct e1000_shared_adapter *shared = &adapter->shared; + + if(ecmd->autoneg == AUTONEG_ENABLE) { + shared->autoneg = 1; + shared->autoneg_advertised = (ecmd->advertising & 0x002F); + } else { + shared->autoneg = 0; + switch(ecmd->speed + ecmd->duplex) { + case SPEED_10 + DUPLEX_HALF: + shared->forced_speed_duplex = e1000_10_half; + break; + case SPEED_10 + DUPLEX_FULL: + shared->forced_speed_duplex = e1000_10_full; + break; + case SPEED_100 + DUPLEX_HALF: + shared->forced_speed_duplex = e1000_100_half; + break; + case SPEED_100 + DUPLEX_FULL: + shared->forced_speed_duplex = e1000_100_full; + break; + case SPEED_1000 + DUPLEX_FULL: + shared->autoneg = 1; + shared->autoneg_advertised = ADVERTISE_1000_FULL; + break; + case SPEED_1000 + DUPLEX_HALF: /* not supported */ + default: + return -EINVAL; + } + } + + /* reset the link */ + + e1000_down(adapter); + e1000_up(adapter); + + return 0; +} + +static inline int +e1000_eeprom_size(struct e1000_shared_adapter *shared) +{ + return 128; +} + +static void +e1000_ethtool_gdrvinfo(struct e1000_adapter *adapter, + struct ethtool_drvinfo *drvinfo) +{ + strncpy(drvinfo->driver, e1000_driver_name, 32); + strncpy(drvinfo->version, e1000_driver_version, 32); + strncpy(drvinfo->fw_version, "", 32); + strncpy(drvinfo->bus_info, adapter->pdev->slot_name, 32); + drvinfo->eedump_len = e1000_eeprom_size(&adapter->shared); + return; +} + +static void +e1000_ethtool_geeprom(struct e1000_adapter *adapter, + struct ethtool_eeprom *eeprom, uint16_t *eeprom_buff) +{ + struct e1000_shared_adapter *shared = &adapter->shared; + int i, max_len; + + eeprom->magic = shared->vendor_id | (shared->device_id << 16); + + max_len = e1000_eeprom_size(shared); + + if ((eeprom->offset + eeprom->len) > max_len) + eeprom->len = (max_len - eeprom->offset); + + for(i = 0; i < max_len; i++) + eeprom_buff[i] = e1000_read_eeprom(&adapter->shared, i); + + return; +} + +static void +e1000_ethtool_gwol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol) +{ + struct e1000_shared_adapter *shared = &adapter->shared; + + if(shared->mac_type < e1000_82544) { + wol->supported = 0; + wol->wolopts = 0; + return; + } + + wol->supported = WAKE_PHY | WAKE_UCAST | + WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC; + + wol->wolopts = 0; + if(adapter->wol & E1000_WUFC_LNKC) + wol->wolopts |= WAKE_PHY; + if(adapter->wol & E1000_WUFC_EX) + wol->wolopts |= WAKE_UCAST; + if(adapter->wol & E1000_WUFC_MC) + wol->wolopts |= WAKE_MCAST; + if(adapter->wol & E1000_WUFC_BC) + wol->wolopts |= WAKE_BCAST; + if(adapter->wol & E1000_WUFC_MAG) + wol->wolopts |= WAKE_MAGIC; + + return; +} + +static int +e1000_ethtool_swol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol) +{ + struct e1000_shared_adapter *shared = &adapter->shared; + + if(shared->mac_type < e1000_82544) + return wol->wolopts == 0 ? 0 : -EOPNOTSUPP; + + adapter->wol = 0; + + if(wol->wolopts & WAKE_PHY) + adapter->wol |= E1000_WUFC_LNKC; + if(wol->wolopts & WAKE_UCAST) + adapter->wol |= E1000_WUFC_EX; + if(wol->wolopts & WAKE_MCAST) + adapter->wol |= E1000_WUFC_MC; + if(wol->wolopts & WAKE_BCAST) + adapter->wol |= E1000_WUFC_BC; + if(wol->wolopts & WAKE_MAGIC) + adapter->wol |= E1000_WUFC_MAG; + + e1000_enable_WOL(adapter); + return 0; +} + +int +e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr) +{ + struct e1000_adapter *adapter = netdev->priv; + void *addr = ifr->ifr_data; + uint32_t cmd; + + if(get_user(cmd, (uint32_t *) addr)) + return -EFAULT; + + switch(cmd) { + case ETHTOOL_GSET: { + struct ethtool_cmd ecmd = {ETHTOOL_GSET}; + e1000_ethtool_gset(adapter, &ecmd); + if(copy_to_user(addr, &ecmd, sizeof(ecmd))) + return -EFAULT; + return 0; + } + case ETHTOOL_SSET: { + struct ethtool_cmd ecmd; + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + if(copy_from_user(&ecmd, addr, sizeof(ecmd))) + return -EFAULT; + return e1000_ethtool_sset(adapter, &ecmd); + } + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo drvinfo = {ETHTOOL_GDRVINFO}; + e1000_ethtool_gdrvinfo(adapter, &drvinfo); + if(copy_to_user(addr, &drvinfo, sizeof(drvinfo))) + return -EFAULT; + return 0; + } + case ETHTOOL_NWAY_RST: { + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + e1000_down(adapter); + e1000_up(adapter); + return 0; + } + case ETHTOOL_GLINK: { + struct ethtool_value link = {ETHTOOL_GLINK}; + link.data = netif_carrier_ok(netdev); + if(copy_to_user(addr, &link, sizeof(link))) + return -EFAULT; + return 0; + } + case ETHTOOL_GWOL: { + struct ethtool_wolinfo wol = {ETHTOOL_GWOL}; + e1000_ethtool_gwol(adapter, &wol); + if(copy_to_user(addr, &wol, sizeof(wol)) != 0) + return -EFAULT; + return 0; + } + case ETHTOOL_SWOL: { + struct ethtool_wolinfo wol; + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + if(copy_from_user(&wol, addr, sizeof(wol)) != 0) + return -EFAULT; + return e1000_ethtool_swol(adapter, &wol); + } + case ETHTOOL_GEEPROM: { + struct ethtool_eeprom eeprom = {ETHTOOL_GEEPROM}; + uint16_t eeprom_buff[256]; + + if(copy_from_user(&eeprom, addr, sizeof(eeprom))) + return -EFAULT; + + e1000_ethtool_geeprom(adapter, &eeprom, eeprom_buff); + + if(copy_to_user(addr, &eeprom, sizeof(eeprom))) + return -EFAULT; + + addr += offsetof(struct ethtool_eeprom, data); + + if(copy_to_user(addr, eeprom_buff + eeprom.offset, eeprom.len)) + return -EFAULT; + return 0; + } + default: + return -EOPNOTSUPP; + } +} + + diff -Nru a/drivers/net/e1000/e1000_mac.c b/drivers/net/e1000/e1000_mac.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/e1000/e1000_mac.c Tue Feb 26 11:58:00 2002 @@ -0,0 +1,1821 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/* e1000_mac.c + * Shared functions for accessing and configuring the MAC + */ + +#include "e1000_mac.h" +#include "e1000_phy.h" + +/****************************************************************************** + * Raises the EEPROM's clock input. + * + * shared - Struct containing variables accessed by shared code + * eecd_reg - EECD's current value + *****************************************************************************/ +static void +e1000_raise_clock(struct e1000_shared_adapter *shared, + uint32_t *eecd_reg) +{ + /* Raise the clock input to the EEPROM (by setting the SK bit), and then + * wait 50 microseconds. + */ + *eecd_reg = *eecd_reg | E1000_EECD_SK; + E1000_WRITE_REG(shared, EECD, *eecd_reg); + usec_delay(50); + return; +} + +/****************************************************************************** + * Lowers the EEPROM's clock input. + * + * shared - Struct containing variables accessed by shared code + * eecd_reg - EECD's current value + *****************************************************************************/ +static void +e1000_lower_clock(struct e1000_shared_adapter *shared, + uint32_t *eecd_reg) +{ + /* Lower the clock input to the EEPROM (by clearing the SK bit), and then + * wait 50 microseconds. + */ + *eecd_reg = *eecd_reg & ~E1000_EECD_SK; + E1000_WRITE_REG(shared, EECD, *eecd_reg); + usec_delay(50); + return; +} + +/****************************************************************************** + * Shift data bits out to the EEPROM. + * + * shared - Struct containing variables accessed by shared code + * data - data to send to the EEPROM + * count - number of bits to shift out + *****************************************************************************/ +static void +e1000_shift_out_bits(struct e1000_shared_adapter *shared, + uint16_t data, + uint16_t count) +{ + uint32_t eecd_reg; + uint32_t mask; + + /* We need to shift "count" bits out to the EEPROM. So, value in the + * "data" parameter will be shifted out to the EEPROM one bit at a time. + * In order to do this, "data" must be broken down into bits. + */ + mask = 0x01 << (count - 1); + eecd_reg = E1000_READ_REG(shared, EECD); + eecd_reg &= ~(E1000_EECD_DO | E1000_EECD_DI); + do { + /* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1", + * and then raising and then lowering the clock (the SK bit controls + * the clock input to the EEPROM). A "0" is shifted out to the EEPROM + * by setting "DI" to "0" and then raising and then lowering the clock. + */ + eecd_reg &= ~E1000_EECD_DI; + + if(data & mask) + eecd_reg |= E1000_EECD_DI; + + E1000_WRITE_REG(shared, EECD, eecd_reg); + + usec_delay(50); + + e1000_raise_clock(shared, &eecd_reg); + e1000_lower_clock(shared, &eecd_reg); + + mask = mask >> 1; + + } while(mask); + + /* We leave the "DI" bit set to "0" when we leave this routine. */ + eecd_reg &= ~E1000_EECD_DI; + E1000_WRITE_REG(shared, EECD, eecd_reg); + return; +} + +/****************************************************************************** + * Shift data bits in from the EEPROM + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +static uint16_t +e1000_shift_in_bits(struct e1000_shared_adapter *shared) +{ + uint32_t eecd_reg; + uint32_t i; + uint16_t data; + + /* In order to read a register from the EEPROM, we need to shift 16 bits + * in from the EEPROM. Bits are "shifted in" by raising the clock input to + * the EEPROM (setting the SK bit), and then reading the value of the "DO" + * bit. During this "shifting in" process the "DI" bit should always be + * clear.. + */ + + eecd_reg = E1000_READ_REG(shared, EECD); + + eecd_reg &= ~(E1000_EECD_DO | E1000_EECD_DI); + data = 0; + + for(i = 0; i < 16; i++) { + data = data << 1; + e1000_raise_clock(shared, &eecd_reg); + + eecd_reg = E1000_READ_REG(shared, EECD); + + eecd_reg &= ~(E1000_EECD_DI); + if(eecd_reg & E1000_EECD_DO) + data |= 1; + + e1000_lower_clock(shared, &eecd_reg); + } + + return data; +} + +/****************************************************************************** + * Prepares EEPROM for access + * + * shared - Struct containing variables accessed by shared code + * + * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This + * function should be called before issuing a command to the EEPROM. + *****************************************************************************/ +static void +e1000_setup_eeprom(struct e1000_shared_adapter *shared) +{ + uint32_t eecd_reg; + + eecd_reg = E1000_READ_REG(shared, EECD); + + /* Clear SK and DI */ + eecd_reg &= ~(E1000_EECD_SK | E1000_EECD_DI); + E1000_WRITE_REG(shared, EECD, eecd_reg); + + /* Set CS */ + eecd_reg |= E1000_EECD_CS; + E1000_WRITE_REG(shared, EECD, eecd_reg); + return; +} + +/****************************************************************************** + * Returns EEPROM to a "standby" state + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +static void +e1000_standby_eeprom(struct e1000_shared_adapter *shared) +{ + uint32_t eecd_reg; + + eecd_reg = E1000_READ_REG(shared, EECD); + + /* Deselct EEPROM */ + eecd_reg &= ~(E1000_EECD_CS | E1000_EECD_SK); + E1000_WRITE_REG(shared, EECD, eecd_reg); + usec_delay(50); + + /* Clock high */ + eecd_reg |= E1000_EECD_SK; + E1000_WRITE_REG(shared, EECD, eecd_reg); + usec_delay(50); + + /* Select EEPROM */ + eecd_reg |= E1000_EECD_CS; + E1000_WRITE_REG(shared, EECD, eecd_reg); + usec_delay(50); + + /* Clock low */ + eecd_reg &= ~E1000_EECD_SK; + E1000_WRITE_REG(shared, EECD, eecd_reg); + usec_delay(50); + return; +} + + +/****************************************************************************** + * Forces the MAC's flow control settings. + * + * shared - Struct containing variables accessed by shared code + * + * Sets the TFCE and RFCE bits in the device control register to reflect + * the adapter settings. TFCE and RFCE need to be explicitly set by + * software when a Copper PHY is used because autonegotiation is managed + * by the PHY rather than the MAC. Software must also configure these + * bits when link is forced on a fiber connection. + *****************************************************************************/ +static void +e1000_force_mac_fc(struct e1000_shared_adapter *shared) +{ + uint32_t ctrl_reg; + + DEBUGFUNC("e1000_force_mac_fc"); + + /* Get the current configuration of the Device Control Register */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + + /* Because we didn't get link via the internal auto-negotiation + * mechanism (we either forced link or we got link via PHY + * auto-neg), we have to manually enable/disable transmit an + * receive flow control. + * + * The "Case" statement below enables/disable flow control + * according to the "shared->fc" parameter. + * + * The possible values of the "fc" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause + * frames but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames + * frames but we do not receive pause frames). + * 3: Both Rx and TX flow control (symmetric) is enabled. + * other: No other values should be possible at this point. + */ + + switch (shared->fc) { + case e1000_fc_none: + ctrl_reg &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE)); + break; + case e1000_fc_rx_pause: + ctrl_reg &= (~E1000_CTRL_TFCE); + ctrl_reg |= E1000_CTRL_RFCE; + break; + case e1000_fc_tx_pause: + ctrl_reg &= (~E1000_CTRL_RFCE); + ctrl_reg |= E1000_CTRL_TFCE; + break; + case e1000_fc_full: + ctrl_reg |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE); + break; + default: + DEBUGOUT("Flow control param set incorrectly\n"); + ASSERT(0); + break; + } + + /* Disable TX Flow Control for 82542 (rev 2.0) */ + if(shared->mac_type == e1000_82542_rev2_0) + ctrl_reg &= (~E1000_CTRL_TFCE); + + + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + return; +} + +/****************************************************************************** + * Reset the transmit and receive units; mask and clear all interrupts. + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +void +e1000_adapter_stop(struct e1000_shared_adapter *shared) +{ + uint32_t ctrl_reg; + uint32_t ctrl_ext_reg; + uint32_t icr_reg; + uint16_t pci_cmd_word; + + DEBUGFUNC("e1000_shared_adapter_stop"); + + /* If we are stopped or resetting exit gracefully and wait to be + * started again before accessing the hardware. + */ + if(shared->adapter_stopped) { + DEBUGOUT("Exiting because the adapter is already stopped!!!\n"); + return; + } + + /* Set the Adapter Stopped flag so other driver functions stop + * touching the Hardware. + */ + shared->adapter_stopped = TRUE; + + /* For 82542 (rev 2.0), disable MWI before issuing a device reset */ + if(shared->mac_type == e1000_82542_rev2_0) { + if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { + DEBUGOUT("Disabling MWI on 82542 rev 2.0\n"); + + pci_cmd_word = shared->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE; + + e1000_write_pci_cfg(shared, PCI_COMMAND_REGISTER, &pci_cmd_word); + } + } + + /* Clear interrupt mask to stop board from generating interrupts */ + DEBUGOUT("Masking off all interrupts\n"); + E1000_WRITE_REG(shared, IMC, 0xffffffff); + + /* Disable the Transmit and Receive units. Then delay to allow + * any pending transactions to complete before we hit the MAC with + * the global reset. + */ + E1000_WRITE_REG(shared, RCTL, 0); + E1000_WRITE_REG(shared, TCTL, E1000_TCTL_PSP); + + /* The tbi_compatibility_on Flag must be cleared when Rctl is cleared. */ + shared->tbi_compatibility_on = FALSE; + + msec_delay(10); + + /* Issue a global reset to the MAC. This will reset the chip's + * transmit, receive, DMA, and link units. It will not effect + * the current PCI configuration. The global reset bit is self- + * clearing, and should clear within a microsecond. + */ + DEBUGOUT("Issuing a global reset to MAC\n"); + ctrl_reg = E1000_READ_REG(shared, CTRL); + E1000_WRITE_REG(shared, CTRL, (ctrl_reg | E1000_CTRL_RST)); + + /* Delay a few ms just to allow the reset to complete */ + msec_delay(10); + +#if DBG + /* Make sure the self-clearing global reset bit did self clear */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + + ASSERT(!(ctrl_reg & E1000_CTRL_RST)); +#endif + + /* Force a reload from the EEPROM */ + ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT); + ctrl_ext_reg |= E1000_CTRL_EXT_EE_RST; + E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg); + msec_delay(2); + + /* Clear interrupt mask to stop board from generating interrupts */ + DEBUGOUT("Masking off all interrupts\n"); + E1000_WRITE_REG(shared, IMC, 0xffffffff); + + /* Clear any pending interrupt events. */ + icr_reg = E1000_READ_REG(shared, ICR); + + /* If MWI was previously enabled, reenable it. */ + if(shared->mac_type == e1000_82542_rev2_0) { + if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { + e1000_write_pci_cfg(shared, + PCI_COMMAND_REGISTER, &shared->pci_cmd_word); + } + } + return; +} + +/****************************************************************************** + * Performs basic configuration of the adapter. + * + * shared - Struct containing variables accessed by shared code + * + * Assumes that the controller has previously been reset and is in a + * post-reset uninitialized state. Initializes the receive address registers, + * multicast table, and VLAN filter table. Calls routines to setup link + * configuration and flow control settings. Clears all on-chip counters. Leaves + * the transmit and receive units disabled and uninitialized. + *****************************************************************************/ +boolean_t +e1000_init_hw(struct e1000_shared_adapter *shared) +{ + uint32_t status_reg; + uint32_t i; + uint16_t pci_cmd_word; + boolean_t status; + + DEBUGFUNC("e1000_init_hw"); + + /* Set the Media Type and exit with error if it is not valid. */ + if(shared->mac_type != e1000_82543) { + /* tbi_compatibility is only valid on 82543 */ + shared->tbi_compatibility_en = FALSE; + } + + if(shared->mac_type >= e1000_82543) { + status_reg = E1000_READ_REG(shared, STATUS); + if(status_reg & E1000_STATUS_TBIMODE) { + shared->media_type = e1000_media_type_fiber; + /* tbi_compatibility not valid on fiber */ + shared->tbi_compatibility_en = FALSE; + } else { + shared->media_type = e1000_media_type_copper; + } + } else { + /* This is an 82542 (fiber only) */ + shared->media_type = e1000_media_type_fiber; + } + + /* Disabling VLAN filtering. */ + DEBUGOUT("Initializing the IEEE VLAN\n"); + E1000_WRITE_REG(shared, VET, 0); + + e1000_clear_vfta(shared); + + /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */ + if(shared->mac_type == e1000_82542_rev2_0) { + if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { + DEBUGOUT("Disabling MWI on 82542 rev 2.0\n"); + pci_cmd_word = shared->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE; + e1000_write_pci_cfg(shared, PCI_COMMAND_REGISTER, &pci_cmd_word); + } + E1000_WRITE_REG(shared, RCTL, E1000_RCTL_RST); + + msec_delay(5); + } + + /* Setup the receive address. This involves initializing all of the Receive + * Address Registers (RARs 0 - 15). + */ + e1000_init_rx_addrs(shared); + + /* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */ + if(shared->mac_type == e1000_82542_rev2_0) { + E1000_WRITE_REG(shared, RCTL, 0); + + msec_delay(1); + + if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { + e1000_write_pci_cfg(shared, + PCI_COMMAND_REGISTER, &shared->pci_cmd_word); + } + } + + /* Zero out the Multicast HASH table */ + DEBUGOUT("Zeroing the MTA\n"); + for(i = 0; i < E1000_MC_TBL_SIZE; i++) + E1000_WRITE_REG_ARRAY(shared, MTA, i, 0); + + /* Call a subroutine to configure the link and setup flow control. */ + status = e1000_setup_fc_and_link(shared); + + /* Clear all of the statistics registers (clear on read). It is + * important that we do this after we have tried to establish link + * because the symbol error count will increment wildly if there + * is no link. + */ + e1000_clear_hw_cntrs(shared); + + return (status); +} + +/****************************************************************************** + * Initializes receive address filters. + * + * shared - Struct containing variables accessed by shared code + * + * Places the MAC address in receive address register 0 and clears the rest + * of the receive addresss registers. Clears the multicast table. Assumes + * the receiver is in reset when the routine is called. + *****************************************************************************/ +void +e1000_init_rx_addrs(struct e1000_shared_adapter *shared) +{ + uint32_t i; + uint32_t addr_low; + uint32_t addr_high; + + DEBUGFUNC("e1000_init_rx_addrs"); + + /* Setup the receive address. */ + DEBUGOUT("Programming MAC Address into RAR[0]\n"); + addr_low = (shared->mac_addr[0] | + (shared->mac_addr[1] << 8) | + (shared->mac_addr[2] << 16) | (shared->mac_addr[3] << 24)); + + addr_high = (shared->mac_addr[4] | + (shared->mac_addr[5] << 8) | E1000_RAH_AV); + + E1000_WRITE_REG_ARRAY(shared, RA, 0, addr_low); + E1000_WRITE_REG_ARRAY(shared, RA, 1, addr_high); + + /* Zero out the other 15 receive addresses. */ + DEBUGOUT("Clearing RAR[1-15]\n"); + for(i = 1; i < E1000_RAR_ENTRIES; i++) { + E1000_WRITE_REG_ARRAY(shared, RA, (i << 1), 0); + E1000_WRITE_REG_ARRAY(shared, RA, ((i << 1) + 1), 0); + } + + return; +} + +/****************************************************************************** + * Updates the MAC's list of multicast addresses. + * + * shared - Struct containing variables accessed by shared code + * mc_addr_list - the list of new multicast addresses + * mc_addr_count - number of addresses + * pad - number of bytes between addresses in the list + * + * The given list replaces any existing list. Clears the last 15 receive + * address registers and the multicast table. Uses receive address registers + * for the first 15 multicast addresses, and hashes the rest into the + * multicast table. + *****************************************************************************/ +void +e1000_mc_addr_list_update(struct e1000_shared_adapter *shared, + uint8_t *mc_addr_list, + uint32_t mc_addr_count, + uint32_t pad) +{ + uint32_t hash_value; + uint32_t i; + uint32_t rar_used_count = 1; /* RAR[0] is used for our MAC address */ + + DEBUGFUNC("e1000_mc_addr_list_update"); + + /* Set the new number of MC addresses that we are being requested to use. */ + shared->num_mc_addrs = mc_addr_count; + + /* Clear RAR[1-15] */ + DEBUGOUT(" Clearing RAR[1-15]\n"); + for(i = rar_used_count; i < E1000_RAR_ENTRIES; i++) { + E1000_WRITE_REG_ARRAY(shared, RA, (i << 1), 0); + E1000_WRITE_REG_ARRAY(shared, RA, ((i << 1) + 1), 0); + } + + /* Clear the MTA */ + DEBUGOUT(" Clearing MTA\n"); + for(i = 0; i < E1000_NUM_MTA_REGISTERS; i++) { + E1000_WRITE_REG_ARRAY(shared, MTA, i, 0); + } + + /* Add the new addresses */ + for(i = 0; i < mc_addr_count; i++) { + DEBUGOUT(" Adding the multicast addresses:\n"); + DEBUGOUT7(" MC Addr #%d =%.2X %.2X %.2X %.2X %.2X %.2X\n", i, + mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad)], + mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 1], + mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 2], + mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 3], + mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 4], + mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 5]); + + hash_value = e1000_hash_mc_addr(shared, + mc_addr_list + + (i * (ETH_LENGTH_OF_ADDRESS + pad))); + + DEBUGOUT1(" Hash value = 0x%03X\n", hash_value); + + /* Place this multicast address in the RAR if there is room, * + * else put it in the MTA + */ + if(rar_used_count < E1000_RAR_ENTRIES) { + e1000_rar_set(shared, + mc_addr_list + (i * (ETH_LENGTH_OF_ADDRESS + pad)), + rar_used_count); + rar_used_count++; + } else { + e1000_mta_set(shared, hash_value); + } + } + + DEBUGOUT("MC Update Complete\n"); + return; +} + +/****************************************************************************** + * Hashes an address to determine its location in the multicast table + * + * shared - Struct containing variables accessed by shared code + * mc_addr - the multicast address to hash + *****************************************************************************/ +uint32_t +e1000_hash_mc_addr(struct e1000_shared_adapter *shared, + uint8_t *mc_addr) +{ + uint32_t hash_value = 0; + + /* The portion of the address that is used for the hash table is + * determined by the mc_filter_type setting. + */ + switch (shared->mc_filter_type) { + /* [0] [1] [2] [3] [4] [5] + * 01 AA 00 12 34 56 + * LSB MSB - According to H/W docs */ + case 0: + /* [47:36] i.e. 0x563 for above example address */ + hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4)); + break; + case 1: /* [46:35] i.e. 0xAC6 for above example address */ + hash_value = ((mc_addr[4] >> 3) | (((uint16_t) mc_addr[5]) << 5)); + break; + case 2: /* [45:34] i.e. 0x5D8 for above example address */ + hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6)); + break; + case 3: /* [43:32] i.e. 0x634 for above example address */ + hash_value = ((mc_addr[4]) | (((uint16_t) mc_addr[5]) << 8)); + break; + } + + hash_value &= 0xFFF; + return (hash_value); +} + +/****************************************************************************** + * Sets the bit in the multicast table corresponding to the hash value. + * + * shared - Struct containing variables accessed by shared code + * hash_value - Multicast address hash value + *****************************************************************************/ +void +e1000_mta_set(struct e1000_shared_adapter *shared, + uint32_t hash_value) +{ + uint32_t hash_bit, hash_reg; + uint32_t mta_reg; + uint32_t temp; + + /* The MTA is a register array of 128 32-bit registers. + * It is treated like an array of 4096 bits. We want to set + * bit BitArray[hash_value]. So we figure out what register + * the bit is in, read it, OR in the new bit, then write + * back the new value. The register is determined by the + * upper 7 bits of the hash value and the bit within that + * register are determined by the lower 5 bits of the value. + */ + hash_reg = (hash_value >> 5) & 0x7F; + hash_bit = hash_value & 0x1F; + + mta_reg = E1000_READ_REG_ARRAY(shared, MTA, hash_reg); + + mta_reg |= (1 << hash_bit); + + /* If we are on an 82544 and we are trying to write an odd offset + * in the MTA, save off the previous entry before writing and + * restore the old value after writing. + */ + if((shared->mac_type == e1000_82544) && ((hash_reg & 0x1) == 1)) { + temp = E1000_READ_REG_ARRAY(shared, MTA, (hash_reg - 1)); + E1000_WRITE_REG_ARRAY(shared, MTA, hash_reg, mta_reg); + E1000_WRITE_REG_ARRAY(shared, MTA, (hash_reg - 1), temp); + } else { + E1000_WRITE_REG_ARRAY(shared, MTA, hash_reg, mta_reg); + } + return; +} + +/****************************************************************************** + * Puts an ethernet address into a receive address register. + * + * shared - Struct containing variables accessed by shared code + * addr - Address to put into receive address register + * index - Receive address register to write + *****************************************************************************/ +void +e1000_rar_set(struct e1000_shared_adapter *shared, + uint8_t *addr, + uint32_t index) +{ + uint32_t rar_low, rar_high; + + /* HW expects these in little endian so we reverse the byte order + * from network order (big endian) to little endian + */ + rar_low = ((uint32_t) addr[0] | + ((uint32_t) addr[1] << 8) | + ((uint32_t) addr[2] << 16) | ((uint32_t) addr[3] << 24)); + + rar_high = ((uint32_t) addr[4] | ((uint32_t) addr[5] << 8) | E1000_RAH_AV); + + E1000_WRITE_REG_ARRAY(shared, RA, (index << 1), rar_low); + E1000_WRITE_REG_ARRAY(shared, RA, ((index << 1) + 1), rar_high); + return; +} + +/****************************************************************************** + * Writes a value to the specified offset in the VLAN filter table. + * + * shared - Struct containing variables accessed by shared code + * offset - Offset in VLAN filer table to write + * value - Value to write into VLAN filter table + *****************************************************************************/ +void +e1000_write_vfta(struct e1000_shared_adapter *shared, + uint32_t offset, + uint32_t value) +{ + uint32_t temp; + + if((shared->mac_type == e1000_82544) && ((offset & 0x1) == 1)) { + temp = E1000_READ_REG_ARRAY(shared, VFTA, (offset - 1)); + E1000_WRITE_REG_ARRAY(shared, VFTA, offset, value); + E1000_WRITE_REG_ARRAY(shared, VFTA, (offset - 1), temp); + } else { + E1000_WRITE_REG_ARRAY(shared, VFTA, offset, value); + } + return; +} + +/****************************************************************************** + * Clears the VLAN filer table + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +void +e1000_clear_vfta(struct e1000_shared_adapter *shared) +{ + uint32_t offset; + + for(offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) + E1000_WRITE_REG_ARRAY(shared, VFTA, offset, 0); + return; +} + +/****************************************************************************** + * Configures flow control and link settings. + * + * shared - Struct containing variables accessed by shared code + * + * Determines which flow control settings to use. Calls the apropriate media- + * specific link configuration function. Configures the flow control settings. + * Assuming the adapter has a valid link partner, a valid link should be + * established. Assumes the hardware has previously been reset and the + * transmitter and receiver are not enabled. + *****************************************************************************/ +boolean_t +e1000_setup_fc_and_link(struct e1000_shared_adapter *shared) +{ + uint32_t ctrl_reg; + uint32_t eecd_reg; + uint32_t ctrl_ext_reg; + boolean_t status = TRUE; + + DEBUGFUNC("e1000_setup_fc_and_link"); + + /* Read the SWDPIO bits and the ILOS bit out of word 0x0A in the + * EEPROM. Store these bits in a variable that we will later write + * to the Device Control Register (CTRL). + */ + eecd_reg = e1000_read_eeprom(shared, EEPROM_INIT_CONTROL1_REG); + + ctrl_reg = + (((eecd_reg & EEPROM_WORD0A_SWDPIO) << SWDPIO_SHIFT) | + ((eecd_reg & EEPROM_WORD0A_ILOS) << ILOS_SHIFT)); + + /* Set the PCI priority bit correctly in the CTRL register. This + * determines if the adapter gives priority to receives, or if it + * gives equal priority to transmits and receives. + */ + if(shared->dma_fairness) + ctrl_reg |= E1000_CTRL_PRIOR; + + /* Read and store word 0x0F of the EEPROM. This word contains bits + * that determine the hardware's default PAUSE (flow control) mode, + * a bit that determines whether the HW defaults to enabling or + * disabling auto-negotiation, and the direction of the + * SW defined pins. If there is no SW over-ride of the flow + * control setting, then the variable shared->fc will + * be initialized based on a value in the EEPROM. + */ + eecd_reg = e1000_read_eeprom(shared, EEPROM_INIT_CONTROL2_REG); + + if(shared->fc > e1000_fc_full) { + if((eecd_reg & EEPROM_WORD0F_PAUSE_MASK) == 0) + shared->fc = e1000_fc_none; + else if((eecd_reg & EEPROM_WORD0F_PAUSE_MASK) == EEPROM_WORD0F_ASM_DIR) + shared->fc = e1000_fc_tx_pause; + else + shared->fc = e1000_fc_full; + } + + /* We want to save off the original Flow Control configuration just + * in case we get disconnected and then reconnected into a different + * hub or switch with different Flow Control capabilities. + */ + shared->original_fc = shared->fc; + + if(shared->mac_type == e1000_82542_rev2_0) + shared->fc &= (~e1000_fc_tx_pause); + + if((shared->mac_type < e1000_82543) && (shared->report_tx_early == 1)) + shared->fc &= (~e1000_fc_rx_pause); + + DEBUGOUT1("After fix-ups FlowControl is now = %x\n", shared->fc); + + /* Take the 4 bits from EEPROM word 0x0F that determine the initial + * polarity value for the SW controlled pins, and setup the + * Extended Device Control reg with that info. + * This is needed because one of the SW controlled pins is used for + * signal detection. So this should be done before e1000_setup_pcs_link() + * or e1000_phy_setup() is called. + */ + if(shared->mac_type == e1000_82543) { + ctrl_ext_reg = ((eecd_reg & EEPROM_WORD0F_SWPDIO_EXT) + << SWDPIO__EXT_SHIFT); + E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg); + } + + /* Call the necessary subroutine to configure the link. */ + if(shared->media_type == e1000_media_type_fiber) + status = e1000_setup_pcs_link(shared, ctrl_reg); + else + status = e1000_phy_setup(shared, ctrl_reg); + + /* Initialize the flow control address, type, and PAUSE timer + * registers to their default values. This is done even if flow + * control is disabled, because it does not hurt anything to + * initialize these registers. + */ + DEBUGOUT("Initializing the Flow Control address, type and timer regs\n"); + + E1000_WRITE_REG(shared, FCAL, FLOW_CONTROL_ADDRESS_LOW); + E1000_WRITE_REG(shared, FCAH, FLOW_CONTROL_ADDRESS_HIGH); + E1000_WRITE_REG(shared, FCT, FLOW_CONTROL_TYPE); + E1000_WRITE_REG(shared, FCTTV, shared->fc_pause_time); + + /* Set the flow control receive threshold registers. Normally, + * these registers will be set to a default threshold that may be + * adjusted later by the driver's runtime code. However, if the + * ability to transmit pause frames in not enabled, then these + * registers will be set to 0. + */ + if(!(shared->fc & e1000_fc_tx_pause)) { + E1000_WRITE_REG(shared, FCRTL, 0); + E1000_WRITE_REG(shared, FCRTH, 0); + } else { + /* We need to set up the Receive Threshold high and low water marks + * as well as (optionally) enabling the transmission of XON frames. + */ + if(shared->fc_send_xon) { + E1000_WRITE_REG(shared, FCRTL, + (shared->fc_low_water | E1000_FCRTL_XONE)); + E1000_WRITE_REG(shared, FCRTH, shared->fc_high_water); + } else { + E1000_WRITE_REG(shared, FCRTL, shared->fc_low_water); + E1000_WRITE_REG(shared, FCRTH, shared->fc_high_water); + } + } + return (status); +} + +/****************************************************************************** + * Sets up link for a fiber based adapter + * + * shared - Struct containing variables accessed by shared code + * ctrl_reg - Current value of the device control register + * + * Manipulates Physical Coding Sublayer functions in order to configure + * link. Assumes the hardware has been previously reset and the transmitter + * and receiver are not enabled. + *****************************************************************************/ +boolean_t +e1000_setup_pcs_link(struct e1000_shared_adapter *shared, + uint32_t ctrl_reg) +{ + uint32_t status_reg; + uint32_t tctl_reg; + uint32_t txcw_reg = 0; + uint32_t i; + + DEBUGFUNC("e1000_setup_pcs_link"); + + /* Setup the collsion distance. Since this is configuring the + * TBI it is assumed that we are in Full Duplex. + */ + tctl_reg = E1000_READ_REG(shared, TCTL); + i = E1000_FDX_COLLISION_DISTANCE; + i <<= E1000_COLD_SHIFT; + tctl_reg |= i; + E1000_WRITE_REG(shared, TCTL, tctl_reg); + + /* Check for a software override of the flow control settings, and + * setup the device accordingly. If auto-negotiation is enabled, + * then software will have to set the "PAUSE" bits to the correct + * value in the Tranmsit Config Word Register (TXCW) and re-start + * auto-negotiation. However, if auto-negotiation is disabled, + * then software will have to manually configure the two flow + * control enable bits in the CTRL register. + * + * The possible values of the "fc" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames + * but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames + * but we do not support receiving pause frames). + * 3: Both Rx and TX flow control (symmetric) are enabled. + * other: No software override. The flow control configuration + * in the EEPROM is used. + */ + switch (shared->fc) { + case e1000_fc_none: /* 0 */ + /* Flow control (RX & TX) is completely disabled by a + * software over-ride. + */ + txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD); + break; + case e1000_fc_rx_pause: /* 1 */ + /* RX Flow control is enabled, and TX Flow control is + * disabled, by a software over-ride. + */ + /* Since there really isn't a way to advertise that we are + * capable of RX Pause ONLY, we will advertise that we + * support both symmetric and asymmetric RX PAUSE. Later + * we will disable the adapter's ability to send PAUSE + * frames. + */ + txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); + break; + case e1000_fc_tx_pause: /* 2 */ + /* TX Flow control is enabled, and RX Flow control is + * disabled, by a software over-ride. + */ + txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR); + break; + case e1000_fc_full: /* 3 */ + /* Flow control (both RX and TX) is enabled by a software + * over-ride. + */ + txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); + break; + default: + /* We should never get here. The value should be 0-3. */ + DEBUGOUT("Flow control param set incorrectly\n"); + ASSERT(0); + break; + } + + /* Since auto-negotiation is enabled, take the link out of reset. + * (the link will be in reset, because we previously reset the + * chip). This will restart auto-negotiation. If auto-neogtiation + * is successful then the link-up status bit will be set and the + * flow control enable bits (RFCE and TFCE) will be set according + * to their negotiated value. + */ + DEBUGOUT("Auto-negotiation enabled\n"); + + E1000_WRITE_REG(shared, TXCW, txcw_reg); + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + shared->txcw_reg = txcw_reg; + msec_delay(1); + + /* If we have a signal then poll for a "Link-Up" indication in the + * Device Status Register. Time-out if a link isn't seen in 500 + * milliseconds seconds (Auto-negotiation should complete in less + * than 500 milliseconds even if the other end is doing it in SW). + */ + if(!(E1000_READ_REG(shared, CTRL) & E1000_CTRL_SWDPIN1)) { + + DEBUGOUT("Looking for Link\n"); + for(i = 0; i < (LINK_UP_TIMEOUT / 10); i++) { + msec_delay(10); + status_reg = E1000_READ_REG(shared, STATUS); + if(status_reg & E1000_STATUS_LU) + break; + } + + if(i == (LINK_UP_TIMEOUT / 10)) { + /* AutoNeg failed to achieve a link, so we'll call the + * "CheckForLink" routine. This routine will force the link + * up if we have "signal-detect". This will allow us to + * communicate with non-autonegotiating link partners. + */ + DEBUGOUT("Never got a valid link from auto-neg!!!\n"); + + shared->autoneg_failed = 1; + e1000_check_for_link(shared); + shared->autoneg_failed = 0; + } else { + shared->autoneg_failed = 0; + DEBUGOUT("Valid Link Found\n"); + } + } else { + DEBUGOUT("No Signal Detected\n"); + } + + return (TRUE); +} + +/****************************************************************************** + * Configures flow control settings after link is established + * + * shared - Struct containing variables accessed by shared code + * + * Should be called immediately after a valid link has been established. + * Forces MAC flow control settings if link was forced. When in MII/GMII mode + * and autonegotiation is enabled, the MAC flow control settings will be set + * based on the flow control negotiated by the PHY. In TBI mode, the TFCE + * and RFCE bits will be automaticaly set to the negotiated flow control mode. + *****************************************************************************/ +void +e1000_config_fc_after_link_up(struct e1000_shared_adapter *shared) +{ + uint16_t mii_status_reg; + uint16_t mii_nway_adv_reg; + uint16_t mii_nway_lp_ability_reg; + uint16_t speed; + uint16_t duplex; + + DEBUGFUNC("e1000_config_fc_after_link_up"); + + /* Check for the case where we have fiber media and auto-neg failed + * so we had to force link. In this case, we need to force the + * configuration of the MAC to match the "fc" parameter. + */ + if(((shared->media_type == e1000_media_type_fiber) + && (shared->autoneg_failed)) + || ((shared->media_type == e1000_media_type_copper) + && (!shared->autoneg))) { + e1000_force_mac_fc(shared); + } + + /* Check for the case where we have copper media and auto-neg is + * enabled. In this case, we need to check and see if Auto-Neg + * has completed, and if so, how the PHY and link partner has + * flow control configured. + */ + if((shared->media_type == e1000_media_type_copper) && shared->autoneg) { + /* Read the MII Status Register and check to see if AutoNeg + * has completed. We read this twice because this reg has + * some "sticky" (latched) bits. + */ + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + + if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) { + /* The AutoNeg process has completed, so we now need to + * read both the Auto Negotiation Advertisement Register + * (Address 4) and the Auto_Negotiation Base Page Ability + * Register (Address 5) to determine how flow control was + * negotiated. + */ + mii_nway_adv_reg = e1000_read_phy_reg(shared, + PHY_AUTONEG_ADV); + mii_nway_lp_ability_reg = e1000_read_phy_reg(shared, + PHY_LP_ABILITY); + + /* Two bits in the Auto Negotiation Advertisement Register + * (Address 4) and two bits in the Auto Negotiation Base + * Page Ability Register (Address 5) determine flow control + * for both the PHY and the link partner. The following + * table, taken out of the IEEE 802.3ab/D6.0 dated March 25, + * 1999, describes these PAUSE resolution bits and how flow + * control is determined based upon these settings. + * NOTE: DC = Don't Care + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution + *-------|---------|-------|---------|-------------------- + * 0 | 0 | DC | DC | e1000_fc_none + * 0 | 1 | 0 | DC | e1000_fc_none + * 0 | 1 | 1 | 0 | e1000_fc_none + * 0 | 1 | 1 | 1 | e1000_fc_tx_pause + * 1 | 0 | 0 | DC | e1000_fc_none + * 1 | DC | 1 | DC | e1000_fc_full + * 1 | 1 | 0 | 0 | e1000_fc_none + * 1 | 1 | 0 | 1 | e1000_fc_rx_pause + * + */ + /* Are both PAUSE bits set to 1? If so, this implies + * Symmetric Flow Control is enabled at both ends. The + * ASM_DIR bits are irrelevant per the spec. + * + * For Symmetric Flow Control: + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 1 | DC | 1 | DC | e1000_fc_full + * + */ + if((mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) { + /* Now we need to check if the user selected RX ONLY + * of pause frames. In this case, we had to advertise + * FULL flow control because we could not advertise RX + * ONLY. Hence, we must now check to see if we need to + * turn OFF the TRANSMISSION of PAUSE frames. + */ + if(shared->original_fc == e1000_fc_full) { + shared->fc = e1000_fc_full; + DEBUGOUT("Flow Control = FULL.\r\n"); + } else { + shared->fc = e1000_fc_rx_pause; + DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n"); + } + } + /* For receiving PAUSE frames ONLY. + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 0 | 1 | 1 | 1 | e1000_fc_tx_pause + * + */ + else if(!(mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && + (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { + shared->fc = e1000_fc_tx_pause; + DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n"); + } + /* For transmitting PAUSE frames ONLY. + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 1 | 1 | 0 | 1 | e1000_fc_rx_pause + * + */ + else if((mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && + !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { + shared->fc = e1000_fc_rx_pause; + DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n"); + } + /* Per the IEEE spec, at this point flow control should be + * disabled. However, we want to consider that we could + * be connected to a legacy switch that doesn't advertise + * desired flow control, but can be forced on the link + * partner. So if we advertised no flow control, that is + * what we will resolve to. If we advertised some kind of + * receive capability (Rx Pause Only or Full Flow Control) + * and the link partner advertised none, we will configure + * ourselves to enable Rx Flow Control only. We can do + * this safely for two reasons: If the link partner really + * didn't want flow control enabled, and we enable Rx, no + * harm done since we won't be receiving any PAUSE frames + * anyway. If the intent on the link partner was to have + * flow control enabled, then by us enabling RX only, we + * can at least receive pause frames and process them. + * This is a good idea because in most cases, since we are + * predominantly a server NIC, more times than not we will + * be asked to delay transmission of packets than asking + * our link partner to pause transmission of frames. + */ + else if(shared->original_fc == e1000_fc_none || + shared->original_fc == e1000_fc_tx_pause) { + shared->fc = e1000_fc_none; + DEBUGOUT("Flow Control = NONE.\r\n"); + } else { + shared->fc = e1000_fc_rx_pause; + DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n"); + } + + /* Now we need to do one last check... If we auto- + * negotiated to HALF DUPLEX, flow control should not be + * enabled per IEEE 802.3 spec. + */ + e1000_get_speed_and_duplex(shared, &speed, &duplex); + + if(duplex == HALF_DUPLEX) + shared->fc = e1000_fc_none; + + /* Now we call a subroutine to actually force the MAC + * controller to use the correct flow control settings. + */ + e1000_force_mac_fc(shared); + } else { + DEBUGOUT("Copper PHY and Auto Neg has not completed.\r\n"); + } + } + return; +} + +/****************************************************************************** + * Checks to see if the link status of the hardware has changed. + * + * shared - Struct containing variables accessed by shared code + * + * Called by any function that needs to check the link status of the adapter. + *****************************************************************************/ +void +e1000_check_for_link(struct e1000_shared_adapter *shared) +{ + uint32_t rxcw_reg; + uint32_t ctrl_reg; + uint32_t status_reg; + uint32_t rctl_reg; + uint16_t phy_data; + uint16_t lp_capability; + + DEBUGFUNC("e1000_check_for_link"); + + ctrl_reg = E1000_READ_REG(shared, CTRL); + status_reg = E1000_READ_REG(shared, STATUS); + rxcw_reg = E1000_READ_REG(shared, RXCW); + + /* If we have a copper PHY then we only want to go out to the PHY + * registers to see if Auto-Neg has completed and/or if our link + * status has changed. The get_link_status flag will be set if we + * receive a Link Status Change interrupt or we have Rx Sequence + * Errors. + */ + if(shared->media_type == e1000_media_type_copper + && shared->get_link_status) { + /* First we want to see if the MII Status Register reports + * link. If so, then we want to get the current speed/duplex + * of the PHY. + * Read the register twice since the link bit is sticky. + */ + phy_data = e1000_read_phy_reg(shared, PHY_STATUS); + phy_data = e1000_read_phy_reg(shared, PHY_STATUS); + + if(phy_data & MII_SR_LINK_STATUS) { + shared->get_link_status = FALSE; + } else { + DEBUGOUT("**** CFL - No link detected. ****\r\n"); + return; + } + + /* If we are forcing speed/duplex, then we simply return since + * we have already determined whether we have link or not. + */ + if(!shared->autoneg) { + return; + } + + switch (shared->phy_id) { + case M88E1000_12_PHY_ID: + case M88E1000_14_PHY_ID: + case M88E1000_I_PHY_ID: + /* We have a M88E1000 PHY and Auto-Neg is enabled. If we + * have Si on board that is 82544 or newer, Auto + * Speed Detection takes care of MAC speed/duplex + * configuration. So we only need to configure Collision + * Distance in the MAC. Otherwise, we need to force + * speed/duplex on the MAC to the current PHY speed/duplex + * settings. + */ + if(shared->mac_type >= e1000_82544) { + DEBUGOUT("CFL - Auto-Neg complete."); + DEBUGOUT("Configuring Collision Distance."); + e1000_config_collision_dist(shared); + } else { + /* Read the Phy Specific Status register to get the + * resolved speed/duplex settings. Then call + * e1000_config_mac_to_phy which will retrieve + * PHY register information and configure the MAC to + * equal the negotiated speed/duplex. + */ + phy_data = e1000_read_phy_reg(shared, + M88E1000_PHY_SPEC_STATUS); + + DEBUGOUT1("CFL - Auto-Neg complete. phy_data = %x\r\n", + phy_data); + e1000_config_mac_to_phy(shared, phy_data); + } + + /* Configure Flow Control now that Auto-Neg has completed. + * We need to first restore the users desired Flow + * Control setting since we may have had to re-autoneg + * with a different link partner. + */ + e1000_config_fc_after_link_up(shared); + break; + + default: + DEBUGOUT("CFL - Invalid PHY detected.\r\n"); + + } /* end switch statement */ + + /* At this point we know that we are on copper, link is up, + * and we are auto-neg'd. These are pre-conditions for checking + * the link parter capabilities register. We use the link partner + * capabilities to determine if TBI Compatibility needs to be turned on + * or turned off. If the link partner advertises any speed in addition + * to Gigabit, then we assume that they are GMII-based and TBI + * compatibility is not needed. + * If no other speeds are advertised, then we assume the link partner + * is TBI-based and we turn on TBI Compatibility. + */ + if(shared->tbi_compatibility_en) { + lp_capability = e1000_read_phy_reg(shared, PHY_LP_ABILITY); + if(lp_capability & (NWAY_LPAR_10T_HD_CAPS | + NWAY_LPAR_10T_FD_CAPS | + NWAY_LPAR_100TX_HD_CAPS | + NWAY_LPAR_100TX_FD_CAPS | + NWAY_LPAR_100T4_CAPS)) { + /* If our link partner advertises below Gig, then they do not + * need the special Tbi Compatibility mode. + */ + if(shared->tbi_compatibility_on) { + /* If we previously were in the mode, turn it off, now. */ + rctl_reg = E1000_READ_REG(shared, RCTL); + rctl_reg &= ~E1000_RCTL_SBP; + E1000_WRITE_REG(shared, RCTL, rctl_reg); + shared->tbi_compatibility_on = FALSE; + } + } else { + /* If the mode is was previously off, turn it on. + * For compatibility with a suspected Tbi link partners, + * we will store bad packets. + * (Certain frames have an additional byte on the end and will + * look like CRC errors to to the hardware). + */ + if(!shared->tbi_compatibility_on) { + shared->tbi_compatibility_on = TRUE; + rctl_reg = E1000_READ_REG(shared, RCTL); + rctl_reg |= E1000_RCTL_SBP; + E1000_WRITE_REG(shared, RCTL, rctl_reg); + } + } + } + } /* end if e1000_media_type_copper statement */ + /* If we don't have link (auto-negotiation failed or link partner + * cannot auto-negotiate) and the cable is plugged in since we don't + * have Loss-Of-Signal (we HAVE a signal) and our link partner is + * not trying to AutoNeg with us (we are receiving idles/data + * then we need to force our link to connect to a non + * auto-negotiating link partner. We also need to give + * auto-negotiation time to complete in case the cable was just + * plugged in. The autoneg_failed flag does this. + */ + else if((shared->media_type == e1000_media_type_fiber) && /* Fiber PHY */ + (!(status_reg & E1000_STATUS_LU)) && /* no link and */ + (!(ctrl_reg & E1000_CTRL_SWDPIN1)) && /* we have signal */ + (!(rxcw_reg & E1000_RXCW_C))) { /* and rxing idle/data */ + if(shared->autoneg_failed == 0) { /* given AutoNeg time */ + shared->autoneg_failed = 1; + return; + } + + DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\r\n"); + + /* Disable auto-negotiation in the TXCW register */ + E1000_WRITE_REG(shared, TXCW, (shared->txcw_reg & ~E1000_TXCW_ANE)); + + /* Force link-up and also force full-duplex. */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + ctrl_reg |= (E1000_CTRL_SLU | E1000_CTRL_FD); + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + /* Configure Flow Control after forcing link up. */ + e1000_config_fc_after_link_up(shared); + + } else if((shared->media_type == e1000_media_type_fiber) && /* Fiber */ + (ctrl_reg & E1000_CTRL_SLU) && /* we have forced link */ + (rxcw_reg & E1000_RXCW_C)) { /* and Rxing /C/ ordered sets */ + /* If we are forcing link and we are receiving /C/ ordered sets, + * then re-enable auto-negotiation in the RXCW register and + * disable forced link in the Device Control register in an attempt + * to AutoNeg with our link partner. + */ + DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\r\n"); + + /* Enable auto-negotiation in the TXCW register and stop + * forcing link. + */ + E1000_WRITE_REG(shared, TXCW, shared->txcw_reg); + + E1000_WRITE_REG(shared, CTRL, (ctrl_reg & ~E1000_CTRL_SLU)); + } + + return; +} + +/****************************************************************************** + * Clears all hardware statistics counters. + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +void +e1000_clear_hw_cntrs(struct e1000_shared_adapter *shared) +{ + volatile uint32_t temp_reg; + + DEBUGFUNC("e1000_clear_hw_cntrs"); + + /* if we are stopped or resetting exit gracefully */ + if(shared->adapter_stopped) { + DEBUGOUT("Exiting because the adapter is stopped!!!\n"); + return; + } + + temp_reg = E1000_READ_REG(shared, CRCERRS); + temp_reg = E1000_READ_REG(shared, SYMERRS); + temp_reg = E1000_READ_REG(shared, MPC); + temp_reg = E1000_READ_REG(shared, SCC); + temp_reg = E1000_READ_REG(shared, ECOL); + temp_reg = E1000_READ_REG(shared, MCC); + temp_reg = E1000_READ_REG(shared, LATECOL); + temp_reg = E1000_READ_REG(shared, COLC); + temp_reg = E1000_READ_REG(shared, DC); + temp_reg = E1000_READ_REG(shared, SEC); + temp_reg = E1000_READ_REG(shared, RLEC); + temp_reg = E1000_READ_REG(shared, XONRXC); + temp_reg = E1000_READ_REG(shared, XONTXC); + temp_reg = E1000_READ_REG(shared, XOFFRXC); + temp_reg = E1000_READ_REG(shared, XOFFTXC); + temp_reg = E1000_READ_REG(shared, FCRUC); + temp_reg = E1000_READ_REG(shared, PRC64); + temp_reg = E1000_READ_REG(shared, PRC127); + temp_reg = E1000_READ_REG(shared, PRC255); + temp_reg = E1000_READ_REG(shared, PRC511); + temp_reg = E1000_READ_REG(shared, PRC1023); + temp_reg = E1000_READ_REG(shared, PRC1522); + temp_reg = E1000_READ_REG(shared, GPRC); + temp_reg = E1000_READ_REG(shared, BPRC); + temp_reg = E1000_READ_REG(shared, MPRC); + temp_reg = E1000_READ_REG(shared, GPTC); + temp_reg = E1000_READ_REG(shared, GORCL); + temp_reg = E1000_READ_REG(shared, GORCH); + temp_reg = E1000_READ_REG(shared, GOTCL); + temp_reg = E1000_READ_REG(shared, GOTCH); + temp_reg = E1000_READ_REG(shared, RNBC); + temp_reg = E1000_READ_REG(shared, RUC); + temp_reg = E1000_READ_REG(shared, RFC); + temp_reg = E1000_READ_REG(shared, ROC); + temp_reg = E1000_READ_REG(shared, RJC); + temp_reg = E1000_READ_REG(shared, TORL); + temp_reg = E1000_READ_REG(shared, TORH); + temp_reg = E1000_READ_REG(shared, TOTL); + temp_reg = E1000_READ_REG(shared, TOTH); + temp_reg = E1000_READ_REG(shared, TPR); + temp_reg = E1000_READ_REG(shared, TPT); + temp_reg = E1000_READ_REG(shared, PTC64); + temp_reg = E1000_READ_REG(shared, PTC127); + temp_reg = E1000_READ_REG(shared, PTC255); + temp_reg = E1000_READ_REG(shared, PTC511); + temp_reg = E1000_READ_REG(shared, PTC1023); + temp_reg = E1000_READ_REG(shared, PTC1522); + temp_reg = E1000_READ_REG(shared, MPTC); + temp_reg = E1000_READ_REG(shared, BPTC); + + if(shared->mac_type < e1000_82543) + return; + + temp_reg = E1000_READ_REG(shared, ALGNERRC); + temp_reg = E1000_READ_REG(shared, RXERRC); + temp_reg = E1000_READ_REG(shared, TNCRS); + temp_reg = E1000_READ_REG(shared, CEXTERR); + temp_reg = E1000_READ_REG(shared, TSCTC); + temp_reg = E1000_READ_REG(shared, TSCTFC); + return; +} + +/****************************************************************************** + * Detects the current speed and duplex settings of the hardware. + * + * shared - Struct containing variables accessed by shared code + * speed - Speed of the connection + * duplex - Duplex setting of the connection + *****************************************************************************/ +void +e1000_get_speed_and_duplex(struct e1000_shared_adapter *shared, + uint16_t *speed, + uint16_t *duplex) +{ + uint32_t status_reg; +#if DBG + uint16_t phy_data; +#endif + + DEBUGFUNC("e1000_get_speed_and_duplex"); + + /* If the adapter is stopped we don't have a speed or duplex */ + if(shared->adapter_stopped) { + *speed = 0; + *duplex = 0; + return; + } + + if(shared->mac_type >= e1000_82543) { + status_reg = E1000_READ_REG(shared, STATUS); + if(status_reg & E1000_STATUS_SPEED_1000) { + *speed = SPEED_1000; + DEBUGOUT("1000 Mbs, "); + } else if(status_reg & E1000_STATUS_SPEED_100) { + *speed = SPEED_100; + DEBUGOUT("100 Mbs, "); + } else { + *speed = SPEED_10; + DEBUGOUT("10 Mbs, "); + } + + if(status_reg & E1000_STATUS_FD) { + *duplex = FULL_DUPLEX; + DEBUGOUT("Full Duplex\r\n"); + } else { + *duplex = HALF_DUPLEX; + DEBUGOUT(" Half Duplex\r\n"); + } + } else { + DEBUGOUT("1000 Mbs, Full Duplex\r\n"); + *speed = SPEED_1000; + *duplex = FULL_DUPLEX; + } + +#if DBG + if(shared->phy_id == M88E1000_12_PHY_ID || + shared->phy_id == M88E1000_14_PHY_ID || + shared->phy_id == M88E1000_I_PHY_ID) { + /* read the phy specific status register */ + phy_data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS); + DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", phy_data); + phy_data = e1000_read_phy_reg(shared, PHY_STATUS); + DEBUGOUT1("Phy MII Status Reg contents = %x\n", phy_data); + DEBUGOUT1("Device Status Reg contents = %x\n", + E1000_READ_REG(shared, STATUS)); + } +#endif + return; +} + +/****************************************************************************** + * Reads a 16 bit word from the EEPROM. + * + * shared - Struct containing variables accessed by shared code + * offset - offset of 16 bit word in the EEPROM to read + *****************************************************************************/ +uint16_t +e1000_read_eeprom(struct e1000_shared_adapter *shared, + uint16_t offset) +{ + uint16_t data; + + /* Prepare the EEPROM for reading */ + e1000_setup_eeprom(shared); + + /* Send the READ command (opcode + addr) */ + e1000_shift_out_bits(shared, EEPROM_READ_OPCODE, 3); + e1000_shift_out_bits(shared, offset, 6); + + /* Read the data */ + data = e1000_shift_in_bits(shared); + + /* End this read operation */ + e1000_standby_eeprom(shared); + + return (data); +} + +/****************************************************************************** + * Verifies that the EEPROM has a valid checksum + * + * shared - Struct containing variables accessed by shared code + * + * Reads the first 64 16 bit words of the EEPROM and sums the values read. + * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is + * valid. + *****************************************************************************/ +boolean_t +e1000_validate_eeprom_checksum(struct e1000_shared_adapter *shared) +{ + uint16_t checksum = 0; + uint16_t i; + + for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) + checksum += e1000_read_eeprom(shared, i); + + if(checksum == (uint16_t) EEPROM_SUM) + return (TRUE); + else + return (FALSE); +} +/****************************************************************************** + * Reads the adapter's part number from the EEPROM + * + * shared - Struct containing variables accessed by shared code + * part_num - Adapter's part number + *****************************************************************************/ +boolean_t +e1000_read_part_num(struct e1000_shared_adapter *shared, + uint32_t *part_num) +{ + uint16_t eeprom_word; + + DEBUGFUNC("e1000_read_part_num"); + + /* Don't read the EEPROM if we are stopped */ + if(shared->adapter_stopped) { + *part_num = 0; + return (FALSE); + } + + /* Get word 0 from EEPROM */ + eeprom_word = e1000_read_eeprom(shared, (uint16_t) (EEPROM_PBA_BYTE_1)); + + DEBUGOUT("Read first part number word\n"); + + /* Save word 0 in upper half is PartNumber */ + *part_num = (uint32_t) eeprom_word; + *part_num = *part_num << 16; + + /* Get word 1 from EEPROM */ + eeprom_word = + e1000_read_eeprom(shared, (uint16_t) (EEPROM_PBA_BYTE_1 + 1)); + + DEBUGOUT("Read second part number word\n"); + + /* Save word 1 in lower half of PartNumber */ + *part_num |= eeprom_word; + + /* read a valid part number */ + return (TRUE); +} + +void +e1000_read_mac_addr(struct e1000_shared_adapter * shared) +{ + uint16_t temp, x; + + for(x = 0; x < NODE_ADDRESS_SIZE; x += 2) { + temp = e1000_read_eeprom(shared, (uint16_t) + (EEPROM_NODE_ADDRESS_BYTE_0 + (x/2))); + shared->perm_mac_addr[x] = (uint8_t) (temp & 0x00FF); + shared->perm_mac_addr[x+1] = (uint8_t) (temp >> 8); + } + + for(x = 0; x < NODE_ADDRESS_SIZE; x++) + shared->mac_addr[x] = shared->perm_mac_addr[x]; +} + +/****************************************************************************** + * Adjusts the statistic counters when a frame is accepted by TBI_ACCEPT + * + * shared - Struct containing variables accessed by shared code + * frame_len - The length of the frame in question + * mac_addr - The Ethernet destination address of the frame in question + *****************************************************************************/ +uint32_t +e1000_tbi_adjust_stats(struct e1000_shared_adapter *shared, + struct e1000_shared_stats *stats, + uint32_t frame_len, + uint8_t *mac_addr) +{ + uint64_t carry_bit; + + /* First adjust the frame length. */ + frame_len--; + /* We need to adjust the statistics counters, since the hardware + * counters overcount this packet as a CRC error and undercount + * the packet as a good packet + */ + /* This packet should not be counted as a CRC error. */ + stats->crcerrs--; + /* This packet does count as a Good Packet Received. */ + stats->gprc++; + + /* Adjust the Good Octets received counters */ + carry_bit = 0x80000000 & stats->gorcl; + stats->gorcl += frame_len; + /* If the high bit of Gorcl (the low 32 bits of the Good Octets + * Received Count) was one before the addition, + * AND it is zero after, then we lost the carry out, + * need to add one to Gorch (Good Octets Received Count High). + * This could be simplified if all environments supported + * 64-bit integers. + */ + if(carry_bit && ((stats->gorcl & 0x80000000) == 0)) + stats->gorch++; + /* Is this a broadcast or multicast? Check broadcast first, + * since the test for a multicast frame will test positive on + * a broadcast frame. + */ + if((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff)) + /* Broadcast packet */ + stats->bprc++; + else if(*mac_addr & 0x01) + /* Multicast packet */ + stats->mprc++; + + if(frame_len == shared->max_frame_size) { + /* In this case, the hardware has overcounted the number of + * oversize frames. + */ + if(stats->roc > 0) + stats->roc--; + } + + /* Adjust the bin counters when the extra byte put the frame in the + * wrong bin. Remember that the frame_len was adjusted above. + */ + if(frame_len == 64) { + stats->prc64++; + stats->prc127--; + } else if(frame_len == 127) { + stats->prc127++; + stats->prc255--; + } else if(frame_len == 255) { + stats->prc255++; + stats->prc511--; + } else if(frame_len == 511) { + stats->prc511++; + stats->prc1023--; + } else if(frame_len == 1023) { + stats->prc1023++; + stats->prc1522--; + } else if(frame_len == 1522) { + stats->prc1522++; + } + return frame_len; +} + +/****************************************************************************** + * Gets the current PCI bus type, speed, and width of the hardware + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +void +e1000_get_bus_info(struct e1000_shared_adapter *shared) +{ + uint32_t status_reg; + + if(shared->mac_type < e1000_82543) { + shared->bus_type = e1000_bus_type_unknown; + shared->bus_speed = e1000_bus_speed_unknown; + shared->bus_width = e1000_bus_width_unknown; + return; + } + + status_reg = E1000_READ_REG(shared, STATUS); + + shared->bus_type = (status_reg & E1000_STATUS_PCIX_MODE) ? + e1000_bus_type_pcix : e1000_bus_type_pci; + + if(shared->bus_type == e1000_bus_type_pci) { + shared->bus_speed = (status_reg & E1000_STATUS_PCI66) ? + e1000_bus_speed_66 : e1000_bus_speed_33; + } else { + switch (status_reg & E1000_STATUS_PCIX_SPEED) { + case E1000_STATUS_PCIX_SPEED_66: + shared->bus_speed = e1000_bus_speed_66; + break; + case E1000_STATUS_PCIX_SPEED_100: + shared->bus_speed = e1000_bus_speed_100; + break; + case E1000_STATUS_PCIX_SPEED_133: + shared->bus_speed = e1000_bus_speed_133; + break; + default: + shared->bus_speed = e1000_bus_speed_reserved; + break; + } + } + + shared->bus_width = (status_reg & E1000_STATUS_BUS64) ? + e1000_bus_width_64 : e1000_bus_width_32; + + return; +} diff -Nru a/drivers/net/e1000/e1000_mac.h b/drivers/net/e1000/e1000_mac.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/e1000/e1000_mac.h Tue Feb 26 11:58:00 2002 @@ -0,0 +1,1383 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/* e1000_mac.h + * Structures, enums, and macros for the MAC + */ + +#ifndef _E1000_MAC_H_ +#define _E1000_MAC_H_ + +#include "e1000_osdep.h" + +/* Forward declarations of structures used by the shared code */ +struct e1000_shared_adapter; +struct e1000_shared_stats; + +/* Enumerated types specific to the e1000 hardware */ +/* Media Access Controlers */ +typedef enum { + e1000_82542_rev2_0 = 0, + e1000_82542_rev2_1, + e1000_82543, + e1000_82544, + e1000_num_macs +} e1000_mac_type; + +/* Media Types */ +typedef enum { + e1000_media_type_copper = 0, + e1000_media_type_fiber = 1, + e1000_num_media_types +} e1000_media_type; + +typedef enum { + e1000_10_half = 0, + e1000_10_full = 1, + e1000_100_half = 2, + e1000_100_full = 3 +} e1000_speed_duplex_type; + +/* Flow Control Settings */ +typedef enum { + e1000_fc_none = 0, + e1000_fc_rx_pause = 1, + e1000_fc_tx_pause = 2, + e1000_fc_full = 3, + e1000_fc_default = 0xFF +} e1000_fc_type; + +/* PCI bus types */ +typedef enum { + e1000_bus_type_unknown = 0, + e1000_bus_type_pci, + e1000_bus_type_pcix +} e1000_bus_type; + +/* PCI bus speeds */ +typedef enum { + e1000_bus_speed_unknown = 0, + e1000_bus_speed_33, + e1000_bus_speed_66, + e1000_bus_speed_100, + e1000_bus_speed_133, + e1000_bus_speed_reserved +} e1000_bus_speed; + +/* PCI bus widths */ +typedef enum { + e1000_bus_width_unknown = 0, + e1000_bus_width_32, + e1000_bus_width_64 +} e1000_bus_width; + + + +/* Function prototypes */ +/* Setup */ +void e1000_adapter_stop(struct e1000_shared_adapter *shared); +boolean_t e1000_init_hw(struct e1000_shared_adapter *shared); +void e1000_init_rx_addrs(struct e1000_shared_adapter *shared); + +/* Filters (multicast, vlan, receive) */ +void e1000_mc_addr_list_update(struct e1000_shared_adapter *shared, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad); +uint32_t e1000_hash_mc_addr(struct e1000_shared_adapter *shared, uint8_t * mc_addr); +void e1000_mta_set(struct e1000_shared_adapter *shared, uint32_t hash_value); +void e1000_rar_set(struct e1000_shared_adapter *shared, uint8_t * mc_addr, uint32_t rar_index); +void e1000_write_vfta(struct e1000_shared_adapter *shared, uint32_t offset, uint32_t value); +void e1000_clear_vfta(struct e1000_shared_adapter *shared); + +/* Link layer setup functions */ +boolean_t e1000_setup_fc_and_link(struct e1000_shared_adapter *shared); +boolean_t e1000_setup_pcs_link(struct e1000_shared_adapter *shared, uint32_t dev_ctrl_reg); +void e1000_config_fc_after_link_up(struct e1000_shared_adapter *shared); +void e1000_check_for_link(struct e1000_shared_adapter *shared); +void e1000_get_speed_and_duplex(struct e1000_shared_adapter *shared, uint16_t * speed, uint16_t * duplex); + +/* EEPROM Functions */ +uint16_t e1000_read_eeprom(struct e1000_shared_adapter *shared, uint16_t reg); +boolean_t e1000_validate_eeprom_checksum(struct e1000_shared_adapter *shared); + +/* Everything else */ +void e1000_clear_hw_cntrs(struct e1000_shared_adapter *shared); +boolean_t e1000_read_part_num(struct e1000_shared_adapter *shared, uint32_t * part_num); +void e1000_read_mac_addr(struct e1000_shared_adapter * shared); +void e1000_get_bus_info(struct e1000_shared_adapter *shared); +uint32_t e1000_tbi_adjust_stats(struct e1000_shared_adapter *shared, struct e1000_shared_stats *stats, uint32_t frame_len, uint8_t * mac_addr); +void e1000_write_pci_cfg(struct e1000_shared_adapter *shared, uint32_t reg, uint16_t * value); + +/* PCI Device IDs */ +#define E1000_DEV_ID_82542 0x1000 +#define E1000_DEV_ID_82543GC_FIBER 0x1001 +#define E1000_DEV_ID_82543GC_COPPER 0x1004 +#define E1000_DEV_ID_82544EI_COPPER 0x1008 +#define E1000_DEV_ID_82544EI_FIBER 0x1009 +#define E1000_DEV_ID_82544GC_COPPER 0x100C +#define E1000_DEV_ID_82544GC_LOM 0x100D +#define NUM_DEV_IDS 7 + +#define NODE_ADDRESS_SIZE 6 +#define ETH_LENGTH_OF_ADDRESS 6 + +/* MAC decode size is 128K - This is the size of BAR0 */ +#define MAC_DECODE_SIZE (128 * 1024) + +#define E1000_82542_2_0_REV_ID 2 +#define E1000_82542_2_1_REV_ID 3 + +#define SPEED_10 10 +#define SPEED_100 100 +#define SPEED_1000 1000 +#define HALF_DUPLEX 1 +#define FULL_DUPLEX 2 + +/* The sizes (in bytes) of a ethernet packet */ +#define ENET_HEADER_SIZE 14 +#define MAXIMUM_ETHERNET_PACKET_SIZE 1514 /* Without FCS */ +#define MINIMUM_ETHERNET_PACKET_SIZE 60 /* Without FCS */ +#define CRC_LENGTH 4 +#define MAX_JUMBO_FRAME_SIZE 0x3F00 + + +/* 802.1q VLAN Packet Sizes */ +#define VLAN_TAG_SIZE 4 /* 802.3ac tag (not DMAed) */ + +/* Ethertype field values */ +#define ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.3ac packet */ +#define ETHERNET_IP_TYPE 0x0800 /* IP packets */ +#define ETHERNET_ARP_TYPE 0x0806 /* Address Resolution Protocol (ARP) */ + +/* Packet Header defines */ +#define IP_PROTOCOL_TCP 6 +#define IP_PROTOCOL_UDP 0x11 + +/* This defines the bits that are set in the Interrupt Mask + * Set/Read Register. Each bit is documented below: + * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0) + * o RXSEQ = Receive Sequence Error + */ +#define POLL_IMS_ENABLE_MASK ( \ + E1000_IMS_RXDMT0 | \ + E1000_IMS_RXSEQ) + +/* This defines the bits that are set in the Interrupt Mask + * Set/Read Register. Each bit is documented below: + * o RXT0 = Receiver Timer Interrupt (ring 0) + * o TXDW = Transmit Descriptor Written Back + * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0) + * o RXSEQ = Receive Sequence Error + * o LSC = Link Status Change + */ +#define IMS_ENABLE_MASK ( \ + E1000_IMS_RXT0 | \ + E1000_IMS_TXDW | \ + E1000_IMS_RXDMT0 | \ + E1000_IMS_RXSEQ | \ + E1000_IMS_LSC) + +/* The number of high/low register pairs in the RAR. The RAR (Receive Address + * Registers) holds the directed and multicast addresses that we monitor. We + * reserve one of these spots for our directed address, allowing us room for + * E1000_RAR_ENTRIES - 1 multicast addresses. + */ +#define E1000_RAR_ENTRIES 16 + +#define MIN_NUMBER_OF_DESCRIPTORS 8 +#define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8 + +/* Receive Descriptor */ +struct e1000_rx_desc { + uint64_t buffer_addr; /* Address of the descriptor's data buffer */ + uint16_t length; /* Length of data DMAed into data buffer */ + uint16_t csum; /* Packet checksum */ + uint8_t status; /* Descriptor status */ + uint8_t errors; /* Descriptor Errors */ + uint16_t special; +}; + +/* Receive Decriptor bit definitions */ +#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */ +#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */ +#define E1000_RXD_STAT_IXSM 0x04 /* Ignore checksum */ +#define E1000_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */ +#define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */ +#define E1000_RXD_STAT_IPCS 0x40 /* IP xsum calculated */ +#define E1000_RXD_STAT_PIF 0x80 /* passed in-exact filter */ +#define E1000_RXD_ERR_CE 0x01 /* CRC Error */ +#define E1000_RXD_ERR_SE 0x02 /* Symbol Error */ +#define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */ +#define E1000_RXD_ERR_CXE 0x10 /* Carrier Extension Error */ +#define E1000_RXD_ERR_TCPE 0x20 /* TCP/UDP Checksum Error */ +#define E1000_RXD_ERR_IPE 0x40 /* IP Checksum Error */ +#define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */ +#define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */ +#define E1000_RXD_SPC_PRI_MASK 0xE000 /* Priority is in upper 3 bits */ +#define E1000_RXD_SPC_PRI_SHIFT 0x000D /* Priority is in upper 3 of 16 */ +#define E1000_RXD_SPC_CFI_MASK 0x1000 /* CFI is bit 12 */ +#define E1000_RXD_SPC_CFI_SHIFT 0x000C /* CFI is bit 12 */ + +/* mask to determine if packets should be dropped due to frame errors */ +#define E1000_RXD_ERR_FRAME_ERR_MASK ( \ + E1000_RXD_ERR_CE | \ + E1000_RXD_ERR_SE | \ + E1000_RXD_ERR_SEQ | \ + E1000_RXD_ERR_CXE | \ + E1000_RXD_ERR_RXE) + +/* Transmit Descriptor */ +struct e1000_tx_desc { + uint64_t buffer_addr; /* Address of the descriptor's data buffer */ + union { + uint32_t data; + struct { + uint16_t length; /* Data buffer length */ + uint8_t cso; /* Checksum offset */ + uint8_t cmd; /* Descriptor control */ + } flags; + } lower; + union { + uint32_t data; + struct { + uint8_t status; /* Descriptor status */ + uint8_t css; /* Checksum start */ + uint16_t special; + } fields; + } upper; +}; + +/* Transmit Descriptor bit definitions */ +#define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */ +#define E1000_TXD_DTYP_C 0x00000000 /* Context Descriptor */ +#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ +#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ +#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */ +#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ +#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */ +#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */ +#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */ +#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */ +#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */ +#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */ +#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */ +#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */ +#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */ +#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */ +#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */ +#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */ +#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */ +#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */ + +/* Offload Context Descriptor */ +struct e1000_context_desc { + union { + uint32_t ip_config; + struct { + uint8_t ipcss; /* IP checksum start */ + uint8_t ipcso; /* IP checksum offset */ + uint16_t ipcse; /* IP checksum end */ + } ip_fields; + } lower_setup; + union { + uint32_t tcp_config; + struct { + uint8_t tucss; /* TCP checksum start */ + uint8_t tucso; /* TCP checksum offset */ + uint16_t tucse; /* TCP checksum end */ + } tcp_fields; + } upper_setup; + uint32_t cmd_and_length; /* */ + union { + uint32_t data; + struct { + uint8_t status; /* Descriptor status */ + uint8_t hdr_len; /* Header length */ + uint16_t mss; /* Maximum segment size */ + } fields; + } tcp_seg_setup; +}; + +/* Offload data descriptor */ +struct e1000_data_desc { + uint64_t buffer_addr; /* Address of the descriptor's buffer address */ + union { + uint32_t data; + struct { + uint16_t length; /* Data buffer length */ + uint8_t typ_len_ext; /* */ + uint8_t cmd; /* */ + } flags; + } lower; + union { + uint32_t data; + struct { + uint8_t status; /* Descriptor status */ + uint8_t popts; /* Packet Options */ + uint16_t special; /* */ + } fields; + } upper; +}; + +/* Filters */ +#define E1000_NUM_UNICAST 16 /* Unicast filter entries */ +#define E1000_MC_TBL_SIZE 128 /* Multicast Filter Table (4096 bits) */ +#define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */ + + +/* Receive Address Register */ +struct e1000_rar { + volatile uint32_t low; /* receive address low */ + volatile uint32_t high; /* receive address high */ +}; + +/* The number of entries in the Multicast Table Array (MTA). */ +#define E1000_NUM_MTA_REGISTERS 128 + +/* IPv4 Address Table Entry */ +struct e1000_ipv4_at_entry { + volatile uint32_t ipv4_addr; /* IP Address (RW) */ + volatile uint32_t reserved; +}; + +/* Four wakeup IP addresses are supported */ +#define E1000_WAKEUP_IP_ADDRESS_COUNT_MAX 4 +#define E1000_IP4AT_SIZE E1000_WAKEUP_IP_ADDRESS_COUNT_MAX +#define E1000_IP6AT_SIZE 1 + +/* IPv6 Address Table Entry */ +struct e1000_ipv6_at_entry { + volatile uint8_t ipv6_addr[16]; +}; + +/* Flexible Filter Length Table Entry */ +struct e1000_fflt_entry { + volatile uint32_t length; /* Flexible Filter Length (RW) */ + volatile uint32_t reserved; +}; + +/* Flexible Filter Mask Table Entry */ +struct e1000_ffmt_entry { + volatile uint32_t mask; /* Flexible Filter Mask (RW) */ + volatile uint32_t reserved; +}; + +/* Flexible Filter Value Table Entry */ +struct e1000_ffvt_entry { + volatile uint32_t value; /* Flexible Filter Value (RW) */ + volatile uint32_t reserved; +}; + +/* Four Flexible Filters are supported */ +#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4 + +/* Each Flexible Filter is at most 128 (0x80) bytes in length */ +#define E1000_FLEXIBLE_FILTER_SIZE_MAX 128 + +#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX +#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX +#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX + +/* Register Set. (82543, 82544) + * + * Registers are defined to be 32 bits and should be accessed as 32 bit values. + * These registers are physically located on the NIC, but are mapped into the + * host memory address space. + * + * RW - register is both readable and writable + * RO - register is read only + * WO - register is write only + * R/clr - register is read only and is cleared when read + * A - register array + */ +#define E1000_CTRL 0x00000 /* Device Control - RW */ +#define E1000_STATUS 0x00008 /* Device Status - RO */ +#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */ +#define E1000_EERD 0x00014 /* EEPROM Read - RW */ +#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */ +#define E1000_MDIC 0x00020 /* MDI Control - RW */ +#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ +#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ +#define E1000_FCT 0x00030 /* Flow Control Type - RW */ +#define E1000_VET 0x00038 /* VLAN Ether Type - RW */ +#define E1000_ICR 0x000C0 /* Interrupt Cause Read - R/clr */ +#define E1000_ITR 0x000C4 /* Interrupt Throttling Rate - RW */ +#define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */ +#define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */ +#define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */ +#define E1000_RCTL 0x00100 /* RX Control - RW */ +#define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */ +#define E1000_TXCW 0x00178 /* TX Configuration Word - RW */ +#define E1000_RXCW 0x00180 /* RX Configuration Word - RO */ +#define E1000_TCTL 0x00400 /* TX Control - RW */ +#define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */ +#define E1000_TBT 0x00448 /* TX Burst Timer - RW */ +#define E1000_LEDCTL 0x00E00 /* LED Control - RW */ +#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */ +#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */ +#define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */ +#define E1000_RDBAL 0x02800 /* RX Descriptor Base Address Low - RW */ +#define E1000_RDBAH 0x02804 /* RX Descriptor Base Address High - RW */ +#define E1000_RDLEN 0x02808 /* RX Descriptor Length - RW */ +#define E1000_RDH 0x02810 /* RX Descriptor Head - RW */ +#define E1000_RDT 0x02818 /* RX Descriptor Tail - RW */ +#define E1000_RDTR 0x02820 /* RX Delay Timer - RW */ +#define E1000_RXDCTL 0x02828 /* RX Descriptor Control - RW */ +#define E1000_RADV 0x0282C /* RX Interrupt Absolute Delay Timer - RW */ +#define E1000_RSRPD 0x02C00 /* RX Small Packet Detect - RW */ +#define E1000_TXDMAC 0x03000 /* TX DMA Control - RW */ +#define E1000_TDBAL 0x03800 /* TX Descriptor Base Address Low - RW */ +#define E1000_TDBAH 0x03804 /* TX Descriptor Base Address High - RW */ +#define E1000_TDLEN 0x03808 /* TX Descriptor Length - RW */ +#define E1000_TDH 0x03810 /* TX Descriptor Head - RW */ +#define E1000_TDT 0x03818 /* TX Descripotr Tail - RW */ +#define E1000_TIDV 0x03820 /* TX Interrupt Delay Value - RW */ +#define E1000_TXDCTL 0x03828 /* TX Descriptor Control - RW */ +#define E1000_TADV 0x0382C /* TX Interrupt Absolute Delay Val - RW */ +#define E1000_TSPMT 0x03830 /* TCP Segmentation PAD & Min Threshold - RW */ +#define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */ +#define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */ +#define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */ +#define E1000_RXERRC 0x0400C /* Receive Error Count - R/clr */ +#define E1000_MPC 0x04010 /* Missed Packet Count - R/clr */ +#define E1000_SCC 0x04014 /* Single Collision Count - R/clr */ +#define E1000_ECOL 0x04018 /* Excessive Collision Count - R/clr */ +#define E1000_MCC 0x0401C /* Multiple Collision Count - R/clr */ +#define E1000_LATECOL 0x04020 /* Late Collision Count - R/clr */ +#define E1000_COLC 0x04028 /* Collision Count - R/clr */ +#define E1000_DC 0x04030 /* Defer Count - R/clr */ +#define E1000_TNCRS 0x04034 /* TX-No CRS - R/clr */ +#define E1000_SEC 0x04038 /* Sequence Error Count - R/clr */ +#define E1000_CEXTERR 0x0403C /* Carrier Extension Error Count - R/clr */ +#define E1000_RLEC 0x04040 /* Receive Length Error Count - R/clr */ +#define E1000_XONRXC 0x04048 /* XON RX Count - R/clr */ +#define E1000_XONTXC 0x0404C /* XON TX Count - R/clr */ +#define E1000_XOFFRXC 0x04050 /* XOFF RX Count - R/clr */ +#define E1000_XOFFTXC 0x04054 /* XOFF TX Count - R/clr */ +#define E1000_FCRUC 0x04058 /* Flow Control RX Unsupported Count- R/clr */ +#define E1000_PRC64 0x0405C /* Packets RX (64 bytes) - R/clr */ +#define E1000_PRC127 0x04060 /* Packets RX (65-127 bytes) - R/clr */ +#define E1000_PRC255 0x04064 /* Packets RX (128-255 bytes) - R/clr */ +#define E1000_PRC511 0x04068 /* Packets RX (255-511 bytes) - R/clr */ +#define E1000_PRC1023 0x0406C /* Packets RX (512-1023 bytes) - R/clr */ +#define E1000_PRC1522 0x04070 /* Packets RX (1024-1522 bytes) - R/clr */ +#define E1000_GPRC 0x04074 /* Good Packets RX Count - R/clr */ +#define E1000_BPRC 0x04078 /* Broadcast Packets RX Count - R/clr */ +#define E1000_MPRC 0x0407C /* Multicast Packets RX Count - R/clr */ +#define E1000_GPTC 0x04080 /* Good Packets TX Count - R/clr */ +#define E1000_GORCL 0x04088 /* Good Octets RX Count Low - R/clr */ +#define E1000_GORCH 0x0408C /* Good Octets RX Count High - R/clr */ +#define E1000_GOTCL 0x04090 /* Good Octets TX Count Low - R/clr */ +#define E1000_GOTCH 0x04094 /* Good Octets TX Count High - R/clr */ +#define E1000_RNBC 0x040A0 /* RX No Buffers Count - R/clr */ +#define E1000_RUC 0x040A4 /* RX Undersize Count - R/clr */ +#define E1000_RFC 0x040A8 /* RX Fragment Count - R/clr */ +#define E1000_ROC 0x040AC /* RX Oversize Count - R/clr */ +#define E1000_RJC 0x040B0 /* RX Jabber Count - R/clr */ +#define E1000_MGTPRC 0x040B4 /* Management Packets RX Count - R/clr */ +#define E1000_MGTPDC 0x040B8 /* Management Packets Dropped Count - R/clr */ +#define E1000_MGTPTC 0x040BC /* Management Packets TX Count - R/clr */ +#define E1000_TORL 0x040C0 /* Total Octets RX Low - R/clr */ +#define E1000_TORH 0x040C4 /* Total Octets RX High - R/clr */ +#define E1000_TOTL 0x040C8 /* Total Octets TX Low - R/clr */ +#define E1000_TOTH 0x040CC /* Total Octets TX High - R/clr */ +#define E1000_TPR 0x040D0 /* Total Packets RX - R/clr */ +#define E1000_TPT 0x040D4 /* Total Packets TX - R/clr */ +#define E1000_PTC64 0x040D8 /* Packets TX (64 bytes) - R/clr */ +#define E1000_PTC127 0x040DC /* Packets TX (65-127 bytes) - R/clr */ +#define E1000_PTC255 0x040E0 /* Packets TX (128-255 bytes) - R/clr */ +#define E1000_PTC511 0x040E4 /* Packets TX (256-511 bytes) - R/clr */ +#define E1000_PTC1023 0x040E8 /* Packets TX (512-1023 bytes) - R/clr */ +#define E1000_PTC1522 0x040EC /* Packets TX (1024-1522 Bytes) - R/clr */ +#define E1000_MPTC 0x040F0 /* Multicast Packets TX Count - R/clr */ +#define E1000_BPTC 0x040F4 /* Broadcast Packets TX Count - R/clr */ +#define E1000_TSCTC 0x040F8 /* TCP Segmentation Context TX - R/clr */ +#define E1000_TSCTFC 0x040FC /* TCP Segmentation Context TX Fail - R/clr */ +#define E1000_RXCSUM 0x05000 /* RX Checksum Control - RW */ +#define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */ +#define E1000_RA 0x05400 /* Receive Address - RW Array */ +#define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */ +#define E1000_WUC 0x05800 /* Wakeup Control - RW */ +#define E1000_WUFC 0x05808 /* Wakeup Filter Control - RW */ +#define E1000_WUS 0x05810 /* Wakeup Status - RO */ +#define E1000_MANC 0x05820 /* Management Control - RW */ +#define E1000_IPAV 0x05838 /* IP Address Valid - RW */ +#define E1000_IP4AT 0x05840 /* IPv4 Address Table - RW Array */ +#define E1000_IP6AT 0x05880 /* IPv6 Address Table - RW Array */ +#define E1000_WUPL 0x05900 /* Wakeup Packet Length - RW */ +#define E1000_WUPM 0x05A00 /* Wakeup Packet Memory - RO A */ +#define E1000_FFLT 0x05F00 /* Flexible Filter Length Table - RW Array */ +#define E1000_FFMT 0x09000 /* Flexible Filter Mask Table - RW Array */ +#define E1000_FFVT 0x09800 /* Flexible Filter Value Table - RW Array */ + +/* Register Set (82542) + * + * Some of the 82542 registers are located at different offsets than they are + * in more current versions of the 8254x. Despite the difference in location, + * the registers function in the same manner. + */ +#define E1000_82542_CTRL E1000_CTRL +#define E1000_82542_STATUS E1000_STATUS +#define E1000_82542_EECD E1000_EECD +#define E1000_82542_EERD E1000_EERD +#define E1000_82542_CTRL_EXT E1000_CTRL_EXT +#define E1000_82542_MDIC E1000_MDIC +#define E1000_82542_FCAL E1000_FCAL +#define E1000_82542_FCAH E1000_FCAH +#define E1000_82542_FCT E1000_FCT +#define E1000_82542_VET E1000_VET +#define E1000_82542_RA 0x00040 +#define E1000_82542_ICR E1000_ICR +#define E1000_82542_ITR E1000_ITR +#define E1000_82542_ICS E1000_ICS +#define E1000_82542_IMS E1000_IMS +#define E1000_82542_IMC E1000_IMC +#define E1000_82542_RCTL E1000_RCTL +#define E1000_82542_RDTR 0x00108 +#define E1000_82542_RDBAL 0x00110 +#define E1000_82542_RDBAH 0x00114 +#define E1000_82542_RDLEN 0x00118 +#define E1000_82542_RDH 0x00120 +#define E1000_82542_RDT 0x00128 +#define E1000_82542_FCRTH 0x00160 +#define E1000_82542_FCRTL 0x00168 +#define E1000_82542_FCTTV E1000_FCTTV +#define E1000_82542_TXCW E1000_TXCW +#define E1000_82542_RXCW E1000_RXCW +#define E1000_82542_MTA 0x00200 +#define E1000_82542_TCTL E1000_TCTL +#define E1000_82542_TIPG E1000_TIPG +#define E1000_82542_TDBAL 0x00420 +#define E1000_82542_TDBAH 0x00424 +#define E1000_82542_TDLEN 0x00428 +#define E1000_82542_TDH 0x00430 +#define E1000_82542_TDT 0x00438 +#define E1000_82542_TIDV 0x00440 +#define E1000_82542_TBT E1000_TBT +#define E1000_82542_VFTA 0x00600 +#define E1000_82542_LEDCTL E1000_LEDCTL +#define E1000_82542_PBA E1000_PBA +#define E1000_82542_RXDCTL E1000_RXDCTL +#define E1000_82542_RADV E1000_RADV +#define E1000_82542_RSRPD E1000_RSRPD +#define E1000_82542_TXDMAC E1000_TXDMAC +#define E1000_82542_TXDCTL E1000_TXDCTL +#define E1000_82542_TADV E1000_TADV +#define E1000_82542_TSPMT E1000_TSPMT +#define E1000_82542_CRCERRS E1000_CRCERRS +#define E1000_82542_ALGNERRC E1000_ALGNERRC +#define E1000_82542_SYMERRS E1000_SYMERRS +#define E1000_82542_RXERRC E1000_RXERRC +#define E1000_82542_MPC E1000_MPC +#define E1000_82542_SCC E1000_SCC +#define E1000_82542_ECOL E1000_ECOL +#define E1000_82542_MCC E1000_MCC +#define E1000_82542_LATECOL E1000_LATECOL +#define E1000_82542_COLC E1000_COLC +#define E1000_82542_DC E1000_DC +#define E1000_82542_TNCRS E1000_TNCRS +#define E1000_82542_SEC E1000_SEC +#define E1000_82542_CEXTERR E1000_CEXTERR +#define E1000_82542_RLEC E1000_RLEC +#define E1000_82542_XONRXC E1000_XONRXC +#define E1000_82542_XONTXC E1000_XONTXC +#define E1000_82542_XOFFRXC E1000_XOFFRXC +#define E1000_82542_XOFFTXC E1000_XOFFTXC +#define E1000_82542_FCRUC E1000_FCRUC +#define E1000_82542_PRC64 E1000_PRC64 +#define E1000_82542_PRC127 E1000_PRC127 +#define E1000_82542_PRC255 E1000_PRC255 +#define E1000_82542_PRC511 E1000_PRC511 +#define E1000_82542_PRC1023 E1000_PRC1023 +#define E1000_82542_PRC1522 E1000_PRC1522 +#define E1000_82542_GPRC E1000_GPRC +#define E1000_82542_BPRC E1000_BPRC +#define E1000_82542_MPRC E1000_MPRC +#define E1000_82542_GPTC E1000_GPTC +#define E1000_82542_GORCL E1000_GORCL +#define E1000_82542_GORCH E1000_GORCH +#define E1000_82542_GOTCL E1000_GOTCL +#define E1000_82542_GOTCH E1000_GOTCH +#define E1000_82542_RNBC E1000_RNBC +#define E1000_82542_RUC E1000_RUC +#define E1000_82542_RFC E1000_RFC +#define E1000_82542_ROC E1000_ROC +#define E1000_82542_RJC E1000_RJC +#define E1000_82542_MGTPRC E1000_MGTPRC +#define E1000_82542_MGTPDC E1000_MGTPDC +#define E1000_82542_MGTPTC E1000_MGTPTC +#define E1000_82542_TORL E1000_TORL +#define E1000_82542_TORH E1000_TORH +#define E1000_82542_TOTL E1000_TOTL +#define E1000_82542_TOTH E1000_TOTH +#define E1000_82542_TPR E1000_TPR +#define E1000_82542_TPT E1000_TPT +#define E1000_82542_PTC64 E1000_PTC64 +#define E1000_82542_PTC127 E1000_PTC127 +#define E1000_82542_PTC255 E1000_PTC255 +#define E1000_82542_PTC511 E1000_PTC511 +#define E1000_82542_PTC1023 E1000_PTC1023 +#define E1000_82542_PTC1522 E1000_PTC1522 +#define E1000_82542_MPTC E1000_MPTC +#define E1000_82542_BPTC E1000_BPTC +#define E1000_82542_TSCTC E1000_TSCTC +#define E1000_82542_TSCTFC E1000_TSCTFC +#define E1000_82542_RXCSUM E1000_RXCSUM +#define E1000_82542_WUC E1000_WUC +#define E1000_82542_WUFC E1000_WUFC +#define E1000_82542_WUS E1000_WUS +#define E1000_82542_MANC E1000_MANC +#define E1000_82542_IPAV E1000_IPAV +#define E1000_82542_IP4AT E1000_IP4AT +#define E1000_82542_IP6AT E1000_IP6AT +#define E1000_82542_WUPL E1000_WUPL +#define E1000_82542_WUPM E1000_WUPM +#define E1000_82542_FFLT E1000_FFLT +#define E1000_82542_FFMT E1000_FFMT +#define E1000_82542_FFVT E1000_FFVT + +/* Statistics counters collected by the MAC */ +struct e1000_shared_stats { + uint64_t crcerrs; + uint64_t algnerrc; + uint64_t symerrs; + uint64_t rxerrc; + uint64_t mpc; + uint64_t scc; + uint64_t ecol; + uint64_t mcc; + uint64_t latecol; + uint64_t colc; + uint64_t dc; + uint64_t tncrs; + uint64_t sec; + uint64_t cexterr; + uint64_t rlec; + uint64_t xonrxc; + uint64_t xontxc; + uint64_t xoffrxc; + uint64_t xofftxc; + uint64_t fcruc; + uint64_t prc64; + uint64_t prc127; + uint64_t prc255; + uint64_t prc511; + uint64_t prc1023; + uint64_t prc1522; + uint64_t gprc; + uint64_t bprc; + uint64_t mprc; + uint64_t gptc; + uint64_t gorcl; + uint64_t gorch; + uint64_t gotcl; + uint64_t gotch; + uint64_t rnbc; + uint64_t ruc; + uint64_t rfc; + uint64_t roc; + uint64_t rjc; + uint64_t mgprc; + uint64_t mgpdc; + uint64_t mgptc; + uint64_t torl; + uint64_t torh; + uint64_t totl; + uint64_t toth; + uint64_t tpr; + uint64_t tpt; + uint64_t ptc64; + uint64_t ptc127; + uint64_t ptc255; + uint64_t ptc511; + uint64_t ptc1023; + uint64_t ptc1522; + uint64_t mptc; + uint64_t bptc; + uint64_t tsctc; + uint64_t tsctfc; +}; + +/* Structure containing variables used by the shared code (e1000_mac.c and + * e1000_phy.c) + */ +struct e1000_shared_adapter { + uint8_t *hw_addr; + e1000_mac_type mac_type; + e1000_media_type media_type; + void *back; + e1000_fc_type fc; + e1000_bus_speed bus_speed; + e1000_bus_width bus_width; + e1000_bus_type bus_type; + uint32_t phy_id; + uint32_t phy_addr; + uint32_t original_fc; + uint32_t txcw_reg; + uint32_t autoneg_failed; + uint32_t max_frame_size; + uint32_t min_frame_size; + uint32_t mc_filter_type; + uint32_t num_mc_addrs; + uint16_t autoneg_advertised; + uint16_t pci_cmd_word; + uint16_t fc_high_water; + uint16_t fc_low_water; + uint16_t fc_pause_time; + uint16_t device_id; + uint16_t vendor_id; + uint16_t subsystem_id; + uint16_t subsystem_vendor_id; + uint8_t revision_id; + boolean_t disable_polarity_correction; + boolean_t get_link_status; + boolean_t tbi_compatibility_en; + boolean_t tbi_compatibility_on; + boolean_t adapter_stopped; + boolean_t fc_send_xon; + boolean_t report_tx_early; + uint8_t autoneg; + uint8_t mdix; + uint8_t forced_speed_duplex; + uint8_t wait_autoneg_complete; + uint8_t dma_fairness; + uint8_t mac_addr[NODE_ADDRESS_SIZE]; + uint8_t perm_mac_addr[NODE_ADDRESS_SIZE]; +}; + + +#define E1000_EEPROM_SWDPIN0 0x0001 /* SWDPIN 0 EEPROM Value */ +#define E1000_EEPROM_LED_LOGIC 0x0020 /* Led Logic Word */ + +/* Register Bit Masks */ +/* Device Control */ +#define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */ +#define E1000_CTRL_BEM 0x00000002 /* Endian Mode.0=little,1=big */ +#define E1000_CTRL_PRIOR 0x00000004 /* Priority on PCI. 0=rx,1=fair */ +#define E1000_CTRL_LRST 0x00000008 /* Link reset. 0=normal,1=reset */ +#define E1000_CTRL_TME 0x00000010 /* Test mode. 0=normal,1=test */ +#define E1000_CTRL_SLE 0x00000020 /* Serial Link on 0=dis,1=en */ +#define E1000_CTRL_ASDE 0x00000020 /* Auto-speed detect enable */ +#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */ +#define E1000_CTRL_ILOS 0x00000080 /* Invert Loss-Of Signal */ +#define E1000_CTRL_SPD_SEL 0x00000300 /* Speed Select Mask */ +#define E1000_CTRL_SPD_10 0x00000000 /* Force 10Mb */ +#define E1000_CTRL_SPD_100 0x00000100 /* Force 100Mb */ +#define E1000_CTRL_SPD_1000 0x00000200 /* Force 1Gb */ +#define E1000_CTRL_BEM32 0x00000400 /* Big Endian 32 mode */ +#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */ +#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */ +#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ +#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ +#define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */ +#define E1000_CTRL_SWDPIN3 0x00200000 /* SWDPIN 3 value */ +#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */ +#define E1000_CTRL_SWDPIO1 0x00800000 /* SWDPIN 1 input or output */ +#define E1000_CTRL_SWDPIO2 0x01000000 /* SWDPIN 2 input or output */ +#define E1000_CTRL_SWDPIO3 0x02000000 /* SWDPIN 3 input or output */ +#define E1000_CTRL_RST 0x04000000 /* Global reset */ +#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */ +#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */ +#define E1000_CTRL_RTE 0x20000000 /* Routing tag enable */ +#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */ +#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */ + +/* Device Status */ +#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */ +#define E1000_STATUS_LU 0x00000002 /* Link up.0=no,1=link */ +#define E1000_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */ +#define E1000_STATUS_FUNC_0 0x00000000 /* Function 0 */ +#define E1000_STATUS_FUNC_1 0x00000004 /* Function 1 */ +#define E1000_STATUS_TXOFF 0x00000010 /* transmission paused */ +#define E1000_STATUS_TBIMODE 0x00000020 /* TBI mode */ +#define E1000_STATUS_SPEED_MASK 0x000000C0 +#define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */ +#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */ +#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */ +#define E1000_STATUS_ASDV 0x00000300 /* Auto speed detect value */ +#define E1000_STATUS_MTXCKOK 0x00000400 /* MTX clock running OK */ +#define E1000_STATUS_PCI66 0x00000800 /* In 66Mhz slot */ +#define E1000_STATUS_BUS64 0x00001000 /* In 64 bit slot */ +#define E1000_STATUS_PCIX_MODE 0x00002000 /* PCI-X mode */ +#define E1000_STATUS_PCIX_SPEED 0x0000C000 /* PCI-X bus speed */ + +/* Constants used to intrepret the masked PCI-X bus speed. */ +#define E1000_STATUS_PCIX_SPEED_66 0x00000000 /* PCI-X bus speed 50-66 MHz */ +#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed 66-100 MHz */ +#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /* PCI-X bus speed 100-133 MHz */ + +/* EEPROM/Flash Control */ +#define E1000_EECD_SK 0x00000001 /* EEPROM Clock */ +#define E1000_EECD_CS 0x00000002 /* EEPROM Chip Select */ +#define E1000_EECD_DI 0x00000004 /* EEPROM Data In */ +#define E1000_EECD_DO 0x00000008 /* EEPROM Data Out */ +#define E1000_EECD_FWE_MASK 0x00000030 +#define E1000_EECD_FWE_DIS 0x00000010 /* Disable FLASH writes */ +#define E1000_EECD_FWE_EN 0x00000020 /* Enable FLASH writes */ +#define E1000_EECD_FWE_SHIFT 4 +#define E1000_EECD_SIZE 0x00000200 /* EEPROM Size (0=64 word 1=256 word) */ +#define E1000_EECD_REQ 0x00000040 /* EEPROM Access Request */ +#define E1000_EECD_GNT 0x00000080 /* EEPROM Access Grant */ +#define E1000_EECD_PRES 0x00000100 /* EEPROM Present */ + +/* EEPROM Read */ +#define E1000_EERD_START 0x00000001 /* Start Read */ +#define E1000_EERD_DONE 0x00000010 /* Read Done */ +#define E1000_EERD_ADDR_SHIFT 8 +#define E1000_EERD_ADDR_MASK 0x0000FF00 /* Read Address */ +#define E1000_EERD_DATA_SHIFT 16 +#define E1000_EERD_DATA_MASK 0xFFFF0000 /* Read Data */ + +/* Extended Device Control */ +#define E1000_CTRL_EXT_GPI0_EN 0x00000001 /* Maps SDP4 to GPI0 */ +#define E1000_CTRL_EXT_GPI1_EN 0x00000002 /* Maps SDP5 to GPI1 */ +#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN +#define E1000_CTRL_EXT_GPI2_EN 0x00000004 /* Maps SDP6 to GPI2 */ +#define E1000_CTRL_EXT_GPI3_EN 0x00000008 /* Maps SDP7 to GPI3 */ +#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Defineable Pin 4 */ +#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Defineable Pin 5 */ +#define E1000_CTRL_EXT_PHY_INT E1000_CTRL_EXT_SDP5_DATA +#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Defineable Pin 6 */ +#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */ +#define E1000_CTRL_EXT_SDP4_DIR 0x00000100 /* Direction of SDP4 0=in 1=out */ +#define E1000_CTRL_EXT_SDP5_DIR 0x00000200 /* Direction of SDP5 0=in 1=out */ +#define E1000_CTRL_EXT_SDP6_DIR 0x00000400 /* Direction of SDP6 0=in 1=out */ +#define E1000_CTRL_EXT_SDP7_DIR 0x00000800 /* Direction of SDP7 0=in 1=out */ +#define E1000_CTRL_EXT_ASDCHK 0x00001000 /* Initiate an ASD sequence */ +#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */ +#define E1000_CTRL_EXT_IPS 0x00004000 /* Invert Power State */ +#define E1000_CTRL_EXT_SPD_BYPS 0x00008000 /* Speed Select Bypass */ +#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000 +#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000 +#define E1000_CTRL_EXT_LINK_MODE_TBI 0x00C00000 +#define E1000_CTRL_EXT_WR_WMARK_MASK 0x03000000 +#define E1000_CTRL_EXT_WR_WMARK_256 0x00000000 +#define E1000_CTRL_EXT_WR_WMARK_320 0x01000000 +#define E1000_CTRL_EXT_WR_WMARK_384 0x02000000 +#define E1000_CTRL_EXT_WR_WMARK_448 0x03000000 + +/* MDI Control */ +#define E1000_MDIC_DATA_MASK 0x0000FFFF +#define E1000_MDIC_REG_MASK 0x001F0000 +#define E1000_MDIC_REG_SHIFT 16 +#define E1000_MDIC_PHY_MASK 0x03E00000 +#define E1000_MDIC_PHY_SHIFT 21 +#define E1000_MDIC_OP_WRITE 0x04000000 +#define E1000_MDIC_OP_READ 0x08000000 +#define E1000_MDIC_READY 0x10000000 +#define E1000_MDIC_INT_EN 0x20000000 +#define E1000_MDIC_ERROR 0x40000000 + +/* LED Control */ +#define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F +#define E1000_LEDCTL_LED0_MODE_SHIFT 0 +#define E1000_LEDCTL_LED0_IVRT 0x00000040 +#define E1000_LEDCTL_LED0_BLINK 0x00000080 +#define E1000_LEDCTL_LED1_MODE_MASK 0x00000F00 +#define E1000_LEDCTL_LED1_MODE_SHIFT 8 +#define E1000_LEDCTL_LED1_IVRT 0x00004000 +#define E1000_LEDCTL_LED1_BLINK 0x00008000 +#define E1000_LEDCTL_LED2_MODE_MASK 0x000F0000 +#define E1000_LEDCTL_LED2_MODE_SHIFT 16 +#define E1000_LEDCTL_LED2_IVRT 0x00400000 +#define E1000_LEDCTL_LED2_BLINK 0x00800000 +#define E1000_LEDCTL_LED3_MODE_MASK 0x0F000000 +#define E1000_LEDCTL_LED3_MODE_SHIFT 24 +#define E1000_LEDCTL_LED3_IVRT 0x40000000 +#define E1000_LEDCTL_LED3_BLINK 0x80000000 + +#define E1000_LEDCTL_MODE_LINK_10_1000 0x0 +#define E1000_LEDCTL_MODE_LINK_100_1000 0x1 +#define E1000_LEDCTL_MODE_LINK_UP 0x2 +#define E1000_LEDCTL_MODE_ACTIVITY 0x3 +#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4 +#define E1000_LEDCTL_MODE_LINK_10 0x5 +#define E1000_LEDCTL_MODE_LINK_100 0x6 +#define E1000_LEDCTL_MODE_LINK_1000 0x7 +#define E1000_LEDCTL_MODE_PCIX_MODE 0x8 +#define E1000_LEDCTL_MODE_FULL_DUPLEX 0x9 +#define E1000_LEDCTL_MODE_COLLISION 0xA +#define E1000_LEDCTL_MODE_BUS_SPEED 0xB +#define E1000_LEDCTL_MODE_BUS_SIZE 0xC +#define E1000_LEDCTL_MODE_PAUSED 0xD +#define E1000_LEDCTL_MODE_LED_ON 0xE +#define E1000_LEDCTL_MODE_LED_OFF 0xF + +/* Receive Address */ +#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */ + +/* Interrupt Cause Read */ +#define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ +#define E1000_ICR_TXQE 0x00000002 /* Transmit Queue empty */ +#define E1000_ICR_LSC 0x00000004 /* Link Status Change */ +#define E1000_ICR_RXSEQ 0x00000008 /* rx sequence error */ +#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */ +#define E1000_ICR_RXO 0x00000040 /* rx overrun */ +#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */ +#define E1000_ICR_MDAC 0x00000200 /* MDIO access complete */ +#define E1000_ICR_RXCFG 0x00000400 /* RX /c/ ordered set */ +#define E1000_ICR_GPI_EN0 0x00000800 /* GP Int 0 */ +#define E1000_ICR_GPI_EN1 0x00001000 /* GP Int 1 */ +#define E1000_ICR_GPI_EN2 0x00002000 /* GP Int 2 */ +#define E1000_ICR_GPI_EN3 0x00004000 /* GP Int 3 */ +#define E1000_ICR_TXD_LOW 0x00008000 +#define E1000_ICR_SRPD 0x00010000 + +/* Interrupt Cause Set */ +#define E1000_ICS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ +#define E1000_ICS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ +#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_ICS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ +#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ +#define E1000_ICS_RXO E1000_ICR_RXO /* rx overrun */ +#define E1000_ICS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ +#define E1000_ICS_MDAC E1000_ICR_MDAC /* MDIO access complete */ +#define E1000_ICS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ +#define E1000_ICS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ +#define E1000_ICS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ +#define E1000_ICS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ +#define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ +#define E1000_ICS_TXD_LOW E1000_ICR_TXD_LOW +#define E1000_ICS_SRPD E1000_ICR_SRPD + +/* Interrupt Mask Set */ +#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ +#define E1000_IMS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ +#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ +#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ +#define E1000_IMS_RXO E1000_ICR_RXO /* rx overrun */ +#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ +#define E1000_IMS_MDAC E1000_ICR_MDAC /* MDIO access complete */ +#define E1000_IMS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ +#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ +#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ +#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ +#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ +#define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW +#define E1000_IMS_SRPD E1000_ICR_SRPD + +/* Interrupt Mask Clear */ +#define E1000_IMC_TXDW E1000_ICR_TXDW /* Transmit desc written back */ +#define E1000_IMC_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ +#define E1000_IMC_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_IMC_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ +#define E1000_IMC_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ +#define E1000_IMC_RXO E1000_ICR_RXO /* rx overrun */ +#define E1000_IMC_RXT0 E1000_ICR_RXT0 /* rx timer intr */ +#define E1000_IMC_MDAC E1000_ICR_MDAC /* MDIO access complete */ +#define E1000_IMC_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ +#define E1000_IMC_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ +#define E1000_IMC_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ +#define E1000_IMC_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ +#define E1000_IMC_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ +#define E1000_IMC_TXD_LOW E1000_ICR_TXD_LOW +#define E1000_IMC_SRPD E1000_ICR_SRPD + +/* Receive Control */ +#define E1000_RCTL_RST 0x00000001 /* Software reset */ +#define E1000_RCTL_EN 0x00000002 /* enable */ +#define E1000_RCTL_SBP 0x00000004 /* store bad packet */ +#define E1000_RCTL_UPE 0x00000008 /* unicast promiscuous enable */ +#define E1000_RCTL_MPE 0x00000010 /* multicast promiscuous enab */ +#define E1000_RCTL_LPE 0x00000020 /* long packet enable */ +#define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */ +#define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */ +#define E1000_RCTL_LBM_SLP 0x00000080 /* serial link loopback mode */ +#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */ +#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min threshold size */ +#define E1000_RCTL_RDMTS_QUAT 0x00000100 /* rx desc min threshold size */ +#define E1000_RCTL_RDMTS_EIGTH 0x00000200 /* rx desc min threshold size */ +#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */ +#define E1000_RCTL_MO_0 0x00000000 /* multicast offset 11:0 */ +#define E1000_RCTL_MO_1 0x00001000 /* multicast offset 12:1 */ +#define E1000_RCTL_MO_2 0x00002000 /* multicast offset 13:2 */ +#define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */ +#define E1000_RCTL_MDR 0x00004000 /* multicast desc ring 0 */ +#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */ +/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */ +#define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */ +#define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */ +#define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */ +#define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */ +/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */ +#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */ +#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */ +#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */ +#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */ +#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */ +#define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */ +#define E1000_RCTL_DPF 0x00400000 /* discard pause frames */ +#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */ +#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ + +/* Receive Descriptor */ +#define E1000_RDT_DELAY 0x0000ffff /* Delay timer (1=1024us) */ +#define E1000_RDT_FPDB 0x80000000 /* Flush descriptor block */ +#define E1000_RDLEN_LEN 0x0007ff80 /* descriptor length */ +#define E1000_RDH_RDH 0x0000ffff /* receive descriptor head */ +#define E1000_RDT_RDT 0x0000ffff /* receive descriptor tail */ + +/* Flow Control */ +#define E1000_FCRTH_RTH 0x0000FFF8 /* Mask Bits[15:3] for RTH */ +#define E1000_FCRTH_XFCE 0x80000000 /* External Flow Control Enable */ +#define E1000_FCRTL_RTL 0x0000FFF8 /* Mask Bits[15:3] for RTL */ +#define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */ + +/* Receive Descriptor Control */ +#define E1000_RXDCTL_PTHRESH 0x0000003F /* RXDCTL Prefetch Threshold */ +#define E1000_RXDCTL_HTHRESH 0x00003F00 /* RXDCTL Host Threshold */ +#define E1000_RXDCTL_WTHRESH 0x003F0000 /* RXDCTL Writeback Threshold */ +#define E1000_RXDCTL_GRAN 0x01000000 /* RXDCTL Granularity */ + +/* Transmit Descriptor Control */ +#define E1000_TXDCTL_PTHRESH 0x000000FF /* TXDCTL Prefetch Threshold */ +#define E1000_TXDCTL_HTHRESH 0x0000FF00 /* TXDCTL Host Threshold */ +#define E1000_TXDCTL_WTHRESH 0x00FF0000 /* TXDCTL Writeback Threshold */ +#define E1000_TXDCTL_GRAN 0x01000000 /* TXDCTL Granularity */ +#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */ + +/* Transmit Configuration Word */ +#define E1000_TXCW_FD 0x00000020 /* TXCW full duplex */ +#define E1000_TXCW_HD 0x00000040 /* TXCW half duplex */ +#define E1000_TXCW_PAUSE 0x00000080 /* TXCW sym pause request */ +#define E1000_TXCW_ASM_DIR 0x00000100 /* TXCW astm pause direction */ +#define E1000_TXCW_PAUSE_MASK 0x00000180 /* TXCW pause request mask */ +#define E1000_TXCW_RF 0x00003000 /* TXCW remote fault */ +#define E1000_TXCW_NP 0x00008000 /* TXCW next page */ +#define E1000_TXCW_CW 0x0000ffff /* TxConfigWord mask */ +#define E1000_TXCW_TXC 0x40000000 /* Transmit Config control */ +#define E1000_TXCW_ANE 0x80000000 /* Auto-neg enable */ + +/* Receive Configuration Word */ +#define E1000_RXCW_CW 0x0000ffff /* RxConfigWord mask */ +#define E1000_RXCW_NC 0x04000000 /* Receive config no carrier */ +#define E1000_RXCW_IV 0x08000000 /* Receive config invalid */ +#define E1000_RXCW_CC 0x10000000 /* Receive config change */ +#define E1000_RXCW_C 0x20000000 /* Receive config */ +#define E1000_RXCW_SYNCH 0x40000000 /* Receive config synch */ +#define E1000_RXCW_ANC 0x80000000 /* Auto-neg complete */ + +/* Transmit Control */ +#define E1000_TCTL_RST 0x00000001 /* software reset */ +#define E1000_TCTL_EN 0x00000002 /* enable tx */ +#define E1000_TCTL_BCE 0x00000004 /* busy check enable */ +#define E1000_TCTL_PSP 0x00000008 /* pad short packets */ +#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */ +#define E1000_TCTL_COLD 0x003ff000 /* collision distance */ +#define E1000_TCTL_SWXOFF 0x00400000 /* SW Xoff transmission */ +#define E1000_TCTL_PBE 0x00800000 /* Packet Burst Enable */ +#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */ +#define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */ + +/* Receive Checksum Control */ +#define E1000_RXCSUM_PCSS_MASK 0x000000FF /* Packet Checksum Start */ +#define E1000_RXCSUM_IPOFL 0x00000100 /* IPv4 checksum offload */ +#define E1000_RXCSUM_TUOFL 0x00000200 /* TCP / UDP checksum offload */ +#define E1000_RXCSUM_IPV6OFL 0x00000400 /* IPv6 checksum offload */ + +/* Definitions for power management and wakeup registers */ +/* Wake Up Control */ +#define E1000_WUC_APME 0x00000001 /* APM Enable */ +#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */ +#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */ +#define E1000_WUC_APMPME 0x00000008 /* Assert PME on APM Wakeup */ + +/* Wake Up Filter Control */ +#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ +#define E1000_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */ +#define E1000_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */ +#define E1000_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */ +#define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */ +#define E1000_WUFC_ARP 0x00000020 /* ARP Request Packet Wakeup Enable */ +#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */ +#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */ +#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */ +#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */ +#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */ +#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */ +#define E1000_WUFC_ALL_FILTERS 0x000F00FF /* Mask for all wakeup filters */ +#define E1000_WUFC_FLX_OFFSET 16 /* Offset to the Flexible Filters bits */ +#define E1000_WUFC_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */ + +/* Wake Up Status */ +#define E1000_WUS_LNKC 0x00000001 /* Link Status Changed */ +#define E1000_WUS_MAG 0x00000002 /* Magic Packet Received */ +#define E1000_WUS_EX 0x00000004 /* Directed Exact Received */ +#define E1000_WUS_MC 0x00000008 /* Directed Multicast Received */ +#define E1000_WUS_BC 0x00000010 /* Broadcast Received */ +#define E1000_WUS_ARP 0x00000020 /* ARP Request Packet Received */ +#define E1000_WUS_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Received */ +#define E1000_WUS_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Received */ +#define E1000_WUS_FLX0 0x00010000 /* Flexible Filter 0 Match */ +#define E1000_WUS_FLX1 0x00020000 /* Flexible Filter 1 Match */ +#define E1000_WUS_FLX2 0x00040000 /* Flexible Filter 2 Match */ +#define E1000_WUS_FLX3 0x00080000 /* Flexible Filter 3 Match */ +#define E1000_WUS_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */ + +/* Management Control */ +#define E1000_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */ +#define E1000_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */ +#define E1000_MANC_R_ON_FORCE 0x00000004 /* Reset on Force TCO - RO */ +#define E1000_MANC_RMCP_EN 0x00000100 /* Enable RCMP 026Fh Filtering */ +#define E1000_MANC_0298_EN 0x00000200 /* Enable RCMP 0298h Filtering */ +#define E1000_MANC_IPV4_EN 0x00000400 /* Enable IPv4 */ +#define E1000_MANC_IPV6_EN 0x00000800 /* Enable IPv6 */ +#define E1000_MANC_SNAP_EN 0x00001000 /* Accept LLC/SNAP */ +#define E1000_MANC_ARP_EN 0x00002000 /* Enable ARP Request Filtering */ +#define E1000_MANC_NEIGHBOR_EN 0x00004000 /* Enable Neighbor Discovery + * Filtering */ +#define E1000_MANC_TCO_RESET 0x00010000 /* TCO Reset Occurred */ +#define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */ +#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */ +#define E1000_MANC_SMB_REQ 0x01000000 /* SMBus Request */ +#define E1000_MANC_SMB_GNT 0x02000000 /* SMBus Grant */ +#define E1000_MANC_SMB_CLK_IN 0x04000000 /* SMBus Clock In */ +#define E1000_MANC_SMB_DATA_IN 0x08000000 /* SMBus Data In */ +#define E1000_MANC_SMB_DATA_OUT 0x10000000 /* SMBus Data Out */ +#define E1000_MANC_SMB_CLK_OUT 0x20000000 /* SMBus Clock Out */ + +#define E1000_MANC_SMB_DATA_OUT_SHIFT 28 /* SMBus Data Out Shift */ +#define E1000_MANC_SMB_CLK_OUT_SHIFT 29 /* SMBus Clock Out Shift */ + +/* Wake Up Packet Length */ +#define E1000_WUPL_LENGTH_MASK 0x0FFF /* Only the lower 12 bits are valid */ + +#define E1000_MDALIGN 4096 + +/* EEPROM Commands */ +#define EEPROM_READ_OPCODE 0x6 /* EERPOM read opcode */ +#define EEPROM_WRITE_OPCODE 0x5 /* EERPOM write opcode */ +#define EEPROM_ERASE_OPCODE 0x7 /* EERPOM erase opcode */ +#define EEPROM_EWEN_OPCODE 0x13 /* EERPOM erase/write enable */ +#define EEPROM_EWDS_OPCODE 0x10 /* EERPOM erast/write disable */ + +/* EEPROM Word Offsets */ +#define EEPROM_INIT_CONTROL1_REG 0x000A +#define EEPROM_INIT_CONTROL2_REG 0x000F +#define EEPROM_FLASH_VERSION 0x0032 +#define EEPROM_CHECKSUM_REG 0x003F + +/* Mask bits for fields in Word 0x0a of the EEPROM */ +#define EEPROM_WORD0A_ILOS 0x0010 +#define EEPROM_WORD0A_SWDPIO 0x01E0 +#define EEPROM_WORD0A_LRST 0x0200 +#define EEPROM_WORD0A_FD 0x0400 +#define EEPROM_WORD0A_66MHZ 0x0800 + +/* Mask bits for fields in Word 0x0f of the EEPROM */ +#define EEPROM_WORD0F_PAUSE_MASK 0x3000 +#define EEPROM_WORD0F_PAUSE 0x1000 +#define EEPROM_WORD0F_ASM_DIR 0x2000 +#define EEPROM_WORD0F_ANE 0x0800 +#define EEPROM_WORD0F_SWPDIO_EXT 0x00F0 + +/* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */ +#define EEPROM_SUM 0xBABA + +/* EEPROM Map defines (WORD OFFSETS)*/ +#define EEPROM_NODE_ADDRESS_BYTE_0 0 +#define EEPROM_PBA_BYTE_1 8 + +/* EEPROM Map Sizes (Byte Counts) */ +#define PBA_SIZE 4 + +/* Collision related configuration parameters */ +#define E1000_COLLISION_THRESHOLD 16 +#define E1000_CT_SHIFT 4 +#define E1000_FDX_COLLISION_DISTANCE 64 +#define E1000_HDX_COLLISION_DISTANCE 64 +#define E1000_GB_HDX_COLLISION_DISTANCE 512 +#define E1000_COLD_SHIFT 12 + +/* The number of Transmit and Receive Descriptors must be a multiple of 8 */ +#define REQ_TX_DESCRIPTOR_MULTIPLE 8 +#define REQ_RX_DESCRIPTOR_MULTIPLE 8 + +/* Default values for the transmit IPG register */ +#define DEFAULT_82542_TIPG_IPGT 10 +#define DEFAULT_82543_TIPG_IPGT_FIBER 9 +#define DEFAULT_82543_TIPG_IPGT_COPPER 8 + +#define E1000_TIPG_IPGT_MASK 0x000003FF +#define E1000_TIPG_IPGR1_MASK 0x000FFC00 +#define E1000_TIPG_IPGR2_MASK 0x3FF00000 + +#define DEFAULT_82542_TIPG_IPGR1 2 +#define DEFAULT_82543_TIPG_IPGR1 8 +#define E1000_TIPG_IPGR1_SHIFT 10 + +#define DEFAULT_82542_TIPG_IPGR2 10 +#define DEFAULT_82543_TIPG_IPGR2 6 +#define E1000_TIPG_IPGR2_SHIFT 20 + +#define E1000_TXDMAC_DPP 0x00000001 + +/* PBA constants */ +#define E1000_PBA_16K 0x0010 /* 16KB, default TX allocation */ +#define E1000_PBA_24K 0x0018 +#define E1000_PBA_40K 0x0028 +#define E1000_PBA_48K 0x0030 /* 48KB, default RX allocation */ + +/* Flow Control Constants */ +#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001 +#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100 +#define FLOW_CONTROL_TYPE 0x8808 + +/* The historical defaults for the flow control values are given below. */ +#define FC_DEFAULT_HI_THRESH (0x8000) /* 32KB */ +#define FC_DEFAULT_LO_THRESH (0x4000) /* 16KB */ +#define FC_DEFAULT_TX_TIMER (0x100) /* ~130 us */ + + +/* The number of bits that we need to shift right to move the "pause" + * bits from the EEPROM (bits 13:12) to the "pause" (bits 8:7) field + * in the TXCW register + */ +#define PAUSE_SHIFT 5 + +/* The number of bits that we need to shift left to move the "SWDPIO" + * bits from the EEPROM (bits 8:5) to the "SWDPIO" (bits 25:22) field + * in the CTRL register + */ +#define SWDPIO_SHIFT 17 + +/* The number of bits that we need to shift left to move the "SWDPIO_EXT" + * bits from the EEPROM word F (bits 7:4) to the bits 11:8 of The + * Extended CTRL register. + * in the CTRL register + */ +#define SWDPIO__EXT_SHIFT 4 + +/* The number of bits that we need to shift left to move the "ILOS" + * bit from the EEPROM (bit 4) to the "ILOS" (bit 7) field + * in the CTRL register + */ +#define ILOS_SHIFT 3 + + +#define RECEIVE_BUFFER_ALIGN_SIZE (256) + +/* The number of milliseconds we wait for auto-negotiation to complete */ +#define LINK_UP_TIMEOUT 500 + +#define E1000_TX_BUFFER_SIZE ((uint32_t)1514) + +/* The carrier extension symbol, as received by the NIC. */ +#define CARRIER_EXTENSION 0x0F + +/* TBI_ACCEPT macro definition: + * + * If Tbi Compatibility mode is turned-on, then we should accept frames with + * receive errors if and only if: + * 1) errors is equal to the CRC error bit. + * 2) The last byte is a Carrier extension (0x0F). + * 3) The frame length (as reported by Hardware) is greater than 64 (60 + * if a VLAN tag was stripped from the frame. + * 4) " " " " " " " <= max_frame_size+1. + * + * This macro requires: + * adapter = a pointer to struct e1000_shared_adapter + * special = the 16 bit special field of the RX descriptor with EOP set + * error = the 8 bit error field of the RX descriptor with EOP set + * length = the sum of all the length fields of the RX descriptors that + * make up the current frame + * last_byte = the last byte of the frame DMAed by the hardware + * max_frame_length = the maximum frame length we want to accept. + * min_frame_length = the minimum frame length we want to accept. + * + * This macro is a conditional that should be used in the interrupt + * handler's Rx processing routine when RxErrors have been detected. + * + * Typical use: + * ... + * if (TBI_ACCEPT) { + * accept_frame = TRUE; + * e1000_tbi_adjust_stats(adapter, MacAddress); + * frame_length--; + * } else { + * accept_frame = FALSE; + * } + * ... + */ + +#define TBI_ACCEPT(adapter, special, errors, length, last_byte) \ + ((adapter)->tbi_compatibility_on && \ + (((errors) & E1000_RXD_ERR_FRAME_ERR_MASK) == E1000_RXD_ERR_CE) && \ + ((last_byte) == CARRIER_EXTENSION) && \ + ((length) <= ((adapter)->max_frame_size + 1)) && \ + ((length) > ((special == 0x0000) ? \ + ((adapter)->min_frame_size) : \ + ((adapter)->min_frame_size - VLAN_TAG_SIZE)))) + + +#endif /* _E1000_MAC_H_ */ diff -Nru a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/e1000/e1000_main.c Tue Feb 26 11:58:00 2002 @@ -0,0 +1,2036 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#define __E1000_MAIN__ +#include "e1000.h" + +char e1000_driver_name[] = "e1000"; + +char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; + +char e1000_driver_version[] = "4.2.4-k1"; + +char e1000_copyright[] = "Copyright (c) 1999-2002 Intel Corporation."; + +/* e1000_pci_tbl - PCI Device ID Table + * + * Private driver_data field (last one) stores an index into e1000_strings + * Wildcard entries (PCI_ANY_ID) should come last + * Last entry must be all 0s + * + * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, + * Class, Class Mask, String Index } + */ +static struct pci_device_id e1000_pci_tbl[] __devinitdata = { + /* Intel(R) PRO/1000 Network Connection */ + {0x8086, 0x1000, 0x8086, 0x1000, 0, 0, 0}, + {0x8086, 0x1001, 0x8086, 0x1003, 0, 0, 0}, + {0x8086, 0x1004, 0x8086, 0x1004, 0, 0, 0}, + {0x8086, 0x1008, 0x8086, 0x1107, 0, 0, 0}, + {0x8086, 0x1009, 0x8086, 0x1109, 0, 0, 0}, + {0x8086, 0x100C, 0x8086, 0x1112, 0, 0, 0}, + /* Compaq Gigabit Ethernet Server Adapter */ + {0x8086, 0x1000, 0x0E11, PCI_ANY_ID, 0, 0, 1}, + {0x8086, 0x1001, 0x0E11, PCI_ANY_ID, 0, 0, 1}, + {0x8086, 0x1004, 0x0E11, PCI_ANY_ID, 0, 0, 1}, + /* IBM Mobile, Desktop & Server Adapters */ + {0x8086, 0x1000, 0x1014, PCI_ANY_ID, 0, 0, 2}, + {0x8086, 0x1001, 0x1014, PCI_ANY_ID, 0, 0, 2}, + {0x8086, 0x1004, 0x1014, PCI_ANY_ID, 0, 0, 2}, + /* Generic */ + {0x8086, 0x1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x1008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x1009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x100C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x100D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + /* required last entry */ + {0,} +}; + +MODULE_DEVICE_TABLE(pci, e1000_pci_tbl); + +static char *e1000_strings[] = { + "Intel(R) PRO/1000 Network Connection", + "Compaq Gigabit Ethernet Server Adapter", + "IBM Mobile, Desktop & Server Adapters" +}; + +/* Local Function Prototypes */ + +int e1000_up(struct e1000_adapter *adapter); +void e1000_down(struct e1000_adapter *adapter); +static int e1000_init_module(void); +static void e1000_exit_module(void); +static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent); +static void e1000_remove(struct pci_dev *pdev); +static void e1000_sw_init(struct e1000_adapter *adapter); +static int e1000_open(struct net_device *netdev); +static int e1000_close(struct net_device *netdev); +static int e1000_setup_tx_resources(struct e1000_adapter *adapter); +static int e1000_setup_rx_resources(struct e1000_adapter *adapter); +static void e1000_configure_tx(struct e1000_adapter *adapter); +static void e1000_configure_rx(struct e1000_adapter *adapter); +static void e1000_setup_rctl(struct e1000_adapter *adapter); +static void e1000_clean_tx_ring(struct e1000_adapter *adapter); +static void e1000_clean_rx_ring(struct e1000_adapter *adapter); +static void e1000_free_tx_resources(struct e1000_adapter *adapter); +static void e1000_free_rx_resources(struct e1000_adapter *adapter); +static void e1000_set_multi(struct net_device *netdev); +static void e1000_update_phy_info(unsigned long data); +static void e1000_watchdog(unsigned long data); +static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev); +static void e1000_tx_timeout(struct net_device *dev); +static struct net_device_stats * e1000_get_stats(struct net_device *netdev); +static int e1000_change_mtu(struct net_device *netdev, int new_mtu); +static int e1000_set_mac(struct net_device *netdev, void *p); +static void e1000_update_stats(struct e1000_adapter *adapter); +static inline void e1000_irq_disable(struct e1000_adapter *adapter); +static inline void e1000_irq_enable(struct e1000_adapter *adapter); +static void e1000_intr(int irq, void *data, struct pt_regs *regs); +static void e1000_clean_tx_irq(struct e1000_adapter *adapter); +static void e1000_clean_rx_irq(struct e1000_adapter *adapter); +static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter); +static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); +static void e1000_reset(struct e1000_adapter *adapter); +static void e1000_enter_82542_rst(struct e1000_adapter *adapter); +static void e1000_leave_82542_rst(struct e1000_adapter *adapter); +static inline void e1000_rx_checksum(struct e1000_adapter *adapter, + struct e1000_rx_desc *rx_desc, + struct sk_buff *skb); +void e1000_enable_WOL(struct e1000_adapter *adapter); + +/* Exported from other modules */ + +extern void e1000_check_options(struct e1000_adapter *adapter); +extern void e1000_proc_dev_setup(struct e1000_adapter *adapter); +extern void e1000_proc_dev_free(struct e1000_adapter *adapter); +extern int e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr); + +static struct pci_driver e1000_driver = { + name: e1000_driver_name, + id_table: e1000_pci_tbl, + probe: e1000_probe, + remove: e1000_remove, + /* Power Managment Hooks */ + suspend: NULL, + resume: NULL +}; + +MODULE_AUTHOR("Intel Corporation, "); +MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver"); +MODULE_LICENSE("Dual BSD/GPL"); + +#ifdef EXPORT_SYMTAB +EXPORT_SYMBOL(e1000_init_module); +EXPORT_SYMBOL(e1000_exit_module); +EXPORT_SYMBOL(e1000_probe); +EXPORT_SYMBOL(e1000_remove); +EXPORT_SYMBOL(e1000_open); +EXPORT_SYMBOL(e1000_close); +EXPORT_SYMBOL(e1000_xmit_frame); +EXPORT_SYMBOL(e1000_intr); +EXPORT_SYMBOL(e1000_set_multi); +EXPORT_SYMBOL(e1000_change_mtu); +EXPORT_SYMBOL(e1000_set_mac); +EXPORT_SYMBOL(e1000_get_stats); +EXPORT_SYMBOL(e1000_watchdog); +EXPORT_SYMBOL(e1000_ioctl); +#endif + +/** + * e1000_init_module - Driver Registration Routine + * + * e1000_init_module is the first routine called when the driver is + * loaded. All it does is register with the PCI subsystem. + **/ + +static int __init +e1000_init_module(void) +{ + printk(KERN_INFO "%s - version %s\n", + e1000_driver_string, e1000_driver_version); + + printk(KERN_INFO "%s\n", e1000_copyright); + + return pci_module_init(&e1000_driver); +} + +module_init(e1000_init_module); + +/** + * e1000_exit_module - Driver Exit Cleanup Routine + * + * e1000_exit_module is called just before the driver is removed + * from memory. + **/ + +static void __exit +e1000_exit_module(void) +{ + pci_unregister_driver(&e1000_driver); + + return; +} + +module_exit(e1000_exit_module); + + +int +e1000_up(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + + if(request_irq(netdev->irq, &e1000_intr, SA_SHIRQ, + netdev->name, netdev)) + return -1; + + /* hardware has been reset, we need to reload some things */ + + e1000_set_multi(netdev); + + e1000_configure_tx(adapter); + e1000_setup_rctl(adapter); + e1000_configure_rx(adapter); + e1000_alloc_rx_buffers(adapter); + + e1000_clear_hw_cntrs(&adapter->shared); + + mod_timer(&adapter->watchdog_timer, jiffies); + e1000_irq_enable(adapter); + + return 0; +} + +void +e1000_down(struct e1000_adapter *adapter) +{ + struct e1000_shared_adapter *shared = &adapter->shared; + struct net_device *netdev = adapter->netdev; + + e1000_irq_disable(adapter); + free_irq(netdev->irq, netdev); + del_timer_sync(&adapter->watchdog_timer); + del_timer_sync(&adapter->phy_info_timer); + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + /* disable the transmit and receive units */ + + E1000_WRITE_REG(shared, RCTL, 0); + E1000_WRITE_REG(shared, TCTL, E1000_TCTL_PSP); + + /* delay to allow PCI transactions to complete */ + + msec_delay(10); + + e1000_clean_tx_ring(adapter); + e1000_clean_rx_ring(adapter); + + e1000_reset(adapter); +} + +static void +e1000_reset(struct e1000_adapter *adapter) +{ + struct e1000_shared_adapter *shared = &adapter->shared; + uint32_t ctrl_ext; + + /* Repartition Pba for greater than 9k mtu + * To take effect CTRL.RST is required. + */ + + if(adapter->rx_buffer_len > E1000_RXBUFFER_8192) + E1000_WRITE_REG(shared, PBA, E1000_JUMBO_PBA); + else + E1000_WRITE_REG(shared, PBA, E1000_DEFAULT_PBA); + + /* 82542 2.0 needs MWI disabled while issuing a reset */ + + if(shared->mac_type == e1000_82542_rev2_0) + e1000_enter_82542_rst(adapter); + + /* global reset */ + + E1000_WRITE_REG(shared, CTRL, E1000_CTRL_RST); + msec_delay(10); + + /* EEPROM reload */ + + ctrl_ext = E1000_READ_REG(shared, CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_EE_RST; + E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext); + msec_delay(5); + + if(shared->mac_type == e1000_82542_rev2_0) + e1000_leave_82542_rst(adapter); + + shared->tbi_compatibility_on = FALSE; + shared->fc = shared->original_fc; + + e1000_init_hw(shared); + + e1000_enable_WOL(adapter); + + return; +} + +/** + * e1000_probe - Device Initialization Routine + * @pdev: PCI device information struct + * @ent: entry in e1000_pci_tbl + * + * Returns 0 on success, negative on failure + * + * e1000_probe initializes an adapter identified by a pci_dev structure. + * The OS initialization, configuring of the adapter private structure, + * and a hardware reset occur. + **/ + +static int __devinit +e1000_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *netdev; + struct e1000_adapter *adapter; + static int cards_found = 0; + unsigned long mmio_start; + int mmio_len; + int i; + + if((i = pci_enable_device(pdev))) + return i; + + if((i = pci_set_dma_mask(pdev, E1000_DMA_MASK))) + return i; + + if((i = pci_request_regions(pdev, e1000_driver_name))) + return i; + + pci_set_master(pdev); + + netdev = alloc_etherdev(sizeof(struct e1000_adapter)); + if(!netdev) + goto err_alloc_etherdev; + + SET_MODULE_OWNER(netdev); + + pci_set_drvdata(pdev, netdev); + adapter = netdev->priv; + adapter->netdev = netdev; + adapter->pdev = pdev; + adapter->shared.back = adapter; + + mmio_start = pci_resource_start(pdev, BAR_0); + mmio_len = pci_resource_len(pdev, BAR_0); + + adapter->shared.hw_addr = ioremap(mmio_start, mmio_len); + if(!adapter->shared.hw_addr) + goto err_ioremap; + + netdev->open = &e1000_open; + netdev->stop = &e1000_close; + netdev->hard_start_xmit = &e1000_xmit_frame; + netdev->get_stats = &e1000_get_stats; + netdev->set_multicast_list = &e1000_set_multi; + netdev->set_mac_address = &e1000_set_mac; + netdev->change_mtu = &e1000_change_mtu; + netdev->do_ioctl = &e1000_ioctl; + netdev->tx_timeout = &e1000_tx_timeout; + netdev->watchdog_timeo = HZ; + + netdev->irq = pdev->irq; + netdev->base_addr = mmio_start; + + adapter->bd_number = cards_found; + adapter->id_string = e1000_strings[ent->driver_data]; + + /* setup the private structure */ + + e1000_sw_init(adapter); + + if(adapter->shared.mac_type >= e1000_82543) { + netdev->features = NETIF_F_SG | + NETIF_F_IP_CSUM | + NETIF_F_HIGHDMA; + } else { + netdev->features = NETIF_F_SG | NETIF_F_HIGHDMA; + } + + /* make sure the EEPROM is good */ + + if(!e1000_validate_eeprom_checksum(&adapter->shared)) + goto err_eeprom; + + /* copy the MAC address out of the EEPROM */ + + e1000_read_mac_addr(&adapter->shared); + memcpy(netdev->dev_addr, adapter->shared.mac_addr, netdev->addr_len); + + if(!is_valid_ether_addr(netdev->dev_addr)) + goto err_eeprom; + + e1000_read_part_num(&adapter->shared, &(adapter->part_num)); + e1000_get_bus_info(&adapter->shared); + + init_timer(&adapter->watchdog_timer); + adapter->watchdog_timer.function = &e1000_watchdog; + adapter->watchdog_timer.data = (unsigned long) adapter; + + init_timer(&adapter->phy_info_timer); + adapter->phy_info_timer.function = &e1000_update_phy_info; + adapter->phy_info_timer.data = (unsigned long) adapter; + + register_netdev(netdev); + + /* we're going to reset, so assume we have no link for now */ + + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + printk(KERN_INFO "%s: %s\n", netdev->name, adapter->id_string); + e1000_check_options(adapter); + e1000_proc_dev_setup(adapter); + + /* reset the hardware with the new settings */ + + e1000_reset(adapter); + + cards_found++; + return 0; + +err_eeprom: + iounmap(adapter->shared.hw_addr); +err_ioremap: + pci_release_regions(pdev); + kfree(netdev); +err_alloc_etherdev: + return -ENOMEM; +} + +/** + * e1000_remove - Device Removal Routine + * @pdev: PCI device information struct + * + * e1000_remove is called by the PCI subsystem to alert the driver + * that it should release a PCI device. The could be caused by a + * Hot-Plug event, or because the driver is going to be removed from + * memory. + * + * This routine is also called to clean up from a failure in + * e1000_probe. The Adapter struct and netdev will always exist, + * all other pointers must be checked for NULL before freeing. + **/ + +static void __devexit +e1000_remove(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev->priv; + + unregister_netdev(netdev); + + e1000_phy_hw_reset(&adapter->shared); + + e1000_proc_dev_free(adapter); + + iounmap(adapter->shared.hw_addr); + pci_release_regions(pdev); + + kfree(netdev); + return; +} + +/** + * e1000_sw_init - Initialize general software structures (struct e1000_adapter) + * @adapter: board private structure to initialize + * + * e1000_sw_init initializes the Adapter private data structure. + * Fields are initialized based on PCI device information and + * OS network device settings (MTU size). + **/ + +static void __devinit +e1000_sw_init(struct e1000_adapter *adapter) +{ + struct e1000_shared_adapter *shared = &adapter->shared; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + + /* PCI config space info */ + + uint16_t *vendor = &shared->vendor_id; + uint16_t *device = &shared->device_id; + uint16_t *subvendor = &shared->subsystem_vendor_id; + uint16_t *subsystem = &shared->subsystem_id; + uint8_t *revision = &shared->revision_id; + + pci_read_config_word(pdev, PCI_VENDOR_ID, vendor); + pci_read_config_word(pdev, PCI_DEVICE_ID, device); + pci_read_config_byte(pdev, PCI_REVISION_ID, revision); + pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, subvendor); + pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, subsystem); + + pci_read_config_word(pdev, PCI_COMMAND, &shared->pci_cmd_word); + + adapter->rx_buffer_len = E1000_RXBUFFER_2048; + shared->max_frame_size = netdev->mtu + ENET_HEADER_SIZE + CRC_LENGTH; + shared->min_frame_size = MINIMUM_ETHERNET_PACKET_SIZE + CRC_LENGTH; + + /* identify the MAC */ + + switch (*device) { + case E1000_DEV_ID_82542: + switch (*revision) { + case E1000_82542_2_0_REV_ID: + shared->mac_type = e1000_82542_rev2_0; + break; + case E1000_82542_2_1_REV_ID: + shared->mac_type = e1000_82542_rev2_1; + break; + default: + shared->mac_type = e1000_82542_rev2_0; + E1000_ERR("Could not identify 82542 revision\n"); + } + break; + case E1000_DEV_ID_82543GC_FIBER: + case E1000_DEV_ID_82543GC_COPPER: + shared->mac_type = e1000_82543; + break; + case E1000_DEV_ID_82544EI_COPPER: + case E1000_DEV_ID_82544EI_FIBER: + case E1000_DEV_ID_82544GC_COPPER: + case E1000_DEV_ID_82544GC_LOM: + shared->mac_type = e1000_82544; + break; + default: + /* should never have loaded on this device */ + BUG(); + } + + /* flow control settings */ + + shared->fc_high_water = FC_DEFAULT_HI_THRESH; + shared->fc_low_water = FC_DEFAULT_LO_THRESH; + shared->fc_pause_time = FC_DEFAULT_TX_TIMER; + shared->fc_send_xon = 1; + + /* Media type - copper or fiber */ + + if(shared->mac_type >= e1000_82543) { + uint32_t status = E1000_READ_REG(shared, STATUS); + + if(status & E1000_STATUS_TBIMODE) + shared->media_type = e1000_media_type_fiber; + else + shared->media_type = e1000_media_type_copper; + } else { + shared->media_type = e1000_media_type_fiber; + } + + if(shared->mac_type < e1000_82543) + shared->report_tx_early = 0; + else + shared->report_tx_early = 1; + + shared->wait_autoneg_complete = FALSE; + shared->tbi_compatibility_en = TRUE; + + atomic_set(&adapter->irq_sem, 1); + spin_lock_init(&adapter->stats_lock); +} + +/** + * e1000_open - Called when a network interface is made active + * @netdev: network interface device structure + * + * Returns 0 on success, negative value on failure + * + * The open entry point is called when a network interface is made + * active by the system (IFF_UP). At this point all resources needed + * for transmit and receive operations are allocated, the interrupt + * handler is registered with the OS, the watchdog timer is started, + * and the stack is notified that the interface is ready. + **/ + +static int +e1000_open(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev->priv; + + /* allocate transmit descriptors */ + + if(e1000_setup_tx_resources(adapter)) + goto err_setup_tx; + + /* allocate receive descriptors */ + + if(e1000_setup_rx_resources(adapter)) + goto err_setup_rx; + + if(e1000_up(adapter)) + goto err_up; + + return 0; + +err_up: + e1000_free_rx_resources(adapter); +err_setup_rx: + e1000_free_tx_resources(adapter); +err_setup_tx: + e1000_reset(adapter); + + return -EBUSY; +} + +/** + * e1000_close - Disables a network interface + * @netdev: network interface device structure + * + * Returns 0, this is not allowed to fail + * + * The close entry point is called when an interface is de-activated + * by the OS. The hardware is still under the drivers control, but + * needs to be disabled. A global MAC reset is issued to stop the + * hardware, and all transmit and receive resources are freed. + **/ + +static int +e1000_close(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev->priv; + + e1000_down(adapter); + + e1000_free_tx_resources(adapter); + e1000_free_rx_resources(adapter); + + return 0; +} + +/** + * e1000_setup_tx_resources - allocate Tx resources (Descriptors) + * @adapter: board private structure + * + * Return 0 on success, negative on failure + * + * e1000_setup_tx_resources allocates all software transmit resources + * and enabled the Tx unit of the MAC. + **/ + +static int +e1000_setup_tx_resources(struct e1000_adapter *adapter) +{ + struct e1000_desc_ring *txdr = &adapter->tx_ring; + struct pci_dev *pdev = adapter->pdev; + int size; + + size = sizeof(struct e1000_buffer) * txdr->count; + txdr->buffer_info = kmalloc(size, GFP_KERNEL); + if(!txdr->buffer_info) { + return -ENOMEM; + } + memset(txdr->buffer_info, 0, size); + + /* round up to nearest 4K */ + + txdr->size = txdr->count * sizeof(struct e1000_tx_desc); + E1000_ROUNDUP(txdr->size, 4096); + + txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma); + if(!txdr->desc) { + kfree(txdr->buffer_info); + return -ENOMEM; + } + memset(txdr->desc, 0, txdr->size); + + atomic_set(&txdr->unused, txdr->count); + txdr->next_to_use = 0; + txdr->next_to_clean = 0; + + return 0; +} + +/** + * e1000_configure_tx - Configure 8254x Transmit Unit after Reset + * @adapter: board private structure + * + * Configure the Tx unit of the MAC after a reset. + **/ + +static void +e1000_configure_tx(struct e1000_adapter *adapter) +{ + uint64_t tdba = adapter->tx_ring.dma; + uint32_t tdlen = adapter->tx_ring.count * sizeof(struct e1000_tx_desc); + uint32_t tctl, tipg; + + E1000_WRITE_REG(&adapter->shared, TDBAL, (tdba & 0x00000000FFFFFFFF)); + E1000_WRITE_REG(&adapter->shared, TDBAH, (tdba >> 32)); + + E1000_WRITE_REG(&adapter->shared, TDLEN, tdlen); + + /* Setup the HW Tx Head and Tail descriptor pointers */ + + E1000_WRITE_REG(&adapter->shared, TDH, 0); + E1000_WRITE_REG(&adapter->shared, TDT, 0); + + /* Set the default values for the Tx Inter Packet Gap timer */ + + switch (adapter->shared.mac_type) { + case e1000_82542_rev2_0: + case e1000_82542_rev2_1: + tipg = DEFAULT_82542_TIPG_IPGT; + tipg |= DEFAULT_82542_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; + tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; + break; + default: + if(adapter->shared.media_type == e1000_media_type_fiber) + tipg = DEFAULT_82543_TIPG_IPGT_FIBER; + else + tipg = DEFAULT_82543_TIPG_IPGT_COPPER; + tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; + tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; + } + E1000_WRITE_REG(&adapter->shared, TIPG, tipg); + + /* Set the Tx Interrupt Delay register */ + + E1000_WRITE_REG(&adapter->shared, TIDV, adapter->tx_int_delay); + + /* Program the Transmit Control Register */ + + tctl = E1000_TCTL_PSP | E1000_TCTL_EN | + (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT); + + if(adapter->link_duplex == FULL_DUPLEX) { + tctl |= E1000_FDX_COLLISION_DISTANCE << E1000_COLD_SHIFT; + } else { + tctl |= E1000_HDX_COLLISION_DISTANCE << E1000_COLD_SHIFT; + } + + E1000_WRITE_REG(&adapter->shared, TCTL, tctl); + +#ifdef CONFIG_PPC + if(adapter->shared.mac_type >= e1000_82543) { + E1000_WRITE_REG(&adapter->shared, TXDCTL, 0x00020000); + } +#endif + + /* Setup Transmit Descriptor Settings for this adapter */ + adapter->txd_cmd = E1000_TXD_CMD_IFCS; + + if(adapter->tx_int_delay > 0) + adapter->txd_cmd |= E1000_TXD_CMD_IDE; + if(adapter->shared.report_tx_early == 1) + adapter->txd_cmd |= E1000_TXD_CMD_RS; + else + adapter->txd_cmd |= E1000_TXD_CMD_RPS; + + return; +} + +/** + * e1000_setup_rx_resources - allocate Rx resources (Descriptors, receive SKBs) + * @adapter: board private structure + * + * Returns 0 on success, negative on failure + * + * e1000_setup_rx_resources allocates all software receive resources + * and network buffers, and enables the Rx unit of the MAC. + **/ + +static int +e1000_setup_rx_resources(struct e1000_adapter *adapter) +{ + struct e1000_desc_ring *rxdr = &adapter->rx_ring; + struct pci_dev *pdev = adapter->pdev; + int size; + + size = sizeof(struct e1000_buffer) * rxdr->count; + rxdr->buffer_info = kmalloc(size, GFP_KERNEL); + if(!rxdr->buffer_info) { + return -ENOMEM; + } + memset(rxdr->buffer_info, 0, size); + + /* Round up to nearest 4K */ + + rxdr->size = rxdr->count * sizeof(struct e1000_rx_desc); + E1000_ROUNDUP(rxdr->size, 4096); + + rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); + + if(!rxdr->desc) { + kfree(rxdr->buffer_info); + return -ENOMEM; + } + memset(rxdr->desc, 0, rxdr->size); + + rxdr->next_to_clean = 0; + rxdr->unused_count = rxdr->count; + rxdr->next_to_use = 0; + + return 0; +} + +/** + * e1000_setup_rctl - configure the receive control register + * @adapter: Board private structure + **/ + +static void +e1000_setup_rctl(struct e1000_adapter *adapter) +{ + uint32_t rctl; + + /* Setup the Receive Control Register */ + rctl = E1000_RCTL_EN | E1000_RCTL_BAM | + E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | + (adapter->shared.mc_filter_type << E1000_RCTL_MO_SHIFT); + + if(adapter->shared.tbi_compatibility_on == 1) + rctl |= E1000_RCTL_SBP; + + switch (adapter->rx_buffer_len) { + case E1000_RXBUFFER_2048: + default: + rctl |= E1000_RCTL_SZ_2048; + break; + case E1000_RXBUFFER_4096: + rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX | E1000_RCTL_LPE; + break; + case E1000_RXBUFFER_8192: + rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX | E1000_RCTL_LPE; + break; + case E1000_RXBUFFER_16384: + rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX | E1000_RCTL_LPE; + break; + } + + E1000_WRITE_REG(&adapter->shared, RCTL, rctl); +} + +/** + * e1000_configure_rx - Configure 8254x Receive Unit after Reset + * @adapter: board private structure + * + * Configure the Rx unit of the MAC after a reset. + **/ + +static void +e1000_configure_rx(struct e1000_adapter *adapter) +{ + uint64_t rdba = adapter->rx_ring.dma; + uint32_t rdlen = adapter->rx_ring.count * sizeof(struct e1000_rx_desc); + uint32_t rctl; + uint32_t rxcsum; + + /* make sure receives are disabled while setting up the descriptors */ + + rctl = E1000_READ_REG(&adapter->shared, RCTL); + E1000_WRITE_REG(&adapter->shared, RCTL, rctl & ~E1000_RCTL_EN); + + /* set the Receive Delay Timer Register */ + + E1000_WRITE_REG(&adapter->shared, RDTR, + adapter->rx_int_delay | E1000_RDT_FPDB); + + /* Setup the Base and Length of the Rx Descriptor Ring */ + + E1000_WRITE_REG(&adapter->shared, RDBAL, (rdba & 0x00000000FFFFFFFF)); + E1000_WRITE_REG(&adapter->shared, RDBAH, (rdba >> 32)); + + E1000_WRITE_REG(&adapter->shared, RDLEN, rdlen); + + /* Setup the HW Rx Head and Tail Descriptor Pointers */ + E1000_WRITE_REG(&adapter->shared, RDH, 0); + E1000_WRITE_REG(&adapter->shared, RDT, 0); + + /* Enable 82543 Receive Checksum Offload for TCP and UDP */ + if((adapter->shared.mac_type >= e1000_82543) && + (adapter->rx_csum == TRUE)) { + rxcsum = E1000_READ_REG(&adapter->shared, RXCSUM); + rxcsum |= E1000_RXCSUM_TUOFL; + E1000_WRITE_REG(&adapter->shared, RXCSUM, rxcsum); + } + +#ifdef CONFIG_PPC + if(adapter->shared.mac_type >= e1000_82543) { + E1000_WRITE_REG(&adapter->shared, RXDCTL, 0x00020000); + } +#endif + + /* Enable Receives */ + + E1000_WRITE_REG(&adapter->shared, RCTL, rctl); + + return; +} + +/** + * e1000_free_tx_resources - Free Tx Resources + * @adapter: board private structure + * + * Free all transmit software resources + **/ + +static void +e1000_free_tx_resources(struct e1000_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + + e1000_clean_tx_ring(adapter); + + kfree(adapter->tx_ring.buffer_info); + adapter->tx_ring.buffer_info = NULL; + + pci_free_consistent(pdev, adapter->tx_ring.size, + adapter->tx_ring.desc, adapter->tx_ring.dma); + + adapter->tx_ring.desc = NULL; + + return; +} + +/** + * e1000_clean_tx_ring - Free Tx Buffers + * @adapter: board private structure + **/ + +static void +e1000_clean_tx_ring(struct e1000_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + unsigned long size; + int i; + + /* Free all the Tx ring sk_buffs */ + + for(i = 0; i < adapter->tx_ring.count; i++) { + if(adapter->tx_ring.buffer_info[i].skb) { + + pci_unmap_page(pdev, + adapter->tx_ring.buffer_info[i].dma, + adapter->tx_ring.buffer_info[i].length, + PCI_DMA_TODEVICE); + + dev_kfree_skb(adapter->tx_ring.buffer_info[i].skb); + + adapter->tx_ring.buffer_info[i].skb = NULL; + } + } + + size = sizeof(struct e1000_buffer) * adapter->tx_ring.count; + memset(adapter->tx_ring.buffer_info, 0, size); + + /* Zero out the descriptor ring */ + + memset(adapter->tx_ring.desc, 0, adapter->tx_ring.size); + + atomic_set(&adapter->tx_ring.unused, adapter->tx_ring.count); + adapter->tx_ring.next_to_use = 0; + adapter->tx_ring.next_to_clean = 0; + + E1000_WRITE_REG(&adapter->shared, TDH, 0); + E1000_WRITE_REG(&adapter->shared, TDT, 0); + + return; +} + +/** + * e1000_free_rx_resources - Free Rx Resources + * @adapter: board private structure + * + * Free all receive software resources + **/ + +static void +e1000_free_rx_resources(struct e1000_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + + e1000_clean_rx_ring(adapter); + + kfree(adapter->rx_ring.buffer_info); + adapter->rx_ring.buffer_info = NULL; + + pci_free_consistent(pdev, adapter->rx_ring.size, + adapter->rx_ring.desc, adapter->rx_ring.dma); + + adapter->rx_ring.desc = NULL; + + return; +} + +/** + * e1000_clean_rx_ring - Free Rx Buffers + * @adapter: board private structure + **/ + +static void +e1000_clean_rx_ring(struct e1000_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + unsigned long size; + int i; + + /* Free all the Rx ring sk_buffs */ + + for(i = 0; i < adapter->rx_ring.count; i++) { + if(adapter->rx_ring.buffer_info[i].skb) { + + pci_unmap_single(pdev, + adapter->rx_ring.buffer_info[i].dma, + adapter->rx_ring.buffer_info[i].length, + PCI_DMA_FROMDEVICE); + + dev_kfree_skb(adapter->rx_ring.buffer_info[i].skb); + + adapter->rx_ring.buffer_info[i].skb = NULL; + } + } + + size = sizeof(struct e1000_buffer) * adapter->rx_ring.count; + memset(adapter->rx_ring.buffer_info, 0, size); + + /* Zero out the descriptor ring */ + + memset(adapter->rx_ring.desc, 0, adapter->rx_ring.size); + + adapter->rx_ring.unused_count = adapter->rx_ring.count; + adapter->rx_ring.next_to_clean = 0; + adapter->rx_ring.next_to_use = 0; + + E1000_WRITE_REG(&adapter->shared, RDH, 0); + E1000_WRITE_REG(&adapter->shared, RDT, 0); + + return; +} + +/* The 82542 2.0 (revision 2) needs to have the receive unit in reset + * and memory write and invalidate disabled for certain operations + */ +static void +e1000_enter_82542_rst(struct e1000_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + struct net_device *netdev = adapter->netdev; + uint16_t pci_command_word = adapter->shared.pci_cmd_word; + uint32_t rctl; + + if(pci_command_word & PCI_COMMAND_INVALIDATE) { + pci_command_word &= ~PCI_COMMAND_INVALIDATE; + pci_write_config_word(pdev, PCI_COMMAND, pci_command_word); + } + + rctl = E1000_READ_REG(&adapter->shared, RCTL); + rctl |= E1000_RCTL_RST; + E1000_WRITE_REG(&adapter->shared, RCTL, rctl); + msec_delay(5); + + if(netif_running(netdev)) + e1000_clean_rx_ring(adapter); + return; +} + +static void +e1000_leave_82542_rst(struct e1000_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + struct net_device *netdev = adapter->netdev; + uint16_t pci_command_word = adapter->shared.pci_cmd_word; + uint32_t rctl; + + rctl = E1000_READ_REG(&adapter->shared, RCTL); + rctl &= ~E1000_RCTL_RST; + E1000_WRITE_REG(&adapter->shared, RCTL, rctl); + msec_delay(5); + + if(pci_command_word & PCI_COMMAND_INVALIDATE) + pci_write_config_word(pdev, PCI_COMMAND, pci_command_word); + + if(netif_running(netdev)) { + e1000_configure_rx(adapter); + e1000_alloc_rx_buffers(adapter); + } + return; +} + +/** + * e1000_set_mac - Change the Ethernet Address of the NIC + * @netdev: network interface device structure + * @p: pointer to an address structure + * + * Returns 0 on success, negative on failure + **/ + +static int +e1000_set_mac(struct net_device *netdev, void *p) +{ + struct e1000_adapter *adapter = netdev->priv; + struct sockaddr *addr = p; + + /* 82542 2.0 needs to be in reset to write receive address registers */ + + if(adapter->shared.mac_type == e1000_82542_rev2_0) + e1000_enter_82542_rst(adapter); + + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + memcpy(adapter->shared.mac_addr, addr->sa_data, netdev->addr_len); + + e1000_rar_set(&adapter->shared, adapter->shared.mac_addr, 0); + + if(adapter->shared.mac_type == e1000_82542_rev2_0) + e1000_leave_82542_rst(adapter); + + return 0; +} + +/** + * e1000_set_multi - Multicast and Promiscuous mode set + * @netdev: network interface device structure + * + * The set_multi entry point is called whenever the multicast address + * list or the network interface flags are updated. This routine is + * resposible for configuring the hardware for proper multicast, + * promiscuous mode, and all-multi behavior. + **/ + +static void +e1000_set_multi(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev->priv; + struct e1000_shared_adapter *shared = &adapter->shared; + struct dev_mc_list *mc_ptr; + uint32_t rctl; + uint32_t hash_value; + int i; + + /* Check for Promiscuous and All Multicast modes */ + + rctl = E1000_READ_REG(shared, RCTL); + + if(netdev->flags & IFF_PROMISC) { + rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); + } else if(netdev->flags & IFF_ALLMULTI) { + rctl |= E1000_RCTL_MPE; + rctl &= ~E1000_RCTL_UPE; + } else { + rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE); + } + + E1000_WRITE_REG(shared, RCTL, rctl); + + /* 82542 2.0 needs to be in reset to write receive address registers */ + + if(shared->mac_type == e1000_82542_rev2_0) + e1000_enter_82542_rst(adapter); + + /* load the first 15 multicast address into the exact filters 1-15 + * RAR 0 is used for the station MAC adddress + * if there are not 15 addresses, go ahead and clear the filters + */ + mc_ptr = netdev->mc_list; + + for(i = 1; i < E1000_RAR_ENTRIES; i++) { + if(mc_ptr) { + e1000_rar_set(shared, mc_ptr->dmi_addr, i); + mc_ptr = mc_ptr->next; + } else { + E1000_WRITE_REG_ARRAY(shared, RA, i << 1, 0); + E1000_WRITE_REG_ARRAY(shared, RA, (i << 1) + 1, 0); + } + } + + /* clear the old settings from the multicast hash table */ + + for(i = 0; i < E1000_NUM_MTA_REGISTERS; i++) + E1000_WRITE_REG_ARRAY(shared, MTA, i, 0); + + /* load any remaining addresses into the hash table */ + + for(; mc_ptr; mc_ptr = mc_ptr->next) { + hash_value = e1000_hash_mc_addr(shared, mc_ptr->dmi_addr); + e1000_mta_set(shared, hash_value); + } + + if(shared->mac_type == e1000_82542_rev2_0) + e1000_leave_82542_rst(adapter); + return; +} + + +/* need to wait a few seconds after link up to get diagnostic information from the phy */ + +static void +e1000_update_phy_info(unsigned long data) +{ + struct e1000_adapter *adapter = (struct e1000_adapter *) data; + e1000_phy_get_info(&adapter->shared, &adapter->phy_info); + return; +} + +/** + * e1000_watchdog - Timer Call-back + * @data: pointer to netdev cast into an unsigned long + **/ + +static void +e1000_watchdog(unsigned long data) +{ + struct e1000_adapter *adapter = (struct e1000_adapter *) data; + struct net_device *netdev = adapter->netdev; + + e1000_check_for_link(&adapter->shared); + + if(E1000_READ_REG(&adapter->shared, STATUS) & E1000_STATUS_LU) { + if(!netif_carrier_ok(netdev)) { + e1000_get_speed_and_duplex(&adapter->shared, + &adapter->link_speed, + &adapter->link_duplex); + + printk(KERN_INFO + "e1000: %s NIC Link is Up %d Mbps %s\n", + netdev->name, adapter->link_speed, + adapter->link_duplex == FULL_DUPLEX ? + "Full Duplex" : "Half Duplex"); + + netif_carrier_on(netdev); + adapter->trans_finish = jiffies; + netif_wake_queue(netdev); + mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ); + } + } else { + if(netif_carrier_ok(netdev)) { + adapter->link_speed = 0; + adapter->link_duplex = 0; + printk(KERN_INFO + "e1000: %s NIC Link is Down\n", + netdev->name); + netif_carrier_off(netdev); + netif_stop_queue(netdev); + } + } + + e1000_update_stats(adapter); + + /* Reset the timer */ + mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); + + return; +} + +/** + * e1000_xmit_frame - Transmit entry point + * @skb: buffer with frame data to transmit + * @netdev: network interface device structure + * + * Returns 0 on success, 1 on error + * + * e1000_xmit_frame is called by the stack to initiate a transmit. + * The out of resource condition is checked after each successful Tx + * so that the stack can be notified, preventing the driver from + * ever needing to drop a frame. The atomic operations on + * tx_ring.unused are used to syncronize with the transmit + * interrupt processing code without the need for a spinlock. + **/ + +#define TXD_USE_COUNT(x) (((x) >> 12) + ((x) & 0x0fff ? 1 : 0)) + +#define SETUP_TXD_PAGE(L, P, O) do { \ + tx_ring->buffer_info[i].length = (L); \ + tx_ring->buffer_info[i].dma = \ + pci_map_page(pdev, (P), (O), (L), PCI_DMA_TODEVICE); \ + tx_desc->buffer_addr = cpu_to_le64(tx_ring->buffer_info[i].dma); \ + tx_desc->lower.data = cpu_to_le32(txd_lower | (L)); \ + tx_desc->upper.data = cpu_to_le32(txd_upper); \ +} while (0) + +#define SETUP_TXD_PTR(L, P) \ + SETUP_TXD_PAGE((L), virt_to_page(P), (unsigned long)(P) & ~PAGE_MASK) + +#define QUEUE_TXD() do { i = (i + 1) % tx_ring->count; \ + atomic_dec(&tx_ring->unused); } while (0) + + +static int +e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev->priv; + struct e1000_desc_ring *tx_ring = &adapter->tx_ring; + struct pci_dev *pdev = adapter->pdev; + struct e1000_tx_desc *tx_desc; + int f, len, offset, txd_needed; + skb_frag_t *frag; + + int i = tx_ring->next_to_use; + uint32_t txd_upper = 0; + uint32_t txd_lower = adapter->txd_cmd; + + + /* If controller appears hung, force transmit timeout */ + + if (time_after(netdev->trans_start, adapter->trans_finish + HZ) && + /* If transmitting XOFFs, we're not really hung */ + !(E1000_READ_REG(&adapter->shared, STATUS) & E1000_STATUS_TXOFF)) { + adapter->trans_finish = jiffies; + netif_stop_queue(netdev); + return 1; + } + + txd_needed = TXD_USE_COUNT(skb->len - skb->data_len); + + for(f = 0; f < skb_shinfo(skb)->nr_frags; f++) { + frag = &skb_shinfo(skb)->frags[f]; + txd_needed += TXD_USE_COUNT(frag->size); + } + + if(skb->ip_summed == CHECKSUM_HW) + txd_needed += 1; + + /* make sure there are enough Tx descriptors available in the ring */ + + if(atomic_read(&tx_ring->unused) <= (txd_needed + 1)) { + adapter->net_stats.tx_dropped++; + netif_stop_queue(netdev); + return 1; + } + + if(skb->ip_summed == CHECKSUM_HW) { + struct e1000_context_desc *context_desc; + uint8_t css = skb->h.raw - skb->data; + uint8_t cso = (skb->h.raw + skb->csum) - skb->data; + + context_desc = E1000_CONTEXT_DESC(*tx_ring, i); + + context_desc->upper_setup.tcp_fields.tucss = css; + context_desc->upper_setup.tcp_fields.tucso = cso; + context_desc->upper_setup.tcp_fields.tucse = 0; + context_desc->tcp_seg_setup.data = 0; + context_desc->cmd_and_length = + cpu_to_le32(txd_lower | E1000_TXD_CMD_DEXT); + + QUEUE_TXD(); + + txd_upper |= E1000_TXD_POPTS_TXSM << 8; + txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; + } + + tx_desc = E1000_TX_DESC(*tx_ring, i); + len = skb->len - skb->data_len; + offset = 0; + + while(len > 4096) { + SETUP_TXD_PTR(4096, skb->data + offset); + QUEUE_TXD(); + + tx_desc = E1000_TX_DESC(*tx_ring, i); + len -= 4096; + offset += 4096; + } + + SETUP_TXD_PTR(len, skb->data + offset); + + for(f = 0; f < skb_shinfo(skb)->nr_frags; f++) { + frag = &skb_shinfo(skb)->frags[f]; + + QUEUE_TXD(); + + tx_desc = E1000_TX_DESC(*tx_ring, i); + len = frag->size; + offset = 0; + + while(len > 4096) { + SETUP_TXD_PAGE(4096, frag->page, + frag->page_offset + offset); + QUEUE_TXD(); + + tx_desc = E1000_TX_DESC(*tx_ring, i); + len -= 4096; + offset += 4096; + } + SETUP_TXD_PAGE(len, frag->page, frag->page_offset + offset); + } + + /* EOP and SKB pointer go with the last fragment */ + + tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP); + tx_ring->buffer_info[i].skb = skb; + + QUEUE_TXD(); + + tx_ring->next_to_use = i; + + /* Move the HW Tx Tail Pointer */ + + E1000_WRITE_REG(&adapter->shared, TDT, i); + + netdev->trans_start = jiffies; + + return 0; +} + +#undef TXD_USE_COUNT +#undef SETUP_TXD +#undef QUEUE_TXD + +/** + * e1000_tx_timeout - Respond to a Tx Hang + * @netdev: network interface device structure + **/ + +static void +e1000_tx_timeout(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev->priv; + + e1000_down(adapter); + e1000_up(adapter); +} + +/** + * e1000_get_stats - Get System Network Statistics + * @netdev: network interface device structure + * + * Returns the address of the device statistics structure. + * The statistics are actually updated from the timer callback. + **/ + +static struct net_device_stats * +e1000_get_stats(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev->priv; + + return &adapter->net_stats; +} + +/** + * e1000_change_mtu - Change the Maximum Transfer Unit + * @netdev: network interface device structure + * @new_mtu: new value for maximum frame size + * + * Returns 0 on success, negative on failure + **/ + +static int +e1000_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct e1000_adapter *adapter = netdev->priv; + int old_mtu = adapter->rx_buffer_len; + int max_frame = new_mtu + ENET_HEADER_SIZE + CRC_LENGTH; + + if((max_frame < MINIMUM_ETHERNET_PACKET_SIZE + CRC_LENGTH) || + (max_frame > MAX_JUMBO_FRAME_SIZE + CRC_LENGTH)) { + E1000_ERR("Invalid MTU setting\n"); + return -EINVAL; + } + + if(max_frame <= MAXIMUM_ETHERNET_PACKET_SIZE + CRC_LENGTH) { + adapter->rx_buffer_len = E1000_RXBUFFER_2048; + + } else if(adapter->shared.mac_type < e1000_82543) { + E1000_ERR("Jumbo Frames not supported on 82542\n"); + return -EINVAL; + + } else if(max_frame <= E1000_RXBUFFER_2048) { + adapter->rx_buffer_len = E1000_RXBUFFER_2048; + + } else if(max_frame <= E1000_RXBUFFER_4096) { + adapter->rx_buffer_len = E1000_RXBUFFER_4096; + + } else if(max_frame <= E1000_RXBUFFER_8192) { + adapter->rx_buffer_len = E1000_RXBUFFER_8192; + + } else { + adapter->rx_buffer_len = E1000_RXBUFFER_16384; + } + + if(old_mtu != adapter->rx_buffer_len && netif_running(netdev)) { + + e1000_down(adapter); + e1000_clean_rx_ring(adapter); + e1000_clean_tx_ring(adapter); + e1000_up(adapter); + } + + netdev->mtu = new_mtu; + adapter->shared.max_frame_size = max_frame; + + return 0; +} + +/** + * e1000_update_stats - Update the board statistics counters + * @adapter: board private structure + **/ + +static void +e1000_update_stats(struct e1000_adapter *adapter) +{ + struct e1000_shared_adapter *shared = &adapter->shared; + unsigned long flags; + +#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF + + spin_lock_irqsave(&adapter->stats_lock, flags); + + /* these counters are modified from e1000_adjust_tbi_stats, + * called from the interrupt context, so they must only + * be written while holding adapter->stats_lock + */ + + adapter->stats.crcerrs += E1000_READ_REG(shared, CRCERRS); + adapter->stats.gprc += E1000_READ_REG(shared, GPRC); + adapter->stats.gorcl += E1000_READ_REG(shared, GORCL); + adapter->stats.gorch += E1000_READ_REG(shared, GORCH); + adapter->stats.bprc += E1000_READ_REG(shared, BPRC); + adapter->stats.mprc += E1000_READ_REG(shared, MPRC); + adapter->stats.roc += E1000_READ_REG(shared, ROC); + adapter->stats.prc64 += E1000_READ_REG(shared, PRC64); + adapter->stats.prc127 += E1000_READ_REG(shared, PRC127); + adapter->stats.prc255 += E1000_READ_REG(shared, PRC255); + adapter->stats.prc511 += E1000_READ_REG(shared, PRC511); + adapter->stats.prc1023 += E1000_READ_REG(shared, PRC1023); + adapter->stats.prc1522 += E1000_READ_REG(shared, PRC1522); + + spin_unlock_irqrestore(&adapter->stats_lock, flags); + + /* the rest of the counters are only modified here */ + + adapter->stats.symerrs += E1000_READ_REG(shared, SYMERRS); + adapter->stats.mpc += E1000_READ_REG(shared, MPC); + adapter->stats.scc += E1000_READ_REG(shared, SCC); + adapter->stats.ecol += E1000_READ_REG(shared, ECOL); + adapter->stats.mcc += E1000_READ_REG(shared, MCC); + adapter->stats.latecol += E1000_READ_REG(shared, LATECOL); + adapter->stats.colc += E1000_READ_REG(shared, COLC); + adapter->stats.dc += E1000_READ_REG(shared, DC); + adapter->stats.sec += E1000_READ_REG(shared, SEC); + adapter->stats.rlec += E1000_READ_REG(shared, RLEC); + adapter->stats.xonrxc += E1000_READ_REG(shared, XONRXC); + adapter->stats.xontxc += E1000_READ_REG(shared, XONTXC); + adapter->stats.xoffrxc += E1000_READ_REG(shared, XOFFRXC); + adapter->stats.xofftxc += E1000_READ_REG(shared, XOFFTXC); + adapter->stats.fcruc += E1000_READ_REG(shared, FCRUC); + adapter->stats.gptc += E1000_READ_REG(shared, GPTC); + adapter->stats.gotcl += E1000_READ_REG(shared, GOTCL); + adapter->stats.gotch += E1000_READ_REG(shared, GOTCH); + adapter->stats.rnbc += E1000_READ_REG(shared, RNBC); + adapter->stats.ruc += E1000_READ_REG(shared, RUC); + adapter->stats.rfc += E1000_READ_REG(shared, RFC); + adapter->stats.rjc += E1000_READ_REG(shared, RJC); + adapter->stats.torl += E1000_READ_REG(shared, TORL); + adapter->stats.torh += E1000_READ_REG(shared, TORH); + adapter->stats.totl += E1000_READ_REG(shared, TOTL); + adapter->stats.toth += E1000_READ_REG(shared, TOTH); + adapter->stats.tpr += E1000_READ_REG(shared, TPR); + adapter->stats.tpt += E1000_READ_REG(shared, TPT); + adapter->stats.ptc64 += E1000_READ_REG(shared, PTC64); + adapter->stats.ptc127 += E1000_READ_REG(shared, PTC127); + adapter->stats.ptc255 += E1000_READ_REG(shared, PTC255); + adapter->stats.ptc511 += E1000_READ_REG(shared, PTC511); + adapter->stats.ptc1023 += E1000_READ_REG(shared, PTC1023); + adapter->stats.ptc1522 += E1000_READ_REG(shared, PTC1522); + adapter->stats.mptc += E1000_READ_REG(shared, MPTC); + adapter->stats.bptc += E1000_READ_REG(shared, BPTC); + + if(adapter->shared.mac_type >= e1000_82543) { + adapter->stats.algnerrc += E1000_READ_REG(shared, ALGNERRC); + adapter->stats.rxerrc += E1000_READ_REG(shared, RXERRC); + adapter->stats.tncrs += E1000_READ_REG(shared, TNCRS); + adapter->stats.cexterr += E1000_READ_REG(shared, CEXTERR); + adapter->stats.tsctc += E1000_READ_REG(shared, TSCTC); + adapter->stats.tsctfc += E1000_READ_REG(shared, TSCTFC); + } + + /* Fill out the OS statistics structure */ + + adapter->net_stats.rx_packets = adapter->stats.gprc; + adapter->net_stats.tx_packets = adapter->stats.gptc; + adapter->net_stats.rx_bytes = adapter->stats.gorcl; + adapter->net_stats.tx_bytes = adapter->stats.gotcl; + adapter->net_stats.multicast = adapter->stats.mprc; + adapter->net_stats.collisions = adapter->stats.colc; + + /* Rx Errors */ + + adapter->net_stats.rx_errors = adapter->stats.rxerrc + + adapter->stats.crcerrs + adapter->stats.algnerrc + + adapter->stats.rlec + adapter->stats.rnbc + + adapter->stats.mpc + adapter->stats.cexterr; + adapter->net_stats.rx_dropped = adapter->stats.rnbc; + adapter->net_stats.rx_length_errors = adapter->stats.rlec; + adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs; + adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc; + adapter->net_stats.rx_fifo_errors = adapter->stats.mpc; + adapter->net_stats.rx_missed_errors = adapter->stats.mpc; + + /* Tx Errors */ + + adapter->net_stats.tx_errors = adapter->stats.ecol + + adapter->stats.latecol; + adapter->net_stats.tx_aborted_errors = adapter->stats.ecol; + adapter->net_stats.tx_window_errors = adapter->stats.latecol; + + /* Tx Dropped needs to be maintained elsewhere */ + + if(adapter->shared.media_type == e1000_media_type_copper) { + adapter->phy_stats.idle_errors += + (e1000_read_phy_reg(shared, PHY_1000T_STATUS) + & PHY_IDLE_ERROR_COUNT_MASK); + adapter->phy_stats.receive_errors += + e1000_read_phy_reg(shared, M88E1000_RX_ERR_CNTR); + } + return; +} + +/** + * e1000_irq_disable - Mask off interrupt generation on the NIC + * @adapter: board private structure + **/ + +static inline void +e1000_irq_disable(struct e1000_adapter *adapter) +{ + atomic_inc(&adapter->irq_sem); + E1000_WRITE_REG(&adapter->shared, IMC, ~0); + synchronize_irq(); + return; +} + +/** + * e1000_irq_enable - Enable default interrupt generation settings + * @adapter: board private structure + **/ + +static inline void +e1000_irq_enable(struct e1000_adapter *adapter) +{ + if(atomic_dec_and_test(&adapter->irq_sem)) + E1000_WRITE_REG(&adapter->shared, IMS, IMS_ENABLE_MASK); + return; +} + +/** + * e1000_intr - Interrupt Handler + * @irq: interrupt number + * @data: pointer to a network interface device structure + * @pt_regs: CPU registers structure + **/ + +static void +e1000_intr(int irq, void *data, struct pt_regs *regs) +{ + struct net_device *netdev = data; + struct e1000_adapter *adapter = netdev->priv; + uint32_t icr; + int i = E1000_MAX_INTR; + + while(i && (icr = E1000_READ_REG(&adapter->shared, ICR))) { + + if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + /* run the watchdog ASAP */ + adapter->shared.get_link_status = 1; + mod_timer(&adapter->watchdog_timer, jiffies); + } + + e1000_clean_rx_irq(adapter); + e1000_clean_tx_irq(adapter); + i--; + } + + return; +} + +/** + * e1000_clean_tx_irq - Reclaim resources after transmit completes + * @adapter: board private structure + **/ + +static void +e1000_clean_tx_irq(struct e1000_adapter *adapter) +{ + struct e1000_desc_ring *tx_ring = &adapter->tx_ring; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_tx_desc *tx_desc; + int i; + + i = tx_ring->next_to_clean; + tx_desc = E1000_TX_DESC(*tx_ring, i); + + while(tx_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { + + if(tx_ring->buffer_info[i].dma) { + + pci_unmap_page(pdev, + tx_ring->buffer_info[i].dma, + tx_ring->buffer_info[i].length, + PCI_DMA_TODEVICE); + + tx_ring->buffer_info[i].dma = 0; + } + + if(tx_ring->buffer_info[i].skb) { + + dev_kfree_skb_irq(tx_ring->buffer_info[i].skb); + + tx_ring->buffer_info[i].skb = NULL; + } + + memset(tx_desc, 0, sizeof(struct e1000_tx_desc)); + mb(); + + atomic_inc(&tx_ring->unused); + i = (i + 1) % tx_ring->count; + tx_desc = E1000_TX_DESC(*tx_ring, i); + + adapter->trans_finish = jiffies; + } + + tx_ring->next_to_clean = i; + + if(netif_queue_stopped(netdev) && netif_carrier_ok(netdev) && + (atomic_read(&tx_ring->unused) > E1000_TX_QUEUE_WAKE)) { + + netif_wake_queue(netdev); + } + return; +} + +/** + * e1000_clean_rx_irq - Send received data up the network stack, + * @adapter: board private structure + **/ + +static void +e1000_clean_rx_irq(struct e1000_adapter *adapter) +{ + struct e1000_desc_ring *rx_ring = &adapter->rx_ring; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_rx_desc *rx_desc; + struct sk_buff *skb; + unsigned long flags; + uint32_t length; + uint8_t last_byte; + int i; + + i = rx_ring->next_to_clean; + rx_desc = E1000_RX_DESC(*rx_ring, i); + + while(rx_desc->status & E1000_RXD_STAT_DD) { + + pci_unmap_single(pdev, + rx_ring->buffer_info[i].dma, + rx_ring->buffer_info[i].length, + PCI_DMA_FROMDEVICE); + + skb = rx_ring->buffer_info[i].skb; + length = le16_to_cpu(rx_desc->length); + + if(!(rx_desc->status & E1000_RXD_STAT_EOP)) { + + /* All receives must fit into a single buffer */ + + E1000_DBG("Receive packet consumed multiple buffers\n"); + + dev_kfree_skb_irq(skb); + memset(rx_desc, 0, 16); + mb(); + rx_ring->buffer_info[i].skb = NULL; + + rx_ring->unused_count++; + + i = (i + 1) % rx_ring->count; + + rx_desc = E1000_RX_DESC(*rx_ring, i); + continue; + } + + if(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) { + + last_byte = *(skb->data + length - 1); + + if(TBI_ACCEPT(&adapter->shared, rx_desc->special, + rx_desc->errors, length, last_byte)) { + + spin_lock_irqsave(&adapter->stats_lock, flags); + + e1000_tbi_adjust_stats(&adapter->shared, + &adapter->stats, + length, skb->data); + + spin_unlock_irqrestore(&adapter->stats_lock, + flags); + length--; + } else { + + dev_kfree_skb_irq(skb); + memset(rx_desc, 0, 16); + mb(); + rx_ring->buffer_info[i].skb = NULL; + + rx_ring->unused_count++; + i = (i + 1) % rx_ring->count; + + rx_desc = E1000_RX_DESC(*rx_ring, i); + continue; + } + } + + /* Good Receive */ + skb_put(skb, length - CRC_LENGTH); + + /* Receive Checksum Offload */ + e1000_rx_checksum(adapter, rx_desc, skb); + + skb->protocol = eth_type_trans(skb, netdev); + netif_rx(skb); + + memset(rx_desc, 0, sizeof(struct e1000_rx_desc)); + mb(); + rx_ring->buffer_info[i].skb = NULL; + + rx_ring->unused_count++; + + i = (i + 1) % rx_ring->count; + + rx_desc = E1000_RX_DESC(*rx_ring, i); + } + + rx_ring->next_to_clean = i; + + e1000_alloc_rx_buffers(adapter); + + return; +} + +/** + * e1000_alloc_rx_buffers - Replace used receive buffers + * @data: address of board private structure + **/ + +static void +e1000_alloc_rx_buffers(struct e1000_adapter *adapter) +{ + struct e1000_desc_ring *rx_ring = &adapter->rx_ring; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_rx_desc *rx_desc; + struct sk_buff *skb; + int reserve_len; + int i; + + if(!netif_running(netdev)) + return; + + reserve_len = 2; + + i = rx_ring->next_to_use; + + while(!rx_ring->buffer_info[i].skb) { + rx_desc = E1000_RX_DESC(*rx_ring, i); + + skb = alloc_skb(adapter->rx_buffer_len + reserve_len, + GFP_ATOMIC); + + if(!skb) { + /* Better luck next round */ + break; + } + + /* Make buffer alignment 2 beyond a 16 byte boundary + * this will result in a 16 byte aligned IP header after + * the 14 byte MAC header is removed + */ + skb_reserve(skb, reserve_len); + + skb->dev = netdev; + + rx_ring->buffer_info[i].skb = skb; + rx_ring->buffer_info[i].length = adapter->rx_buffer_len; + rx_ring->buffer_info[i].dma = + pci_map_single(pdev, + skb->data, + adapter->rx_buffer_len, + PCI_DMA_FROMDEVICE); + + rx_desc->buffer_addr = cpu_to_le64(rx_ring->buffer_info[i].dma); + + /* move tail */ + E1000_WRITE_REG(&adapter->shared, RDT, i); + + atomic_dec(&rx_ring->unused); + + i = (i + 1) % rx_ring->count; + } + + rx_ring->next_to_use = i; + return; +} + +/** + * e1000_ioctl - + * @netdev: + * @ifreq: + * @cmd: + **/ + +static int +e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + switch (cmd) { + case SIOCETHTOOL: + return e1000_ethtool_ioctl(netdev, ifr); + default: + return -EOPNOTSUPP; + } +} + +/** + * e1000_rx_checksum - Receive Checksum Offload for 82543 + * @adapter: board private structure + * @rx_desc: receive descriptor + * @sk_buff: socket buffer with received data + **/ + +static inline void +e1000_rx_checksum(struct e1000_adapter *adapter, + struct e1000_rx_desc *rx_desc, + struct sk_buff *skb) +{ + /* 82543 or newer only */ + if((adapter->shared.mac_type < e1000_82543) || + /* Ignore Checksum bit is set */ + (rx_desc->status & E1000_RXD_STAT_IXSM) || + /* TCP Checksum has not been calculated */ + (!(rx_desc->status & E1000_RXD_STAT_TCPCS))) { + skb->ip_summed = CHECKSUM_NONE; + return; + } + + /* At this point we know the hardware did the TCP checksum */ + /* now look at the TCP checksum error bit */ + if(rx_desc->errors & E1000_RXD_ERR_TCPE) { + /* let the stack verify checksum errors */ + skb->ip_summed = CHECKSUM_NONE; + adapter->hw_csum_err++; + } else { + /* TCP checksum is good */ + skb->ip_summed = CHECKSUM_UNNECESSARY; + adapter->hw_csum_good++; + } + return; +} + + +/** + * e1000_enable_WOL - Wake On Lan Support (Magic Pkt) + * @adapter: Adapter structure + **/ + +void +e1000_enable_WOL(struct e1000_adapter *adapter) +{ + uint32_t wuc; + + if(adapter->shared.mac_type < e1000_82544) + return; + + if(adapter->wol) { + wuc = E1000_WUC_APME | E1000_WUC_PME_EN | + E1000_WUC_PME_STATUS | E1000_WUC_APMPME; + + E1000_WRITE_REG(&adapter->shared, WUC, wuc); + + E1000_WRITE_REG(&adapter->shared, WUFC, adapter->wol); + } + + return; +} + +void +e1000_write_pci_cfg(struct e1000_shared_adapter *shared, + uint32_t reg, uint16_t *value) +{ + struct e1000_adapter *adapter = shared->back; + + pci_write_config_word(adapter->pdev, reg, *value); + return; +} + +/* e1000_main.c */ diff -Nru a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/e1000/e1000_osdep.h Tue Feb 26 11:58:00 2002 @@ -0,0 +1,142 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +/* glue for the OS independant part of e1000 + * includes register access macros + */ + +#ifndef _E1000_OSDEP_H_ +#define _E1000_OSDEP_H_ + +#include +#include +#include +#include +#include + +#define usec_delay(x) udelay(x) +#define msec_delay(x) do { if(in_interrupt()) { \ + mdelay(x); \ + } else { \ + set_current_state(TASK_UNINTERRUPTIBLE); \ + schedule_timeout((x * HZ)/1000); \ + } } while(0) + +#define PCI_COMMAND_REGISTER PCI_COMMAND +#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE + +typedef enum { + FALSE = 0, + TRUE = 1 +} boolean_t; + +#define ASSERT(x) if(!(x)) BUG() +#define MSGOUT(S, A, B) printk(KERN_DEBUG S "\n", A, B) + +#if DBG +#define DEBUGOUT(S) printk(KERN_DEBUG S "\n") +#define DEBUGOUT1(S, A...) printk(KERN_DEBUG S "\n", A) +#else +#define DEBUGOUT(S) +#define DEBUGOUT1(S, A...) +#endif + +#define DEBUGFUNC(F) DEBUGOUT(F) +#define DEBUGOUT2 DEBUGOUT1 +#define DEBUGOUT3 DEBUGOUT2 +#define DEBUGOUT7 DEBUGOUT3 + + +#define E1000_WRITE_REG(a, reg, value) ( \ + ((a)->mac_type >= e1000_82543) ? \ + (writel((value), ((a)->hw_addr + E1000_##reg))) : \ + (writel((value), ((a)->hw_addr + E1000_82542_##reg)))) + +#define E1000_READ_REG(a, reg) ( \ + ((a)->mac_type >= e1000_82543) ? \ + readl((a)->hw_addr + E1000_##reg) : \ + readl((a)->hw_addr + E1000_82542_##reg)) + +#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) ( \ + ((a)->mac_type >= e1000_82543) ? \ + writel((value), ((a)->hw_addr + E1000_##reg + ((offset) << 2))) : \ + writel((value), ((a)->hw_addr + E1000_82542_##reg + ((offset) << 2)))) + +#define E1000_READ_REG_ARRAY(a, reg, offset) ( \ + ((a)->mac_type >= e1000_82543) ? \ + readl((a)->hw_addr + E1000_##reg + ((offset) << 2)) : \ + readl((a)->hw_addr + E1000_82542_##reg + ((offset) << 2))) + +#endif /* _E1000_OSDEP_H_ */ diff -Nru a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/e1000/e1000_param.c Tue Feb 26 11:58:00 2002 @@ -0,0 +1,709 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include "e1000.h" + +/* This is the only thing that needs to be changed to adjust the + * maximum number of ports that the driver can manage. + */ + +#define E1000_MAX_NIC 32 + +#define OPTION_UNSET -1 +#define OPTION_DISABLED 0 +#define OPTION_ENABLED 1 + +/* Module Parameters are always initialized to -1, so that the driver + * can tell the difference between no user specified value or the + * user asking for the default value. + * The true default values are loaded in when e1000_check_options is called. + * + * This is a GCC extension to ANSI C. + * See the item "Labeled Elements in Initializers" in the section + * "Extensions to the C Language Family" of the GCC documentation. + */ + +#define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET } + +/* All parameters are treated the same, as an integer array of values. + * This macro just reduces the need to repeat the same declaration code + * over and over (plus this helps to avoid typo bugs). + */ + +#define E1000_PARAM(X, S) \ +static const int __devinitdata X[E1000_MAX_NIC + 1] = E1000_PARAM_INIT; \ +MODULE_PARM(X, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); \ +MODULE_PARM_DESC(X, S); + +/* Transmit Descriptor Count + * + * Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers + * Valid Range: 80-4096 for 82544 + * + * Default Value: 256 + */ + +E1000_PARAM(TxDescriptors, "Number of transmit descriptors"); + +/* Receive Descriptor Count + * + * Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers + * Valid Range: 80-4096 for 82544 + * + * Default Value: 80 + */ + +E1000_PARAM(RxDescriptors, "Number of receive descriptors"); + +/* User Specified Speed Override + * + * Valid Range: 0, 10, 100, 1000 + * - 0 - auto-negotiate at all supported speeds + * - 10 - only link at 10 Mbps + * - 100 - only link at 100 Mbps + * - 1000 - only link at 1000 Mbps + * + * Default Value: 0 + */ + +E1000_PARAM(Speed, "Speed setting"); + +/* User Specified Duplex Override + * + * Valid Range: 0-2 + * - 0 - auto-negotiate for duplex + * - 1 - only link at half duplex + * - 2 - only link at full duplex + * + * Default Value: 0 + */ + +E1000_PARAM(Duplex, "Duplex setting"); + +/* Auto-negotiation Advertisement Override + * + * Valid Range: 0x00-0x0F, 0x20-0x2F + * + * The AutoNeg value is a bit mask describing which speed and duplex + * combinations should be advertised during auto-negotiation. + * The supported speed and duplex modes are listed below + * + * Bit 7 6 5 4 3 2 1 0 + * Speed (Mbps) N/A N/A 1000 N/A 100 100 10 10 + * Duplex Full Full Half Full Half + * + * Default Value: 0x2F + */ + +E1000_PARAM(AutoNeg, "Advertised auto-negotiation setting"); + +/* User Specified Flow Control Override + * + * Valid Range: 0-3 + * - 0 - No Flow Control + * - 1 - Rx only, respond to PAUSE frames but do not generate them + * - 2 - Tx only, generate PAUSE frames but ignore them on receive + * - 3 - Full Flow Control Support + * + * Default Value: Read flow control settings from the EEPROM + */ + +E1000_PARAM(FlowControl, "Flow Control setting"); + +/* XsumRX - Receive Checksum Offload Enable/Disable + * + * Valid Range: 0, 1 + * - 0 - disables all checksum offload + * - 1 - enables receive IP/TCP/UDP checksum offload + * on 82543 based NICs + * + * Default Value: 1 + */ + +E1000_PARAM(XsumRX, "Disable or enable Receive Checksum offload"); + +/* Transmit Interrupt Delay in units of 1.024 microseconds + * + * Valid Range: 0-65535 + * + * Default Value: 64 + */ + +E1000_PARAM(TxIntDelay, "Transmit Interrupt Delay"); + +/* Receive Interrupt Delay in units of 1.024 microseconds + * + * Valid Range: 0-65535 + * + * Default Value: 64 + */ + +E1000_PARAM(RxIntDelay, "Receive Interrupt Delay"); + +/* MDI-X Support Enable/Disable - Applies only to Copper PHY + * + * Valid Range: 0, 3 + * - 0 - Auto in all modes + * - 1 - MDI + * - 2 - MDI-X + * - 3 - Auto in 1000 Base-T mode (MDI in 10 Base-T and 100 Base-T) + * + * Default Value: 0 (Auto) + */ + +E1000_PARAM(MdiX, "Set MDI/MDI-X Mode"); + +/* Automatic Correction of Reversed Cable Polarity Enable/Disable + * This setting applies only to Copper PHY + * + * Valid Range: 0, 1 + * - 0 - Disabled + * - 1 - Enabled + * + * Default Value: 1 (Enabled) + */ + +E1000_PARAM(DisablePolarityCorrection, + "Disable or enable Automatic Correction for Reversed Cable Polarity"); + + +#define AUTONEG_ADV_DEFAULT 0x2F +#define AUTONEG_ADV_MASK 0x2F +#define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL + +#define DEFAULT_TXD 256 +#define MAX_TXD 256 +#define MIN_TXD 80 +#define MAX_82544_TXD 4096 + +#define DEFAULT_RXD 80 +#define MAX_RXD 256 +#define MIN_RXD 80 +#define MAX_82544_RXD 4096 + +#define DEFAULT_TIDV 64 +#define MAX_TIDV 0xFFFF +#define MIN_TIDV 0 + +#define DEFAULT_RIDV 64 +#define MAX_RIDV 0xFFFF +#define MIN_RIDV 0 + +#define DEFAULT_MDIX 0 +#define MAX_MDIX 3 +#define MIN_MDIX 0 + + +struct e1000_option { + enum { enable_option, range_option, list_option } type; + char *name; + char *err; + int def; + union { + struct { /* range_option info */ + int min; + int max; + } r; + struct { /* list_option info */ + int nr; + struct e1000_opt_list { int i; char *str; } *p; + } l; + } arg; +}; + + +static int __devinit +e1000_validate_option(int *value, struct e1000_option *opt) +{ + if(*value == OPTION_UNSET) { + *value = opt->def; + return 0; + } + + switch (opt->type) { + case enable_option: + switch (*value) { + case OPTION_ENABLED: + printk(KERN_INFO "%s Enabled\n", opt->name); + return 0; + case OPTION_DISABLED: + printk(KERN_INFO "%s Disabled\n", opt->name); + return 0; + } + break; + case range_option: + if(*value >= opt->arg.r.min && *value <= opt->arg.r.max) { + printk(KERN_INFO "%s set to %i\n", opt->name, *value); + return 0; + } + break; + case list_option: { + int i; + struct e1000_opt_list *ent; + + for(i = 0; i < opt->arg.l.nr; i++) { + ent = &opt->arg.l.p[i]; + if(*value == ent->i) { + if(ent->str[0] != '\0') + printk(KERN_INFO "%s\n", ent->str); + return 0; + } + } + } + break; + default: + BUG(); + } + + printk(KERN_INFO "Invalid %s specified (%i) %s\n", + opt->name, *value, opt->err); + *value = opt->def; + return -1; +} + +#define LIST_LEN(l) (sizeof(l) / sizeof(l[0])) + +static void e1000_check_fiber_options(struct e1000_adapter *adapter); +static void e1000_check_copper_options(struct e1000_adapter *adapter); + +/** + * e1000_check_options - Range Checking for Command Line Parameters + * @adapter: board private structure + * + * This routine checks all command line paramters for valid user + * input. If an invalid value is given, or if no user specified + * value exists, a default value is used. The final value is stored + * in a variable in the adapter structure. + **/ + +void __devinit +e1000_check_options(struct e1000_adapter *adapter) +{ + int bd = adapter->bd_number; + if(bd >= E1000_MAX_NIC) { + printk(KERN_NOTICE + "Warning: no configuration for board #%i\n", bd); + printk(KERN_NOTICE "Using defaults for all values\n"); + bd = E1000_MAX_NIC; + } + + { /* Transmit Descriptor Count */ + struct e1000_option opt = { + type: range_option, + name: "Transmit Descriptors", + err: "using default of " __MODULE_STRING(DEFAULT_TXD), + def: DEFAULT_TXD, + arg: { r: { min: MIN_TXD }} + }; + struct e1000_desc_ring *tx_ring = &adapter->tx_ring; + e1000_mac_type mac_type = adapter->shared.mac_type; + opt.arg.r.max = mac_type < e1000_82544 ? MAX_TXD : MAX_82544_TXD; + + tx_ring->count = TxDescriptors[bd]; + e1000_validate_option(&tx_ring->count, &opt); + E1000_ROUNDUP(tx_ring->count, REQ_TX_DESCRIPTOR_MULTIPLE); + } + { /* Receive Descriptor Count */ + struct e1000_option opt = { + type: range_option, + name: "Receive Descriptors", + err: "using default of " __MODULE_STRING(DEFAULT_RXD), + def: DEFAULT_RXD, + arg: { r: { min: MIN_RXD }} + }; + struct e1000_desc_ring *rx_ring = &adapter->rx_ring; + e1000_mac_type mac_type = adapter->shared.mac_type; + opt.arg.r.max = mac_type < e1000_82544 ? MAX_RXD : MAX_82544_RXD; + + rx_ring->count = RxDescriptors[bd]; + e1000_validate_option(&rx_ring->count, &opt); + E1000_ROUNDUP(rx_ring->count, REQ_RX_DESCRIPTOR_MULTIPLE); + } + { /* Checksum Offload Enable/Disable */ + struct e1000_option opt = { + type: enable_option, + name: "Checksum Offload", + err: "defaulting to Enabled", + def: OPTION_ENABLED + }; + + int rx_csum = XsumRX[bd]; + e1000_validate_option(&rx_csum, &opt); + adapter->rx_csum = rx_csum; + } + { /* Flow Control */ + + struct e1000_opt_list fc_list[] = + {{ e1000_fc_none, "Flow Control Disabled" }, + { e1000_fc_rx_pause,"Flow Control Receive Only" }, + { e1000_fc_tx_pause,"Flow Control Transmit Only" }, + { e1000_fc_full, "Flow Control Enabled" }, + { e1000_fc_default, "Flow Control Hardware Default" }}; + + struct e1000_option opt = { + type: list_option, + name: "Flow Control", + err: "reading default settings from EEPROM", + def: e1000_fc_default, + arg: { l: { nr: LIST_LEN(fc_list), p: fc_list }} + }; + + int fc = FlowControl[bd]; + e1000_validate_option(&fc, &opt); + adapter->shared.fc = adapter->shared.original_fc = fc; + } + { /* Transmit Interrupt Delay */ + struct e1000_option opt = { + type: range_option, + name: "Transmit Interrupt Delay", + err: "using default of " __MODULE_STRING(DEFAULT_TIDV), + def: DEFAULT_TIDV, + arg: { r: { min: MIN_TIDV, max: MAX_TIDV }} + }; + + adapter->tx_int_delay = TxIntDelay[bd]; + e1000_validate_option(&adapter->tx_int_delay, &opt); + } + { /* Receive Interrupt Delay */ + struct e1000_option opt = { + type: range_option, + name: "Receive Interrupt Delay", + err: "using default of " __MODULE_STRING(DEFAULT_RIDV), + def: DEFAULT_RIDV, + arg: { r: { min: MIN_RIDV, max: MAX_RIDV }} + }; + + adapter->rx_int_delay = RxIntDelay[bd]; + e1000_validate_option(&adapter->rx_int_delay, &opt); + } + + switch(adapter->shared.media_type) { + case e1000_media_type_fiber: + e1000_check_fiber_options(adapter); + break; + case e1000_media_type_copper: + e1000_check_copper_options(adapter); + break; + default: + BUG(); + } +} + +/** + * e1000_check_fiber_options - Range Checking for Link Options, Fiber Version + * @adapter: board private structure + * + * Handles speed and duplex options on fiber adapters + **/ + +static void __devinit +e1000_check_fiber_options(struct e1000_adapter *adapter) +{ + int bd = adapter->bd_number; + bd = bd > E1000_MAX_NIC ? E1000_MAX_NIC : bd; + + if((Speed[bd] != OPTION_UNSET)) { + printk(KERN_INFO "Speed not valid for fiber adapters, " + "parameter ignored\n"); + } + if((Duplex[bd] != OPTION_UNSET)) { + printk(KERN_INFO "Duplex not valid for fiber adapters, " + "parameter ignored\n"); + } + if((AutoNeg[bd] != OPTION_UNSET)) { + printk(KERN_INFO "AutoNeg not valid for fiber adapters, " + "parameter ignored\n"); + } +} + +/** + * e1000_check_copper_options - Range Checking for Link Options, Copper Version + * @adapter: board private structure + * + * Handles speed and duplex options on copper adapters + **/ + +static void __devinit +e1000_check_copper_options(struct e1000_adapter *adapter) +{ + int speed, dplx; + int bd = adapter->bd_number; + bd = bd > E1000_MAX_NIC ? E1000_MAX_NIC : bd; + + { /* Speed */ + struct e1000_opt_list speed_list[] = {{ 0, "" }, + { SPEED_10, "" }, + { SPEED_100, "" }, + { SPEED_1000, "" }}; + struct e1000_option opt = { + type: list_option, + name: "Speed", + err: "parameter ignored", + def: 0, + arg: { l: { nr: LIST_LEN(speed_list), p: speed_list }} + }; + + speed = Speed[bd]; + e1000_validate_option(&speed, &opt); + } + { /* Duplex */ + struct e1000_opt_list dplx_list[] = {{ 0, "" }, + { HALF_DUPLEX, "" }, + { FULL_DUPLEX, "" }}; + struct e1000_option opt = { + type: list_option, + name: "Duplex", + err: "parameter ignored", + def: 0, + arg: { l: { nr: LIST_LEN(dplx_list), p: dplx_list }} + }; + + dplx = Duplex[bd]; + e1000_validate_option(&dplx, &opt); + } + + if(AutoNeg[bd] != OPTION_UNSET && (speed != 0 || dplx != 0)) { + printk(KERN_INFO + "AutoNeg specified along with Speed or Duplex, " + "parameter ignored\n"); + adapter->shared.autoneg_advertised = AUTONEG_ADV_DEFAULT; + } else { /* Autoneg */ + struct e1000_opt_list an_list[] = + #define AA "Autoneg advertising " + {{ 0x01, AA "10/HD" }, + { 0x02, AA "10/FD" }, + { 0x03, AA "10/FD, 10/HD" }, + { 0x04, AA "100/HD" }, + { 0x05, AA "100/HD, 10/HD" }, + { 0x06, AA "100/HD, 10/FD" }, + { 0x07, AA "100/HD, 10/FD, 10/HD" }, + { 0x08, AA "100/FD" }, + { 0x09, AA "100/FD, 10/HD" }, + { 0x0a, AA "100/FD, 10/FD" }, + { 0x0b, AA "100/FD, 10/FD, 10/HD" }, + { 0x0c, AA "100/FD, 100/HD" }, + { 0x0d, AA "100/FD, 100/HD, 10/HD" }, + { 0x0e, AA "100/FD, 100/HD, 10/FD" }, + { 0x0f, AA "100/FD, 100/HD, 10/FD, 10/HD" }, + { 0x20, AA "1000/FD" }, + { 0x21, AA "1000/FD, 10/HD" }, + { 0x22, AA "1000/FD, 10/FD" }, + { 0x23, AA "1000/FD, 10/FD, 10/HD" }, + { 0x24, AA "1000/FD, 100/HD" }, + { 0x25, AA "1000/FD, 100/HD, 10/HD" }, + { 0x26, AA "1000/FD, 100/HD, 10/FD" }, + { 0x27, AA "1000/FD, 100/HD, 10/FD, 10/HD" }, + { 0x28, AA "1000/FD, 100/FD" }, + { 0x29, AA "1000/FD, 100/FD, 10/HD" }, + { 0x2a, AA "1000/FD, 100/FD, 10/FD" }, + { 0x2b, AA "1000/FD, 100/FD, 10/FD, 10/HD" }, + { 0x2c, AA "1000/FD, 100/FD, 100/HD" }, + { 0x2d, AA "1000/FD, 100/FD, 100/HD, 10/HD" }, + { 0x2e, AA "1000/FD, 100/FD, 100/HD, 10/FD" }, + { 0x2f, AA "1000/FD, 100/FD, 100/HD, 10/FD, 10/HD" }}; + + struct e1000_option opt = { + type: list_option, + name: "Autoneg", + err: "parameter ignored", + def: AUTONEG_ADV_DEFAULT, + arg: { l: { nr: LIST_LEN(an_list), p: an_list }} + }; + + int an = AutoNeg[bd]; + e1000_validate_option(&an, &opt); + adapter->shared.autoneg_advertised = an; + } + + switch (speed + dplx) { + case 0: + adapter->shared.autoneg = 1; + if(Speed[bd] != OPTION_UNSET || Duplex[bd] != OPTION_UNSET) + printk(KERN_INFO + "Speed and duplex autonegotiation enabled\n"); + break; + case HALF_DUPLEX: + printk(KERN_INFO "Half Duplex specified without Speed\n"); + printk(KERN_INFO "Using Autonegotiation at Half Duplex only\n"); + adapter->shared.autoneg = 1; + adapter->shared.autoneg_advertised = ADVERTISE_10_HALF | + ADVERTISE_100_HALF; + break; + case FULL_DUPLEX: + printk(KERN_INFO "Full Duplex specified without Speed\n"); + printk(KERN_INFO "Using Autonegotiation at Full Duplex only\n"); + adapter->shared.autoneg = 1; + adapter->shared.autoneg_advertised = ADVERTISE_10_FULL | + ADVERTISE_100_FULL | + ADVERTISE_1000_FULL; + break; + case SPEED_10: + printk(KERN_INFO "10 Mbps Speed specified without Duplex\n"); + printk(KERN_INFO "Using Autonegotiation at 10 Mbps only\n"); + adapter->shared.autoneg = 1; + adapter->shared.autoneg_advertised = ADVERTISE_10_HALF | + ADVERTISE_10_FULL; + break; + case SPEED_10 + HALF_DUPLEX: + printk(KERN_INFO "Forcing to 10 Mbps Half Duplex\n"); + adapter->shared.autoneg = 0; + adapter->shared.forced_speed_duplex = e1000_10_half; + adapter->shared.autoneg_advertised = 0; + break; + case SPEED_10 + FULL_DUPLEX: + printk(KERN_INFO "Forcing to 10 Mbps Full Duplex\n"); + adapter->shared.autoneg = 0; + adapter->shared.forced_speed_duplex = e1000_10_full; + adapter->shared.autoneg_advertised = 0; + break; + case SPEED_100: + printk(KERN_INFO "100 Mbps Speed specified without Duplex\n"); + printk(KERN_INFO "Using Autonegotiation at 100 Mbps only\n"); + adapter->shared.autoneg = 1; + adapter->shared.autoneg_advertised = ADVERTISE_100_HALF | + ADVERTISE_100_FULL; + break; + case SPEED_100 + HALF_DUPLEX: + printk(KERN_INFO "Forcing to 100 Mbps Half Duplex\n"); + adapter->shared.autoneg = 0; + adapter->shared.forced_speed_duplex = e1000_100_half; + adapter->shared.autoneg_advertised = 0; + break; + case SPEED_100 + FULL_DUPLEX: + printk(KERN_INFO "Forcing to 100 Mbps Full Duplex\n"); + adapter->shared.autoneg = 0; + adapter->shared.forced_speed_duplex = e1000_100_full; + adapter->shared.autoneg_advertised = 0; + break; + case SPEED_1000: + printk(KERN_INFO "1000 Mbps Speed specified without Duplex\n"); + printk(KERN_INFO + "Using Autonegotiation at 1000 Mbps Full Duplex only\n"); + adapter->shared.autoneg = 1; + adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL; + break; + case SPEED_1000 + HALF_DUPLEX: + printk(KERN_INFO "Half Duplex is not supported at 1000 Mbps\n"); + printk(KERN_INFO + "Using Autonegotiation at 1000 Mbps Full Duplex only\n"); + adapter->shared.autoneg = 1; + adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL; + break; + case SPEED_1000 + FULL_DUPLEX: + printk(KERN_INFO + "Using Autonegotiation at 1000 Mbps Full Duplex only\n"); + adapter->shared.autoneg = 1; + adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL; + break; + default: + BUG(); + } + + /* a few other copper only options */ + + { /* MDI/MDI-X */ + struct e1000_option opt = { + type: range_option, + name: "MDI/MDI-X", + err: "using default of " __MODULE_STRING(DEFAULT_MDIX), + def: DEFAULT_MDIX, + arg: { r: { min: MIN_MDIX, max: MAX_MDIX }} + }; + + int mdix = MdiX[bd]; + e1000_validate_option(&mdix, &opt); + adapter->shared.mdix = mdix; + } + { /* Automatic Correction for Reverse Cable Polarity */ + /* option is actually to disable polarity correction, + * so setting to OPTION_ENABLED turns the hardware feature off */ + struct e1000_option opt = { + type: enable_option, + name: "Disable Polarity Correction", + err: "defaulting to Disabled", + def: OPTION_DISABLED, + }; + + int dpc = DisablePolarityCorrection[bd]; + e1000_validate_option(&dpc, &opt); + adapter->shared.disable_polarity_correction = dpc; + } + + /* Speed, AutoNeg and MDI/MDI-X must all play nice */ + if (!e1000_validate_mdi_setting(&(adapter->shared))) { + printk(KERN_INFO "Speed, AutoNeg and MDI-X specifications are " + "incompatible. Setting MDI-X to a compatible value.\n"); + } +} + diff -Nru a/drivers/net/e1000/e1000_phy.c b/drivers/net/e1000/e1000_phy.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/e1000/e1000_phy.c Tue Feb 26 11:58:00 2002 @@ -0,0 +1,1485 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/* e1000_phy.c + * Shared functions for accessing and configuring the PHY + */ + +#include "e1000_mac.h" +#include "e1000_phy.h" + +/****************************************************************************** +* Raises the Management Data Clock +* +* shared - Struct containing variables accessed by shared code +* ctrl_reg - Device control register's current value +******************************************************************************/ +static void +e1000_raise_mdc(struct e1000_shared_adapter *shared, + uint32_t *ctrl_reg) +{ + /* Raise the clock input to the Management Data Clock (by setting + * the MDC bit), and then delay 2 microseconds. + */ + E1000_WRITE_REG(shared, CTRL, (*ctrl_reg | E1000_CTRL_MDC)); + usec_delay(2); + return; +} + +/****************************************************************************** +* Lowers the Management Data Clock +* +* shared - Struct containing variables accessed by shared code +* ctrl_reg - Device control register's current value +******************************************************************************/ +static void +e1000_lower_mdc(struct e1000_shared_adapter *shared, + uint32_t *ctrl_reg) +{ + /* Lower the clock input to the Management Data Clock (by clearing + * the MDC bit), and then delay 2 microseconds. + */ + E1000_WRITE_REG(shared, CTRL, (*ctrl_reg & ~E1000_CTRL_MDC)); + usec_delay(2); + return; +} + +/****************************************************************************** +* Shifts data bits out to the PHY +* +* shared - Struct containing variables accessed by shared code +* data - Data to send out to the PHY +* count - Number of bits to shift out +* +* Bits are shifted out in MSB to LSB order. +******************************************************************************/ +static void +e1000_phy_shift_out(struct e1000_shared_adapter *shared, + uint32_t data, + uint16_t count) +{ + uint32_t ctrl_reg; + uint32_t mask; + + ASSERT(count <= 32); + + /* We need to shift "count" number of bits out to the PHY. So, the + * value in the "Data" parameter will be shifted out to the PHY + * one bit at a time. In order to do this, "Data" must be broken + * down into bits, which is what the "while" logic does below. + */ + mask = 0x01; + mask <<= (count - 1); + + ctrl_reg = E1000_READ_REG(shared, CTRL); + + /* Set MDIO_DIR (SWDPIO1) and MDC_DIR (SWDPIO2) direction bits to + * be used as output pins. + */ + ctrl_reg |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR); + + while(mask) { + /* A "1" is shifted out to the PHY by setting the MDIO bit to + * "1" and then raising and lowering the Management Data Clock + * (MDC). A "0" is shifted out to the PHY by setting the MDIO + * bit to "0" and then raising and lowering the clock. + */ + if(data & mask) + ctrl_reg |= E1000_CTRL_MDIO; + else + ctrl_reg &= ~E1000_CTRL_MDIO; + + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + usec_delay(2); + + e1000_raise_mdc(shared, &ctrl_reg); + e1000_lower_mdc(shared, &ctrl_reg); + + mask = mask >> 1; + } + + /* Clear the data bit just before leaving this routine. */ + ctrl_reg &= ~E1000_CTRL_MDIO; + return; +} + +/****************************************************************************** +* Shifts data bits in from the PHY +* +* shared - Struct containing variables accessed by shared code +* +* Bits are shifted in in MSB to LSB order. +******************************************************************************/ +static uint16_t +e1000_phy_shift_in(struct e1000_shared_adapter *shared) +{ + uint32_t ctrl_reg; + uint16_t data = 0; + uint8_t i; + + /* In order to read a register from the PHY, we need to shift in a + * total of 18 bits from the PHY. The first two bit (TurnAround) + * times are used to avoid contention on the MDIO pin when a read + * operation is performed. These two bits are ignored by us and + * thrown away. Bits are "shifted in" by raising the clock input + * to the Management Data Clock (setting the MDC bit), and then + * reading the value of the MDIO bit. + */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + + /* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as + * input. + */ + ctrl_reg &= ~E1000_CTRL_MDIO_DIR; + ctrl_reg &= ~E1000_CTRL_MDIO; + + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + /* Raise and Lower the clock before reading in the data. This + * accounts for the TurnAround bits. The first clock occurred + * when we clocked out the last bit of the Register Address. + */ + e1000_raise_mdc(shared, &ctrl_reg); + e1000_lower_mdc(shared, &ctrl_reg); + + for(data = 0, i = 0; i < 16; i++) { + data = data << 1; + e1000_raise_mdc(shared, &ctrl_reg); + + ctrl_reg = E1000_READ_REG(shared, CTRL); + + /* Check to see if we shifted in a "1". */ + if(ctrl_reg & E1000_CTRL_MDIO) + data |= 1; + + e1000_lower_mdc(shared, &ctrl_reg); + } + + e1000_raise_mdc(shared, &ctrl_reg); + e1000_lower_mdc(shared, &ctrl_reg); + + /* Clear the MDIO bit just before leaving this routine. */ + ctrl_reg &= ~E1000_CTRL_MDIO; + + return (data); +} + +/****************************************************************************** +* Force PHY speed and duplex settings to shared->forced_speed_duplex +* +* shared - Struct containing variables accessed by shared code +******************************************************************************/ +static void +e1000_phy_force_speed_duplex(struct e1000_shared_adapter *shared) +{ + uint32_t tctl_reg; + uint32_t ctrl_reg; + uint32_t shift; + uint16_t mii_ctrl_reg; + uint16_t mii_status_reg; + uint16_t phy_data; + uint16_t i; + + DEBUGFUNC("e1000_phy_force_speed_duplex"); + + /* Turn off Flow control if we are forcing speed and duplex. */ + shared->fc = e1000_fc_none; + + DEBUGOUT1("shared->fc = %d\n", shared->fc); + + /* Read the Device Control Register. */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + + /* Set the bits to Force Speed and Duplex in the Device Ctrl Reg. */ + ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); + ctrl_reg &= ~(DEVICE_SPEED_MASK); + + /* Clear the Auto Speed Detect Enable bit. */ + ctrl_reg &= ~E1000_CTRL_ASDE; + + /* Read the MII Control Register. */ + mii_ctrl_reg = e1000_read_phy_reg(shared, PHY_CTRL); + + /* We need to disable autoneg in order to force link and duplex. */ + + mii_ctrl_reg &= ~MII_CR_AUTO_NEG_EN; + + /* Are we forcing Full or Half Duplex? */ + if(shared->forced_speed_duplex == e1000_100_full || + shared->forced_speed_duplex == e1000_10_full) { + + /* We want to force full duplex so we SET the full duplex bits + * in the Device and MII Control Registers. + */ + ctrl_reg |= E1000_CTRL_FD; + mii_ctrl_reg |= MII_CR_FULL_DUPLEX; + + DEBUGOUT("Full Duplex\n"); + } else { + + /* We want to force half duplex so we CLEAR the full duplex + * bits in the Device and MII Control Registers. + */ + ctrl_reg &= ~E1000_CTRL_FD; + mii_ctrl_reg &= ~MII_CR_FULL_DUPLEX; /* Do this implies HALF */ + + DEBUGOUT("Half Duplex\n"); + } + + /* Are we forcing 100Mbps??? */ + if(shared->forced_speed_duplex == e1000_100_full || + shared->forced_speed_duplex == e1000_100_half) { + + /* Set the 100Mb bit and turn off the 1000Mb and 10Mb bits. */ + ctrl_reg |= E1000_CTRL_SPD_100; + mii_ctrl_reg |= MII_CR_SPEED_100; + mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10); + + DEBUGOUT("Forcing 100mb "); + } else { /* Force 10MB Full or Half */ + + /* Set the 10Mb bit and turn off the 1000Mb and 100Mb bits. */ + ctrl_reg &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); + mii_ctrl_reg |= MII_CR_SPEED_10; + mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100); + + DEBUGOUT("Forcing 10mb "); + } + + /* Now we need to configure the Collision Distance. We need to read + * the Transmit Control Register to do this. + * Note: This must be done for both Half or Full Duplex. + */ + tctl_reg = E1000_READ_REG(shared, TCTL); + DEBUGOUT1("tctl_reg = %x\n", tctl_reg); + + if(!(mii_ctrl_reg & MII_CR_FULL_DUPLEX)) { + + /* We are in Half Duplex mode so we need to set up our collision + * distance for 10/100. + */ + tctl_reg &= ~E1000_TCTL_COLD; + shift = E1000_HDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + } else { + /* We are in Full Duplex mode. We have the same collision + * distance regardless of speed. + */ + tctl_reg &= ~E1000_TCTL_COLD; + shift = E1000_FDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + } + + /* Write the configured values back to the Transmit Control Reg. */ + E1000_WRITE_REG(shared, TCTL, tctl_reg); + + /* Write the configured values back to the Device Control Reg. */ + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + /* Write the MII Control Register with the new PHY configuration. */ + phy_data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); + + /* Clear Auto-Crossover to force MDI manually. + * M88E1000 requires MDI forced whenever speed/duplex is forced + */ + phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; + + e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_data); + + DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data); + + /* Need to reset the PHY or these bits will get ignored. */ + mii_ctrl_reg |= MII_CR_RESET; + + e1000_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg); + + /* The wait_autoneg_complete flag may be a little misleading here. + * Since we are forcing speed and duplex, Auto-Neg is not enabled. + * But we do want to delay for a period while forcing only so we + * don't generate false No Link messages. So we will wait here + * only if the user has set wait_autoneg_complete to 1, which is + * the default. + */ + if(shared->wait_autoneg_complete) { + /* We will wait for autoneg to complete. */ + DEBUGOUT("Waiting for forced speed/duplex link.\n"); + mii_status_reg = 0; + + /* We will wait for autoneg to complete or 4.5 seconds to expire. */ + for(i = PHY_FORCE_TIME; i > 0; i--) { + /* Read the MII Status Register and wait for Auto-Neg + * Complete bit to be set. + */ + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + + if(mii_status_reg & MII_SR_LINK_STATUS) + break; + + msec_delay(100); + } /* end for loop */ + + if(i == 0) { /* We didn't get link */ + + /* Reset the DSP and wait again for link. */ + e1000_phy_reset_dsp(shared); + } + + /* This loop will early-out if the link condition has been met. */ + for(i = PHY_FORCE_TIME; i > 0; i--) { + if(mii_status_reg & MII_SR_LINK_STATUS) + break; + + msec_delay(100); + /* Read the MII Status Register and wait for Auto-Neg + * Complete bit to be set. + */ + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + + } /* end for loop */ + } /* end if wait_autoneg_complete */ + /* + * Because we reset the PHY above, we need to re-force TX_CLK in the + * Extended PHY Specific Control Register to 25MHz clock. This + * value defaults back to a 2.5MHz clock when the PHY is reset. + */ + phy_data = e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL); + + phy_data |= M88E1000_EPSCR_TX_CLK_25; + + e1000_write_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL, phy_data); + + /* In addition, because of the s/w reset above, we need to enable + * CRS on TX. This must be set for both full and half duplex + * operation. + */ + phy_data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); + + phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; + + e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_data); + DEBUGOUT1("M88E1000 Phy Specific Ctrl Reg = %4x\r\n", phy_data); + + return; +} + +/***************************************************************************** +* Reads the value from a PHY register +* +* shared - Struct containing variables accessed by shared code +* reg_addr - address of the PHY register to read +******************************************************************************/ +uint16_t +e1000_read_phy_reg(struct e1000_shared_adapter *shared, + uint32_t reg_addr) +{ + uint32_t i; + uint32_t data = 0; + uint32_t command = 0; + + ASSERT(reg_addr <= MAX_PHY_REG_ADDRESS); + + if(shared->mac_type > e1000_82543) { + /* Set up Op-code, Phy Address, and + * register address in the MDI Control register. The MAC will + * take care of interfacing with the PHY to retrieve the + * desired data. + */ + command = ((reg_addr << E1000_MDIC_REG_SHIFT) | + (shared->phy_addr << E1000_MDIC_PHY_SHIFT) | + (E1000_MDIC_OP_READ)); + + E1000_WRITE_REG(shared, MDIC, command); + + /* Check every 10 usec to see if the read completed. The read + * may take as long as 64 usecs (we'll wait 100 usecs max) + * from the CPU Write to the Ready bit assertion. + */ + for(i = 0; i < 64; i++) { + usec_delay(10); + + data = E1000_READ_REG(shared, MDIC); + + if(data & E1000_MDIC_READY) + break; + } + } else { + /* We must first send a preamble through the MDIO pin to signal the + * beginning of an MII instruction. This is done by sending 32 + * consecutive "1" bits. + */ + e1000_phy_shift_out(shared, PHY_PREAMBLE, PHY_PREAMBLE_SIZE); + + /* Now combine the next few fields that are required for a read + * operation. We use this method instead of calling the + * e1000_phy_shift_out routine five different times. The format of + * a MII read instruction consists of a shift out of 14 bits and is + * defined as follows: + * + * followed by a shift in of 18 bits. This first two bits shifted + * in are TurnAround bits used to avoid contention on the MDIO pin + * when a READ operation is performed. These two bits are thrown + * away followed by a shift in of 16 bits which contains the + * desired data. + */ + command = ((reg_addr) | + (shared->phy_addr << 5) | + (PHY_OP_READ << 10) | (PHY_SOF << 12)); + + e1000_phy_shift_out(shared, command, 14); + + /* Now that we've shifted out the read command to the MII, we need + * to "shift in" the 16-bit value (18 total bits) of the requested + * PHY register address. + */ + data = (uint32_t) e1000_phy_shift_in(shared); + } + + ASSERT(!(data & E1000_MDIC_ERROR)); + + return ((uint16_t) data); +} + +/****************************************************************************** +* Writes a value to a PHY register +* +* shared - Struct containing variables accessed by shared code +* reg_addr - address of the PHY register to write +* data - data to write to the PHY +******************************************************************************/ +void +e1000_write_phy_reg(struct e1000_shared_adapter *shared, + uint32_t reg_addr, + uint16_t data) +{ + uint32_t i; + uint32_t command = 0; + uint32_t mdic_reg; + + ASSERT(reg_addr <= MAX_PHY_REG_ADDRESS); + + if(shared->mac_type > e1000_82543) { + /* Set up Op-code, Phy Address, register + * address, and data intended for the PHY register in the MDI + * Control register. The MAC will take care of interfacing + * with the PHY to send the desired data. + */ + command = (((uint32_t) data) | + (reg_addr << E1000_MDIC_REG_SHIFT) | + (shared->phy_addr << E1000_MDIC_PHY_SHIFT) | + (E1000_MDIC_OP_WRITE)); + + E1000_WRITE_REG(shared, MDIC, command); + + /* Check every 10 usec to see if the read completed. The read + * may take as long as 64 usecs (we'll wait 100 usecs max) + * from the CPU Write to the Ready bit assertion. + */ + for(i = 0; i < 10; i++) { + usec_delay(10); + + mdic_reg = E1000_READ_REG(shared, MDIC); + + if(mdic_reg & E1000_MDIC_READY) + break; + } + } else { + /* We'll need to use the SW defined pins to shift the write command + * out to the PHY. We first send a preamble to the PHY to signal the + * beginning of the MII instruction. This is done by sending 32 + * consecutive "1" bits. + */ + e1000_phy_shift_out(shared, PHY_PREAMBLE, PHY_PREAMBLE_SIZE); + + /* Now combine the remaining required fields that will indicate + * a write operation. We use this method instead of calling the + * e1000_phy_shift_out routine for each field in the command. The + * format of a MII write instruction is as follows: + * . + */ + command = ((PHY_TURNAROUND) | + (reg_addr << 2) | + (shared->phy_addr << 7) | + (PHY_OP_WRITE << 12) | (PHY_SOF << 14)); + command <<= 16; + command |= ((uint32_t) data); + + e1000_phy_shift_out(shared, command, 32); + } + return; +} + +/****************************************************************************** +* Returns the PHY to the power-on reset state +* +* shared - Struct containing variables accessed by shared code +******************************************************************************/ +void +e1000_phy_hw_reset(struct e1000_shared_adapter *shared) +{ + uint32_t ctrl_reg; + uint32_t ctrl_ext_reg; + + DEBUGFUNC("e1000_phy_hw_reset"); + + DEBUGOUT("Resetting Phy...\n"); + + if(shared->mac_type > e1000_82543) { + /* Read the device control register and assert the + * E1000_CTRL_PHY_RST bit. Hold for 20ms and then take it out + * of reset. + */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + + ctrl_reg |= E1000_CTRL_PHY_RST; + + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + msec_delay(20); + + ctrl_reg &= ~E1000_CTRL_PHY_RST; + + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + msec_delay(20); + } else { + /* Read the Extended Device Control Register, assert the + * PHY_RESET_DIR bit. Then clock it out to the PHY. + */ + ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT); + + ctrl_ext_reg |= E1000_CTRL_PHY_RESET_DIR4; + + E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg); + + msec_delay(20); + + /* Set the reset bit in the device control register and clock + * it out to the PHY. + */ + ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT); + + ctrl_ext_reg &= ~E1000_CTRL_PHY_RESET4; + + E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg); + + msec_delay(20); + + ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT); + + ctrl_ext_reg |= E1000_CTRL_PHY_RESET4; + + E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg); + + msec_delay(20); + } + return; +} + +/****************************************************************************** +* Resets the PHY +* +* shared - Struct containing variables accessed by shared code +* +* Sets bit 15 of the MII Control regiser +******************************************************************************/ +boolean_t +e1000_phy_reset(struct e1000_shared_adapter *shared) +{ + uint16_t reg_data; + uint16_t i; + + DEBUGFUNC("e1000_phy_reset"); + + /* Read the MII control register, set the reset bit and write the + * value back by clocking it out to the PHY. + */ + reg_data = e1000_read_phy_reg(shared, PHY_CTRL); + + reg_data |= MII_CR_RESET; + + e1000_write_phy_reg(shared, PHY_CTRL, reg_data); + + /* Wait for bit 15 of the MII Control Register to be cleared + * indicating the PHY has been reset. + */ + i = 0; + while((reg_data & MII_CR_RESET) && i++ < 500) { + reg_data = e1000_read_phy_reg(shared, PHY_CTRL); + usec_delay(1); + } + + if(i >= 500) { + DEBUGOUT("Timeout waiting for PHY to reset.\n"); + return FALSE; + } + return TRUE; +} + +/****************************************************************************** +* Detects which PHY is present and the speed and duplex +* +* shared - Struct containing variables accessed by shared code +* ctrl_reg - current value of the device control register +******************************************************************************/ +boolean_t +e1000_phy_setup(struct e1000_shared_adapter *shared, + uint32_t ctrl_reg) +{ + uint16_t mii_ctrl_reg; + uint16_t mii_status_reg; + uint16_t phy_specific_ctrl_reg; + uint16_t mii_autoneg_adv_reg; + uint16_t mii_1000t_ctrl_reg; + uint16_t i; + uint16_t data; + uint16_t autoneg_hw_setting; + uint16_t autoneg_fc_setting; + boolean_t restart_autoneg = FALSE; + boolean_t force_autoneg_restart = FALSE; + + DEBUGFUNC("e1000_phy_setup"); + + /* We want to enable the Auto-Speed Detection bit in the Device + * Control Register. When set to 1, the MAC automatically detects + * the resolved speed of the link and self-configures appropriately. + * The Set Link Up bit must also be set for this behavior work + * properly. + */ + /* Nothing but 82543 and newer */ + ASSERT(shared->mac_type >= e1000_82543); + + /* With 82543, we need to force speed/duplex + * on the MAC equal to what the PHY speed/duplex configuration is. + * In addition, on 82543, we need to perform a hardware reset + * on the PHY to take it out of reset. + */ + if(shared->mac_type >= e1000_82544) { + ctrl_reg |= E1000_CTRL_SLU; + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + } else { + ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU); + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + if(shared->mac_type == e1000_82543) + e1000_phy_hw_reset(shared); + } + + if(!e1000_detect_gig_phy(shared)) { + /* No PHY detected, return FALSE */ + DEBUGOUT("PhySetup failure, did not detect valid phy.\n"); + return (FALSE); + } + + DEBUGOUT1("Phy ID = %x \n", shared->phy_id); + + /* Read the MII Control Register. */ + mii_ctrl_reg = e1000_read_phy_reg(shared, PHY_CTRL); + + DEBUGOUT1("MII Ctrl Reg contents = %x\n", mii_ctrl_reg); + + /* Check to see if the Auto Neg Enable bit is set in the MII Control + * Register. If not, we could be in a situation where a driver was + * loaded previously and was forcing speed and duplex. Then the + * driver was unloaded but a e1000_phy_hw_reset was not performed, so + * link was still being forced and link was still achieved. Then + * the driver was reloaded with the intention to auto-negotiate, but + * since link is already established we end up not restarting + * auto-neg. So if the auto-neg bit is not enabled and the driver + * is being loaded with the desire to auto-neg, we set this flag to + * to ensure the restart of the auto-neg engine later in the logic. + */ + if(!(mii_ctrl_reg & MII_CR_AUTO_NEG_EN)) + force_autoneg_restart = TRUE; + + /* Clear the isolate bit for normal operation and write it back to + * the MII Control Reg. Although the spec says this doesn't need + * to be done when the PHY address is not equal to zero, we do it + * anyway just to be safe. + */ + mii_ctrl_reg &= ~(MII_CR_ISOLATE); + + e1000_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg); + + data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); + + /* Enable CRS on TX. This must be set for half-duplex operation. */ + data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; + + DEBUGOUT1("M88E1000 PSCR: %x \n", data); + + e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, data); + + data = e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL); + + /* Force TX_CLK in the Extended PHY Specific Control Register + * to 25MHz clock. + */ + data |= M88E1000_EPSCR_TX_CLK_25; + + e1000_write_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL, data); + + /* Certain PHYs will set the default of MII register 4 differently. + * We need to check this against our fc value. If it is + * different, we need to setup up register 4 correctly and restart + * autonegotiation. + */ + /* Read the MII Auto-Neg Advertisement Register (Address 4). */ + mii_autoneg_adv_reg = e1000_read_phy_reg(shared, PHY_AUTONEG_ADV); + + /* Shift right to put 10T-Half bit in bit 0 + * Isolate the four bits for 100/10 Full/Half. + */ + autoneg_hw_setting = (mii_autoneg_adv_reg >> 5) & 0xF; + + /* Get the 1000T settings. */ + mii_1000t_ctrl_reg = e1000_read_phy_reg(shared, PHY_1000T_CTRL); + + /* Isolate and OR in the 1000T settings. */ + autoneg_hw_setting |= ((mii_1000t_ctrl_reg & 0x0300) >> 4); + + /* mask all bits in the MII Auto-Neg Advertisement Register + * except for ASM_DIR and PAUSE and shift. This value + * will be used later to see if we need to restart Auto-Negotiation. + */ + autoneg_fc_setting = ((mii_autoneg_adv_reg & 0x0C00) >> 10); + + /* Perform some bounds checking on the shared->autoneg_advertised + * parameter. If this variable is zero, then set it to the default. + */ + shared->autoneg_advertised &= AUTONEG_ADVERTISE_SPEED_DEFAULT; + + /* If autoneg_advertised is zero, we assume it was not defaulted + * by the calling code so we set to advertise full capability. + */ + if(shared->autoneg_advertised == 0) + shared->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT; + + /* We could be in the situation where Auto-Neg has already completed + * and the user has not indicated any overrides. In this case we + * simply need to call e1000_get_speed_and_duplex to obtain the Auto- + * Negotiated speed and duplex, then return. + */ + if(!force_autoneg_restart && shared->autoneg && + (shared->autoneg_advertised == autoneg_hw_setting) && + (shared->fc == autoneg_fc_setting)) { + + DEBUGOUT("No overrides - Reading MII Status Reg..\n"); + + /* Read the MII Status Register. We read this twice because + * certain bits are "sticky" and need to be read twice. + */ + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + + DEBUGOUT1("MII Status Reg contents = %x\n", mii_status_reg); + + /* Do we have link now? (if so, auto-neg has completed) */ + if(mii_status_reg & MII_SR_LINK_STATUS) { + data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS); + DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", data); + + /* We have link, so we need to finish the config process: + * 1) Set up the MAC to the current PHY speed/duplex + * if we are on 82543. If we + * are on newer silicon, we only need to configure + * collision distance in the Transmit Control Register. + * 2) Set up flow control on the MAC to that established + * with the link partner. + */ + if(shared->mac_type >= e1000_82544) + e1000_config_collision_dist(shared); + else + e1000_config_mac_to_phy(shared, data); + + e1000_config_fc_after_link_up(shared); + + return (TRUE); + } + } + + /* Options: + * MDI/MDI-X = 0 (default) + * 0 - Auto for all speeds + * 1 - MDI mode + * 2 - MDI-X mode + * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) + */ + phy_specific_ctrl_reg = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); + + phy_specific_ctrl_reg &= ~M88E1000_PSCR_AUTO_X_MODE; + + switch (shared->mdix) { + case 1: + phy_specific_ctrl_reg |= M88E1000_PSCR_MDI_MANUAL_MODE; + break; + case 2: + phy_specific_ctrl_reg |= M88E1000_PSCR_MDIX_MANUAL_MODE; + break; + case 3: + phy_specific_ctrl_reg |= M88E1000_PSCR_AUTO_X_1000T; + break; + case 0: + default: + phy_specific_ctrl_reg |= M88E1000_PSCR_AUTO_X_MODE; + break; + } + + e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_specific_ctrl_reg); + + /* Options: + * disable_polarity_correction = 0 (default) + * Automatic Correction for Reversed Cable Polarity + * 0 - Disabled + * 1 - Enabled + */ + phy_specific_ctrl_reg = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); + + phy_specific_ctrl_reg &= ~M88E1000_PSCR_POLARITY_REVERSAL; + + if(shared->disable_polarity_correction == 1) + phy_specific_ctrl_reg |= M88E1000_PSCR_POLARITY_REVERSAL; + + e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_specific_ctrl_reg); + + /* Options: + * autoneg = 1 (default) + * PHY will advertise value(s) parsed from + * autoneg_advertised and fc + * autoneg = 0 + * PHY will be set to 10H, 10F, 100H, or 100F + * depending on value parsed from forced_speed_duplex. + */ + + /* Is autoneg enabled? This is enabled by default or by software override. + * If so, call e1000_phy_setup_autoneg routine to parse the + * autoneg_advertised and fc options. If autoneg is NOT enabled, then the + * user should have provided a speed/duplex override. If so, then call + * e1000_phy_force_speed_duplex to parse and set this up. Otherwise, + * we are in an error situation and need to bail. + */ + if(shared->autoneg) { + DEBUGOUT("Reconfiguring auto-neg advertisement params\n"); + restart_autoneg = e1000_phy_setup_autoneg(shared); + } else { + DEBUGOUT("Forcing speed and duplex\n"); + e1000_phy_force_speed_duplex(shared); + } + + /* Based on information parsed above, check the flag to indicate + * whether we need to restart Auto-Neg. + */ + if(restart_autoneg) { + DEBUGOUT("Restarting Auto-Neg\n"); + + /* Read the MII Control Register. */ + mii_ctrl_reg = e1000_read_phy_reg(shared, PHY_CTRL); + + /* Restart auto-negotiation by setting the Auto Neg Enable bit and + * the Auto Neg Restart bit. + */ + mii_ctrl_reg |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); + + e1000_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg); + + /* Does the user want to wait for Auto-Neg to complete here, or + * check at a later time (for example, callback routine). + */ + if(shared->wait_autoneg_complete) + e1000_wait_autoneg(shared); + } /* end if restart_autoneg */ + + /* Read the MII Status Register. */ + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + + DEBUGOUT1("Checking for link status - MII Status Reg contents = %x\n", + mii_status_reg); + + /* Check link status. Wait up to 100 microseconds for link to + * become valid. + */ + for(i = 0; i < 10; i++) { + if(mii_status_reg & MII_SR_LINK_STATUS) + break; + usec_delay(10); + DEBUGOUT(". "); + + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + } + + if(mii_status_reg & MII_SR_LINK_STATUS) { + /* Yes, so configure MAC to PHY settings as well as flow control + * registers. + */ + data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS); + + DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", data); + + /* We have link, so we need to finish the config process: + * 1) Set up the MAC to the current PHY speed/duplex + * if we are on 82543. If we + * are on newer silicon, we only need to configure + * collision distance in the Transmit Control Register. + * 2) Set up flow control on the MAC to that established with + * the link partner. + */ + if(shared->mac_type >= e1000_82544) + e1000_config_collision_dist(shared); + else + e1000_config_mac_to_phy(shared, data); + + e1000_config_fc_after_link_up(shared); + + DEBUGOUT("Valid link established!!!\n"); + } else { + DEBUGOUT("Unable to establish link!!!\n"); + } + + return (TRUE); +} + +/****************************************************************************** +* Configures PHY autoneg and flow control advertisement settings +* +* shared - Struct containing variables accessed by shared code +******************************************************************************/ +boolean_t +e1000_phy_setup_autoneg(struct e1000_shared_adapter *shared) +{ + uint16_t mii_autoneg_adv_reg; + uint16_t mii_1000t_ctrl_reg; + + DEBUGFUNC("e1000_phy_setup_autoneg"); + + /* Read the MII Auto-Neg Advertisement Register (Address 4). */ + mii_autoneg_adv_reg = e1000_read_phy_reg(shared, PHY_AUTONEG_ADV); + + /* Read the MII 1000Base-T Control Register (Address 9). */ + mii_1000t_ctrl_reg = e1000_read_phy_reg(shared, PHY_1000T_CTRL); + + /* Need to parse both autoneg_advertised and fc and set up + * the appropriate PHY registers. First we will parse for + * autoneg_advertised software override. Since we can advertise + * a plethora of combinations, we need to check each bit + * individually. + */ + + /* First we clear all the 10/100 mb speed bits in the Auto-Neg + * Advertisement Register (Address 4) and the 1000 mb speed bits in + * the 1000Base-T Control Register (Address 9). + */ + mii_autoneg_adv_reg &= ~REG4_SPEED_MASK; + mii_1000t_ctrl_reg &= ~REG9_SPEED_MASK; + + DEBUGOUT1("autoneg_advertised %x\n", shared->autoneg_advertised); + + /* Do we want to advertise 10 Mb Half Duplex? */ + if(shared->autoneg_advertised & ADVERTISE_10_HALF) { + DEBUGOUT("Advertise 10mb Half duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS; + } + + /* Do we want to advertise 10 Mb Full Duplex? */ + if(shared->autoneg_advertised & ADVERTISE_10_FULL) { + DEBUGOUT("Advertise 10mb Full duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS; + } + + /* Do we want to advertise 100 Mb Half Duplex? */ + if(shared->autoneg_advertised & ADVERTISE_100_HALF) { + DEBUGOUT("Advertise 100mb Half duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS; + } + + /* Do we want to advertise 100 Mb Full Duplex? */ + if(shared->autoneg_advertised & ADVERTISE_100_FULL) { + DEBUGOUT("Advertise 100mb Full duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS; + } + + /* We do not allow the Phy to advertise 1000 Mb Half Duplex */ + if(shared->autoneg_advertised & ADVERTISE_1000_HALF) { + DEBUGOUT("Advertise 1000mb Half duplex requested, request denied!\n"); + } + + /* Do we want to advertise 1000 Mb Full Duplex? */ + if(shared->autoneg_advertised & ADVERTISE_1000_FULL) { + DEBUGOUT("Advertise 1000mb Full duplex\n"); + mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS; + } + + /* Check for a software override of the flow control settings, and + * setup the PHY advertisement registers accordingly. If + * auto-negotiation is enabled, then software will have to set the + * "PAUSE" bits to the correct value in the Auto-Negotiation + * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-negotiation. + * + * The possible values of the "fc" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames + * but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames + * but we do not support receiving pause frames). + * 3: Both Rx and TX flow control (symmetric) are enabled. + * other: No software override. The flow control configuration + * in the EEPROM is used. + */ + switch (shared->fc) { + case e1000_fc_none: /* 0 */ + /* Flow control (RX & TX) is completely disabled by a + * software over-ride. + */ + mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + case e1000_fc_rx_pause: /* 1 */ + /* RX Flow control is enabled, and TX Flow control is + * disabled, by a software over-ride. + */ + + /* Since there really isn't a way to advertise that we are + * capable of RX Pause ONLY, we will advertise that we + * support both symmetric and asymmetric RX PAUSE. Later + * (in e1000_config_fc_after_link_up) we will disable the + *shared's ability to send PAUSE frames. + */ + mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + case e1000_fc_tx_pause: /* 2 */ + /* TX Flow control is enabled, and RX Flow control is + * disabled, by a software over-ride. + */ + mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR; + mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE; + break; + case e1000_fc_full: /* 3 */ + /* Flow control (both RX and TX) is enabled by a software + * over-ride. + */ + mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + default: + /* We should never get here. The value should be 0-3. */ + DEBUGOUT("Flow control param set incorrectly\n"); + ASSERT(0); + break; + } + + /* Write the MII Auto-Neg Advertisement Register (Address 4). */ + e1000_write_phy_reg(shared, PHY_AUTONEG_ADV, mii_autoneg_adv_reg); + + DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); + + /* Write the MII 1000Base-T Control Register (Address 9). */ + e1000_write_phy_reg(shared, PHY_1000T_CTRL, mii_1000t_ctrl_reg); + return (TRUE); +} + +/****************************************************************************** +* Sets MAC speed and duplex settings to reflect the those in the PHY +* +* shared - Struct containing variables accessed by shared code +* mii_reg - data to write to the MII control register +* +* The contents of the PHY register containing the needed information need to +* be passed in. +******************************************************************************/ +void +e1000_config_mac_to_phy(struct e1000_shared_adapter *shared, + uint16_t mii_reg) +{ + uint32_t ctrl_reg; + uint32_t tctl_reg; + uint32_t shift; + + DEBUGFUNC("e1000_config_mac_to_phy"); + + /* We need to read the Transmit Control register to configure the + * collision distance. + * Note: This must be done for both Half or Full Duplex. + */ + tctl_reg = E1000_READ_REG(shared, TCTL); + DEBUGOUT1("tctl_reg = %x\n", tctl_reg); + + /* Read the Device Control Register and set the bits to Force Speed + * and Duplex. + */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + + ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); + ctrl_reg &= ~(DEVICE_SPEED_MASK); + + DEBUGOUT1("MII Register Data = %x\r\n", mii_reg); + + /* Clear the ILOS bit. */ + ctrl_reg &= ~E1000_CTRL_ILOS; + + /* Set up duplex in the Device Control and Transmit Control + * registers depending on negotiated values. + */ + if(mii_reg & M88E1000_PSSR_DPLX) { + ctrl_reg |= E1000_CTRL_FD; + + /* We are in Full Duplex mode. We have the same collision + * distance regardless of speed. + */ + tctl_reg &= ~E1000_TCTL_COLD; + shift = E1000_FDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + } else { + ctrl_reg &= ~E1000_CTRL_FD; + + /* We are in Half Duplex mode. Our Half Duplex collision + * distance is different for Gigabit than for 10/100 so we will + * set accordingly. + */ + if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) { + /* 1000Mbs HDX */ + tctl_reg &= ~E1000_TCTL_COLD; + shift = E1000_GB_HDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + tctl_reg |= E1000_TCTL_PBE; /* Enable Packet Bursting */ + } else { + /* 10/100Mbs HDX */ + tctl_reg &= ~E1000_TCTL_COLD; + shift = E1000_HDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + } + } + + /* Set up speed in the Device Control register depending on + * negotiated values. + */ + if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) + ctrl_reg |= E1000_CTRL_SPD_1000; + else if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS) + ctrl_reg |= E1000_CTRL_SPD_100; + else + ctrl_reg &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); + + /* Write the configured values back to the Transmit Control Reg. */ + E1000_WRITE_REG(shared, TCTL, tctl_reg); + + /* Write the configured values back to the Device Control Reg. */ + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + return; +} + +/****************************************************************************** +* Sets the collision distance in the Transmit Control register +* +* shared - Struct containing variables accessed by shared code +* +* Link should have been established previously. Reads the speed and duplex +* information from the Device Status register. +******************************************************************************/ +void +e1000_config_collision_dist(struct e1000_shared_adapter *shared) +{ + uint32_t tctl_reg; + uint16_t speed; + uint16_t duplex; + uint32_t shift; + + DEBUGFUNC("e1000_config_collision_dist"); + + /* Get our current speed and duplex from the Device Status Register. */ + e1000_get_speed_and_duplex(shared, &speed, &duplex); + + /* We need to configure the Collision Distance for both Full or + * Half Duplex. + */ + tctl_reg = E1000_READ_REG(shared, TCTL); + DEBUGOUT1("tctl_reg = %x\n", tctl_reg); + + /* mask the Collision Distance bits in the Transmit Control Reg. */ + tctl_reg &= ~E1000_TCTL_COLD; + + if(duplex == FULL_DUPLEX) { + /* We are in Full Duplex mode. Therefore, the collision distance + * is the same regardless of speed. + */ + shift = E1000_FDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + } else { + /* We are in Half Duplex mode. Half Duplex collision distance is + * different for Gigabit vs. 10/100, so we will set accordingly. + */ + if(speed == SPEED_1000) { /* 1000Mbs HDX */ + shift = E1000_GB_HDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + tctl_reg |= E1000_TCTL_PBE; /* Enable Packet Bursting */ + } else { /* 10/100Mbs HDX */ + shift = E1000_HDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + } + } + + /* Write the configured values back to the Transmit Control Reg. */ + E1000_WRITE_REG(shared, TCTL, tctl_reg); + + return; +} + +/****************************************************************************** +* Probes the expected PHY address for known PHY IDs +* +* shared - Struct containing variables accessed by shared code +******************************************************************************/ +boolean_t +e1000_detect_gig_phy(struct e1000_shared_adapter *shared) +{ + uint32_t phy_id_high; + uint16_t phy_id_low; + + DEBUGFUNC("e1000_detect_gig_phy"); + + /* Read the PHY ID Registers to identify which PHY is onboard. */ + shared->phy_addr = 1; + + phy_id_high = e1000_read_phy_reg(shared, PHY_ID1); + + usec_delay(2); + + phy_id_low = e1000_read_phy_reg(shared, PHY_ID2); + + shared->phy_id = (phy_id_low | (phy_id_high << 16)) & PHY_REVISION_MASK; + + if(shared->phy_id == M88E1000_12_PHY_ID || + shared->phy_id == M88E1000_14_PHY_ID || + shared->phy_id == M88E1000_I_PHY_ID) { + + DEBUGOUT2("phy_id 0x%x detected at address 0x%x\n", + shared->phy_id, shared->phy_addr); + return (TRUE); + } else { + DEBUGOUT("Could not auto-detect Phy!\n"); + return (FALSE); + } +} + +/****************************************************************************** +* Resets the PHY's DSP +* +* shared - Struct containing variables accessed by shared code +******************************************************************************/ +void +e1000_phy_reset_dsp(struct e1000_shared_adapter *shared) +{ + e1000_write_phy_reg(shared, 29, 0x1d); + e1000_write_phy_reg(shared, 30, 0xc1); + e1000_write_phy_reg(shared, 30, 0x00); + return; +} + +/****************************************************************************** +* Blocks until autoneg completes or times out (~4.5 seconds) +* +* shared - Struct containing variables accessed by shared code +******************************************************************************/ +boolean_t +e1000_wait_autoneg(struct e1000_shared_adapter *shared) +{ + uint16_t i; + uint16_t mii_status_reg; + boolean_t autoneg_complete = FALSE; + + DEBUGFUNC("e1000_wait_autoneg"); + + /* We will wait for autoneg to complete. */ + DEBUGOUT("Waiting for Auto-Neg to complete.\n"); + mii_status_reg = 0; + + /* We will wait for autoneg to complete or 4.5 seconds to expire. */ + + for(i = PHY_AUTO_NEG_TIME; i > 0; i--) { + /* Read the MII Status Register and wait for Auto-Neg + * Complete bit to be set. + */ + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + + if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) { + autoneg_complete = TRUE; + break; + } + + msec_delay(100); + } + + return (autoneg_complete); +} + +/****************************************************************************** +* Get PHY information from various PHY registers +* +* shared - Struct containing variables accessed by shared code +* phy_status_info - PHY information structure +******************************************************************************/ +boolean_t +e1000_phy_get_info(struct e1000_shared_adapter *shared, + struct e1000_phy_info *phy_status_info) +{ + uint16_t phy_mii_status_reg; + uint16_t phy_specific_ctrl_reg; + uint16_t phy_specific_status_reg; + uint16_t phy_specific_ext_ctrl_reg; + uint16_t phy_1000t_stat_reg; + + phy_status_info->cable_length = e1000_cable_length_undefined; + phy_status_info->extended_10bt_distance = + e1000_10bt_ext_dist_enable_undefined; + phy_status_info->cable_polarity = e1000_rev_polarity_undefined; + phy_status_info->polarity_correction = e1000_polarity_reversal_undefined; + phy_status_info->link_reset = e1000_down_no_idle_undefined; + phy_status_info->mdix_mode = e1000_auto_x_mode_undefined; + phy_status_info->local_rx = e1000_1000t_rx_status_undefined; + phy_status_info->remote_rx = e1000_1000t_rx_status_undefined; + + /* PHY info only valid for copper media. */ + if(shared == NULL || shared->media_type != e1000_media_type_copper) + return FALSE; + + /* PHY info only valid for LINK UP. Read MII status reg + * back-to-back to get link status. + */ + phy_mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + phy_mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + if((phy_mii_status_reg & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) + return FALSE; + + /* Read various PHY registers to get the PHY info. */ + phy_specific_ctrl_reg = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); + phy_specific_status_reg = + e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS); + phy_specific_ext_ctrl_reg = + e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL); + phy_1000t_stat_reg = e1000_read_phy_reg(shared, PHY_1000T_STATUS); + + phy_status_info->cable_length = + ((phy_specific_status_reg & M88E1000_PSSR_CABLE_LENGTH) >> + M88E1000_PSSR_CABLE_LENGTH_SHIFT); + + phy_status_info->extended_10bt_distance = + (phy_specific_ctrl_reg & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >> + M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT; + + phy_status_info->cable_polarity = + (phy_specific_status_reg & M88E1000_PSSR_REV_POLARITY) >> + M88E1000_PSSR_REV_POLARITY_SHIFT; + + phy_status_info->polarity_correction = + (phy_specific_ctrl_reg & M88E1000_PSCR_POLARITY_REVERSAL) >> + M88E1000_PSCR_POLARITY_REVERSAL_SHIFT; + + phy_status_info->link_reset = + (phy_specific_ext_ctrl_reg & M88E1000_EPSCR_DOWN_NO_IDLE) >> + M88E1000_EPSCR_DOWN_NO_IDLE_SHIFT; + + phy_status_info->mdix_mode = + (phy_specific_status_reg & M88E1000_PSSR_MDIX) >> + M88E1000_PSSR_MDIX_SHIFT; + + phy_status_info->local_rx = + (phy_1000t_stat_reg & SR_1000T_LOCAL_RX_STATUS) >> + SR_1000T_LOCAL_RX_STATUS_SHIFT; + + phy_status_info->remote_rx = + (phy_1000t_stat_reg & SR_1000T_REMOTE_RX_STATUS) >> + SR_1000T_REMOTE_RX_STATUS_SHIFT; + + return TRUE; +} + +boolean_t +e1000_validate_mdi_setting(struct e1000_shared_adapter *shared) +{ + if(!shared->autoneg && (shared->mdix == 0 || shared->mdix == 3)) { + shared->mdix = 1; + return FALSE; + } + return TRUE; +} diff -Nru a/drivers/net/e1000/e1000_phy.h b/drivers/net/e1000/e1000_phy.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/e1000/e1000_phy.h Tue Feb 26 11:58:00 2002 @@ -0,0 +1,422 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/* e1000_phy.h + * Structures, enums, and macros for the PHY + */ + +#ifndef _E1000_PHY_H_ +#define _E1000_PHY_H_ + +#include "e1000_osdep.h" + +/* PHY status info structure and supporting enums */ +typedef enum { + e1000_cable_length_50 = 0, + e1000_cable_length_50_80, + e1000_cable_length_80_110, + e1000_cable_length_110_140, + e1000_cable_length_140, + e1000_cable_length_undefined = 0xFF +} e1000_cable_length; + +typedef enum { + e1000_10bt_ext_dist_enable_normal = 0, + e1000_10bt_ext_dist_enable_lower, + e1000_10bt_ext_dist_enable_undefined = 0xFF +} e1000_10bt_ext_dist_enable; + +typedef enum { + e1000_rev_polarity_normal = 0, + e1000_rev_polarity_reversed, + e1000_rev_polarity_undefined = 0xFF +} e1000_rev_polarity; + +typedef enum { + e1000_polarity_reversal_enabled = 0, + e1000_polarity_reversal_disabled, + e1000_polarity_reversal_undefined = 0xFF +} e1000_polarity_reversal; + +typedef enum { + e1000_down_no_idle_no_detect = 0, + e1000_down_no_idle_detect, + e1000_down_no_idle_undefined = 0xFF +} e1000_down_no_idle; + +typedef enum { + e1000_auto_x_mode_manual_mdi = 0, + e1000_auto_x_mode_manual_mdix, + e1000_auto_x_mode_auto1, + e1000_auto_x_mode_auto2, + e1000_auto_x_mode_undefined = 0xFF +} e1000_auto_x_mode; + +typedef enum { + e1000_1000t_rx_status_not_ok = 0, + e1000_1000t_rx_status_ok, + e1000_1000t_rx_status_undefined = 0xFF +} e1000_1000t_rx_status; + +struct e1000_phy_info { + e1000_cable_length cable_length; + e1000_10bt_ext_dist_enable extended_10bt_distance; + e1000_rev_polarity cable_polarity; + e1000_polarity_reversal polarity_correction; + e1000_down_no_idle link_reset; + e1000_auto_x_mode mdix_mode; + e1000_1000t_rx_status local_rx; + e1000_1000t_rx_status remote_rx; +}; + +struct e1000_phy_stats { + uint32_t idle_errors; + uint32_t receive_errors; +}; + +/* Function Prototypes */ +uint16_t e1000_read_phy_reg(struct e1000_shared_adapter *shared, uint32_t reg_addr); +void e1000_write_phy_reg(struct e1000_shared_adapter *shared, uint32_t reg_addr, uint16_t data); +void e1000_phy_hw_reset(struct e1000_shared_adapter *shared); +boolean_t e1000_phy_reset(struct e1000_shared_adapter *shared); +boolean_t e1000_phy_setup(struct e1000_shared_adapter *shared, uint32_t ctrl_reg); +boolean_t e1000_phy_setup_autoneg(struct e1000_shared_adapter *shared); +void e1000_config_mac_to_phy(struct e1000_shared_adapter *shared, uint16_t mii_reg); +void e1000_config_collision_dist(struct e1000_shared_adapter *shared); +boolean_t e1000_detect_gig_phy(struct e1000_shared_adapter *shared); +void e1000_phy_reset_dsp(struct e1000_shared_adapter *shared); +boolean_t e1000_wait_autoneg(struct e1000_shared_adapter *shared); +boolean_t e1000_phy_get_info(struct e1000_shared_adapter *shared, struct e1000_phy_info *phy_status_info); +boolean_t e1000_validate_mdi_setting(struct e1000_shared_adapter *shared); + +/* Bit definitions for the Management Data IO (MDIO) and Management Data + * Clock (MDC) pins in the Device Control Register. + */ +#define E1000_CTRL_PHY_RESET_DIR E1000_CTRL_SWDPIO0 +#define E1000_CTRL_PHY_RESET E1000_CTRL_SWDPIN0 +#define E1000_CTRL_MDIO_DIR E1000_CTRL_SWDPIO2 +#define E1000_CTRL_MDIO E1000_CTRL_SWDPIN2 +#define E1000_CTRL_MDC_DIR E1000_CTRL_SWDPIO3 +#define E1000_CTRL_MDC E1000_CTRL_SWDPIN3 +#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR +#define E1000_CTRL_PHY_RESET4 E1000_CTRL_EXT_SDP4_DATA + +/* PHY 1000 MII Register/Bit Definitions */ +/* PHY Registers defined by IEEE */ +#define PHY_CTRL 0x00 /* Control Register */ +#define PHY_STATUS 0x01 /* Status Regiser */ +#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */ +#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */ +#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */ +#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */ +#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */ +#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */ +#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */ +#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */ +#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ +#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */ + +/* M88E1000 Specific Registers */ +#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */ +#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */ +#define M88E1000_INT_ENABLE 0x12 /* Interrupt Enable Register */ +#define M88E1000_INT_STATUS 0x13 /* Interrupt Status Register */ +#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */ +#define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */ + +#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ + +/* PHY Control Register */ +#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */ +#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */ +#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ +#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ +#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */ +#define MII_CR_POWER_DOWN 0x0800 /* Power down */ +#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ +#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */ +#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ +#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ + +/* PHY Status Register */ +#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */ +#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */ +#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ +#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */ +#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */ +#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ +#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */ +#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */ +#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */ +#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */ +#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */ +#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */ +#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */ +#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */ +#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */ + +/* Autoneg Advertisement Register */ +#define NWAY_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */ +#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */ +#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */ +#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */ +#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */ +#define NWAY_AR_100T4_CAPS 0x0200 /* 100T4 Capable */ +#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */ +#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */ +#define NWAY_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */ +#define NWAY_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */ + +/* Link Partner Ability Register (Base Page) */ +#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */ +#define NWAY_LPAR_10T_HD_CAPS 0x0020 /* LP is 10T Half Duplex Capable */ +#define NWAY_LPAR_10T_FD_CAPS 0x0040 /* LP is 10T Full Duplex Capable */ +#define NWAY_LPAR_100TX_HD_CAPS 0x0080 /* LP is 100TX Half Duplex Capable */ +#define NWAY_LPAR_100TX_FD_CAPS 0x0100 /* LP is 100TX Full Duplex Capable */ +#define NWAY_LPAR_100T4_CAPS 0x0200 /* LP is 100T4 Capable */ +#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */ +#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */ +#define NWAY_LPAR_REMOTE_FAULT 0x2000 /* LP has detected Remote Fault */ +#define NWAY_LPAR_ACKNOWLEDGE 0x4000 /* LP has rx'd link code word */ +#define NWAY_LPAR_NEXT_PAGE 0x8000 /* Next Page ability supported */ + +/* Autoneg Expansion Register */ +#define NWAY_ER_LP_NWAY_CAPS 0x0001 /* LP has Auto Neg Capability */ +#define NWAY_ER_PAGE_RXD 0x0002 /* LP is 10T Half Duplex Capable */ +#define NWAY_ER_NEXT_PAGE_CAPS 0x0004 /* LP is 10T Full Duplex Capable */ +#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */ +#define NWAY_ER_PAR_DETECT_FAULT 0x0100 /* LP is 100TX Full Duplex Capable */ + +/* Next Page TX Register */ +#define NPTX_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */ +#define NPTX_TOGGLE 0x0800 /* Toggles between exchanges + * of different NP + */ +#define NPTX_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg + * 0 = cannot comply with msg + */ +#define NPTX_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */ +#define NPTX_NEXT_PAGE 0x8000 /* 1 = addition NP will follow + * 0 = sending last NP + */ + +/* Link Partner Next Page Register */ +#define LP_RNPR_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */ +#define LP_RNPR_TOGGLE 0x0800 /* Toggles between exchanges + * of different NP + */ +#define LP_RNPR_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg + * 0 = cannot comply with msg + */ +#define LP_RNPR_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */ +#define LP_RNPR_ACKNOWLDGE 0x4000 /* 1 = ACK / 0 = NO ACK */ +#define LP_RNPR_NEXT_PAGE 0x8000 /* 1 = addition NP will follow + * 0 = sending last NP + */ + +/* 1000BASE-T Control Register */ +#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause bit */ +#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ +#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ +#define CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port */ + /* 0=DTE device */ +#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */ + /* 0=Configure PHY as Slave */ +#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */ + /* 0=Automatic Master/Slave config */ +#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */ +#define CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */ +#define CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */ +#define CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */ +#define CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */ + +/* 1000BASE-T Status Register */ +#define SR_1000T_IDLE_ERROR_CNT 0x00FF /* Num idle errors since last read */ +#define SR_1000T_ASYM_PAUSE_DIR 0x0100 /* LP asymmetric pause direction bit */ +#define SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */ +#define SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */ +#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */ +#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */ +#define SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local TX is Master, 0=Slave */ +#define SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */ +#define SR_1000T_REMOTE_RX_STATUS_SHIFT 12 +#define SR_1000T_LOCAL_RX_STATUS_SHIFT 13 + +/* Extended Status Register */ +#define IEEE_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */ +#define IEEE_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */ +#define IEEE_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */ +#define IEEE_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */ + +#define PHY_TX_POLARITY_MASK 0x0100 /* register 10h bit 8 (polarity bit) */ +#define PHY_TX_NORMAL_POLARITY 0 /* register 10h bit 8 (normal polarity) */ + +#define AUTO_POLARITY_DISABLE 0x0010 /* register 11h bit 4 */ + /* (0=enable, 1=disable) */ + +/* M88E1000 PHY Specific Control Register */ +#define M88E1000_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */ +#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */ +#define M88E1000_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */ +#define M88E1000_PSCR_CLK125_DISABLE 0x0010 /* 1=CLK125 low, + * 0=CLK125 toggling + */ +#define M88E1000_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5 */ + /* Manual MDI configuration */ +#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */ +#define M88E1000_PSCR_AUTO_X_1000T 0x0040 /* 1000BASE-T: Auto crossover, + * 100BASE-TX/10BASE-T: + * MDI Mode + */ +#define M88E1000_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled + * all speeds. + */ +#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE 0x0080 + /* 1=Enable Extended 10BASE-T distance + * (Lower 10BASE-T RX Threshold) + * 0=Normal 10BASE-T RX Threshold */ +#define M88E1000_PSCR_MII_5BIT_ENABLE 0x0100 + /* 1=5-Bit interface in 100BASE-TX + * 0=MII interface in 100BASE-TX */ +#define M88E1000_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */ +#define M88E1000_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */ +#define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */ + +#define M88E1000_PSCR_POLARITY_REVERSAL_SHIFT 1 +#define M88E1000_PSCR_AUTO_X_MODE_SHIFT 5 +#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7 + +/* M88E1000 PHY Specific Status Register */ +#define M88E1000_PSSR_JABBER 0x0001 /* 1=Jabber */ +#define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */ +#define M88E1000_PSSR_MDIX 0x0040 /* 1=MDIX; 0=MDI */ +#define M88E1000_PSSR_CABLE_LENGTH 0x0380 /* 0=<50M;1=50-80M;2=80-110M; + * 3=110-140M;4=>140M */ +#define M88E1000_PSSR_LINK 0x0400 /* 1=Link up, 0=Link down */ +#define M88E1000_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */ +#define M88E1000_PSSR_PAGE_RCVD 0x1000 /* 1=Page received */ +#define M88E1000_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */ +#define M88E1000_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */ +#define M88E1000_PSSR_10MBS 0x0000 /* 00=10Mbs */ +#define M88E1000_PSSR_100MBS 0x4000 /* 01=100Mbs */ +#define M88E1000_PSSR_1000MBS 0x8000 /* 10=1000Mbs */ + +#define M88E1000_PSSR_REV_POLARITY_SHIFT 1 +#define M88E1000_PSSR_MDIX_SHIFT 6 +#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7 + +/* M88E1000 Extended PHY Specific Control Register */ +#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */ +#define M88E1000_EPSCR_DOWN_NO_IDLE 0x8000 /* 1=Lost lock detect enabled. + * Will assert lost lock and bring + * link down if idle not seen + * within 1ms in 1000BASE-T + */ +#define M88E1000_EPSCR_TX_CLK_2_5 0x0060 /* 2.5 MHz TX_CLK */ +#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */ +#define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */ + +#define M88E1000_EPSCR_DOWN_NO_IDLE_SHIFT 15 + +/* Bit definitions for valid PHY IDs. */ +#define M88E1000_12_PHY_ID 0x01410C50 +#define M88E1000_14_PHY_ID 0x01410C40 +#define M88E1000_I_PHY_ID 0x01410C30 + +/* Miscellaneous PHY bit definitions. */ +#define PHY_PREAMBLE 0xFFFFFFFF +#define PHY_SOF 0x01 +#define PHY_OP_READ 0x02 +#define PHY_OP_WRITE 0x01 +#define PHY_TURNAROUND 0x02 +#define PHY_PREAMBLE_SIZE 32 +#define MII_CR_SPEED_1000 0x0040 +#define MII_CR_SPEED_100 0x2000 +#define MII_CR_SPEED_10 0x0000 +#define E1000_PHY_ADDRESS 0x01 +#define PHY_AUTO_NEG_TIME 45 /* 4.5 Seconds */ +#define PHY_FORCE_TIME 20 /* 2.0 Seconds */ +#define PHY_REVISION_MASK 0xFFFFFFF0 +#define DEVICE_SPEED_MASK 0x00000300 /* Device Ctrl Reg Speed Mask */ +#define REG4_SPEED_MASK 0x01E0 +#define REG9_SPEED_MASK 0x0300 +#define ADVERTISE_10_HALF 0x0001 +#define ADVERTISE_10_FULL 0x0002 +#define ADVERTISE_100_HALF 0x0004 +#define ADVERTISE_100_FULL 0x0008 +#define ADVERTISE_1000_HALF 0x0010 +#define ADVERTISE_1000_FULL 0x0020 +#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F /* Everything but 1000-Half */ + +#endif /* _E1000_PHY_H_ */ diff -Nru a/drivers/net/e1000/e1000_proc.c b/drivers/net/e1000/e1000_proc.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/e1000/e1000_proc.c Tue Feb 26 11:58:00 2002 @@ -0,0 +1,760 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/* + * Proc fs support. + * + * Read-only files created by driver (if CONFIG_PROC_FS): + * + * /proc/net/PRO_LAN_Adapters/.info + * /proc/net/PRO_LAN_Adapters// + * + * where is the system device name, i.e eth0. + * is the driver attribute name. + * + * There is one file for each driver attribute, where the contents + * of the file is the attribute value. The ethx.info file contains + * a list of all driver attributes in one file. + * + */ + +#include "e1000.h" + +#ifdef CONFIG_PROC_FS + +#include + +#define ADAPTERS_PROC_DIR "PRO_LAN_Adapters" +#define TAG_MAX_LENGTH 36 + +extern char e1000_driver_name[]; +extern char e1000_driver_version[]; + +/* + * The list of driver proc attributes is stored in a proc_list link + * list. The list is build with proc_list_setup and is used to + * build the proc fs nodes. The private data for each node is the + * corresponding link in the link list. + */ + +struct proc_list { + struct list_head list; /* link list */ + char tag[TAG_MAX_LENGTH]; /* attribute name */ + void *data; /* attribute data */ + size_t len; /* sizeof data */ + char *(*func)(void *, size_t, char *); /* format data func */ +}; + +static int +e1000_proc_read(char *page, char **start, off_t off, int count, int *eof) +{ + int len = strlen(page); + + page[len++] = '\n'; + + if(len <= off + count) + *eof = 1; + *start = page + off; + len -= off; + if(len > count) + len = count; + if(len < 0) + len = 0; + + return len; +} + +static int +e1000_proc_info_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct list_head *proc_list_head = data, *curr; + struct proc_list *elem; + char *p = page; + char buf[64]; + + list_for_each(curr, proc_list_head) { + elem = list_entry(curr, struct proc_list, list); + + if(strlen(elem->tag) == 0) + p += sprintf(p, "\n"); + else + p += sprintf(p, "%-32s %s\n", elem->tag, + elem->func(elem->data, elem->len, buf)); + } + + *p = '\0'; + + return e1000_proc_read(page, start, off, count, eof); +} + +static int +e1000_proc_single_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct proc_list *elem = data; + + sprintf(page, "%s", elem->func(elem->data, elem->len, page)); + + return e1000_proc_read(page, start, off, count, eof); +} + +static void __devexit +e1000_proc_dirs_free(char *name, struct list_head *proc_list_head) +{ + struct proc_dir_entry *intel_proc_dir, *proc_dir; + char info_name[strlen(name) + strlen(".info")]; + + for(intel_proc_dir = proc_net->subdir; intel_proc_dir; + intel_proc_dir = intel_proc_dir->next) { + if((intel_proc_dir->namelen == strlen(ADAPTERS_PROC_DIR)) && + (memcmp(intel_proc_dir->name, + ADAPTERS_PROC_DIR, strlen(ADAPTERS_PROC_DIR)) == 0)) + break; + } + + if(!intel_proc_dir) + return; + + for(proc_dir = intel_proc_dir->subdir; proc_dir; + proc_dir = proc_dir->next) { + if ((proc_dir->namelen == strlen(name)) && + !memcmp(proc_dir->name, name, strlen(name))) + break; + } + + if(proc_dir) { + struct list_head *curr; + struct proc_list *elem; + + list_for_each(curr, proc_list_head) { + elem = list_entry(curr, struct proc_list, list); + remove_proc_entry(elem->tag, proc_dir); + } + + strcpy(info_name, name); + strcat(info_name, ".info"); + + remove_proc_entry(info_name, intel_proc_dir); + remove_proc_entry(name, intel_proc_dir); + } + + /* If the intel dir is empty, remove it */ + + for(proc_dir = intel_proc_dir->subdir; proc_dir; + proc_dir = proc_dir->next) { + + /* ignore . and .. */ + + if(*(proc_dir->name) == '.') + continue; + break; + } + + if(!proc_dir) + remove_proc_entry(ADAPTERS_PROC_DIR, proc_net); + + return; +} + + +static int __devinit +e1000_proc_singles_create(struct proc_dir_entry *parent, + struct list_head *proc_list_head) +{ + struct list_head *curr; + struct proc_list *elem; + + list_for_each(curr, proc_list_head) { + struct proc_dir_entry *proc_entry; + + elem = list_entry(curr, struct proc_list, list); + + if(strlen(elem->tag) == 0) + continue; + + if(!(proc_entry = + create_proc_entry(elem->tag, S_IFREG, parent))) + return 0; + + proc_entry->read_proc = e1000_proc_single_read; + proc_entry->data = elem; + SET_MODULE_OWNER(proc_entry); + } + + return 1; +} + +static int __devinit +e1000_proc_dirs_create(char *name, struct list_head *proc_list_head) +{ + struct proc_dir_entry *intel_proc_dir, *proc_dir, *info_entry; + char info_name[strlen(name) + strlen(".info")]; + + for(intel_proc_dir = proc_net->subdir; intel_proc_dir; + intel_proc_dir = intel_proc_dir->next) { + if((intel_proc_dir->namelen == strlen(ADAPTERS_PROC_DIR)) && + (memcmp(intel_proc_dir->name, + ADAPTERS_PROC_DIR, strlen(ADAPTERS_PROC_DIR)) == 0)) + break; + } + + if(!intel_proc_dir) + if(!(intel_proc_dir = + create_proc_entry(ADAPTERS_PROC_DIR, + S_IFDIR, proc_net))) + return 0; + + if(!(proc_dir = + create_proc_entry(name, S_IFDIR, intel_proc_dir))) + return 0; + SET_MODULE_OWNER(proc_dir); + + if(!e1000_proc_singles_create(proc_dir, proc_list_head)) + return 0; + + strcpy(info_name, name); + strcat(info_name, ".info"); + + if(!(info_entry = + create_proc_entry(info_name, S_IFREG, intel_proc_dir))) + return 0; + SET_MODULE_OWNER(info_entry); + + info_entry->read_proc = e1000_proc_info_read; + info_entry->data = proc_list_head; + + return 1; +} + +static void __devinit +e1000_proc_list_add(struct list_head *proc_list_head, char *tag, + void *data, size_t len, + char *(*func)(void *, size_t, char *)) +{ + struct proc_list *new = (struct proc_list *) + kmalloc(sizeof(struct proc_list), GFP_KERNEL); + + if(!new) + return; + + strncpy(new->tag, tag, TAG_MAX_LENGTH); + new->data = data; + new->len = len; + new->func = func; + + list_add_tail(&new->list, proc_list_head); + + return; +} + +static void __devexit +e1000_proc_list_free(struct list_head *proc_list_head) +{ + struct proc_list *elem; + + while(!list_empty(proc_list_head)) { + elem = list_entry(proc_list_head->next, struct proc_list, list); + list_del(&elem->list); + kfree(elem); + } + + return; +} + +/* + * General purpose formating functions + */ + +static char * +e1000_proc_str(void *data, size_t len, char *buf) +{ + sprintf(buf, "%s", (char *)data); + return buf; +} + +static char * +e1000_proc_hex(void *data, size_t len, char *buf) +{ + switch(len) { + case sizeof(uint8_t): + sprintf(buf, "0x%02x", *(uint8_t *)data); + break; + case sizeof(uint16_t): + sprintf(buf, "0x%04x", *(uint16_t *)data); + break; + case sizeof(uint32_t): + sprintf(buf, "0x%08x", *(uint32_t *)data); + break; + case sizeof(uint64_t): + sprintf(buf, "0x%08Lx", (unsigned long long)*(uint64_t *)data); + break; + } + return buf; +} + +static char * +e1000_proc_unsigned(void *data, size_t len, char *buf) +{ + switch(len) { + case sizeof(uint8_t): + sprintf(buf, "%u", *(uint8_t *)data); + break; + case sizeof(uint16_t): + sprintf(buf, "%u", *(uint16_t *)data); + break; + case sizeof(uint32_t): + sprintf(buf, "%u", *(uint32_t *)data); + break; + case sizeof(uint64_t): + sprintf(buf, "%Lu", (unsigned long long)*(uint64_t *)data); + break; + } + return buf; +} + +/* + * Specific formating functions + */ + +static char * +e1000_proc_part_number(void *data, size_t len, char *buf) +{ + sprintf(buf, "%06x-%03x", *(uint32_t *)data >> 8, + *(uint32_t *)data & 0x000000FF); + return buf; +} + +static char * +e1000_proc_slot(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + sprintf(buf, "%u", PCI_SLOT(adapter->pdev->devfn)); + return buf; +} + +static char * +e1000_proc_bus_type(void *data, size_t len, char *buf) +{ + e1000_bus_type bus_type = *(e1000_bus_type *)data; + sprintf(buf, + bus_type == e1000_bus_type_pci ? "PCI" : + bus_type == e1000_bus_type_pcix ? "PCI-X" : + "UNKNOWN"); + return buf; +} + +static char * +e1000_proc_bus_speed(void *data, size_t len, char *buf) +{ + e1000_bus_speed bus_speed = *(e1000_bus_speed *)data; + sprintf(buf, + bus_speed == e1000_bus_speed_33 ? "33MHz" : + bus_speed == e1000_bus_speed_66 ? "66MHz" : + bus_speed == e1000_bus_speed_100 ? "100MHz" : + bus_speed == e1000_bus_speed_133 ? "133MHz" : + "UNKNOWN"); + return buf; +} + +static char * +e1000_proc_bus_width(void *data, size_t len, char *buf) +{ + e1000_bus_width bus_width = *(e1000_bus_width *)data; + sprintf(buf, + bus_width == e1000_bus_width_32 ? "32-bit" : + bus_width == e1000_bus_width_64 ? "64-bit" : + "UNKNOWN"); + return buf; +} + +static char * +e1000_proc_hwaddr(void *data, size_t len, char *buf) +{ + unsigned char *hwaddr = data; + sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", + hwaddr[0], hwaddr[1], hwaddr[2], + hwaddr[3], hwaddr[4], hwaddr[5]); + return buf; +} + +static char * +e1000_proc_link(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + sprintf(buf, netif_running(adapter->netdev) ? + netif_carrier_ok(adapter->netdev) ? + "up" : "down" : "N/A"); + return buf; +} + +static char * +e1000_proc_link_speed(void *data, size_t len, char *buf) +{ + uint16_t link_speed = *(uint16_t *)data; + sprintf(buf, link_speed ? "%u" : "N/A", link_speed); + return buf; +} + +static char * +e1000_proc_link_duplex(void *data, size_t len, char *buf) +{ + uint16_t link_duplex = *(uint16_t *)data; + sprintf(buf, + link_duplex == FULL_DUPLEX ? "Full" : + link_duplex == HALF_DUPLEX ? "Half" : + "N/A"); + return buf; +} + +static char * +e1000_proc_state(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + sprintf(buf, adapter->netdev->flags & IFF_UP ? "up" : "down"); + return buf; +} + +static char * +e1000_proc_media_type(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + sprintf(buf, + adapter->shared.media_type == e1000_media_type_copper ? + "Copper" : "Fiber"); + return buf; +} + +static char * +e1000_proc_cable_length(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + e1000_cable_length cable_length = adapter->phy_info.cable_length; + sprintf(buf, "%s%s", + cable_length == e1000_cable_length_50 ? "0-50" : + cable_length == e1000_cable_length_50_80 ? "50-80" : + cable_length == e1000_cable_length_80_110 ? "80-110" : + cable_length == e1000_cable_length_110_140 ? "110-140" : + cable_length == e1000_cable_length_140 ? "> 140" : + "Unknown", + cable_length != e1000_cable_length_undefined ? + " Meters (+/- 20 Meters)" : ""); + return buf; +} + +static char * +e1000_proc_extended(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + e1000_10bt_ext_dist_enable dist_enable = + adapter->phy_info.extended_10bt_distance; + sprintf(buf, + dist_enable == e1000_10bt_ext_dist_enable_normal ? "Disabled" : + dist_enable == e1000_10bt_ext_dist_enable_lower ? "Enabled" : + "Unknown"); + return buf; +} + +static char * +e1000_proc_cable_polarity(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + e1000_rev_polarity polarity = adapter->phy_info.cable_polarity; + sprintf(buf, + polarity == e1000_rev_polarity_normal ? "Normal" : + polarity == e1000_rev_polarity_reversed ? "Reversed" : + "Unknown"); + return buf; +} + +static char * +e1000_proc_polarity_correction(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + e1000_polarity_reversal correction = + adapter->phy_info.polarity_correction; + sprintf(buf, + correction == e1000_polarity_reversal_enabled ? "Disabled" : + correction == e1000_polarity_reversal_disabled ? "Enabled" : + "Undefined"); + return buf; +} + +static char * +e1000_proc_link_reset_enabled(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + e1000_down_no_idle link_reset = adapter->phy_info.link_reset; + sprintf(buf, + link_reset == e1000_down_no_idle_no_detect ? "Disabled" : + link_reset == e1000_down_no_idle_detect ? "Enabled" : + "Unknown"); + return buf; +} + +static char * +e1000_proc_mdi_x_enabled(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + e1000_auto_x_mode mdix_mode = adapter->phy_info.mdix_mode; + sprintf(buf, mdix_mode == 0 ? "MDI" : "MDI-X"); + return buf; +} + +static char * +e1000_proc_rx_status(void *data, size_t len, char *buf) +{ + e1000_1000t_rx_status rx_status = *(e1000_1000t_rx_status *)data; + sprintf(buf, + rx_status == e1000_1000t_rx_status_not_ok ? "NOT_OK" : + rx_status == e1000_1000t_rx_status_ok ? "OK" : + "Unknown"); + return buf; +} + +/* + * e1000_proc_list_setup - build link list of proc praramters + * @adapter: board private structure + * + * Order matters - ethx.info entries are ordered in the order links + * are added to list. + */ + +#define LIST_ADD_F(T,D,F) \ + e1000_proc_list_add(proc_list_head, (T), (D), sizeof(*(D)), (F)) +#define LIST_ADD_BLANK() LIST_ADD_F("", NULL, NULL) +#define LIST_ADD_S(T,D) LIST_ADD_F((T), (D), e1000_proc_str) +#define LIST_ADD_H(T,D) LIST_ADD_F((T), (D), e1000_proc_hex) +#define LIST_ADD_U(T,D) LIST_ADD_F((T), (D), e1000_proc_unsigned) + +static void __devinit +e1000_proc_list_setup(struct e1000_adapter *adapter) +{ + struct e1000_shared_adapter *shared = &adapter->shared; + struct list_head *proc_list_head = &adapter->proc_list_head; + + INIT_LIST_HEAD(proc_list_head); + + LIST_ADD_S("Description", adapter->id_string); + LIST_ADD_F("Part_Number", &adapter->part_num, e1000_proc_part_number); + LIST_ADD_S("Driver_Name", e1000_driver_name); + LIST_ADD_S("Driver_Version", e1000_driver_version); + LIST_ADD_H("PCI_Vendor", &shared->vendor_id); + LIST_ADD_H("PCI_Device_ID", &shared->device_id); + LIST_ADD_H("PCI_Subsystem_Vendor", &shared->subsystem_vendor_id); + LIST_ADD_H("PCI_Subsystem_ID", &shared->subsystem_id); + LIST_ADD_H("PCI_Revision_ID", &shared->revision_id); + LIST_ADD_U("PCI_Bus", &adapter->pdev->bus->number); + LIST_ADD_F("PCI_Slot", adapter, e1000_proc_slot); + + if(adapter->shared.mac_type >= e1000_82543) { + LIST_ADD_F("PCI_Bus_Type", + &shared->bus_type, e1000_proc_bus_type); + LIST_ADD_F("PCI_Bus_Speed", + &shared->bus_speed, e1000_proc_bus_speed); + LIST_ADD_F("PCI_Bus_Width", + &shared->bus_width, e1000_proc_bus_width); + } + + LIST_ADD_U("IRQ", &adapter->pdev->irq); + LIST_ADD_S("System_Device_Name", adapter->netdev->name); + LIST_ADD_F("Current_HWaddr", + adapter->netdev->dev_addr, e1000_proc_hwaddr); + LIST_ADD_F("Permanent_HWaddr", + adapter->shared.perm_mac_addr, e1000_proc_hwaddr); + + LIST_ADD_BLANK(); + + LIST_ADD_F("Link", adapter, e1000_proc_link); + LIST_ADD_F("Speed", &adapter->link_speed, e1000_proc_link_speed); + LIST_ADD_F("Duplex", &adapter->link_duplex, e1000_proc_link_duplex); + LIST_ADD_F("State", adapter, e1000_proc_state); + + LIST_ADD_BLANK(); + + /* Standard net device stats */ + LIST_ADD_U("Rx_Packets", &adapter->net_stats.rx_packets); + LIST_ADD_U("Tx_Packets", &adapter->net_stats.tx_packets); + LIST_ADD_U("Rx_Bytes", &adapter->net_stats.rx_bytes); + LIST_ADD_U("Tx_Bytes", &adapter->net_stats.tx_bytes); + LIST_ADD_U("Rx_Errors", &adapter->net_stats.rx_errors); + LIST_ADD_U("Tx_Errors", &adapter->net_stats.tx_errors); + LIST_ADD_U("Rx_Dropped", &adapter->net_stats.rx_dropped); + LIST_ADD_U("Tx_Dropped", &adapter->net_stats.tx_dropped); + + LIST_ADD_U("Multicast", &adapter->net_stats.multicast); + LIST_ADD_U("Collisions", &adapter->net_stats.collisions); + + LIST_ADD_U("Rx_Length_Errors", &adapter->net_stats.rx_length_errors); + LIST_ADD_U("Rx_Over_Errors", &adapter->net_stats.rx_over_errors); + LIST_ADD_U("Rx_CRC_Errors", &adapter->net_stats.rx_crc_errors); + LIST_ADD_U("Rx_Frame_Errors", &adapter->net_stats.rx_frame_errors); + LIST_ADD_U("Rx_FIFO_Errors", &adapter->net_stats.rx_fifo_errors); + LIST_ADD_U("Rx_Missed_Errors", &adapter->net_stats.rx_missed_errors); + + LIST_ADD_U("Tx_Aborted_Errors", &adapter->net_stats.tx_aborted_errors); + LIST_ADD_U("Tx_Carrier_Errors", &adapter->net_stats.tx_carrier_errors); + LIST_ADD_U("Tx_FIFO_Errors", &adapter->net_stats.tx_fifo_errors); + LIST_ADD_U("Tx_Heartbeat_Errors", + &adapter->net_stats.tx_heartbeat_errors); + LIST_ADD_U("Tx_Window_Errors", &adapter->net_stats.tx_window_errors); + + /* 8254x-specific stats */ + LIST_ADD_U("Tx_Abort_Late_Coll", &adapter->stats.latecol); + LIST_ADD_U("Tx_Deferred_Ok", &adapter->stats.dc); + LIST_ADD_U("Tx_Single_Coll_Ok", &adapter->stats.scc); + LIST_ADD_U("Tx_Multi_Coll_Ok", &adapter->stats.mcc); + LIST_ADD_U("Rx_Long_Length_Errors", &adapter->stats.roc); + LIST_ADD_U("Rx_Short_Length_Errors", &adapter->stats.ruc); + + /* The 82542 does not have an alignment error count register */ + if(adapter->shared.mac_type >= e1000_82543) + LIST_ADD_U("Rx_Align_Errors", &adapter->stats.algnerrc); + + LIST_ADD_U("Rx_Flow_Control_XON", &adapter->stats.xonrxc); + LIST_ADD_U("Rx_Flow_Control_XOFF", &adapter->stats.xoffrxc); + LIST_ADD_U("Tx_Flow_Control_XON", &adapter->stats.xontxc); + LIST_ADD_U("Tx_Flow_Control_XOFF", &adapter->stats.xofftxc); + LIST_ADD_U("Rx_CSum_Offload_Good", &adapter->hw_csum_good); + LIST_ADD_U("Rx_CSum_Offload_Errors", &adapter->hw_csum_err); + + LIST_ADD_BLANK(); + + /* Cable diags */ + LIST_ADD_F("PHY_Media_Type", adapter, e1000_proc_media_type); + if(adapter->shared.media_type == e1000_media_type_copper) { + LIST_ADD_F("PHY_Cable_Length", + adapter, e1000_proc_cable_length); + LIST_ADD_F("PHY_Extended_10Base_T_Distance", + adapter, e1000_proc_extended); + LIST_ADD_F("PHY_Cable_Polarity", + adapter, e1000_proc_cable_polarity); + LIST_ADD_F("PHY_Disable_Polarity_Correction", + adapter, e1000_proc_polarity_correction); + LIST_ADD_U("PHY_Idle_Errors", + &adapter->phy_stats.idle_errors); + LIST_ADD_F("PHY_Link_Reset_Enabled", + adapter, e1000_proc_link_reset_enabled); + LIST_ADD_U("PHY_Receive_Errors", + &adapter->phy_stats.receive_errors); + LIST_ADD_F("PHY_MDI_X_Enabled", + adapter, e1000_proc_mdi_x_enabled); + LIST_ADD_F("PHY_Local_Receiver_Status", + &adapter->phy_info.local_rx, + e1000_proc_rx_status); + LIST_ADD_F("PHY_Remote_Receiver_Status", + &adapter->phy_info.remote_rx, + e1000_proc_rx_status); + } + + return; +} + +/* + * e1000_proc_dev_setup - create proc fs nodes and link list + * @adapter: board private structure + */ + +void __devinit +e1000_proc_dev_setup(struct e1000_adapter *adapter) +{ + e1000_proc_list_setup(adapter); + + e1000_proc_dirs_create(adapter->netdev->name,&adapter->proc_list_head); + + return; +} + +/* + * e1000_proc_dev_free - free proc fs nodes and link list + * @adapter: board private structure + */ + +void __devexit +e1000_proc_dev_free(struct e1000_adapter *adapter) +{ + e1000_proc_dirs_free(adapter->netdev->name, &adapter->proc_list_head); + + e1000_proc_list_free(&adapter->proc_list_head); + + return; +} + +#else /* CONFIG_PROC_FS */ + +void __devinit e1000_proc_dev_setup(struct e1000_adapter *adapter) {} +void __devexit e1000_proc_dev_free(struct e1000_adapter *adapter) {} + +#endif /* CONFIG_PROC_FS */ + diff -Nru a/drivers/net/eepro100.c b/drivers/net/eepro100.c --- a/drivers/net/eepro100.c Tue Feb 26 11:57:57 2002 +++ b/drivers/net/eepro100.c Tue Feb 26 11:57:57 2002 @@ -2288,7 +2288,7 @@ name: "eepro100", id_table: eepro100_pci_tbl, probe: eepro100_init_one, - remove: eepro100_remove_one, + remove: __devexit_p(eepro100_remove_one), #ifdef CONFIG_PM suspend: eepro100_suspend, resume: eepro100_resume, diff -Nru a/drivers/net/epic100.c b/drivers/net/epic100.c --- a/drivers/net/epic100.c Tue Feb 26 11:57:59 2002 +++ b/drivers/net/epic100.c Tue Feb 26 11:57:59 2002 @@ -1533,7 +1533,7 @@ name: DRV_NAME, id_table: epic_pci_tbl, probe: epic_init_one, - remove: epic_remove_one, + remove: __devexit_p(epic_remove_one), #ifdef CONFIG_PM suspend: epic_suspend, resume: epic_resume, diff -Nru a/drivers/net/fc/Makefile b/drivers/net/fc/Makefile --- a/drivers/net/fc/Makefile Tue Feb 26 11:57:58 2002 +++ b/drivers/net/fc/Makefile Tue Feb 26 11:57:58 2002 @@ -1,7 +1,7 @@ # # Makefile for linux/drivers/net/fc # -# 9 Aug 2000, Christoph Hellwig +# 9 Aug 2000, Christoph Hellwig # Rewritten to use lists instead of if-statements. # diff -Nru a/drivers/net/fealnx.c b/drivers/net/fealnx.c --- a/drivers/net/fealnx.c Tue Feb 26 11:58:00 2002 +++ b/drivers/net/fealnx.c Tue Feb 26 11:58:00 2002 @@ -1929,7 +1929,7 @@ name: "fealnx", id_table: fealnx_pci_tbl, probe: fealnx_init_one, - remove: fealnx_remove_one, + remove: __devexit_p(fealnx_remove_one), }; static int __init fealnx_init(void) diff -Nru a/drivers/net/hamachi.c b/drivers/net/hamachi.c --- a/drivers/net/hamachi.c Tue Feb 26 11:57:59 2002 +++ b/drivers/net/hamachi.c Tue Feb 26 11:57:59 2002 @@ -1978,7 +1978,7 @@ } -static void __exit hamachi_remove_one (struct pci_dev *pdev) +static void __devexit hamachi_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); @@ -2008,7 +2008,7 @@ name: DRV_NAME, id_table: hamachi_pci_tbl, probe: hamachi_init_one, - remove: hamachi_remove_one, + remove: __devexit_p(hamachi_remove_one), }; static int __init hamachi_init (void) diff -Nru a/drivers/net/hamradio/Makefile b/drivers/net/hamradio/Makefile --- a/drivers/net/hamradio/Makefile Tue Feb 26 11:57:56 2002 +++ b/drivers/net/hamradio/Makefile Tue Feb 26 11:57:56 2002 @@ -7,7 +7,7 @@ # Joerg Reuter DL1BKE # # 20000806 Rewritten to use lists instead of if-statements. -# Christoph Hellwig +# Christoph Hellwig # diff -Nru a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c --- a/drivers/net/ioc3-eth.c Tue Feb 26 11:57:56 2002 +++ b/drivers/net/ioc3-eth.c Tue Feb 26 11:57:56 2002 @@ -1516,7 +1516,7 @@ name: "ioc3-eth", id_table: ioc3_pci_tbl, probe: ioc3_probe, - remove: ioc3_remove_one, + remove: __devexit_p(ioc3_remove_one), }; static int __init ioc3_init_module(void) diff -Nru a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile --- a/drivers/net/irda/Makefile Tue Feb 26 11:57:59 2002 +++ b/drivers/net/irda/Makefile Tue Feb 26 11:57:59 2002 @@ -2,7 +2,7 @@ # # Makefile for the Linux IrDA infrared port device drivers. # -# 9 Aug 2000, Christoph Hellwig +# 9 Aug 2000, Christoph Hellwig # Rewritten to use lists instead of if-statements. # diff -Nru a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c --- a/drivers/net/irda/vlsi_ir.c Tue Feb 26 11:57:56 2002 +++ b/drivers/net/irda/vlsi_ir.c Tue Feb 26 11:57:56 2002 @@ -1291,7 +1291,7 @@ name: drivername, id_table: vlsi_irda_table, probe: vlsi_irda_probe, - remove: vlsi_irda_remove, + remove: __devexit_p(vlsi_irda_remove), suspend: vlsi_irda_suspend, resume: vlsi_irda_resume, }; diff -Nru a/drivers/net/natsemi.c b/drivers/net/natsemi.c --- a/drivers/net/natsemi.c Tue Feb 26 11:57:56 2002 +++ b/drivers/net/natsemi.c Tue Feb 26 11:57:56 2002 @@ -1925,6 +1925,8 @@ /* get link status */ case ETHTOOL_GLINK: { struct ethtool_value edata = {ETHTOOL_GLINK}; + /* LSTATUS is latched low until a read - so read twice */ + mdio_read(dev, 1, MII_BMSR); edata.data = (mdio_read(dev, 1, MII_BMSR)&BMSR_LSTATUS) ? 1:0; if (copy_to_user(useraddr, &edata, sizeof(edata))) return -EFAULT; @@ -2504,7 +2506,7 @@ name: DRV_NAME, id_table: natsemi_pci_tbl, probe: natsemi_probe1, - remove: natsemi_remove1, + remove: __devexit_p(natsemi_remove1), #ifdef CONFIG_PM suspend: natsemi_suspend, resume: natsemi_resume, diff -Nru a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c --- a/drivers/net/ne2k-pci.c Tue Feb 26 11:57:58 2002 +++ b/drivers/net/ne2k-pci.c Tue Feb 26 11:57:58 2002 @@ -642,7 +642,7 @@ static struct pci_driver ne2k_driver = { name: DRV_NAME, probe: ne2k_pci_init_one, - remove: ne2k_pci_remove_one, + remove: __devexit_p(ne2k_pci_remove_one), id_table: ne2k_pci_tbl, }; diff -Nru a/drivers/net/ns83820.c b/drivers/net/ns83820.c --- a/drivers/net/ns83820.c Tue Feb 26 11:58:00 2002 +++ b/drivers/net/ns83820.c Tue Feb 26 11:58:00 2002 @@ -1637,7 +1637,7 @@ name: "ns83820", id_table: ns83820_pci_tbl, probe: ns83820_init_one, - remove: ns83820_remove_one, + remove: __devexit_p(ns83820_remove_one), #if 0 /* FIXME: implement */ suspend: , resume: , diff -Nru a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c --- a/drivers/net/pci-skeleton.c Tue Feb 26 11:57:56 2002 +++ b/drivers/net/pci-skeleton.c Tue Feb 26 11:57:56 2002 @@ -1956,7 +1956,7 @@ name: MODNAME, id_table: netdrv_pci_tbl, probe: netdrv_init_one, - remove: netdrv_remove_one, + remove: __devexit_p(netdrv_remove_one), #ifdef CONFIG_PM suspend: netdrv_suspend, resume: netdrv_resume, diff -Nru a/drivers/net/pcmcia/Config.help b/drivers/net/pcmcia/Config.help --- a/drivers/net/pcmcia/Config.help Tue Feb 26 11:57:58 2002 +++ b/drivers/net/pcmcia/Config.help Tue Feb 26 11:57:58 2002 @@ -133,7 +133,7 @@ This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). - The module will be called xircom_tulip_cb.o. If you want to compile + The module will be called xircom_cb.o. If you want to compile it as a module, say M here and read . If unsure, say N. diff -Nru a/drivers/net/pcmcia/xircom_cb.c b/drivers/net/pcmcia/xircom_cb.c --- a/drivers/net/pcmcia/xircom_cb.c Tue Feb 26 11:58:00 2002 +++ b/drivers/net/pcmcia/xircom_cb.c Tue Feb 26 11:58:00 2002 @@ -170,7 +170,7 @@ name: "xircom_cb", id_table: xircom_pci_table, probe: xircom_probe, - remove: xircom_remove, + remove: __devexit_p(xircom_remove), }; diff -Nru a/drivers/net/pcmcia/xircom_tulip_cb.c b/drivers/net/pcmcia/xircom_tulip_cb.c --- a/drivers/net/pcmcia/xircom_tulip_cb.c Tue Feb 26 11:57:57 2002 +++ b/drivers/net/pcmcia/xircom_tulip_cb.c Tue Feb 26 11:57:57 2002 @@ -1709,7 +1709,7 @@ name: DRV_NAME, id_table: xircom_pci_table, probe: xircom_init_one, - remove: xircom_remove_one, + remove: __devexit_p(xircom_remove_one), #ifdef CONFIG_PM suspend: xircom_suspend, resume: xircom_resume diff -Nru a/drivers/net/rcpci45.c b/drivers/net/rcpci45.c --- a/drivers/net/rcpci45.c Tue Feb 26 11:57:58 2002 +++ b/drivers/net/rcpci45.c Tue Feb 26 11:57:58 2002 @@ -115,7 +115,7 @@ MODULE_DEVICE_TABLE (pci, rcpci45_pci_table); MODULE_LICENSE("GPL"); -static void __exit +static void __devexit rcpci45_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata (pdev); @@ -267,7 +267,7 @@ name: "rcpci45", id_table: rcpci45_pci_table, probe: rcpci45_init_one, - remove: rcpci45_remove_one, + remove: __devexit_p(rcpci45_remove_one), }; static int __init diff -Nru a/drivers/net/sis900.c b/drivers/net/sis900.c --- a/drivers/net/sis900.c Tue Feb 26 11:57:59 2002 +++ b/drivers/net/sis900.c Tue Feb 26 11:57:59 2002 @@ -2129,7 +2129,7 @@ name: SIS900_MODULE_NAME, id_table: sis900_pci_tbl, probe: sis900_probe, - remove: sis900_remove, + remove: __devexit_p(sis900_remove), }; static int __init sis900_init_module(void) diff -Nru a/drivers/net/starfire.c b/drivers/net/starfire.c --- a/drivers/net/starfire.c Tue Feb 26 11:57:58 2002 +++ b/drivers/net/starfire.c Tue Feb 26 11:57:58 2002 @@ -1982,7 +1982,7 @@ static struct pci_driver starfire_driver = { name: DRV_NAME, probe: starfire_init_one, - remove: starfire_remove_one, + remove: __devexit_p(starfire_remove_one), id_table: starfire_pci_tbl, }; diff -Nru a/drivers/net/sundance.c b/drivers/net/sundance.c --- a/drivers/net/sundance.c Tue Feb 26 11:57:56 2002 +++ b/drivers/net/sundance.c Tue Feb 26 11:57:56 2002 @@ -1463,7 +1463,7 @@ name: DRV_NAME, id_table: sundance_pci_tbl, probe: sundance_probe1, - remove: sundance_remove1, + remove: __devexit_p(sundance_remove1), }; static int __init sundance_init(void) diff -Nru a/drivers/net/sungem.c b/drivers/net/sungem.c --- a/drivers/net/sungem.c Tue Feb 26 11:58:00 2002 +++ b/drivers/net/sungem.c Tue Feb 26 11:58:00 2002 @@ -2835,7 +2835,7 @@ name: GEM_MODULE_NAME, id_table: gem_pci_tbl, probe: gem_init_one, - remove: gem_remove_one, + remove: __devexit_p(gem_remove_one), #ifdef CONFIG_PM suspend: gem_suspend, resume: gem_resume, diff -Nru a/drivers/net/tlan.c b/drivers/net/tlan.c --- a/drivers/net/tlan.c Tue Feb 26 11:57:57 2002 +++ b/drivers/net/tlan.c Tue Feb 26 11:57:57 2002 @@ -431,7 +431,7 @@ name: "tlan", id_table: tlan_pci_tbl, probe: tlan_init_one, - remove: tlan_remove_one, + remove: __devexit_p(tlan_remove_one), }; static int __init tlan_probe(void) diff -Nru a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/tokenring/3c359.c Tue Feb 26 11:58:00 2002 @@ -0,0 +1,1816 @@ +/* + * 3c359.c (c) 2000 Mike Phillips (mikep@linuxtr.net) All Rights Reserved + * + * Linux driver for 3Com 3c359 Tokenlink Velocity XL PCI NIC + * + * Base Driver Olympic: + * Written 1999 Peter De Schrijver & Mike Phillips + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + * 7/17/00 - Clean up, version number 0.9.0. Ready to release to the world. + * + * 2/16/01 - Port up to kernel 2.4.2 ready for submission into the kernel. + * 3/05/01 - Last clean up stuff before submission. + * 2/15/01 - Finally, update to new pci api. + * + * To Do: + */ + +/* + * Technical Card Details + * + * All access to data is done with 16/8 bit transfers. The transfer + * method really sucks. You can only read or write one location at a time. + * + * Also, the microcode for the card must be uploaded if the card does not have + * the flashrom on board. This is a 28K bloat in the driver when compiled + * as a module. + * + * Rx is very simple, status into a ring of descriptors, dma data transfer, + * interrupts to tell us when a packet is received. + * + * Tx is a little more interesting. Similar scenario, descriptor and dma data + * transfers, but we don't have to interrupt the card to tell it another packet + * is ready for transmission, we are just doing simple memory writes, not io or mmio + * writes. The card can be set up to simply poll on the next + * descriptor pointer and when this value is non-zero will automatically download + * the next packet. The card then interrupts us when the packet is done. + * + */ + +#define XL_DEBUG 0 + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "3c359.h" + +static char version[] __devinitdata = +"3c359.c v1.2.0 2/17/01 - Mike Phillips (mikep@linuxtr.net)" ; + +MODULE_AUTHOR("Mike Phillips ") ; +MODULE_DESCRIPTION("3Com 3C359 Velocity XL Token Ring Adapter Driver \n") ; + +/* Module paramters */ + +/* Ring Speed 0,4,16 + * 0 = Autosense + * 4,16 = Selected speed only, no autosense + * This allows the card to be the first on the ring + * and become the active monitor. + * + * WARNING: Some hubs will allow you to insert + * at the wrong speed. + * + * The adapter will _not_ fail to open if there are no + * active monitors on the ring, it will simply open up in + * its last known ringspeed if no ringspeed is specified. + */ + +static int ringspeed[XL_MAX_ADAPTERS] = {0,} ; + +MODULE_PARM(ringspeed, "1-" __MODULE_STRING(XL_MAX_ADAPTERS) "i"); +MODULE_PARM_DESC(ringspeed,"3c359: Ringspeed selection - 4,16 or 0") ; + +/* Packet buffer size */ + +static int pkt_buf_sz[XL_MAX_ADAPTERS] = {0,} ; + +MODULE_PARM(pkt_buf_sz, "1-" __MODULE_STRING(XL_MAX_ADAPTERS) "i") ; +MODULE_PARM_DESC(pkt_buf_sz,"3c359: Initial buffer size") ; +/* Message Level */ + +static int message_level[XL_MAX_ADAPTERS] = {0,} ; + +MODULE_PARM(message_level, "1-" __MODULE_STRING(XL_MAX_ADAPTERS) "i") ; +MODULE_PARM_DESC(message_level, "3c359: Level of reported messages \n") ; +/* + * This is a real nasty way of doing this, but otherwise you + * will be stuck with 1555 lines of hex #'s in the code. + */ + +#include "3c359_microcode.h" + +static struct pci_device_id xl_pci_tbl[] __devinitdata = +{ + {PCI_VENDOR_ID_3COM,PCI_DEVICE_ID_3COM_3C359, PCI_ANY_ID, PCI_ANY_ID, }, + { } /* terminate list */ +}; +MODULE_DEVICE_TABLE(pci,xl_pci_tbl) ; + +static int xl_init(struct net_device *dev); +static int xl_open(struct net_device *dev); +static int xl_open_hw(struct net_device *dev) ; +static int xl_hw_reset(struct net_device *dev); +static int xl_xmit(struct sk_buff *skb, struct net_device *dev); +static void xl_dn_comp(struct net_device *dev); +static int xl_close(struct net_device *dev); +static void xl_set_rx_mode(struct net_device *dev); +static void xl_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static struct net_device_stats * xl_get_stats(struct net_device *dev); +static int xl_set_mac_address(struct net_device *dev, void *addr) ; +static void xl_arb_cmd(struct net_device *dev); +static void xl_asb_cmd(struct net_device *dev) ; +static void xl_srb_cmd(struct net_device *dev, int srb_cmd) ; +static void xl_wait_misr_flags(struct net_device *dev) ; +static int xl_change_mtu(struct net_device *dev, int mtu); +static void xl_srb_bh(struct net_device *dev) ; +static void xl_asb_bh(struct net_device *dev) ; +static void xl_reset(struct net_device *dev) ; +static void xl_freemem(struct net_device *dev) ; + + +/* EEProm Access Functions */ +static u16 xl_ee_read(struct net_device *dev, int ee_addr) ; +static void xl_ee_write(struct net_device *dev, int ee_addr, u16 ee_value) ; + +/* Debugging functions */ +#if XL_DEBUG +static void print_tx_state(struct net_device *dev) ; +static void print_rx_state(struct net_device *dev) ; + +static void print_tx_state(struct net_device *dev) +{ + + struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + struct xl_tx_desc *txd ; + u8 *xl_mmio = xl_priv->xl_mmio ; + int i ; + + printk("tx_ring_head: %d, tx_ring_tail: %d, free_ent: %d \n",xl_priv->tx_ring_head, + xl_priv->tx_ring_tail, xl_priv->free_ring_entries) ; + printk("Ring , Address , FSH , DnNextPtr, Buffer, Buffer_Len \n"); + for (i = 0; i < 16; i++) { + txd = &(xl_priv->xl_tx_ring[i]) ; + printk("%d, %08lx, %08x, %08x, %08x, %08x \n", i, virt_to_bus(txd), + txd->framestartheader, txd->dnnextptr, txd->buffer, txd->buffer_length ) ; + } + + printk("DNLISTPTR = %04x \n", readl(xl_mmio + MMIO_DNLISTPTR) ); + + printk("DmaCtl = %04x \n", readl(xl_mmio + MMIO_DMA_CTRL) ); + printk("Queue status = %0x \n",netif_running(dev) ) ; +} + +static void print_rx_state(struct net_device *dev) +{ + + struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + struct xl_rx_desc *rxd ; + u8 *xl_mmio = xl_priv->xl_mmio ; + int i ; + + printk("rx_ring_tail: %d \n", xl_priv->rx_ring_tail) ; + printk("Ring , Address , FrameState , UPNextPtr, FragAddr, Frag_Len \n"); + for (i = 0; i < 16; i++) { + /* rxd = (struct xl_rx_desc *)xl_priv->rx_ring_dma_addr + (i * sizeof(struct xl_rx_desc)) ; */ + rxd = &(xl_priv->xl_rx_ring[i]) ; + printk("%d, %08lx, %08x, %08x, %08x, %08x \n", i, virt_to_bus(rxd), + rxd->framestatus, rxd->upnextptr, rxd->upfragaddr, rxd->upfraglen ) ; + } + + printk("UPLISTPTR = %04x \n", readl(xl_mmio + MMIO_UPLISTPTR) ); + + printk("DmaCtl = %04x \n", readl(xl_mmio + MMIO_DMA_CTRL) ); + printk("Queue status = %0x \n",netif_running(dev) ) ; +} +#endif + +/* + * Read values from the on-board EEProm. This looks very strange + * but you have to wait for the EEProm to get/set the value before + * passing/getting the next value from the nic. As with all requests + * on this nic it has to be done in two stages, a) tell the nic which + * memory address you want to access and b) pass/get the value from the nic. + * With the EEProm, you have to wait before and inbetween access a) and b). + * As this is only read at initialization time and the wait period is very + * small we shouldn't have to worry about scheduling issues. + */ + +static u16 xl_ee_read(struct net_device *dev, int ee_addr) +{ + struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + u8 *xl_mmio = xl_priv->xl_mmio ; + + /* Wait for EEProm to not be busy */ + writel(IO_WORD_READ | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + while ( readw(xl_mmio + MMIO_MACDATA) & EEBUSY ) ; + + /* Tell EEProm what we want to do and where */ + writel(IO_WORD_WRITE | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(EEREAD + ee_addr, xl_mmio + MMIO_MACDATA) ; + + /* Wait for EEProm to not be busy */ + writel(IO_WORD_READ | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + while ( readw(xl_mmio + MMIO_MACDATA) & EEBUSY ) ; + + /* Tell EEProm what we want to do and where */ + writel(IO_WORD_WRITE | EECONTROL , xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(EEREAD + ee_addr, xl_mmio + MMIO_MACDATA) ; + + /* Finally read the value from the EEProm */ + writel(IO_WORD_READ | EEDATA , xl_mmio + MMIO_MAC_ACCESS_CMD) ; + return readw(xl_mmio + MMIO_MACDATA) ; +} + +/* + * Write values to the onboard eeprom. As with eeprom read you need to + * set which location to write, wait, value to write, wait, with the + * added twist of having to enable eeprom writes as well. + */ + +static void xl_ee_write(struct net_device *dev, int ee_addr, u16 ee_value) +{ + struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + u8 *xl_mmio = xl_priv->xl_mmio ; + + /* Wait for EEProm to not be busy */ + writel(IO_WORD_READ | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + while ( readw(xl_mmio + MMIO_MACDATA) & EEBUSY ) ; + + /* Enable write/erase */ + writel(IO_WORD_WRITE | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(EE_ENABLE_WRITE, xl_mmio + MMIO_MACDATA) ; + + /* Wait for EEProm to not be busy */ + writel(IO_WORD_READ | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + while ( readw(xl_mmio + MMIO_MACDATA) & EEBUSY ) ; + + /* Put the value we want to write into EEDATA */ + writel(IO_WORD_WRITE | EEDATA, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(ee_value, xl_mmio + MMIO_MACDATA) ; + + /* Tell EEProm to write eevalue into ee_addr */ + writel(IO_WORD_WRITE | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(EEWRITE + ee_addr, xl_mmio + MMIO_MACDATA) ; + + /* Wait for EEProm to not be busy, to ensure write gets done */ + writel(IO_WORD_READ | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + while ( readw(xl_mmio + MMIO_MACDATA) & EEBUSY ) ; + + return ; +} + +int __devinit xl_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct net_device *dev ; + struct xl_private *xl_priv ; + static int card_no = -1 ; + int i ; + + card_no++ ; + + if (pci_enable_device(pdev)) { + return -ENODEV ; + } + + pci_set_master(pdev); + + if ((i = pci_request_regions(pdev,"3c359"))) { + return i ; + } ; + + /* + * Allowing init_trdev to allocate the dev->priv structure will align xl_private + * on a 32 bytes boundary which we need for the rx/tx descriptors + */ + + dev = alloc_trdev(sizeof(struct xl_private)) ; + if (!dev) { + pci_release_regions(pdev) ; + return -ENOMEM ; + } + xl_priv = dev->priv ; + +#if XL_DEBUG + printk("pci_device: %p, dev:%p, dev->priv: %p, ba[0]: %10x, ba[1]:%10x\n", + pdev, dev, dev->priv, (unsigned int)pdev->resource[0].start, (unsigned int)pdev->resource[1].start) ; +#endif + + dev->irq=pdev->irq; + dev->base_addr=pci_resource_start(pdev,0) ; + dev->init=NULL ; /* Must be null with new api, otherwise get called twice */ + xl_priv->xl_card_name = (char *)pdev->name ; + xl_priv->xl_mmio=ioremap(pci_resource_start(pdev,1), XL_IO_SPACE); + xl_priv->pdev = pdev ; + + if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000) ) + xl_priv->pkt_buf_sz = PKT_BUF_SZ ; + else + xl_priv->pkt_buf_sz = pkt_buf_sz[card_no] ; + + dev->mtu = xl_priv->pkt_buf_sz - TR_HLEN ; + xl_priv->xl_ring_speed = ringspeed[card_no] ; + xl_priv->xl_message_level = message_level[card_no] ; + xl_priv->xl_functional_addr[0] = xl_priv->xl_functional_addr[1] = xl_priv->xl_functional_addr[2] = xl_priv->xl_functional_addr[3] = 0 ; + xl_priv->xl_copy_all_options = 0 ; + + if((i = xl_init(dev))) { + iounmap(xl_priv->xl_mmio) ; + kfree(dev) ; + pci_release_regions(pdev) ; + return i ; + } + + dev->open=&xl_open; + dev->hard_start_xmit=&xl_xmit; + dev->change_mtu=&xl_change_mtu; + dev->stop=&xl_close; + dev->do_ioctl=NULL; + dev->set_multicast_list=&xl_set_rx_mode; + dev->get_stats=&xl_get_stats ; + dev->set_mac_address=&xl_set_mac_address ; + SET_MODULE_OWNER(dev); + + pci_set_drvdata(pdev,dev) ; + if ((i = register_netdev(dev))) { + printk(KERN_ERR "3C359, register netdev failed\n") ; + pci_set_drvdata(pdev,NULL) ; + iounmap(xl_priv->xl_mmio) ; + kfree(dev) ; + pci_release_regions(pdev) ; + return i ; + } + + printk(KERN_INFO "3C359: %s registered as: %s\n",xl_priv->xl_card_name,dev->name) ; + + return 0; +} + + +static int __init xl_init(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + + printk(KERN_INFO "%s \n", version); + printk(KERN_INFO "%s: I/O at %hx, MMIO at %p, using irq %d\n", + xl_priv->xl_card_name, (unsigned int)dev->base_addr ,xl_priv->xl_mmio, dev->irq); + + spin_lock_init(&xl_priv->xl_lock) ; + + return xl_hw_reset(dev) ; + +} + + +/* + * Hardware reset. This needs to be a separate entity as we need to reset the card + * when we change the EEProm settings. + */ + +static int xl_hw_reset(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + u8 *xl_mmio = xl_priv->xl_mmio ; + unsigned long t ; + u16 i ; + u16 result_16 ; + u8 result_8 ; + u16 start ; + int j ; + + /* + * Reset the card. If the card has got the microcode on board, we have + * missed the initialization interrupt, so we must always do this. + */ + + writew( GLOBAL_RESET, xl_mmio + MMIO_COMMAND ) ; + + /* + * Must wait for cmdInProgress bit (12) to clear before continuing with + * card configuration. + */ + + t=jiffies; + while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { + schedule(); + if(jiffies-t > 40*HZ) { + printk(KERN_ERR "%s: 3COM 3C359 Velocity XL card not responding to global reset.\n", dev->name); + return -ENODEV; + } + } + + /* + * Enable pmbar by setting bit in CPAttention + */ + + writel( (IO_BYTE_READ | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + result_8 = readb(xl_mmio + MMIO_MACDATA) ; + result_8 = result_8 | CPA_PMBARVIS ; + writel( (IO_BYTE_WRITE | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(result_8, xl_mmio + MMIO_MACDATA) ; + + /* + * Read cpHold bit in pmbar, if cleared we have got Flashrom on board. + * If not, we need to upload the microcode to the card + */ + + writel( (IO_WORD_READ | PMBAR),xl_mmio + MMIO_MAC_ACCESS_CMD); + +#if XL_DEBUG + printk(KERN_INFO "Read from PMBAR = %04x \n", readw(xl_mmio + MMIO_MACDATA)) ; +#endif + + if ( readw( (xl_mmio + MMIO_MACDATA)) & PMB_CPHOLD ) { + + /* Set PmBar, privateMemoryBase bits (8:2) to 0 */ + + writel( (IO_WORD_READ | PMBAR),xl_mmio + MMIO_MAC_ACCESS_CMD); + result_16 = readw(xl_mmio + MMIO_MACDATA) ; + result_16 = result_16 & ~((0x7F) << 2) ; + writel( (IO_WORD_WRITE | PMBAR), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(result_16,xl_mmio + MMIO_MACDATA) ; + + /* Set CPAttention, memWrEn bit */ + + writel( (IO_BYTE_READ | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + result_8 = readb(xl_mmio + MMIO_MACDATA) ; + result_8 = result_8 | CPA_MEMWREN ; + writel( (IO_BYTE_WRITE | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(result_8, xl_mmio + MMIO_MACDATA) ; + + /* + * Now to write the microcode into the shared ram + * The microcode must finish at position 0xFFFF, so we must subtract + * to get the start position for the code + */ + + start = (0xFFFF - (mc_size) + 1 ) ; /* Looks strange but ensures compiler only uses 16 bit unsigned int for this */ + + printk(KERN_INFO "3C359: Uploading Microcode: "); + + for (i = start,j=0; (j < mc_size && i <= 0xffff) ; i++,j++) { + writel(MEM_BYTE_WRITE | 0XD0000 | i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(microcode[j],xl_mmio + MMIO_MACDATA) ; + if (j % 1024 == 0) + printk("."); + } + printk("\n") ; + + for (i=0;i < 16; i++) { + writel( (MEM_BYTE_WRITE | 0xDFFF0) + i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(microcode[mc_size - 16 + i], xl_mmio + MMIO_MACDATA) ; + } + + /* + * Have to write the start address of the upload to FFF4, but + * the address must be >> 4. You do not want to know how long + * it took me to discover this. + */ + + writel(MEM_WORD_WRITE | 0xDFFF4, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(start >> 4, xl_mmio + MMIO_MACDATA); + + /* Clear the CPAttention, memWrEn Bit */ + + writel( (IO_BYTE_READ | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + result_8 = readb(xl_mmio + MMIO_MACDATA) ; + result_8 = result_8 & ~CPA_MEMWREN ; + writel( (IO_BYTE_WRITE | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(result_8, xl_mmio + MMIO_MACDATA) ; + + /* Clear the cpHold bit in pmbar */ + + writel( (IO_WORD_READ | PMBAR),xl_mmio + MMIO_MAC_ACCESS_CMD); + result_16 = readw(xl_mmio + MMIO_MACDATA) ; + result_16 = result_16 & ~PMB_CPHOLD ; + writel( (IO_WORD_WRITE | PMBAR), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(result_16,xl_mmio + MMIO_MACDATA) ; + + + } /* If microcode upload required */ + + /* + * The card should now go though a self test procedure and get itself ready + * to be opened, we must wait for an srb response with the initialization + * information. + */ + +#if XL_DEBUG + printk(KERN_INFO "%s: Microcode uploaded, must wait for the self test to complete\n", dev->name); +#endif + + writew(SETINDENABLE | 0xFFF, xl_mmio + MMIO_COMMAND) ; + + t=jiffies; + while ( !(readw(xl_mmio + MMIO_INTSTATUS_AUTO) & INTSTAT_SRB) ) { + schedule(); + if(jiffies-t > 15*HZ) { + printk(KERN_ERR "3COM 3C359 Velocity XL card not responding.\n"); + return -ENODEV; + } + } + + /* + * Write the RxBufArea with D000, RxEarlyThresh, TxStartThresh, + * DnPriReqThresh, read the tech docs if you want to know what + * values they need to be. + */ + + writel(MMIO_WORD_WRITE | RXBUFAREA, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(0xD000, xl_mmio + MMIO_MACDATA) ; + + writel(MMIO_WORD_WRITE | RXEARLYTHRESH, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(0X0020, xl_mmio + MMIO_MACDATA) ; + + writew( SETTXSTARTTHRESH | 0x40 , xl_mmio + MMIO_COMMAND) ; + + writeb(0x04, xl_mmio + MMIO_DNBURSTTHRESH) ; + writeb(0x04, xl_mmio + DNPRIREQTHRESH) ; + + /* + * Read WRBR to provide the location of the srb block, have to use byte reads not word reads. + * Tech docs have this wrong !!!! + */ + + writel(MMIO_BYTE_READ | WRBR, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + xl_priv->srb = readb(xl_mmio + MMIO_MACDATA) << 8 ; + writel( (MMIO_BYTE_READ | WRBR) + 1, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + xl_priv->srb = xl_priv->srb | readb(xl_mmio + MMIO_MACDATA) ; + +#if XL_DEBUG + writel(IO_WORD_READ | SWITCHSETTINGS, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + if ( readw(xl_mmio + MMIO_MACDATA) & 2) { + printk(KERN_INFO "Default ring speed 4 mbps \n") ; + } else { + printk(KERN_INFO "Default ring speed 16 mbps \n") ; + } + printk(KERN_INFO "%s: xl_priv->srb = %04x\n",xl_priv->xl_card_name, xl_priv->srb); +#endif + + return 0; +} + +static int xl_open(struct net_device *dev) +{ + struct xl_private *xl_priv=(struct xl_private *)dev->priv; + u8 * xl_mmio = xl_priv->xl_mmio ; + u8 i ; + u16 hwaddr[3] ; /* Should be u8[6] but we get word return values */ + int open_err ; + + u16 switchsettings, switchsettings_eeprom ; + + if(request_irq(dev->irq, &xl_interrupt, SA_SHIRQ , "3c359", dev)) { + return -EAGAIN; + } + + /* + * Read the information from the EEPROM that we need. I know we + * should use ntohs, but the word gets stored reversed in the 16 + * bit field anyway and it all works its self out when we memcpy + * it into dev->dev_addr. + */ + + hwaddr[0] = xl_ee_read(dev,0x10) ; + hwaddr[1] = xl_ee_read(dev,0x11) ; + hwaddr[2] = xl_ee_read(dev,0x12) ; + + /* Ring speed */ + + switchsettings_eeprom = xl_ee_read(dev,0x08) ; + switchsettings = switchsettings_eeprom ; + + if (xl_priv->xl_ring_speed != 0) { + if (xl_priv->xl_ring_speed == 4) + switchsettings = switchsettings | 0x02 ; + else + switchsettings = switchsettings & ~0x02 ; + } + + /* Only write EEProm if there has been a change */ + if (switchsettings != switchsettings_eeprom) { + xl_ee_write(dev,0x08,switchsettings) ; + /* Hardware reset after changing EEProm */ + xl_hw_reset(dev) ; + } + + memcpy(dev->dev_addr,hwaddr,dev->addr_len) ; + + open_err = xl_open_hw(dev) ; + + /* + * This really needs to be cleaned up with better error reporting. + */ + + if (open_err != 0) { /* Something went wrong with the open command */ + if (open_err & 0x07) { /* Wrong speed, retry at different speed */ + printk(KERN_WARNING "%s: Open Error, retrying at different ringspeed \n", dev->name) ; + switchsettings = switchsettings ^ 2 ; + xl_ee_write(dev,0x08,switchsettings) ; + xl_hw_reset(dev) ; + open_err = xl_open_hw(dev) ; + if (open_err != 0) { + printk(KERN_WARNING "%s: Open error returned a second time, we're bombing out now\n", dev->name); + free_irq(dev->irq,dev) ; + return -ENODEV ; + } + } else { + printk(KERN_WARNING "%s: Open Error = %04x\n", dev->name, open_err) ; + free_irq(dev->irq,dev) ; + return -ENODEV ; + } + } + + /* + * Now to set up the Rx and Tx buffer structures + */ + /* These MUST be on 8 byte boundaries */ + xl_priv->xl_tx_ring = kmalloc((sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) + 7, GFP_DMA | GFP_KERNEL) ; + xl_priv->xl_rx_ring = kmalloc((sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) +7, GFP_DMA | GFP_KERNEL) ; + memset(xl_priv->xl_tx_ring,0,sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) ; + memset(xl_priv->xl_rx_ring,0,sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) ; + + /* Setup Rx Ring */ + for (i=0 ; i < XL_RX_RING_SIZE ; i++) { + struct sk_buff *skb ; + + skb = dev_alloc_skb(xl_priv->pkt_buf_sz) ; + if (skb==NULL) + break ; + + skb->dev = dev ; + xl_priv->xl_rx_ring[i].upfragaddr = pci_map_single(xl_priv->pdev, skb->data,xl_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE) ; + xl_priv->xl_rx_ring[i].upfraglen = xl_priv->pkt_buf_sz | RXUPLASTFRAG; + xl_priv->rx_ring_skb[i] = skb ; + } + + if (i==0) { + printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers. Adapter disabled \n",dev->name) ; + free_irq(dev->irq,dev) ; + return -EIO ; + } + + xl_priv->rx_ring_no = i ; + xl_priv->rx_ring_tail = 0 ; + xl_priv->rx_ring_dma_addr = pci_map_single(xl_priv->pdev,xl_priv->xl_rx_ring, sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE, PCI_DMA_TODEVICE) ; + for (i=0;i<(xl_priv->rx_ring_no-1);i++) { + xl_priv->xl_rx_ring[i].upnextptr = xl_priv->rx_ring_dma_addr + (sizeof (struct xl_rx_desc) * (i+1)) ; + } + xl_priv->xl_rx_ring[i].upnextptr = 0 ; + + writel(xl_priv->rx_ring_dma_addr, xl_mmio + MMIO_UPLISTPTR) ; + + /* Setup Tx Ring */ + + xl_priv->tx_ring_dma_addr = pci_map_single(xl_priv->pdev,xl_priv->xl_tx_ring, sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE,PCI_DMA_TODEVICE) ; + + xl_priv->tx_ring_head = 1 ; + xl_priv->tx_ring_tail = 255 ; /* Special marker for first packet */ + xl_priv->free_ring_entries = XL_TX_RING_SIZE ; + + /* + * Setup the first dummy DPD entry for polling to start working. + */ + + xl_priv->xl_tx_ring[0].framestartheader = TXDPDEMPTY ; + xl_priv->xl_tx_ring[0].buffer = 0 ; + xl_priv->xl_tx_ring[0].buffer_length = 0 ; + xl_priv->xl_tx_ring[0].dnnextptr = 0 ; + + writel(xl_priv->tx_ring_dma_addr, xl_mmio + MMIO_DNLISTPTR) ; + writel(DNUNSTALL, xl_mmio + MMIO_COMMAND) ; + writel(UPUNSTALL, xl_mmio + MMIO_COMMAND) ; + writel(DNENABLE, xl_mmio + MMIO_COMMAND) ; + writeb(0x40, xl_mmio + MMIO_DNPOLL) ; + + /* + * Enable interrupts on the card + */ + + writel(SETINTENABLE | INT_MASK, xl_mmio + MMIO_COMMAND) ; + writel(SETINDENABLE | INT_MASK, xl_mmio + MMIO_COMMAND) ; + + netif_start_queue(dev) ; + return 0; + +} + +static int xl_open_hw(struct net_device *dev) +{ + struct xl_private *xl_priv=(struct xl_private *)dev->priv; + u8 * xl_mmio = xl_priv->xl_mmio ; + u16 vsoff ; + char ver_str[33]; + int open_err ; + int i ; + unsigned long t ; + + /* + * Okay, let's build up the Open.NIC srb command + * + */ + + writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(OPEN_NIC, xl_mmio + MMIO_MACDATA) ; + + /* + * Use this as a test byte, if it comes back with the same value, the command didn't work + */ + + writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb)+ 2, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(0xff,xl_mmio + MMIO_MACDATA) ; + + /* Open options */ + writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb) + 8, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(0x00, xl_mmio + MMIO_MACDATA) ; + writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb) + 9, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(0x00, xl_mmio + MMIO_MACDATA) ; + + /* + * Node address, be careful here, the docs say you can just put zeros here and it will use + * the hardware address, it doesn't, you must include the node address in the open command. + */ + + if (xl_priv->xl_laa[0]) { /* If using a LAA address */ + for (i=10;i<16;i++) { + writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb) + i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(xl_priv->xl_laa[i],xl_mmio + MMIO_MACDATA) ; + } + memcpy(dev->dev_addr,xl_priv->xl_laa,dev->addr_len) ; + } else { /* Regular hardware address */ + for (i=10;i<16;i++) { + writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb) + i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(dev->dev_addr[i-10], xl_mmio + MMIO_MACDATA) ; + } + } + + /* Default everything else to 0 */ + for (i = 16; i < 34; i++) { + writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb) + i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(0x00,xl_mmio + MMIO_MACDATA) ; + } + + /* + * Set the csrb bit in the MISR register + */ + + xl_wait_misr_flags(dev) ; + writel(MEM_BYTE_WRITE | MF_CSRB, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(0xFF, xl_mmio + MMIO_MACDATA) ; + writel(MMIO_BYTE_WRITE | MISR_SET, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(MISR_CSRB , xl_mmio + MMIO_MACDATA) ; + + /* + * Now wait for the command to run + */ + + t=jiffies; + while (! (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_SRB)) { + schedule(); + if(jiffies-t > 40*HZ) { + printk(KERN_ERR "3COM 3C359 Velocity XL card not responding.\n"); + break ; + } + } + + /* + * Let's interpret the open response + */ + + writel( (MEM_BYTE_READ | 0xD0000 | xl_priv->srb)+2, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + if (readb(xl_mmio + MMIO_MACDATA)!=0) { + open_err = readb(xl_mmio + MMIO_MACDATA) << 8 ; + writel( (MEM_BYTE_READ | 0xD0000 | xl_priv->srb) + 7, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + open_err |= readb(xl_mmio + MMIO_MACDATA) ; + return open_err ; + } else { + writel( (MEM_WORD_READ | 0xD0000 | xl_priv->srb) + 8, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + xl_priv->asb = ntohs(readw(xl_mmio + MMIO_MACDATA)) ; + printk(KERN_INFO "%s: Adapter Opened Details: ",dev->name) ; + printk("ASB: %04x",xl_priv->asb ) ; + writel( (MEM_WORD_READ | 0xD0000 | xl_priv->srb) + 10, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + printk(", SRB: %04x",ntohs(readw(xl_mmio + MMIO_MACDATA)) ) ; + + writel( (MEM_WORD_READ | 0xD0000 | xl_priv->srb) + 12, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + xl_priv->arb = ntohs(readw(xl_mmio + MMIO_MACDATA)) ; + printk(", ARB: %04x \n",xl_priv->arb ) ; + writel( (MEM_WORD_READ | 0xD0000 | xl_priv->srb) + 14, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + vsoff = ntohs(readw(xl_mmio + MMIO_MACDATA)) ; + + /* + * Interesting, sending the individual characters directly to printk was causing klogd to use + * use 100% of processor time, so we build up the string and print that instead. + */ + + for (i=0;i<0x20;i++) { + writel( (MEM_BYTE_READ | 0xD0000 | vsoff) + i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + ver_str[i] = readb(xl_mmio + MMIO_MACDATA) ; + } + ver_str[i] = '\0' ; + printk(KERN_INFO "%s: Microcode version String: %s \n",dev->name,ver_str); + } + + /* + * Issue the AckInterrupt + */ + writew(ACK_INTERRUPT | SRBRACK | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + + return 0 ; +} + +/* + * There are two ways of implementing rx on the 359 NIC, either + * interrupt driven or polling. We are going to uses interrupts, + * it is the easier way of doing things. + * + * The Rx works with a ring of Rx descriptors. At initialise time the ring + * entries point to the next entry except for the last entry in the ring + * which points to 0. The card is programmed with the location of the first + * available descriptor and keeps reading the next_ptr until next_ptr is set + * to 0. Hopefully with a ring size of 16 the card will never get to read a next_ptr + * of 0. As the Rx interrupt is received we copy the frame up to the protocol layers + * and then point the end of the ring to our current position and point our current + * position to 0, therefore making the current position the last position on the ring. + * The last position on the ring therefore loops continually loops around the rx ring. + * + * rx_ring_tail is the position on the ring to process next. (Think of a snake, the head + * expands as the card adds new packets and we go around eating the tail processing the + * packets.) + * + * Undoubtably it could be streamlined and improved upon, but at the moment it works + * and the fast path through the routine is fine. + * + * adv_rx_ring could be inlined to increase performance, but its called a *lot* of times + * in xl_rx so would increase the size of the function significantly. + */ + +static void adv_rx_ring(struct net_device *dev) /* Advance rx_ring, cut down on bloat in xl_rx */ +{ + struct xl_private *xl_priv=(struct xl_private *)dev->priv; + int prev_ring_loc ; + + prev_ring_loc = (xl_priv->rx_ring_tail + XL_RX_RING_SIZE - 1) & (XL_RX_RING_SIZE - 1); + xl_priv->xl_rx_ring[prev_ring_loc].upnextptr = xl_priv->rx_ring_dma_addr + (sizeof (struct xl_rx_desc) * xl_priv->rx_ring_tail) ; + xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].framestatus = 0 ; + xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upnextptr = 0 ; + xl_priv->rx_ring_tail++ ; + xl_priv->rx_ring_tail &= (XL_RX_RING_SIZE-1) ; + + return ; +} + +static void xl_rx(struct net_device *dev) +{ + struct xl_private *xl_priv=(struct xl_private *)dev->priv; + u8 * xl_mmio = xl_priv->xl_mmio ; + struct sk_buff *skb, *skb2 ; + int frame_length = 0, copy_len = 0 ; + int temp_ring_loc ; + + /* + * Receive the next frame, loop around the ring until all frames + * have been received. + */ + + while (xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].framestatus & (RXUPDCOMPLETE | RXUPDFULL) ) { /* Descriptor to process */ + + if (xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].framestatus & RXUPDFULL ) { /* UpdFull, Multiple Descriptors used for the frame */ + + /* + * This is a pain, you need to go through all the descriptors until the last one + * for this frame to find the framelength + */ + + temp_ring_loc = xl_priv->rx_ring_tail ; + + while (xl_priv->xl_rx_ring[temp_ring_loc].framestatus & RXUPDFULL ) { + temp_ring_loc++ ; + temp_ring_loc &= (XL_RX_RING_SIZE-1) ; + } + + frame_length = xl_priv->xl_rx_ring[temp_ring_loc].framestatus & 0x7FFF ; + + skb = dev_alloc_skb(frame_length) ; + + if (skb==NULL) { /* No memory for frame, still need to roll forward the rx ring */ + printk(KERN_WARNING "%s: dev_alloc_skb failed - multi buffer !\n", dev->name) ; + while (xl_priv->rx_ring_tail != temp_ring_loc) + adv_rx_ring(dev) ; + + adv_rx_ring(dev) ; /* One more time just for luck :) */ + xl_priv->xl_stats.rx_dropped++ ; + + writel(ACK_INTERRUPT | UPCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; + return ; + } + + skb->dev = dev ; + + while (xl_priv->rx_ring_tail != temp_ring_loc) { + copy_len = xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfraglen & 0x7FFF ; + frame_length -= copy_len ; + pci_dma_sync_single(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; + memcpy(skb_put(skb,copy_len), xl_priv->rx_ring_skb[xl_priv->rx_ring_tail]->data, copy_len) ; + adv_rx_ring(dev) ; + } + + /* Now we have found the last fragment */ + pci_dma_sync_single(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; + memcpy(skb_put(skb,copy_len), xl_priv->rx_ring_skb[xl_priv->rx_ring_tail]->data, frame_length) ; +/* memcpy(skb_put(skb,frame_length), bus_to_virt(xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr), frame_length) ; */ + adv_rx_ring(dev) ; + skb->protocol = tr_type_trans(skb,dev) ; + netif_rx(skb) ; + + } else { /* Single Descriptor Used, simply swap buffers over, fast path */ + + frame_length = xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].framestatus & 0x7FFF ; + + skb = dev_alloc_skb(xl_priv->pkt_buf_sz) ; + + if (skb==NULL) { /* Still need to fix the rx ring */ + printk(KERN_WARNING "%s: dev_alloc_skb failed in rx, single buffer \n",dev->name) ; + adv_rx_ring(dev) ; + xl_priv->xl_stats.rx_dropped++ ; + writel(ACK_INTERRUPT | UPCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; + return ; + } + + skb->dev = dev ; + + skb2 = xl_priv->rx_ring_skb[xl_priv->rx_ring_tail] ; + pci_unmap_single(xl_priv->pdev, xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr, xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; + skb_put(skb2, frame_length) ; + skb2->protocol = tr_type_trans(skb2,dev) ; + + xl_priv->rx_ring_skb[xl_priv->rx_ring_tail] = skb ; + xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr = pci_map_single(xl_priv->pdev,skb->data,xl_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE) ; + xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfraglen = xl_priv->pkt_buf_sz | RXUPLASTFRAG ; + adv_rx_ring(dev) ; + xl_priv->xl_stats.rx_packets++ ; + xl_priv->xl_stats.rx_bytes += frame_length ; + + netif_rx(skb2) ; + } /* if multiple buffers */ + dev->last_rx = jiffies ; + } /* while packet to do */ + + /* Clear the updComplete interrupt */ + writel(ACK_INTERRUPT | UPCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; + return ; +} + +/* + * This is ruthless, it doesn't care what state the card is in it will + * completely reset the adapter. + */ + +static void xl_reset(struct net_device *dev) +{ + struct xl_private *xl_priv=(struct xl_private *)dev->priv; + u8 * xl_mmio = xl_priv->xl_mmio ; + unsigned long t; + + writew( GLOBAL_RESET, xl_mmio + MMIO_COMMAND ) ; + + /* + * Must wait for cmdInProgress bit (12) to clear before continuing with + * card configuration. + */ + + t=jiffies; + while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { + if(jiffies-t > 40*HZ) { + printk(KERN_ERR "3COM 3C359 Velocity XL card not responding.\n"); + break ; + } + } + +} + +static void xl_freemem(struct net_device *dev) +{ + struct xl_private *xl_priv=(struct xl_private *)dev->priv ; + int i ; + + for (i=0;irx_ring_skb[xl_priv->rx_ring_tail]) ; + pci_unmap_single(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE) ; + xl_priv->rx_ring_tail++ ; + xl_priv->rx_ring_tail &= XL_RX_RING_SIZE-1; + } + + /* unmap ring */ + pci_unmap_single(xl_priv->pdev,xl_priv->rx_ring_dma_addr, sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE, PCI_DMA_FROMDEVICE) ; + + pci_unmap_single(xl_priv->pdev,xl_priv->tx_ring_dma_addr, sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE, PCI_DMA_TODEVICE) ; + + kfree(xl_priv->xl_rx_ring) ; + kfree(xl_priv->xl_tx_ring) ; + + return ; +} + +static void xl_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct xl_private *xl_priv =(struct xl_private *)dev->priv; + u8 * xl_mmio = xl_priv->xl_mmio ; + u16 intstatus, macstatus ; + + if (!dev) { + printk(KERN_WARNING "Device structure dead, aaahhhh !\n") ; + return ; + } + + intstatus = readw(xl_mmio + MMIO_INTSTATUS) ; + + if (!(intstatus & 1)) /* We didn't generate the interrupt */ + return ; + + spin_lock(&xl_priv->xl_lock) ; + + /* + * Process the interrupt + */ + /* + * Something fishy going on here, we shouldn't get 0001 ints, not fatal though. + */ + if (intstatus == 0x0001) { + writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + printk(KERN_INFO "%s: 00001 int received \n",dev->name) ; + } else { + if (intstatus & (HOSTERRINT | SRBRINT | ARBCINT | UPCOMPINT | DNCOMPINT | HARDERRINT | (1<<8) | TXUNDERRUN | ASBFINT)) { + + /* + * Host Error. + * It may be possible to recover from this, but usually it means something + * is seriously fubar, so we just close the adapter. + */ + + if (intstatus & HOSTERRINT) { + printk(KERN_WARNING "%s: Host Error, performing global reset, intstatus = %04x \n",dev->name,intstatus) ; + writew( GLOBAL_RESET, xl_mmio + MMIO_COMMAND ) ; + printk(KERN_WARNING "%s: Resetting hardware: \n", dev->name); + netif_stop_queue(dev) ; + xl_freemem(dev) ; + free_irq(dev->irq,dev); + xl_reset(dev) ; + writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + spin_unlock(&xl_priv->xl_lock) ; + return ; + } /* Host Error */ + + if (intstatus & SRBRINT ) { /* Srbc interrupt */ + writel(ACK_INTERRUPT | SRBRACK | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + if (xl_priv->srb_queued) + xl_srb_bh(dev) ; + } /* SRBR Interrupt */ + + if (intstatus & TXUNDERRUN) { /* Issue DnReset command */ + writel(DNRESET, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { /* Wait for command to run */ + /* !!! FIX-ME !!!! + Must put a timeout check here ! */ + /* Empty Loop */ + } + printk(KERN_WARNING "%s: TX Underrun received \n",dev->name) ; + writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + } /* TxUnderRun */ + + if (intstatus & ARBCINT ) { /* Arbc interrupt */ + xl_arb_cmd(dev) ; + } /* Arbc */ + + if (intstatus & ASBFINT) { + if (xl_priv->asb_queued == 1) { + xl_asb_cmd(dev) ; + } else if (xl_priv->asb_queued == 2) { + xl_asb_bh(dev) ; + } else { + writel(ACK_INTERRUPT | LATCH_ACK | ASBFACK, xl_mmio + MMIO_COMMAND) ; + } + } /* Asbf */ + + if (intstatus & UPCOMPINT ) /* UpComplete */ + xl_rx(dev) ; + + if (intstatus & DNCOMPINT ) /* DnComplete */ + xl_dn_comp(dev) ; + + if (intstatus & HARDERRINT ) { /* Hardware error */ + writel(MMIO_WORD_READ | MACSTATUS, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + macstatus = readw(xl_mmio + MMIO_MACDATA) ; + printk(KERN_WARNING "%s: MacStatusError, details: ", dev->name); + if (macstatus & (1<<14)) + printk(KERN_WARNING "tchk error: Unrecoverable error \n") ; + if (macstatus & (1<<3)) + printk(KERN_WARNING "eint error: Internal watchdog timer expired \n") ; + if (macstatus & (1<<2)) + printk(KERN_WARNING "aint error: Host tried to perform illegal operation \n") ; + printk(KERN_WARNING "Instatus = %02x, macstatus = %02x\n",intstatus,macstatus) ; + printk(KERN_WARNING "%s: Resetting hardware: \n", dev->name); + netif_stop_queue(dev) ; + xl_freemem(dev) ; + free_irq(dev->irq,dev); + unregister_trdev(dev) ; + kfree(dev) ; + xl_reset(dev) ; + writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + spin_unlock(&xl_priv->xl_lock) ; + return ; + } + } else { + printk(KERN_WARNING "%s: Received Unknown interrupt : %04x \n", dev->name, intstatus) ; + writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + } + } + + /* Turn interrupts back on */ + + writel( SETINDENABLE | INT_MASK, xl_mmio + MMIO_COMMAND) ; + writel( SETINTENABLE | INT_MASK, xl_mmio + MMIO_COMMAND) ; + + spin_unlock(&xl_priv->xl_lock) ; +} + +/* + * Tx - Polling configuration + */ + +static int xl_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct xl_private *xl_priv=(struct xl_private *)dev->priv; + struct xl_tx_desc *txd ; + int tx_head, tx_tail, tx_prev ; + unsigned long flags ; + + spin_lock_irqsave(&xl_priv->xl_lock,flags) ; + + netif_stop_queue(dev) ; + + if (xl_priv->free_ring_entries > 1 ) { + /* + * Set up the descriptor for the packet + */ + tx_head = xl_priv->tx_ring_head ; + tx_tail = xl_priv->tx_ring_tail ; + + txd = &(xl_priv->xl_tx_ring[tx_head]) ; + txd->dnnextptr = 0 ; + txd->framestartheader = skb->len | TXDNINDICATE ; + txd->buffer = pci_map_single(xl_priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE) ; + txd->buffer_length = skb->len | TXDNFRAGLAST ; + xl_priv->tx_ring_skb[tx_head] = skb ; + xl_priv->xl_stats.tx_packets++ ; + xl_priv->xl_stats.tx_bytes += skb->len ; + + /* + * Set the nextptr of the previous descriptor equal to this descriptor, add XL_TX_RING_SIZE -1 + * to ensure no negative numbers in unsigned locations. + */ + + tx_prev = (xl_priv->tx_ring_head + XL_TX_RING_SIZE - 1) & (XL_TX_RING_SIZE - 1) ; + + xl_priv->tx_ring_head++ ; + xl_priv->tx_ring_head &= (XL_TX_RING_SIZE - 1) ; + xl_priv->free_ring_entries-- ; + + xl_priv->xl_tx_ring[tx_prev].dnnextptr = xl_priv->tx_ring_dma_addr + (sizeof (struct xl_tx_desc) * tx_head) ; + + /* Sneaky, by doing a read on DnListPtr we can force the card to poll on the DnNextPtr */ + /* readl(xl_mmio + MMIO_DNLISTPTR) ; */ + + netif_wake_queue(dev) ; + + spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ; + + return 0; + } else { + spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ; + return 1; + } + +} + +/* + * The NIC has told us that a packet has been downloaded onto the card, we must + * find out which packet it has done, clear the skb and information for the packet + * then advance around the ring for all tranmitted packets + */ + +static void xl_dn_comp(struct net_device *dev) +{ + struct xl_private *xl_priv=(struct xl_private *)dev->priv; + u8 * xl_mmio = xl_priv->xl_mmio ; + struct xl_tx_desc *txd ; + + + if (xl_priv->tx_ring_tail == 255) {/* First time */ + xl_priv->xl_tx_ring[0].framestartheader = 0 ; + xl_priv->xl_tx_ring[0].dnnextptr = 0 ; + xl_priv->tx_ring_tail = 1 ; + } + + while (xl_priv->xl_tx_ring[xl_priv->tx_ring_tail].framestartheader & TXDNCOMPLETE ) { + txd = &(xl_priv->xl_tx_ring[xl_priv->tx_ring_tail]) ; + pci_unmap_single(xl_priv->pdev,txd->buffer, xl_priv->tx_ring_skb[xl_priv->tx_ring_tail]->len, PCI_DMA_TODEVICE) ; + txd->framestartheader = 0 ; + txd->buffer = 0xdeadbeef ; + txd->buffer_length = 0 ; + dev_kfree_skb_irq(xl_priv->tx_ring_skb[xl_priv->tx_ring_tail]) ; + xl_priv->tx_ring_tail++ ; + xl_priv->tx_ring_tail &= (XL_TX_RING_SIZE - 1) ; + xl_priv->free_ring_entries++ ; + } + + netif_wake_queue(dev) ; + + writel(ACK_INTERRUPT | DNCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; +} + +/* + * Close the adapter properly. + * This srb reply cannot be handled from interrupt context as we have + * to free the interrupt from the driver. + */ + +static int xl_close(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + u8 * xl_mmio = xl_priv->xl_mmio ; + unsigned long t ; + + netif_stop_queue(dev) ; + + /* + * Close the adapter, need to stall the rx and tx queues. + */ + + writew(DNSTALL, xl_mmio + MMIO_COMMAND) ; + t=jiffies; + while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { + schedule(); + if(jiffies-t > 10*HZ) { + printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-DNSTALL not responding.\n", dev->name); + break ; + } + } + writew(DNDISABLE, xl_mmio + MMIO_COMMAND) ; + t=jiffies; + while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { + schedule(); + if(jiffies-t > 10*HZ) { + printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-DNDISABLE not responding.\n", dev->name); + break ; + } + } + writew(UPSTALL, xl_mmio + MMIO_COMMAND) ; + t=jiffies; + while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { + schedule(); + if(jiffies-t > 10*HZ) { + printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-UPSTALL not responding.\n", dev->name); + break ; + } + } + + /* Turn off interrupts, we will still get the indication though + * so we can trap it + */ + + writel(SETINTENABLE, xl_mmio + MMIO_COMMAND) ; + + xl_srb_cmd(dev,CLOSE_NIC) ; + + t=jiffies; + while (!(readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_SRB)) { + schedule(); + if(jiffies-t > 10*HZ) { + printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-CLOSENIC not responding.\n", dev->name); + break ; + } + } + /* Read the srb response from the adapter */ + + writel(MEM_BYTE_READ | 0xd0000 | xl_priv->srb, xl_mmio + MMIO_MAC_ACCESS_CMD); + if (readb(xl_mmio + MMIO_MACDATA) != CLOSE_NIC) { + printk(KERN_INFO "%s: CLOSE_NIC did not get a CLOSE_NIC response \n",dev->name) ; + } else { + writel((MEM_BYTE_READ | 0xd0000 | xl_priv->srb) +2, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + if (readb(xl_mmio + MMIO_MACDATA)==0) { + printk(KERN_INFO "%s: Adapter has been closed \n",dev->name) ; + writew(ACK_INTERRUPT | SRBRACK | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + + xl_freemem(dev) ; + free_irq(dev->irq,dev) ; + } else { + printk(KERN_INFO "%s: Close nic command returned error code %02x\n",dev->name, readb(xl_mmio + MMIO_MACDATA)) ; + } + } + + /* Reset the upload and download logic */ + + writew(UPRESET, xl_mmio + MMIO_COMMAND) ; + t=jiffies; + while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { + schedule(); + if(jiffies-t > 10*HZ) { + printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-UPRESET not responding.\n", dev->name); + break ; + } + } + writew(DNRESET, xl_mmio + MMIO_COMMAND) ; + t=jiffies; + while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { + schedule(); + if(jiffies-t > 10*HZ) { + printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-DNRESET not responding.\n", dev->name); + break ; + } + } + xl_hw_reset(dev) ; + return 0 ; +} + +static void xl_set_rx_mode(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + struct dev_mc_list *dmi ; + unsigned char dev_mc_address[4] ; + u16 options ; + int i ; + + if (dev->flags & IFF_PROMISC) + options = 0x0004 ; + else + options = 0x0000 ; + + if (options ^ xl_priv->xl_copy_all_options) { /* Changed, must send command */ + xl_priv->xl_copy_all_options = options ; + xl_srb_cmd(dev, SET_RECEIVE_MODE) ; + return ; + } + + dev_mc_address[0] = dev_mc_address[1] = dev_mc_address[2] = dev_mc_address[3] = 0 ; + + for (i=0,dmi=dev->mc_list;i < dev->mc_count; i++,dmi = dmi->next) { + dev_mc_address[0] |= dmi->dmi_addr[2] ; + dev_mc_address[1] |= dmi->dmi_addr[3] ; + dev_mc_address[2] |= dmi->dmi_addr[4] ; + dev_mc_address[3] |= dmi->dmi_addr[5] ; + } + + if (memcmp(xl_priv->xl_functional_addr,dev_mc_address,4) != 0) { /* Options have changed, run the command */ + memcpy(xl_priv->xl_functional_addr, dev_mc_address,4) ; + xl_srb_cmd(dev, SET_FUNC_ADDRESS) ; + } + return ; +} + + +/* + * We issued an srb command and now we must read + * the response from the completed command. + */ + +static void xl_srb_bh(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + u8 * xl_mmio = xl_priv->xl_mmio ; + u8 srb_cmd, ret_code ; + int i ; + + writel(MEM_BYTE_READ | 0xd0000 | xl_priv->srb, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + srb_cmd = readb(xl_mmio + MMIO_MACDATA) ; + writel((MEM_BYTE_READ | 0xd0000 | xl_priv->srb) +2, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + ret_code = readb(xl_mmio + MMIO_MACDATA) ; + + /* Ret_code is standard across all commands */ + + switch (ret_code) { + case 1: + printk(KERN_INFO "%s: Command: %d - Invalid Command code\n",dev->name,srb_cmd) ; + break ; + case 4: + printk(KERN_INFO "%s: Command: %d - Adapter is closed, must be open for this command \n",dev->name,srb_cmd) ; + break ; + + case 6: + printk(KERN_INFO "%s: Command: %d - Options Invalid for command \n",dev->name,srb_cmd) ; + break ; + + case 0: /* Successful command execution */ + switch (srb_cmd) { + case READ_LOG: /* Returns 14 bytes of data from the NIC */ + if(xl_priv->xl_message_level) + printk(KERN_INFO "%s: READ.LOG 14 bytes of data ",dev->name) ; + /* + * We still have to read the log even if message_level = 0 and we don't want + * to see it + */ + for (i=0;i<14;i++) { + writel(MEM_BYTE_READ | 0xd0000 | xl_priv->srb | i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + if(xl_priv->xl_message_level) + printk("%02x:",readb(xl_mmio + MMIO_MACDATA)) ; + } + printk("\n") ; + break ; + case SET_FUNC_ADDRESS: + if(xl_priv->xl_message_level) + printk(KERN_INFO "%s: Functional Address Set \n",dev->name) ; + break ; + case CLOSE_NIC: + if(xl_priv->xl_message_level) + printk(KERN_INFO "%s: Received CLOSE_NIC interrupt in interrupt handler \n",dev->name) ; + break ; + case SET_MULTICAST_MODE: + if(xl_priv->xl_message_level) + printk(KERN_INFO "%s: Multicast options successfully changed\n",dev->name) ; + break ; + case SET_RECEIVE_MODE: + if(xl_priv->xl_message_level) { + if (xl_priv->xl_copy_all_options == 0x0004) + printk(KERN_INFO "%s: Entering promiscuous mode \n", dev->name) ; + else + printk(KERN_INFO "%s: Entering normal receive mode \n",dev->name) ; + } + break ; + + } /* switch */ + break ; + } /* switch */ + return ; +} + +static struct net_device_stats * xl_get_stats(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + return (struct net_device_stats *) &xl_priv->xl_stats; +} + +static int xl_set_mac_address (struct net_device *dev, void *addr) +{ + struct sockaddr *saddr = addr ; + struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + + if (netif_running(dev)) { + printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name) ; + return -EIO ; + } + + memcpy(xl_priv->xl_laa, saddr->sa_data,dev->addr_len) ; + + if (xl_priv->xl_message_level) { + printk(KERN_INFO "%s: MAC/LAA Set to = %x.%x.%x.%x.%x.%x\n",dev->name, xl_priv->xl_laa[0], + xl_priv->xl_laa[1], xl_priv->xl_laa[2], + xl_priv->xl_laa[3], xl_priv->xl_laa[4], + xl_priv->xl_laa[5]); + } + + return 0 ; +} + +static void xl_arb_cmd(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv; + u8 * xl_mmio = xl_priv->xl_mmio ; + u8 arb_cmd ; + u16 lan_status, lan_status_diff ; + + writel( ( MEM_BYTE_READ | 0xD0000 | xl_priv->arb), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + arb_cmd = readb(xl_mmio + MMIO_MACDATA) ; + + if (arb_cmd == RING_STATUS_CHANGE) { /* Ring.Status.Change */ + writel( ( (MEM_WORD_READ | 0xD0000 | xl_priv->arb) + 6), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + + printk(KERN_INFO "%s: Ring Status Change: New Status = %04x\n", dev->name, ntohs(readw(xl_mmio + MMIO_MACDATA) )) ; + + lan_status = ntohs(readw(xl_mmio + MMIO_MACDATA)); + + /* Acknowledge interrupt, this tells nic we are done with the arb */ + writel(ACK_INTERRUPT | ARBCACK | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + + lan_status_diff = xl_priv->xl_lan_status ^ lan_status ; + + if (lan_status_diff & (LSC_LWF | LSC_ARW | LSC_FPE | LSC_RR) ) { + if (lan_status_diff & LSC_LWF) + printk(KERN_WARNING "%s: Short circuit detected on the lobe\n",dev->name); + if (lan_status_diff & LSC_ARW) + printk(KERN_WARNING "%s: Auto removal error\n",dev->name); + if (lan_status_diff & LSC_FPE) + printk(KERN_WARNING "%s: FDX Protocol Error\n",dev->name); + if (lan_status_diff & LSC_RR) + printk(KERN_WARNING "%s: Force remove MAC frame received\n",dev->name); + + /* Adapter has been closed by the hardware */ + + netif_stop_queue(dev); + xl_freemem(dev) ; + free_irq(dev->irq,dev); + + printk(KERN_WARNING "%s: Adapter has been closed \n", dev->name) ; + } /* If serious error */ + + if (xl_priv->xl_message_level) { + if (lan_status_diff & LSC_SIG_LOSS) + printk(KERN_WARNING "%s: No receive signal detected \n", dev->name) ; + if (lan_status_diff & LSC_HARD_ERR) + printk(KERN_INFO "%s: Beaconing \n",dev->name); + if (lan_status_diff & LSC_SOFT_ERR) + printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame \n",dev->name); + if (lan_status_diff & LSC_TRAN_BCN) + printk(KERN_INFO "%s: We are tranmitting the beacon, aaah\n",dev->name); + if (lan_status_diff & LSC_SS) + printk(KERN_INFO "%s: Single Station on the ring \n", dev->name); + if (lan_status_diff & LSC_RING_REC) + printk(KERN_INFO "%s: Ring recovery ongoing\n",dev->name); + if (lan_status_diff & LSC_FDX_MODE) + printk(KERN_INFO "%s: Operating in FDX mode\n",dev->name); + } + + if (lan_status_diff & LSC_CO) { + if (xl_priv->xl_message_level) + printk(KERN_INFO "%s: Counter Overflow \n", dev->name); + /* Issue READ.LOG command */ + xl_srb_cmd(dev, READ_LOG) ; + } + + /* There is no command in the tech docs to issue the read_sr_counters */ + if (lan_status_diff & LSC_SR_CO) { + if (xl_priv->xl_message_level) + printk(KERN_INFO "%s: Source routing counters overflow\n", dev->name); + } + + xl_priv->xl_lan_status = lan_status ; + + } /* Lan.change.status */ + else if ( arb_cmd == RECEIVE_DATA) { /* Received.Data */ +#if XL_DEBUG + printk(KERN_INFO "Received.Data \n") ; +#endif + writel( ((MEM_WORD_READ | 0xD0000 | xl_priv->arb) + 6), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + xl_priv->mac_buffer = ntohs(readw(xl_mmio + MMIO_MACDATA)) ; + + /* Now we are going to be really basic here and not do anything + * with the data at all. The tech docs do not give me enough + * information to calculate the buffers properly so we're + * just going to tell the nic that we've dealt with the frame + * anyway. + */ + + dev->last_rx = jiffies ; + /* Acknowledge interrupt, this tells nic we are done with the arb */ + writel(ACK_INTERRUPT | ARBCACK | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + + /* Is the ASB free ? */ + + xl_priv->asb_queued = 0 ; + writel( ((MEM_BYTE_READ | 0xD0000 | xl_priv->asb) + 2), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + if (readb(xl_mmio + MMIO_MACDATA) != 0xff) { + xl_priv->asb_queued = 1 ; + + xl_wait_misr_flags(dev) ; + + writel(MEM_BYTE_WRITE | MF_ASBFR, xl_mmio + MMIO_MAC_ACCESS_CMD); + writeb(0xff, xl_mmio + MMIO_MACDATA) ; + writel(MMIO_BYTE_WRITE | MISR_SET, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(MISR_ASBFR, xl_mmio + MMIO_MACDATA) ; + return ; + /* Drop out and wait for the bottom half to be run */ + } + + xl_asb_cmd(dev) ; + + } else { + printk(KERN_WARNING "%s: Received unknown arb (xl_priv) command: %02x \n",dev->name,arb_cmd) ; + } + + /* Acknowledge the arb interrupt */ + + writel(ACK_INTERRUPT | ARBCACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; + + return ; +} + + +/* + * There is only one asb command, but we can get called from different + * places. + */ + +static void xl_asb_cmd(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + u8 * xl_mmio = xl_priv->xl_mmio ; + + if (xl_priv->asb_queued == 1) + writel(ACK_INTERRUPT | LATCH_ACK | ASBFACK, xl_mmio + MMIO_COMMAND) ; + + writel(MEM_BYTE_WRITE | 0xd0000 | xl_priv->asb, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(0x81, xl_mmio + MMIO_MACDATA) ; + + writel(MEM_WORD_WRITE | 0xd0000 | xl_priv->asb | 6, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(ntohs(xl_priv->mac_buffer), xl_mmio + MMIO_MACDATA) ; + + xl_wait_misr_flags(dev) ; + + writel(MEM_BYTE_WRITE | MF_RASB, xl_mmio + MMIO_MAC_ACCESS_CMD); + writeb(0xff, xl_mmio + MMIO_MACDATA) ; + + writel(MMIO_BYTE_WRITE | MISR_SET, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(MISR_RASB, xl_mmio + MMIO_MACDATA) ; + + xl_priv->asb_queued = 2 ; + + return ; +} + +/* + * This will only get called if there was an error + * from the asb cmd. + */ +static void xl_asb_bh(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + u8 * xl_mmio = xl_priv->xl_mmio ; + u8 ret_code ; + + writel(MMIO_BYTE_READ | 0xd0000 | xl_priv->asb | 2, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + ret_code = readb(xl_mmio + MMIO_MACDATA) ; + switch (ret_code) { + case 0x01: + printk(KERN_INFO "%s: ASB Command, unrecognized command code \n",dev->name) ; + break ; + case 0x26: + printk(KERN_INFO "%s: ASB Command, unexpected receive buffer \n", dev->name) ; + break ; + case 0x40: + printk(KERN_INFO "%s: ASB Command, Invalid Station ID \n", dev->name) ; + break ; + } + xl_priv->asb_queued = 0 ; + writel(ACK_INTERRUPT | LATCH_ACK | ASBFACK, xl_mmio + MMIO_COMMAND) ; + return ; +} + +/* + * Issue srb commands to the nic + */ + +static void xl_srb_cmd(struct net_device *dev, int srb_cmd) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + u8 * xl_mmio = xl_priv->xl_mmio ; + + switch (srb_cmd) { + case READ_LOG: + writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(READ_LOG, xl_mmio + MMIO_MACDATA) ; + break; + + case CLOSE_NIC: + writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(CLOSE_NIC, xl_mmio + MMIO_MACDATA) ; + break ; + + case SET_RECEIVE_MODE: + writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(SET_RECEIVE_MODE, xl_mmio + MMIO_MACDATA) ; + writel(MEM_WORD_WRITE | 0xD0000 | xl_priv->srb | 4, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(xl_priv->xl_copy_all_options, xl_mmio + MMIO_MACDATA) ; + break ; + + case SET_FUNC_ADDRESS: + writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(SET_FUNC_ADDRESS, xl_mmio + MMIO_MACDATA) ; + writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb | 6 , xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(xl_priv->xl_functional_addr[0], xl_mmio + MMIO_MACDATA) ; + writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb | 7 , xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(xl_priv->xl_functional_addr[1], xl_mmio + MMIO_MACDATA) ; + writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb | 8 , xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(xl_priv->xl_functional_addr[2], xl_mmio + MMIO_MACDATA) ; + writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb | 9 , xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(xl_priv->xl_functional_addr[3], xl_mmio + MMIO_MACDATA) ; + break ; + } /* switch */ + + + xl_wait_misr_flags(dev) ; + + /* Write 0xff to the CSRB flag */ + writel(MEM_BYTE_WRITE | MF_CSRB , xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(0xFF, xl_mmio + MMIO_MACDATA) ; + /* Set csrb bit in MISR register to process command */ + writel(MMIO_BYTE_WRITE | MISR_SET, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(MISR_CSRB, xl_mmio + MMIO_MACDATA) ; + xl_priv->srb_queued = 1 ; + + return ; +} + +/* + * This is nasty, to use the MISR command you have to wait for 6 memory locations + * to be zero. This is the way the driver does on other OS'es so we should be ok with + * the empty loop. + */ + +static void xl_wait_misr_flags(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + u8 * xl_mmio = xl_priv->xl_mmio ; + + int i ; + + writel(MMIO_BYTE_READ | MISR_RW, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + if (readb(xl_mmio + MMIO_MACDATA) != 0) { /* Misr not clear */ + for (i=0; i<6; i++) { + writel(MEM_BYTE_READ | 0xDFFE0 | i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + while (readb(xl_mmio + MMIO_MACDATA) != 0 ) {} ; /* Empty Loop */ + } + } + + writel(MMIO_BYTE_WRITE | MISR_AND, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(0x80, xl_mmio + MMIO_MACDATA) ; + + return ; +} + +/* + * Change mtu size, this should work the same as olympic + */ + +static int xl_change_mtu(struct net_device *dev, int mtu) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv; + u16 max_mtu ; + + if (xl_priv->xl_ring_speed == 4) + max_mtu = 4500 ; + else + max_mtu = 18000 ; + + if (mtu > max_mtu) + return -EINVAL ; + if (mtu < 100) + return -EINVAL ; + + dev->mtu = mtu ; + xl_priv->pkt_buf_sz = mtu + TR_HLEN ; + + return 0 ; +} + +static void __devexit xl_remove_one (struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + struct xl_private *xl_priv=(struct xl_private *)dev->priv; + + unregister_trdev(dev); + iounmap(xl_priv->xl_mmio) ; + pci_release_regions(pdev) ; + pci_set_drvdata(pdev,NULL) ; + kfree(dev); + return ; +} + +static struct pci_driver xl_3c359_driver = { + name: "3c359", + id_table: xl_pci_tbl, + probe: xl_probe, + remove: __devexit_p(xl_remove_one), +}; + +static int __init xl_pci_init (void) +{ + return pci_module_init (&xl_3c359_driver); +} + + +static void __exit xl_pci_cleanup (void) +{ + pci_unregister_driver (&xl_3c359_driver); +} + +module_init(xl_pci_init); +module_exit(xl_pci_cleanup); + +MODULE_LICENSE("GPL") ; diff -Nru a/drivers/net/tokenring/3c359.h b/drivers/net/tokenring/3c359.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/tokenring/3c359.h Tue Feb 26 11:58:00 2002 @@ -0,0 +1,290 @@ +/* + * 3c359.h (c) 2000 Mike Phillips (mikep@linuxtr.net) All Rights Reserved + * + * Linux driver for 3Com 3C359 Token Link PCI XL cards. + * + * This software may be used and distributed according to the terms + * of the GNU General Public License Version 2 or (at your option) + * any later verion, incorporated herein by reference. + */ + +/* Memory Access Commands */ +#define IO_BYTE_READ 0x28 << 24 +#define IO_BYTE_WRITE 0x18 << 24 +#define IO_WORD_READ 0x20 << 24 +#define IO_WORD_WRITE 0x10 << 24 +#define MMIO_BYTE_READ 0x88 << 24 +#define MMIO_BYTE_WRITE 0x48 << 24 +#define MMIO_WORD_READ 0x80 << 24 +#define MMIO_WORD_WRITE 0x40 << 24 +#define MEM_BYTE_READ 0x8C << 24 +#define MEM_BYTE_WRITE 0x4C << 24 +#define MEM_WORD_READ 0x84 << 24 +#define MEM_WORD_WRITE 0x44 << 24 + +#define PMBAR 0x1C80 +#define PMB_CPHOLD (1<<10) + +#define CPATTENTION 0x180D +#define CPA_PMBARVIS (1<<7) +#define CPA_MEMWREN (1<<6) + +#define SWITCHSETTINGS 0x1C88 +#define EECONTROL 0x1C8A +#define EEDATA 0x1C8C +#define EEREAD 0x0080 +#define EEWRITE 0x0040 +#define EEERASE 0x0060 +#define EE_ENABLE_WRITE 0x0030 +#define EEBUSY (1<<15) + +#define WRBR 0xCDE02 +#define WWOR 0xCDE04 +#define WWCR 0xCDE06 +#define MACSTATUS 0xCDE08 +#define MISR_RW 0xCDE0B +#define MISR_AND 0xCDE2B +#define MISR_SET 0xCDE4B +#define RXBUFAREA 0xCDE10 +#define RXEARLYTHRESH 0xCDE12 +#define TXSTARTTHRESH 0x58 +#define DNPRIREQTHRESH 0x2C + +#define MISR_CSRB (1<<5) +#define MISR_RASB (1<<4) +#define MISR_SRBFR (1<<3) +#define MISR_ASBFR (1<<2) +#define MISR_ARBF (1<<1) + +/* MISR Flags memory locations */ +#define MF_SSBF 0xDFFE0 +#define MF_ARBF 0xDFFE1 +#define MF_ASBFR 0xDFFE2 +#define MF_SRBFR 0xDFFE3 +#define MF_RASB 0xDFFE4 +#define MF_CSRB 0xDFFE5 + +#define MMIO_MACDATA 0x10 +#define MMIO_MAC_ACCESS_CMD 0x14 +#define MMIO_TIMER 0x1A +#define MMIO_DMA_CTRL 0x20 +#define MMIO_DNLISTPTR 0x24 +#define MMIO_HASHFILTER 0x28 +#define MMIO_CONFIG 0x29 +#define MMIO_DNPRIREQTHRESH 0x2C +#define MMIO_DNPOLL 0x2D +#define MMIO_UPPKTSTATUS 0x30 +#define MMIO_FREETIMER 0x34 +#define MMIO_COUNTDOWN 0x36 +#define MMIO_UPLISTPTR 0x38 +#define MMIO_UPPOLL 0x3C +#define MMIO_UPBURSTTHRESH 0x40 +#define MMIO_DNBURSTTHRESH 0x41 +#define MMIO_INTSTATUS_AUTO 0x56 +#define MMIO_TXSTARTTHRESH 0x58 +#define MMIO_INTERRUPTENABLE 0x5A +#define MMIO_INDICATIONENABLE 0x5C +#define MMIO_COMMAND 0x5E /* These two are meant to be the same */ +#define MMIO_INTSTATUS 0x5E /* Makes the code more readable this way */ +#define INTSTAT_CMD_IN_PROGRESS (1<<12) +#define INTSTAT_SRB (1<<14) +#define INTSTAT_INTLATCH (1<<0) + +/* Indication / Interrupt Mask + * Annoyingly the bits to be set in the indication and interrupt enable + * do not match with the actual bits received in the interrupt, although + * they are in the same order. + * The mapping for the indication / interrupt are: + * Bit Indication / Interrupt + * 0 HostError + * 1 txcomplete + * 2 updneeded + * 3 rxcomplete + * 4 intrequested + * 5 macerror + * 6 dncomplete + * 7 upcomplete + * 8 txunderrun + * 9 asbf + * 10 srbr + * 11 arbc + * + * The only ones we don't want to receive are txcomplete and rxcomplete + * we use dncomplete and upcomplete instead. + */ + +#define INT_MASK 0xFF5 + +/* Note the subtle difference here, IND and INT */ + +#define SETINDENABLE (8<<12) +#define SETINTENABLE (7<<12) +#define SRBBIT (1<<10) +#define ASBBIT (1<<9) +#define ARBBIT (1<<11) + +#define SRB 0xDFE90 +#define ASB 0xDFED0 +#define ARB 0xD0000 +#define SCRATCH 0xDFEF0 + +#define INT_REQUEST 0x6000 /* (6 << 12) */ +#define ACK_INTERRUPT 0x6800 /* (13 <<11) */ +#define GLOBAL_RESET 0x00 +#define DNDISABLE 0x5000 +#define DNENABLE 0x4800 +#define DNSTALL 0x3002 +#define DNRESET 0x5800 +#define DNUNSTALL 0x3003 +#define UPRESET 0x2800 +#define UPSTALL 0x3000 +#define UPUNSTALL 0x3001 +#define SETCONFIG 0x4000 +#define SETTXSTARTTHRESH 0x9800 + +/* Received Interrupts */ +#define ASBFINT (1<<13) +#define SRBRINT (1<<14) +#define ARBCINT (1<<15) +#define TXUNDERRUN (1<<11) + +#define UPCOMPINT (1<<10) +#define DNCOMPINT (1<<9) +#define HARDERRINT (1<<7) +#define RXCOMPLETE (1<<4) +#define TXCOMPINT (1<<2) +#define HOSTERRINT (1<<1) + +/* Receive descriptor bits */ +#define RXOVERRUN (1<<19) +#define RXFC (1<<21) +#define RXAR (1<<22) +#define RXUPDCOMPLETE (1<<23) +#define RXUPDFULL (1<<24) +#define RXUPLASTFRAG (1<<31) + +/* Transmit descriptor bits */ +#define TXDNCOMPLETE (1<<16) +#define TXTXINDICATE (1<<27) +#define TXDPDEMPTY (1<<29) +#define TXDNINDICATE (1<<31) +#define TXDNFRAGLAST (1<<31) + +/* Interrupts to Acknowledge */ +#define LATCH_ACK 1 +#define TXCOMPACK (1<<1) +#define INTREQACK (1<<2) +#define DNCOMPACK (1<<3) +#define UPCOMPACK (1<<4) +#define ASBFACK (1<<5) +#define SRBRACK (1<<6) +#define ARBCACK (1<<7) + +#define XL_IO_SPACE 128 +#define SRB_COMMAND_SIZE 50 + +/* Adapter Commands */ +#define REQUEST_INT 0x00 +#define MODIFY_OPEN_PARMS 0x01 +#define RESTORE_OPEN_PARMS 0x02 +#define OPEN_NIC 0x03 +#define CLOSE_NIC 0x04 +#define SET_SLEEP_MODE 0x05 +#define SET_GROUP_ADDRESS 0x06 +#define SET_FUNC_ADDRESS 0x07 +#define READ_LOG 0x08 +#define SET_MULTICAST_MODE 0x0C +#define CHANGE_WAKEUP_PATTERN 0x0D +#define GET_STATISTICS 0x13 +#define SET_RECEIVE_MODE 0x1F + +/* ARB Commands */ +#define RECEIVE_DATA 0x81 +#define RING_STATUS_CHANGE 0x84 + +/* ASB Commands */ +#define ASB_RECEIVE_DATE 0x81 + +/* Defines for LAN STATUS CHANGE reports */ +#define LSC_SIG_LOSS 0x8000 +#define LSC_HARD_ERR 0x4000 +#define LSC_SOFT_ERR 0x2000 +#define LSC_TRAN_BCN 0x1000 +#define LSC_LWF 0x0800 +#define LSC_ARW 0x0400 +#define LSC_FPE 0x0200 +#define LSC_RR 0x0100 +#define LSC_CO 0x0080 +#define LSC_SS 0x0040 +#define LSC_RING_REC 0x0020 +#define LSC_SR_CO 0x0010 +#define LSC_FDX_MODE 0x0004 + +#define XL_MAX_ADAPTERS 8 /* 0x08 __MODULE_STRING can't hand 0xnn */ + +/* 3c359 defaults for buffers */ + +#define XL_RX_RING_SIZE 16 /* must be a power of 2 */ +#define XL_TX_RING_SIZE 16 /* must be a power of 2 */ + +#define PKT_BUF_SZ 4096 /* Default packet size */ + +/* 3c359 data structures */ + +struct xl_tx_desc { + u32 dnnextptr ; + u32 framestartheader ; + u32 buffer ; + u32 buffer_length ; +}; + +struct xl_rx_desc { + u32 upnextptr ; + u32 framestatus ; + u32 upfragaddr ; + u32 upfraglen ; +}; + +struct xl_private { + + + /* These two structures must be aligned on 8 byte boundaries */ + + /* struct xl_rx_desc xl_rx_ring[XL_RX_RING_SIZE]; */ + /* struct xl_tx_desc xl_tx_ring[XL_TX_RING_SIZE]; */ + struct xl_rx_desc *xl_rx_ring ; + struct xl_tx_desc *xl_tx_ring ; + struct sk_buff *tx_ring_skb[XL_TX_RING_SIZE], *rx_ring_skb[XL_RX_RING_SIZE]; + int tx_ring_head, tx_ring_tail ; + int rx_ring_tail, rx_ring_no ; + int free_ring_entries ; + + u16 srb; + u16 arb; + u16 asb; + + u8 *xl_mmio; + char *xl_card_name; + struct pci_dev *pdev ; + + spinlock_t xl_lock ; + + volatile int srb_queued; + struct wait_queue *srb_wait; + volatile int asb_queued; + + struct net_device_stats xl_stats ; + + u16 mac_buffer ; + u16 xl_lan_status ; + u8 xl_ring_speed ; + u16 pkt_buf_sz ; + u8 xl_message_level; + u16 xl_copy_all_options ; + unsigned char xl_functional_addr[4] ; + u16 xl_addr_table_addr, xl_parms_addr ; + u8 xl_laa[6] ; + u32 rx_ring_dma_addr ; + u32 tx_ring_dma_addr ; +}; + diff -Nru a/drivers/net/tokenring/3c359_microcode.h b/drivers/net/tokenring/3c359_microcode.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/tokenring/3c359_microcode.h Tue Feb 26 11:58:00 2002 @@ -0,0 +1,1585 @@ + +/* + * The firmware this driver downloads into the tokenring card is a + * separate program and is not GPL'd source code, even though the Linux + * side driver and the routine that loads this data into the card are. + * + * This firmware is licensed to you strictly for use in conjunction + * with the use of 3Com 3C359 TokenRing adapters. There is no + * waranty expressed or implied about its fitness for any purpose. + */ + +/* 3c359_microcode.mac: 3Com 3C359 Tokenring microcode. + * + * Notes: + * - Loaded from xl_init upon adapter initialization. + * + * Available from 3Com as part of their standard 3C359 driver. + * + * mc_size *must* must match the microcode being used, each version is a + * different length. + */ + + +#if defined(CONFIG_3C359) || defined(CONFIG_3C359_MODULE) + +static int mc_size = 24880 ; + +u8 microcode[] = { + 0xfe,0x3a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x33,0x2f,0x30,0x32,0x2f,0x39,0x39,0x20,0x31 +,0x37,0x3a,0x31,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46 +,0x00,0x00,0x07,0xff,0x02,0x00,0xfe,0x9f,0x06,0x00,0x00,0x7c,0x48,0x00,0x00,0x70 +,0x82,0x00,0xff,0xff,0x86,0x00,0xff,0xff,0x88,0x00,0xff,0xff,0x9a,0x00,0xff,0xff +,0xff,0xff,0x11,0x00,0xc0,0x00,0xff,0xff,0xff,0xff,0x11,0x22,0x33,0x44,0x55,0x66 +,0x33,0x43,0x4f,0x4d,0x20,0x42,0x41,0x42,0x45,0x11,0x40,0xc0,0x00,0xff,0xff,0xff +,0xff,0x11,0x22,0x33,0x44,0x55,0x66,0x53,0x74,0x61,0x72,0x74,0x20,0x6f,0x66,0x20 +,0x4c,0x4c,0x43,0x20,0x66,0x72,0x61,0x6d,0x65,0x2e,0x20,0x20,0x54,0x6f,0x74,0x61 +,0x6c,0x20,0x64,0x61,0x74,0x61,0x20,0x73,0x69,0x7a,0x65,0x20,0x69,0x73,0x20,0x78 +,0x78,0x78,0x20,0x20,0x20,0x42,0x41,0x42,0x45,0xe8,0xd2,0x01,0x83,0x3e,0xf7,0x34 +,0x00,0x75,0x21,0xe8,0x41,0x00,0x83,0x3e,0xf7,0x34,0x00,0x75,0x17,0xe8,0x82,0x00 +,0x83,0x3e,0xf7,0x34,0x00,0x75,0x0d,0xe8,0xbf,0x00,0x83,0x3e,0xf7,0x34,0x00,0x75 +,0x03,0xe8,0x41,0x02,0xc3,0x1e,0xb8,0x00,0xf0,0x8e,0xd8,0x33,0xf6,0xb9,0x00,0x80 +,0x33,0xdb,0xad,0x03,0xd8,0xe2,0xfb,0x1f,0xb8,0x00,0x00,0x83,0xfb,0x00,0x74,0x03 +,0xb8,0x22,0x00,0xa3,0xf7,0x34,0xc3,0xfa,0xba,0x56,0x00,0xb0,0xff,0xee,0x33,0xc0 +,0x8e,0xc0,0x33,0xf6,0xb9,0xff,0x7f,0x83,0x3e,0xff,0x34,0x00,0x74,0x08,0x8d,0x3e +,0x30,0x61,0xd1,0xef,0x2b,0xcf,0x26,0x8b,0x1c,0x26,0xc7,0x04,0xff,0xff,0x26,0x83 +,0x3c,0xff,0x75,0x17,0x26,0xc7,0x04,0x00,0x00,0x26,0x83,0x3c,0x00,0x75,0x0c,0x26 +,0x89,0x1c,0x46,0x46,0xe2,0xe0,0xb8,0x00,0x00,0xeb,0x03,0xb8,0x24,0x00,0xa3,0xf7 +,0x34,0xc3,0xfa,0xb4,0xd7,0x9e,0x73,0x3a,0x75,0x38,0x79,0x36,0x7b,0x34,0x9f,0xb1 +,0x05,0xd2,0xec,0x73,0x2d,0xb0,0x40,0xd0,0xe0,0x71,0x27,0x79,0x25,0xd0,0xe0,0x73 +,0x21,0x7b,0x1f,0x32,0xc0,0x75,0x1b,0x32,0xe4,0x9e,0x72,0x16,0x74,0x14,0x78,0x12 +,0x7a,0x10,0x9f,0xd2,0xec,0x72,0x0b,0xd0,0xe4,0x70,0x07,0x75,0x05,0xb8,0x00,0x00 +,0xeb,0x03,0xb8,0x26,0x00,0xa3,0xf7,0x34,0xc3,0xfa,0xba,0x5a,0x00,0x33,0xc0,0xef +,0xef,0xef,0xef,0xb0,0x00,0xe6,0x56,0xb0,0x00,0xe6,0x54,0xba,0x52,0x00,0xb8,0x01 +,0x01,0xef,0xe8,0xca,0x00,0x3c,0x01,0x75,0x7f,0xe8,0x83,0x00,0xba,0x52,0x00,0xb8 +,0x02,0x02,0xef,0xe8,0xb9,0x00,0x3c,0x02,0x75,0x6e,0xe8,0x7a,0x00,0xba,0x52,0x00 +,0xb8,0x04,0x04,0xef,0xe8,0xa8,0x00,0x3c,0x04,0x75,0x5d,0xe8,0x71,0x00,0xba,0x52 +,0x00,0xb8,0x08,0x08,0xef,0xe8,0x97,0x00,0x3c,0x08,0x75,0x4c,0xe8,0x68,0x00,0xba +,0x52,0x00,0xb8,0x10,0x10,0xef,0xe8,0x86,0x00,0x3c,0x10,0x75,0x3b,0xe8,0x5f,0x00 +,0xba,0x52,0x00,0xb8,0x20,0x20,0xef,0xe8,0x75,0x00,0x3c,0x20,0x75,0x2a,0xe8,0x56 +,0x00,0xba,0x52,0x00,0xb8,0x40,0x40,0xef,0xe8,0x64,0x00,0x3c,0x40,0x75,0x19,0xe8 +,0x4d,0x00,0xba,0x52,0x00,0xb8,0x80,0x80,0xef,0xe8,0x53,0x00,0x3c,0x80,0x75,0x08 +,0xe8,0x44,0x00,0xb8,0x00,0x00,0xeb,0x03,0xb8,0x28,0x00,0xa3,0xf7,0x34,0xc3,0xba +,0x5a,0x00,0xb8,0x00,0x80,0xef,0xc3,0xba,0x5a,0x00,0xb8,0x01,0x80,0xef,0xc3,0xba +,0x5a,0x00,0xb8,0x02,0x80,0xef,0xc3,0xba,0x5a,0x00,0xb8,0x03,0x80,0xef,0xc3,0xba +,0x5a,0x00,0xb8,0x04,0x80,0xef,0xc3,0xba,0x5a,0x00,0xb8,0x05,0x80,0xef,0xc3,0xba +,0x5a,0x00,0xb8,0x06,0x80,0xef,0xc3,0xba,0x5a,0x00,0xb8,0x07,0x80,0xef,0xc3,0xb9 +,0xff,0xff,0xe4,0x58,0xe4,0x54,0x3c,0x00,0x75,0x03,0x49,0x75,0xf7,0xc3,0xfa,0x32 +,0xc0,0xe6,0x56,0xe4,0x56,0x3c,0x00,0x74,0x03,0xe9,0x82,0x00,0xb0,0xff,0xe6,0x56 +,0xe4,0x56,0x3c,0xff,0x75,0x78,0xba,0x52,0x00,0xb8,0xff,0xff,0xef,0xed,0x3c,0xff +,0x75,0x6c,0xb8,0x00,0xff,0xef,0xed,0x3c,0x00,0x75,0x63,0xb0,0xff,0xe6,0x54,0xe4 +,0x54,0x3c,0xff,0x75,0x59,0x32,0xc0,0xe6,0x54,0xe4,0x54,0x3c,0x00,0x75,0x4f,0xb0 +,0x0f,0xe6,0x50,0xe4,0x50,0x24,0x0f,0x3c,0x0f,0x75,0x43,0xb0,0x00,0xe6,0x50,0xe4 +,0x50,0x24,0x0f,0x3c,0x00,0x75,0x37,0x8c,0xc8,0x8e,0xc0,0xbe,0x70,0x00,0x26,0x8b +,0x14,0x26,0x8b,0x5c,0x02,0xb8,0x00,0x00,0xef,0xed,0x23,0xc3,0x3d,0x00,0x00,0x75 +,0x1d,0xb8,0xff,0xff,0x23,0xc3,0xef,0x8b,0xc8,0xed,0x23,0xc3,0x3b,0xc1,0x75,0x0e +,0x83,0xc6,0x04,0x26,0x83,0x3c,0xff,0x75,0xd5,0xb8,0x00,0x00,0xeb,0x03,0xb8,0x2a +,0x00,0xa3,0xf7,0x34,0xc3,0xfa,0x33,0xc0,0xbf,0x00,0x20,0xb9,0x17,0x00,0xf3,0xab +,0xbf,0x00,0x30,0xb9,0x17,0x00,0xf3,0xab,0xbf,0x00,0x22,0xb9,0x40,0x00,0xf3,0xab +,0xbf,0x00,0x32,0xb9,0x40,0x00,0xf3,0xab,0xfc,0x1e,0x8c,0xc8,0x8e,0xd8,0x33,0xc0 +,0x8e,0xc0,0xbe,0x92,0x00,0xbf,0x00,0x20,0xb9,0x17,0x00,0xf3,0xa4,0xbe,0xa9,0x00 +,0xbf,0x00,0x22,0xb9,0x40,0x00,0xf3,0xa4,0x1f,0xc7,0x06,0xfb,0x34,0x64,0x00,0xba +,0x08,0x00,0xb8,0x0f,0x00,0xef,0xe8,0x82,0x01,0xe8,0x9b,0x01,0x72,0x0d,0xc7,0x06 +,0xf7,0x34,0x2c,0x00,0xc7,0x06,0xf9,0x34,0x04,0x00,0xc3,0xba,0x0a,0x00,0x33,0xc0 +,0xef,0xe8,0x98,0x01,0xe8,0xb5,0x01,0xb8,0x17,0x00,0xba,0x9c,0x00,0xef,0xb8,0x00 +,0x10,0xba,0x9a,0x00,0xef,0xb8,0x17,0x00,0xa9,0x01,0x00,0x74,0x01,0x40,0xba,0x8c +,0x00,0xef,0xb8,0x00,0x18,0xba,0x86,0x00,0xef,0xb8,0x0c,0x00,0xba,0x82,0x00,0xef +,0xba,0x02,0x00,0xed,0x25,0xf9,0xff,0x0d,0x02,0x00,0xef,0xba,0x06,0x00,0x33,0xc0 +,0xef,0xba,0x04,0x00,0xb8,0x60,0x00,0xef,0xba,0x00,0x00,0xb8,0x18,0x00,0xef,0xba +,0x80,0x00,0xb9,0xff,0xff,0xed,0xa9,0x01,0x00,0x75,0x04,0xe2,0xf8,0xeb,0x3e,0xba +,0x0a,0x00,0xed,0xa9,0x00,0x40,0x74,0x35,0xa9,0x00,0x20,0x74,0x30,0x33,0xc0,0xef +,0x51,0xb9,0xc8,0x00,0xe2,0xfe,0x59,0x1e,0x06,0x1f,0x26,0x8b,0x0e,0x02,0x30,0x83 +,0xf9,0x17,0x75,0x18,0x49,0x49,0xbe,0x02,0x20,0xbf,0x06,0x30,0xf3,0xa6,0x1f,0x23 +,0xc9,0x75,0x0a,0xff,0x0e,0xfb,0x34,0x74,0x12,0xe9,0x4d,0xff,0x1f,0xb8,0x2c,0x00 +,0xbb,0x00,0x00,0xa3,0xf7,0x34,0x89,0x1e,0xf9,0x34,0xc3,0xc7,0x06,0xfb,0x34,0x64 +,0x00,0xe8,0xd3,0x00,0x72,0x0d,0xc7,0x06,0xf7,0x34,0x2c,0x00,0xc7,0x06,0xf9,0x34 +,0x04,0x00,0xc3,0xe8,0xd6,0x00,0xe8,0xf3,0x00,0xb8,0x03,0x00,0xba,0x82,0x00,0xef +,0xb8,0x40,0x80,0xba,0x98,0x00,0xef,0xb8,0x00,0x11,0xba,0x96,0x00,0xef,0xb8,0x40 +,0x00,0xa9,0x01,0x00,0x74,0x01,0x40,0xba,0x92,0x00,0xef,0xb8,0x00,0x19,0xba,0x8e +,0x00,0xef,0xba,0x02,0x00,0xed,0x25,0xf9,0xff,0x0d,0x06,0x00,0xef,0xba,0x06,0x00 +,0x33,0xc0,0xef,0xba,0x00,0x00,0xb8,0x18,0x00,0xef,0xba,0x80,0x00,0xb9,0xff,0xff +,0xed,0xa9,0x20,0x00,0x75,0x04,0xe2,0xf8,0xeb,0x43,0xba,0x0a,0x00,0xed,0xa9,0x00 +,0x40,0x74,0x3a,0xa9,0x00,0x20,0x74,0x35,0x33,0xc0,0xef,0x51,0xb9,0xc8,0x00,0xe2 +,0xfe,0x59,0x1e,0x06,0x1f,0x26,0x8b,0x0e,0x02,0x32,0x83,0xf9,0x40,0x75,0x1d,0x49 +,0x49,0xbe,0x02,0x22,0xbf,0x06,0x32,0xf3,0xa6,0x1f,0x23,0xc9,0x75,0x0f,0xff,0x0e +,0xfb,0x34,0x74,0x03,0xe9,0x5a,0xff,0xb8,0x00,0x00,0xeb,0x0b,0x1f,0xb8,0x2c,0x00 +,0xbb,0x02,0x00,0x89,0x1e,0xf9,0x34,0xa3,0xf7,0x34,0xc3,0xba,0x02,0x00,0xb8,0x00 +,0x9c,0xef,0xba,0x00,0x00,0xb8,0x00,0x84,0xef,0x33,0xc0,0xef,0xba,0x0a,0x00,0xef +,0xba,0x0e,0x00,0x33,0xc0,0xef,0xc3,0xba,0x0a,0x00,0xb9,0xff,0xff,0xed,0x25,0x00 +,0x60,0x3d,0x00,0x60,0x74,0x04,0xe2,0xf5,0xf8,0xc3,0xf9,0xc3,0xb0,0x00,0xe6,0x56 +,0xb8,0x00,0xff,0xba,0x52,0x00,0xef,0xb9,0xff,0xff,0xba,0x58,0x00,0xed,0x25,0xef +,0x00,0x74,0x08,0xba,0x5a,0x00,0x33,0xc0,0xef,0xe2,0xef,0xc3,0xba,0x80,0x00,0xed +,0xba,0x84,0x00,0xef,0xba,0x80,0x00,0xed,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0xc6,0x06,0xec,0x34,0x15,0x33,0xc0,0x8e,0xd8,0x8e,0xc0,0x1e,0x8c,0xc8,0xbe,0x40 +,0x54,0xbf,0x60,0xfe,0x8e,0xd8,0xb9,0x10,0x00,0xf3,0xa4,0x1f,0xc7,0x06,0x80,0x36 +,0x10,0x35,0xc7,0x06,0x8c,0x36,0x30,0x35,0x8d,0x06,0x38,0x35,0xa3,0x30,0x35,0xa3 +,0x32,0x35,0x05,0x33,0x01,0xa3,0x34,0x35,0xc7,0x06,0x36,0x35,0x50,0x01,0xc7,0x06 +,0x84,0x36,0x80,0xfe,0xc7,0x06,0x88,0x36,0xc0,0xfe,0xc6,0x06,0xc2,0xfe,0xff,0xc6 +,0x06,0x93,0x36,0x80,0xc6,0x06,0x92,0x36,0x00,0xc6,0x06,0x80,0xfe,0x80,0xc7,0x06 +,0x82,0xfe,0x54,0x50,0xc7,0x06,0x84,0xfe,0x2b,0x4d,0xe5,0xce,0xa9,0x02,0x00,0x75 +,0x08,0xc6,0x06,0x81,0xfe,0x23,0xe9,0x05,0x00,0xc6,0x06,0x81,0xfe,0x22,0xa1,0xf7 +,0x34,0xa3,0x86,0xfe,0xb8,0x48,0x34,0x86,0xe0,0xa3,0x88,0xfe,0x8d,0x06,0x4e,0x34 +,0x86,0xe0,0xa3,0x8a,0xfe,0xb8,0x58,0x34,0x86,0xe0,0xa3,0x8c,0xfe,0xb8,0x9c,0x34 +,0x86,0xe0,0xa3,0x8e,0xfe,0x8d,0x06,0x20,0x03,0x86,0xe0,0xa3,0x90,0xfe,0x33,0xc0 +,0xba,0x72,0x00,0xef,0x33,0xc0,0xba,0x74,0x00,0xef,0xba,0x76,0x00,0xef,0xb8,0x80 +,0xfe,0x86,0xe0,0xba,0x72,0x00,0xef,0xe8,0xbf,0x07,0xba,0x0c,0x01,0xb8,0x40,0x40 +,0xef,0xed,0xba,0x6a,0x00,0xb8,0x03,0x00,0xc1,0xe0,0x08,0x0d,0x03,0x00,0xef,0xb9 +,0x0a,0x00,0xe8,0x94,0x00,0xba,0x6a,0x00,0xb8,0x03,0x00,0xc1,0xe0,0x08,0xef,0xa1 +,0x32,0x34,0xa3,0xa2,0x33,0xc7,0x06,0xa6,0x33,0x04,0x00,0x8d,0x06,0xa0,0x33,0xc1 +,0xe8,0x04,0xcd,0x39,0xc7,0x06,0x90,0x36,0xff,0xff,0xe9,0xe3,0x00,0x63,0x0d,0x66 +,0x0d,0x66,0x0d,0x8a,0x0d,0xe6,0x0e,0x75,0x12,0x2e,0x0f,0x03,0x0f,0x50,0x0f,0x60 +,0x0d,0x60,0x0d,0x60,0x0d,0xed,0x0f,0xe9,0x12,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60 +,0x0d,0x60,0x0d,0x22,0x10,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0xfe,0x10,0x60 +,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0xaf,0x0f,0x32,0x10,0x37 +,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60 +,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60 +,0x0d,0x64,0x0e,0x00,0x0f,0x95,0x09,0x60,0x0a,0x49,0xbb,0xff,0xff,0xba,0x6a,0x00 +,0xed,0xa9,0x00,0x20,0x74,0x38,0x80,0x3e,0x80,0xfe,0x12,0x75,0x31,0xe8,0x4a,0x00 +,0xa1,0x32,0x34,0xa3,0xa2,0x33,0xc7,0x06,0xa6,0x33,0x04,0x00,0x8d,0x06,0xa0,0x33 +,0xc1,0xe8,0x04,0xcd,0x39,0xe8,0x22,0x00,0xc7,0x06,0xf3,0x34,0x46,0x00,0xc7,0x06 +,0xf5,0x34,0xff,0xff,0xc7,0x06,0x90,0x36,0xff,0xff,0x58,0xe9,0x32,0x00,0x4b,0x83 +,0xfb,0x00,0x75,0xb9,0x83,0xf9,0x00,0x75,0xb0,0xc3,0x52,0xba,0x6a,0x00,0xb8,0x03 +,0x00,0xc1,0xe0,0x08,0x0d,0x03,0x00,0xef,0x5a,0xc3,0x52,0xba,0x6a,0x00,0xb8,0x03 +,0x00,0xc1,0xe0,0x08,0xef,0x5a,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x68,0x80,0x07,0xa1,0x90,0x36,0xcd,0x35,0x8b,0x36,0x24,0x02,0x2e,0xff,0xa4,0x35 +,0x0a,0xfa,0x8a,0x26,0x94,0x36,0x88,0x26,0xe8,0x34,0xc6,0x06,0x94,0x36,0x00,0xfb +,0x22,0xe4,0x75,0x01,0xc3,0xf6,0xc4,0x20,0x74,0x7d,0xf6,0xc4,0x08,0x74,0x05,0x80 +,0x0e,0x92,0x36,0x04,0x80,0x26,0xe8,0x34,0xd7,0xc4,0x1e,0x84,0x36,0x26,0x8b,0x37 +,0x81,0xe6,0xff,0x00,0x83,0xfe,0x20,0x76,0x05,0xb0,0x01,0xe9,0x28,0x00,0x53,0x06 +,0xd1,0xe6,0x2e,0xff,0x94,0x9d,0x06,0x07,0x5b,0x26,0x88,0x47,0x02,0x3c,0xff,0x74 +,0x07,0x3c,0xfe,0x75,0x11,0xe9,0x3b,0x00,0xf6,0x06,0x92,0x36,0x08,0x75,0x34,0xf6 +,0x06,0x92,0x36,0x04,0x74,0x2d,0x80,0x26,0x92,0x36,0xf3,0x80,0x3e,0x95,0x36,0x00 +,0x75,0x21,0x26,0x80,0x3f,0x05,0x75,0x13,0xc6,0x06,0x95,0x36,0x00,0x26,0x80,0x7f +,0x06,0x00,0x74,0x07,0x26,0x8b,0x47,0x04,0xa2,0x95,0x36,0xba,0x0c,0x01,0xb8,0x40 +,0x40,0xef,0xed,0x8a,0x26,0xe8,0x34,0xf6,0xc4,0x10,0x75,0x03,0xe9,0x5b,0x00,0xf6 +,0xc4,0x04,0x74,0x05,0x80,0x0e,0x92,0x36,0x01,0x80,0x26,0xe8,0x34,0xeb,0xc4,0x3e +,0x88,0x36,0x26,0x8b,0x35,0x83,0xe6,0x7f,0x83,0xfe,0x12,0x72,0x08,0x26,0xc6,0x45 +,0x02,0x01,0xe9,0x24,0x00,0x83,0xc6,0x20,0xd1,0xe6,0x2e,0xff,0x94,0x9d,0x06,0xc4 +,0x3e,0x88,0x36,0x26,0x88,0x45,0x02,0x3c,0xff,0x75,0x0e,0xf6,0x06,0x92,0x36,0x01 +,0x74,0x14,0xf6,0x06,0x92,0x36,0x02,0x75,0x0d,0x80,0x26,0x92,0x36,0xfc,0xba,0x0c +,0x01,0xb8,0x20,0x20,0xef,0xed,0x8a,0x26,0xe8,0x34,0xf6,0xc4,0x08,0x74,0x22,0x80 +,0x26,0xe8,0x34,0xf7,0x80,0x0e,0x92,0x36,0x04,0xf6,0x06,0x92,0x36,0x08,0x74,0x11 +,0x80,0x26,0x92,0x36,0xf3,0xba,0x0c,0x01,0xb8,0x40,0x40,0xef,0xed,0x8a,0x26,0xe8 +,0x34,0xf6,0xc4,0x04,0x74,0x22,0x80,0x26,0xe8,0x34,0xfb,0x80,0x0e,0x92,0x36,0x01 +,0xf6,0x06,0x92,0x36,0x02,0x75,0x11,0x80,0x26,0x92,0x36,0xfe,0xba,0x0c,0x01,0xb8 +,0x20,0x20,0xef,0xed,0x8a,0x26,0xe8,0x34,0xf6,0xc4,0x01,0x74,0x67,0x80,0x26,0xe8 +,0x34,0xfe,0x80,0x3e,0xe8,0xff,0x00,0x74,0x39,0x80,0x3e,0xe8,0xff,0x04,0x74,0x32 +,0x80,0x3e,0xe8,0xff,0x01,0x75,0x21,0xe5,0x80,0xa9,0x00,0x07,0x74,0x0a,0xba,0x9e +,0x00,0xb8,0x00,0x02,0xef,0xe9,0xef,0xff,0xc6,0x06,0xe8,0xff,0x03,0xba,0x0c,0x01 +,0xb8,0x08,0x08,0xef,0xed,0xe9,0x28,0x00,0x80,0x3e,0xe8,0xff,0x03,0x74,0x06,0xe9 +,0x1e,0x00,0xe9,0x00,0x00,0xba,0x10,0x01,0xb8,0x02,0x02,0xef,0xed,0xe5,0x00,0x0d +,0x18,0x00,0xe7,0x00,0xe5,0x82,0x0d,0x02,0x00,0xe7,0x82,0xc6,0x06,0xe8,0xff,0x04 +,0x8a,0x26,0xe8,0x34,0xf6,0xc4,0x02,0x74,0x0d,0x80,0x26,0xe8,0x34,0xfd,0x80,0x26 +,0x92,0x36,0xbf,0xe8,0x4f,0x0b,0xfa,0xa0,0xe8,0x34,0x08,0x06,0x94,0x36,0xc6,0x06 +,0xe8,0x34,0x00,0xfb,0xc3,0xe8,0xe7,0x0f,0xc4,0x1e,0x84,0x36,0x2e,0xff,0x16,0x01 +,0x07,0x26,0x88,0x47,0x02,0xe9,0x7e,0xfe,0xe8,0x2d,0x10,0xc4,0x1e,0x84,0x36,0x2e +,0xff,0x16,0x03,0x07,0x26,0x88,0x47,0x02,0xe9,0x6b,0xfe,0x8e,0x06,0x26,0x02,0x2e +,0xff,0x16,0x07,0x07,0xc3,0xc3,0x83,0x3e,0xf5,0x34,0x00,0x74,0x0f,0xff,0x0e,0xf3 +,0x34,0x75,0x09,0xe8,0xc4,0xfd,0xc7,0x06,0xf5,0x34,0x00,0x00,0xf6,0x06,0x93,0x36 +,0x20,0x74,0x30,0xa1,0xc2,0x34,0x3b,0x06,0xe9,0x34,0xa3,0xe9,0x34,0x74,0x24,0x80 +,0x3e,0x95,0x36,0x00,0x75,0x1d,0xf7,0x06,0xe6,0x34,0x20,0x00,0x74,0x12,0xa9,0x20 +,0x00,0x74,0x0d,0x83,0x26,0xc2,0x34,0xdf,0x83,0x26,0xe9,0x34,0xdf,0xe9,0x03,0x00 +,0xe8,0xdd,0x09,0xba,0x06,0x01,0xed,0x8b,0xd0,0x81,0xe2,0x00,0xc0,0xc1,0xea,0x0e +,0x03,0x16,0x74,0x34,0xc1,0xe0,0x02,0x11,0x06,0x72,0x34,0x73,0x04,0xff,0x06,0x74 +,0x34,0xba,0x02,0x01,0xed,0x8b,0xd0,0x81,0xe2,0x00,0xc0,0xc1,0xea,0x0e,0x03,0x16 +,0x70,0x34,0xc1,0xe0,0x02,0x11,0x06,0x6e,0x34,0x73,0x04,0xff,0x06,0x70,0x34,0xc7 +,0x06,0xa6,0x33,0x04,0x00,0xc7,0x06,0xaa,0x33,0x00,0x00,0x8d,0x06,0xa0,0x33,0xc1 +,0xe8,0x04,0xcd,0x39,0xc3,0x95,0x09,0x95,0x09,0x65,0x09,0x78,0x09,0x95,0x09,0x95 +,0x09,0x91,0x07,0x95,0x09,0x96,0x09,0x8b,0x09,0x95,0x09,0x95,0x09,0x95,0x09,0x95 +,0x09,0x95,0x09,0x95,0x09,0x8b,0xc0,0x8b,0xc0,0x8b,0xc0,0x8b,0xc0,0x8b,0xc0,0x90 +,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xe9,0xcc,0x00,0x8c,0xc0,0x40,0x8e,0xc0,0x26 +,0x8b,0x0e,0x06,0x00,0x86,0xe9,0x26,0x89,0x0e,0x06,0x00,0x8c,0xc2,0xc1,0xe2,0x04 +,0xbe,0x0e,0x00,0x26,0xa1,0x04,0x00,0xd0,0xe0,0x24,0xc0,0x8a,0xe0,0xc0,0xec,0x04 +,0x0a,0xc4,0x26,0xa2,0x05,0x00,0x26,0xa1,0x08,0x00,0xa9,0x00,0xc0,0x74,0x03,0xe9 +,0x9e,0x00,0x26,0xf6,0x06,0x10,0x00,0x80,0x75,0x03,0xe9,0x0a,0x00,0x26,0xa0,0x16 +,0x00,0x24,0x1f,0x32,0xe4,0x03,0xf0,0x80,0x3e,0xec,0x34,0x06,0x72,0x5c,0x80,0x3e +,0x95,0x36,0x00,0x75,0x66,0x8b,0xfa,0x33,0xdb,0x8e,0xc3,0x26,0x89,0x1d,0x26,0x88 +,0x5d,0x04,0x51,0x50,0xc4,0x1e,0x8c,0x36,0xb9,0x0f,0x00,0x33,0xc0,0xe8,0x21,0x09 +,0x58,0x59,0x0b,0xdb,0x74,0x34,0xfe,0x0e,0xe6,0x3a,0x26,0xc6,0x07,0x81,0x26,0xc6 +,0x47,0x01,0x00,0x26,0xc6,0x47,0x02,0xff,0x26,0xc7,0x47,0x04,0x00,0x00,0x26,0x89 +,0x4f,0x0a,0x86,0xf2,0x26,0x89,0x57,0x06,0x26,0x89,0x77,0x08,0x26,0xc6,0x47,0x09 +,0x00,0x26,0xc6,0x47,0x0c,0x02,0xe8,0x8c,0x09,0xc3,0xff,0x06,0xec,0x33,0x8c,0xc0 +,0x48,0x8e,0xc0,0xfa,0xe8,0x97,0x10,0xfb,0xe9,0xeb,0xff,0x8c,0xc0,0x48,0x8e,0xc0 +,0xfa,0xe8,0x8a,0x10,0xfb,0xc3,0x8c,0xc0,0x8e,0xc0,0xfa,0xe8,0x80,0x10,0xfb,0xc3 +,0x80,0x3e,0x95,0x36,0x00,0x75,0x03,0xe9,0xc2,0x00,0xbf,0x08,0x00,0x26,0xf6,0x06 +,0x10,0x00,0x80,0x75,0x05,0x03,0xfe,0xe9,0x0c,0x00,0x26,0xa0,0x16,0x00,0x24,0x1f +,0x32,0xe4,0x03,0xf0,0x03,0xfe,0xa0,0x95,0x36,0x3c,0x00,0x75,0x03,0xe9,0x9c,0x00 +,0x3c,0x01,0x74,0x0b,0x3c,0x02,0x74,0x14,0x3c,0x03,0x74,0x1d,0xe9,0x8d,0x00,0xc6 +,0x06,0x96,0x36,0x01,0xe8,0x3c,0x01,0x72,0x27,0xe9,0x80,0x00,0xc6,0x06,0x96,0x36 +,0x02,0xe8,0x83,0x00,0x72,0x1a,0xe9,0x73,0x00,0xc6,0x06,0x96,0x36,0x01,0xe8,0x22 +,0x01,0x72,0x0d,0xc6,0x06,0x96,0x36,0x02,0xe8,0x6c,0x00,0x72,0x03,0xe9,0x5c,0x00 +,0x53,0x06,0x50,0xc4,0x1e,0x8c,0x36,0xb9,0x0b,0x00,0x33,0xc0,0xe8,0x42,0x08,0x58 +,0x26,0xc6,0x07,0x82,0x26,0xc6,0x47,0x02,0xff,0x8d,0x06,0xe0,0xfe,0x86,0xc4,0x26 +,0x89,0x47,0x06,0xa0,0x96,0x36,0x26,0x88,0x47,0x08,0xe8,0xc8,0x08,0x07,0x5b,0x83 +,0x26,0xad,0x36,0xfe,0xa1,0xad,0x36,0xe7,0x04,0xba,0x10,0x01,0xb8,0x80,0x80,0xef +,0xed,0xba,0x10,0x01,0xb8,0x02,0x02,0xef,0xed,0x52,0xba,0xe0,0x00,0xb8,0x41,0x10 +,0xef,0x5a,0xb8,0x9c,0x03,0xcd,0x39,0xc6,0x06,0x95,0x36,0x00,0x8c,0xc0,0x48,0x8e +,0xc0,0xfa,0xe8,0xa9,0x0f,0xfb,0xc3,0x1e,0x06,0x1f,0x06,0x33,0xc0,0x8e,0xc0,0x8b +,0xf0,0x8d,0x3e,0x20,0xf3,0x51,0xb1,0x0a,0x26,0x83,0x7d,0x0c,0x01,0x75,0x2a,0x57 +,0x26,0x83,0x7d,0x0e,0x00,0x74,0x06,0xe8,0x2f,0x00,0xe9,0x03,0x00,0xe8,0x66,0x07 +,0x5f,0x73,0x16,0x33,0xc0,0x8e,0xd8,0x26,0x8b,0x4d,0x12,0x8d,0x75,0x20,0x8d,0x3e +,0xe0,0xfe,0xf3,0xa4,0x59,0x07,0x1f,0xf9,0xc3,0xfe,0xc9,0x74,0x07,0x81,0xc7,0x20 +,0x01,0xe9,0xc4,0xff,0x59,0x07,0x1f,0xf8,0xc3,0x51,0x50,0x53,0x56,0x52,0x57,0x33 +,0xdb,0x26,0x8a,0x5d,0x0e,0x26,0x8b,0x4d,0x12,0x8d,0x7d,0x20,0x5a,0x87,0xd7,0x26 +,0x8a,0x45,0x14,0x87,0xd7,0x42,0x32,0xff,0x80,0xff,0x08,0x75,0x08,0xfe,0xcb,0x22 +,0xdb,0x75,0xea,0x33,0xdb,0x23,0xdb,0x74,0x06,0xfe,0xc7,0xd0,0xc8,0x73,0x0c,0x50 +,0x26,0x8a,0x05,0x38,0x04,0x58,0x74,0x03,0xe9,0x0a,0x00,0x49,0x46,0x47,0x23,0xc9 +,0x74,0x0a,0xe9,0xd3,0xff,0x5a,0x5e,0x5b,0x58,0x59,0xf8,0xc3,0x5a,0x5e,0x5b,0x58 +,0x59,0xf9,0xc3,0x1e,0x06,0x1f,0x06,0x33,0xc0,0x8e,0xc0,0x86,0xcd,0x2b,0xce,0x8b +,0xf7,0x8b,0xc1,0x33,0xc9,0x80,0x3c,0xff,0x74,0x16,0x80,0xf9,0x06,0x73,0x09,0x32 +,0xc9,0x46,0x48,0x74,0x2e,0xe9,0xed,0xff,0x3d,0x60,0x00,0x73,0x0c,0xe9,0x23,0x00 +,0xfe,0xc1,0x46,0x48,0x74,0x1d,0xe9,0xdc,0xff,0xb8,0x10,0x00,0x8d,0x3e,0x18,0x34 +,0x32,0xed,0xb1,0x06,0xf3,0xa6,0x74,0x03,0xe9,0x08,0x00,0x48,0x23,0xc0,0x74,0x07 +,0xe9,0xe9,0xff,0x07,0x1f,0xf8,0xc3,0x8d,0x36,0x18,0x34,0x33,0xc0,0x8e,0xd8,0x8d +,0x3e,0xe0,0xfe,0xb8,0x10,0x00,0xb9,0x06,0x00,0x56,0xf3,0xa4,0x5e,0x48,0x3d,0x00 +,0x00,0x75,0xf3,0x07,0x1f,0xf9,0xc3,0xff,0x06,0xe4,0x33,0xc6,0x06,0xeb,0x34,0x00 +,0x26,0x8b,0x45,0x06,0x86,0xe0,0xc1,0xe8,0x04,0x48,0x06,0x8e,0xc0,0xfe,0x06,0xe6 +,0x3a,0xfa,0xe8,0x69,0x0e,0xfb,0x07,0xb0,0xff,0xc3,0x00,0x00,0x00,0x00,0x00,0x00 +,0xb0,0x01,0xc3,0xb0,0x00,0xc3,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3 +,0x8b,0x0e,0x97,0x36,0x81,0xe1,0x80,0x30,0x26,0x8b,0x47,0x04,0x25,0x7f,0xcf,0x0b +,0xc1,0xa3,0x97,0x36,0xa3,0xe6,0x34,0xb0,0x00,0xc3,0xf6,0x06,0x93,0x36,0x20,0x74 +,0x03,0xb0,0x03,0xc3,0x26,0x8b,0x47,0x08,0xa3,0x97,0x36,0xa3,0xe6,0x34,0x26,0x8a +,0x47,0x20,0xa2,0xfd,0x34,0x3c,0x01,0x75,0x06,0xc7,0x06,0xa1,0x36,0x00,0x00,0x26 +,0x8a,0x47,0x21,0xa2,0xfe,0x34,0x26,0x8b,0x47,0x0a,0xa3,0x18,0x34,0xa3,0x58,0x34 +,0x26,0x8b,0x47,0x0c,0xa3,0x1a,0x34,0xa3,0x5a,0x34,0x26,0x8b,0x47,0x0e,0xa3,0x1c +,0x34,0xa3,0x5c,0x34,0xc6,0x06,0x2a,0x34,0xc0,0x26,0x8b,0x47,0x14,0x25,0x7f,0xff +,0x09,0x06,0x2c,0x34,0x26,0x8b,0x47,0x16,0x25,0xff,0xfe,0x25,0xff,0xfc,0x09,0x06 +,0x2e,0x34,0xc6,0x06,0x00,0x34,0xc0,0x26,0x8b,0x47,0x10,0xa3,0x02,0x34,0x26,0x8b +,0x47,0x12,0xa3,0x04,0x34,0x06,0x53,0xe8,0x84,0x0a,0x5b,0x07,0x3d,0x00,0x00,0x75 +,0x07,0x80,0x0e,0x92,0x36,0x08,0xb0,0xfe,0xc3,0xb9,0x00,0x01,0xa1,0xac,0x33,0x33 +,0xd2,0xf7,0xf9,0xa3,0xae,0x33,0x91,0x49,0x33,0xd2,0xf7,0xe9,0x05,0x00,0x3b,0xa3 +,0x46,0x34,0xbf,0x00,0x3b,0x89,0x3e,0x44,0x34,0xba,0x68,0x00,0xb8,0xe0,0xe0,0xef +,0xa1,0xae,0x33,0xe7,0x62,0xa1,0xae,0x33,0xba,0x08,0x01,0xef,0xa1,0x44,0x34,0xe7 +,0x64,0xa1,0x44,0x34,0xba,0x0a,0x01,0xef,0xb8,0x00,0x01,0x2d,0x04,0x00,0x0d,0x00 +,0x10,0xe7,0x92,0xc3,0x3d,0x00,0x00,0x74,0x0a,0x26,0x89,0x47,0x07,0xe8,0x83,0x3a +,0xb0,0x07,0xc3,0xa1,0xae,0x33,0x26,0x89,0x47,0x2b,0xa1,0x44,0x34,0x26,0x89,0x47 +,0x2d,0xa1,0x46,0x34,0x26,0x89,0x47,0x2f,0x80,0x0e,0x93,0x36,0x20,0xa1,0x88,0x36 +,0x86,0xe0,0x26,0x89,0x47,0x08,0xa1,0x84,0x36,0x86,0xe0,0x26,0x89,0x47,0x0a,0xa1 +,0x80,0x36,0x86,0xe0,0x26,0x89,0x47,0x0c,0xb8,0x60,0xfe,0x86,0xe0,0x26,0x89,0x47 +,0x0e,0xa0,0xa1,0x36,0x26,0x88,0x47,0x10,0x8b,0x36,0x88,0x36,0x26,0xc6,0x44,0x02 +,0xff,0xe5,0x9e,0xa9,0x00,0x08,0x74,0x0c,0xba,0x84,0x00,0xed,0x0d,0x08,0x00,0xef +,0xba,0x8e,0x00,0xef,0xe5,0x02,0x25,0xf9,0xff,0xe7,0x02,0xba,0x10,0x01,0xb8,0x02 +,0x02,0xef,0xed,0xb0,0x00,0xc3,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x01,0xc3 +,0x80,0x26,0x93,0x36,0x9f,0xe8,0x8d,0x0a,0x80,0x0e,0x92,0x36,0x08,0xb0,0xfe,0xc3 +,0xb0,0x00,0xc3,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0xc6,0x06,0x2a +,0x34,0xc0,0x26,0x8b,0x47,0x06,0x25,0x7f,0xff,0xa3,0x2c,0x34,0x26,0x8b,0x47,0x08 +,0x25,0xff,0xfe,0x25,0xff,0xfc,0xa3,0x2e,0x34,0xcd,0x52,0xb0,0x00,0xc3,0xf6,0x06 +,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0xc6,0x06,0x00,0x34,0xc0,0x26,0x8b,0x47 +,0x06,0xa3,0x02,0x34,0x26,0x8b,0x47,0x08,0xa3,0x04,0x34,0xcd,0x52,0xb0,0x00,0xc3 +,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0x57,0x8d,0x7f,0x06,0x51,0xb9 +,0x07,0x00,0x33,0xc0,0xf3,0xab,0x59,0x8d,0x7f,0x06,0xa1,0x7a,0x34,0x03,0x06,0x39 +,0x37,0x26,0x88,0x05,0xa1,0x95,0x37,0x26,0x88,0x45,0x02,0xa1,0x80,0x34,0x03,0x06 +,0x76,0x34,0x26,0x88,0x45,0x07,0xa1,0xc6,0x34,0x26,0x88,0x45,0x09,0xa1,0xd8,0x33 +,0x26,0x88,0x45,0x0a,0x33,0xc0,0xa3,0x7a,0x34,0xa3,0x39,0x37,0xa3,0x95,0x37,0xa3 +,0x80,0x34,0xa3,0x76,0x34,0xa3,0xc6,0x34,0xa3,0xd8,0x33,0x5f,0xb0,0x00,0xc3,0xf6 +,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0x26,0x8b,0x4f,0x04,0x83,0xf9,0x06 +,0x74,0x12,0x83,0xf9,0x04,0x74,0x0d,0x83,0xf9,0x00,0x74,0x08,0x83,0xf9,0x02,0x74 +,0x03,0xb0,0x01,0xc3,0x89,0x0e,0xe8,0x3a,0x83,0x26,0xab,0x36,0xf9,0x09,0x0e,0xab +,0x36,0xe5,0x02,0x25,0xf9,0xff,0x0b,0xc1,0xe7,0x02,0xb0,0x00,0xc3,0xf6,0x06,0x93 +,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0x26,0x8b,0x4f,0x04,0x80,0xf9,0xff,0x74,0x08 +,0x80,0xf9,0x00,0x74,0x10,0xb0,0x01,0xc3,0x83,0x0e,0xad,0x36,0x02,0xa1,0xad,0x36 +,0xe7,0x04,0xe9,0x0a,0x00,0x83,0x26,0xad,0x36,0xfd,0xa1,0xad,0x36,0xe7,0x04,0xb0 +,0x00,0xc3,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0xe8,0xd5,0x04,0xb0 +,0x00,0xc3,0xf6,0x06,0x93,0x36,0x80,0x75,0x03,0xb0,0x01,0xc3,0x26,0x83,0x7f,0x06 +,0x05,0x75,0x03,0xe9,0x9d,0x00,0x26,0x8b,0x57,0x04,0x26,0x8b,0x47,0x08,0x26,0x81 +,0x7f,0x06,0x00,0x80,0x75,0x08,0xed,0x26,0x89,0x47,0x0a,0xe9,0x9d,0x00,0x26,0x83 +,0x7f,0x06,0x01,0x75,0x04,0xef,0xe9,0x92,0x00,0x26,0x81,0x7f,0x06,0x01,0x80,0x75 +,0x09,0xef,0xed,0x26,0x89,0x47,0x0a,0xe9,0x81,0x00,0x26,0x83,0x7f,0x06,0x02,0x75 +,0x07,0x26,0x21,0x47,0x04,0xe9,0x73,0x00,0x26,0x81,0x7f,0x06,0x02,0x80,0x75,0x0c +,0x26,0x21,0x47,0x04,0xed,0x26,0x89,0x47,0x0a,0xe9,0x5f,0x00,0x26,0x83,0x7f,0x06 +,0x03,0x75,0x07,0x26,0x09,0x47,0x04,0xe9,0x51,0x00,0x26,0x81,0x7f,0x06,0x03,0x80 +,0x75,0x0c,0x26,0x09,0x47,0x04,0xed,0x26,0x89,0x47,0x0a,0xe9,0x3d,0x00,0x26,0x83 +,0x7f,0x06,0x04,0x75,0x07,0x26,0x31,0x47,0x04,0xe9,0x2f,0x00,0x26,0x81,0x7f,0x06 +,0x04,0x80,0x75,0x0c,0x26,0x31,0x47,0x04,0xed,0x26,0x89,0x47,0x0a,0xe9,0x1b,0x00 +,0xb0,0x01,0xc3,0xfa,0x53,0x26,0x8b,0x4f,0x08,0x0b,0xc9,0x74,0x0c,0x8d,0x1e,0xe0 +,0xfe,0xe8,0x52,0xff,0x83,0xc3,0x08,0xe2,0xf8,0x5b,0xfb,0xb0,0x00,0xc3,0xf6,0x06 +,0x93,0x36,0x80,0x75,0x0a,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x01,0xc3,0x8d +,0x3e,0xe0,0xfe,0xe5,0x00,0x26,0x89,0x05,0xe5,0x02,0x26,0x89,0x45,0x02,0xa1,0xad +,0x36,0x26,0x89,0x45,0x04,0xe5,0x06,0x26,0x89,0x45,0x06,0xe5,0x08,0x26,0x89,0x45 +,0x08,0xe5,0x0a,0x26,0x89,0x45,0x0a,0xe5,0x0e,0x26,0x89,0x45,0x0c,0xe5,0x48,0x26 +,0x89,0x45,0x0e,0xe5,0x4a,0x26,0x89,0x45,0x10,0xe5,0x4c,0x26,0x89,0x45,0x12,0xa1 +,0xb7,0x36,0x26,0x89,0x45,0x14,0xe5,0x50,0x26,0x89,0x45,0x16,0xe5,0x52,0x26,0x89 +,0x45,0x18,0xe5,0x54,0x26,0x89,0x45,0x1a,0xe5,0x56,0x26,0x89,0x45,0x1c,0xe5,0x58 +,0x26,0x89,0x45,0x1e,0xe5,0x62,0x26,0x89,0x45,0x20,0xe5,0x64,0x26,0x89,0x45,0x22 +,0xe5,0x66,0x26,0x89,0x45,0x24,0xe5,0x68,0x26,0x89,0x45,0x26,0xe5,0x6a,0x26,0x89 +,0x45,0x28,0xe5,0x6c,0x26,0x89,0x45,0x2a,0xe5,0x70,0x26,0x89,0x45,0x2c,0xe5,0x72 +,0x26,0x89,0x45,0x2e,0xe5,0x74,0x26,0x89,0x45,0x30,0xe5,0x76,0x26,0x89,0x45,0x32 +,0xe5,0x7c,0x26,0x89,0x45,0x34,0xe5,0x7e,0x26,0x89,0x45,0x36,0xe5,0x80,0x26,0x89 +,0x45,0x38,0xe5,0x82,0x26,0x89,0x45,0x3a,0xe5,0x86,0x26,0x89,0x45,0x3c,0xe5,0x88 +,0x26,0x89,0x45,0x3e,0xe5,0x9a,0x26,0x89,0x45,0x40,0xe5,0x9e,0x26,0x89,0x45,0x42 +,0xe5,0xcc,0x26,0x89,0x45,0x44,0xe5,0xce,0x26,0x89,0x45,0x46,0xe5,0xd0,0x26,0x89 +,0x45,0x48,0xe5,0xd2,0x26,0x89,0x45,0x4a,0xba,0x00,0x01,0xed,0x11,0x06,0x66,0x34 +,0x73,0x04,0xff,0x06,0x68,0x34,0x26,0x89,0x45,0x4c,0xba,0x02,0x01,0xed,0xc1,0xe0 +,0x02,0x11,0x06,0x6e,0x34,0x73,0x04,0xff,0x06,0x70,0x34,0x26,0x89,0x45,0x4e,0xba +,0x04,0x01,0xed,0x11,0x06,0x6a,0x34,0x73,0x04,0xff,0x06,0x6c,0x34,0x26,0x89,0x45 +,0x50,0xba,0x06,0x01,0xed,0xc1,0xe0,0x02,0x11,0x06,0x72,0x34,0x73,0x04,0xff,0x06 +,0x74,0x34,0x26,0x89,0x45,0x52,0xba,0x08,0x01,0xed,0x26,0x89,0x45,0x54,0xba,0x0a +,0x01,0xed,0x26,0x89,0x45,0x56,0xba,0x0c,0x01,0xed,0x26,0x89,0x45,0x58,0xba,0x0e +,0x01,0xed,0x01,0x06,0x7a,0x34,0x26,0x89,0x45,0x5e,0xba,0x10,0x01,0xed,0x26,0x89 +,0x45,0x5c,0xb0,0x00,0xc3,0xf6,0x06,0x93,0x36,0x80,0x74,0x07,0xf6,0x06,0x93,0x36 +,0x20,0x75,0x03,0xb0,0x01,0xc3,0x26,0x80,0x7f,0x06,0x00,0x75,0x30,0x80,0x3e,0x95 +,0x36,0x00,0x74,0x52,0xc6,0x06,0x95,0x36,0x00,0x83,0x26,0xad,0x36,0xfe,0xa1,0xad +,0x36,0xe7,0x04,0xba,0x10,0x01,0xb8,0x80,0x80,0xef,0xed,0xba,0x10,0x01,0xb8,0x02 +,0x02,0xef,0xed,0xba,0xe0,0x00,0xb8,0x00,0x10,0xef,0xb0,0x00,0xc3,0x26,0x8b,0x47 +,0x04,0x3d,0x00,0x00,0x74,0x20,0x3d,0x03,0x00,0x77,0x1b,0xba,0x10,0x01,0xb8,0x02 +,0x00,0xef,0xba,0xe0,0x00,0xb8,0x01,0x10,0xef,0x83,0x0e,0xad,0x36,0x01,0xa1,0xad +,0x36,0xe7,0x04,0xb0,0x00,0xc3,0xb0,0x06,0xc3,0xf6,0x06,0x93,0x36,0x80,0x75,0x03 +,0xb0,0x01,0xc3,0x26,0x83,0x7f,0x04,0x01,0x74,0x0a,0x26,0x83,0x7f,0x04,0x02,0x74 +,0x19,0xb0,0x06,0xc3,0x26,0x83,0x7f,0x06,0x0c,0x77,0xf6,0x26,0x83,0x7f,0x0a,0x60 +,0x77,0xef,0xe8,0x10,0x00,0x72,0x0b,0xb0,0x46,0xc3,0xe8,0x4e,0x00,0x72,0x03,0xb0 +,0x46,0xc3,0xb0,0x00,0xc3,0x51,0xb1,0x0a,0x8b,0x3e,0x20,0xf3,0x26,0x83,0x7d,0x0c +,0x02,0x75,0x03,0xe9,0x0e,0x00,0xfe,0xc9,0x74,0x07,0x81,0xc7,0x20,0x01,0xe9,0xeb +,0xff,0x59,0xf8,0xc3,0x57,0x8d,0x7d,0x0e,0x8d,0x77,0x06,0xb9,0x12,0x00,0xf3,0xa4 +,0x8d,0x7d,0x20,0x8d,0x36,0xe0,0xfe,0x26,0x8b,0x4d,0x12,0xf3,0xa4,0xff,0x06,0x01 +,0x35,0x5f,0x26,0xc7,0x45,0x0c,0x01,0x00,0x59,0xf9,0xc3,0x51,0xb1,0x0a,0x8d,0x3e +,0x20,0xf3,0x8d,0x36,0xe0,0xfe,0x26,0x83,0x7d,0x0c,0x01,0x75,0x1b,0x57,0xe8,0x25 +,0x00,0x5f,0x73,0x14,0x33,0xc0,0xb9,0x20,0x01,0xf3,0xaa,0x26,0xc7,0x45,0x0c,0x02 +,0x00,0xff,0x0e,0x01,0x35,0x59,0xf9,0xc3,0xfe,0xc9,0x74,0x07,0x81,0xc7,0x20,0x01 +,0xe9,0xd3,0xff,0x59,0xf8,0xc3,0x51,0x26,0x8b,0x4d,0x12,0x8d,0x7d,0x20,0xf3,0xa6 +,0x74,0x03,0x59,0xf8,0xc3,0x59,0xf9,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x80,0x3e,0xec,0x34,0x06,0x72,0x33,0xff,0x06,0xf0,0x33,0x50,0xc4,0x1e,0x8c,0x36 +,0xb9,0x0f,0x00,0x33,0xc0,0xe8,0x29,0x00,0x58,0x81,0x26,0xc2,0x34,0xdf,0x7f,0x81 +,0x26,0xe9,0x34,0xdf,0x7f,0x0b,0xdb,0x74,0x11,0x26,0xc6,0x07,0x84,0x26,0xc6,0x47 +,0x02,0xff,0x26,0x89,0x47,0x06,0xe8,0xac,0x00,0xc3,0xff,0x06,0xea,0x33,0xe9,0xf5 +,0xff,0x57,0x26,0x8b,0x3f,0x03,0xf9,0x26,0x3b,0x7f,0x02,0x74,0x16,0x26,0x3b,0x7f +,0x04,0x7c,0x2a,0x3d,0x00,0x00,0x75,0x13,0x8d,0x7f,0x08,0x03,0xf9,0x26,0x3b,0x7f +,0x02,0x7c,0x14,0xff,0x06,0xde,0x33,0x33,0xdb,0x5f,0xc3,0x26,0x8b,0x7f,0x02,0x26 +,0x89,0x3f,0x03,0xf9,0xe9,0x06,0x00,0x26,0x89,0x3f,0x26,0x29,0x0f,0x26,0xc7,0x05 +,0xff,0xff,0x26,0x87,0x3f,0x26,0x89,0x0d,0x8d,0x5d,0x02,0x50,0x8b,0xfb,0x83,0xe9 +,0x02,0x33,0xc0,0xf3,0xaa,0x58,0xfe,0x0e,0xec,0x34,0x5f,0xc3,0x8b,0x7c,0x02,0x3b +,0x3c,0x74,0x2f,0x83,0x3d,0xff,0x75,0x0b,0x8d,0x7c,0x08,0x89,0x7c,0x02,0x83,0x3d +,0xff,0x74,0x1e,0x8a,0x45,0x02,0x3c,0x81,0x75,0x0c,0x80,0x3e,0xeb,0x34,0x00,0x74 +,0x05,0x33,0xc0,0xe9,0x0b,0x00,0x8b,0x0d,0x01,0x4c,0x02,0x8d,0x75,0x02,0x83,0xe9 +,0x02,0xc3,0x80,0x3e,0xec,0x34,0x06,0x72,0x05,0x33,0xc0,0xe9,0xf3,0xff,0xff,0x06 +,0xee,0x33,0xe9,0xbe,0xff,0xf6,0x06,0x92,0x36,0x40,0x74,0x01,0xc3,0x57,0x56,0x51 +,0x52,0x8b,0x36,0x8c,0x36,0xe8,0xa4,0xff,0x75,0x03,0xe9,0x1a,0x00,0xe9,0x1c,0x00 +,0xfe,0x06,0xec,0x34,0xc4,0x3e,0x80,0x36,0xf3,0xa4,0x80,0x0e,0x92,0x36,0x40,0xba +,0x0c,0x01,0xb8,0x80,0x80,0xef,0xed,0x5a,0x59,0x5e,0x5f,0xc3,0xff,0x06,0xe0,0x33 +,0x80,0x3c,0x81,0x75,0x0c,0xff,0x06,0xe2,0x33,0xc6,0x06,0xeb,0x34,0x01,0xe9,0xcf +,0xff,0x80,0x3c,0x84,0x75,0x07,0xff,0x06,0xe6,0x33,0xe9,0xc3,0xff,0xff,0x06,0xe8 +,0x33,0xe9,0xbc,0xff,0x8d,0x3e,0xe0,0xfe,0xa1,0x72,0x34,0xc7,0x06,0x72,0x34,0x00 +,0x00,0x89,0x05,0xa1,0x74,0x34,0xc7,0x06,0x74,0x34,0x00,0x00,0x89,0x45,0x02,0xba +,0x04,0x01,0xed,0x89,0x45,0x04,0xc7,0x45,0x06,0x00,0x00,0xa1,0x6e,0x34,0xc7,0x06 +,0x6e,0x34,0x00,0x00,0x89,0x45,0x08,0xa1,0x70,0x34,0xc7,0x06,0x70,0x34,0x00,0x00 +,0x89,0x45,0x0a,0xba,0x00,0x01,0xed,0x89,0x45,0x0c,0xc7,0x45,0x0e,0x00,0x00,0x32 +,0xe4,0xba,0x0e,0x01,0xec,0x89,0x45,0x10,0xa1,0x7e,0x34,0xc7,0x06,0x7e,0x34,0x00 +,0x00,0x89,0x45,0x12,0xa1,0x8c,0x34,0xc7,0x06,0x8c,0x34,0x00,0x00,0x89,0x45,0x14 +,0xa1,0x8a,0x34,0xc7,0x06,0x8a,0x34,0x00,0x00,0x89,0x45,0x16,0xa1,0x7c,0x34,0xc7 +,0x06,0x7c,0x34,0x00,0x00,0x89,0x45,0x18,0xa1,0x88,0x34,0xc7,0x06,0x88,0x34,0x00 +,0x00,0x89,0x45,0x1a,0xa1,0xca,0x33,0xc7,0x06,0xca,0x33,0x00,0x00,0x89,0x45,0x1c +,0xa1,0x78,0x34,0xc7,0x06,0x78,0x34,0x00,0x00,0x89,0x45,0x1e,0xa1,0xc6,0x34,0xc7 +,0x06,0xc6,0x34,0x00,0x00,0x89,0x45,0x20,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0xfa,0x33,0xc0,0x8e,0xd8,0x8e,0xc0,0xb8,0xa0,0x01,0xc1,0xe8,0x04,0x8e,0xd0,0x8d +,0x26,0x80,0x00,0xe8,0x00,0x01,0xe8,0x10,0xeb,0x8b,0x1e,0xf7,0x34,0x8b,0x16,0xf9 +,0x34,0x8b,0x36,0xff,0x34,0x33,0xc0,0xb9,0xef,0xff,0x8d,0x3e,0x14,0x00,0x2b,0xcf +,0x2b,0xce,0xd1,0xe9,0xf3,0xab,0x89,0x1e,0xf7,0x34,0x89,0x16,0xf9,0x34,0x83,0xfe +,0x00,0x74,0x0c,0xb9,0xef,0xff,0xbf,0x80,0xfe,0x2b,0xcf,0xd1,0xe9,0xf3,0xab,0xb9 +,0xff,0xff,0x81,0xe9,0x00,0x3b,0x83,0xfe,0x00,0x74,0x03,0xe9,0x1b,0x00,0x51,0x1e +,0xb8,0x00,0xe0,0x8e,0xd8,0x33,0xf6,0x8d,0x3e,0x00,0xd8,0xb9,0x00,0x0c,0xf3,0xa5 +,0x1f,0x59,0xbe,0xff,0xff,0x81,0xee,0x00,0xd8,0x2b,0xce,0x81,0xe1,0x00,0xff,0x89 +,0x0e,0xac,0x33,0x8d,0x06,0x20,0x02,0xc1,0xe8,0x04,0xa3,0x32,0x34,0x8e,0xd0,0x36 +,0xc7,0x06,0x1e,0x00,0x80,0x18,0x36,0xc7,0x06,0x22,0x00,0xff,0x7f,0x36,0xc7,0x06 +,0x0a,0x00,0xff,0xff,0x36,0xc7,0x06,0x1c,0x00,0x80,0x00,0x8d,0x06,0xa0,0x02,0xc1 +,0xe8,0x04,0xa3,0x30,0x34,0x8e,0xd0,0x36,0xc7,0x06,0x1e,0x00,0x50,0x28,0x36,0xc7 +,0x06,0x0a,0x00,0xff,0xff,0x36,0xc7,0x06,0x1c,0x00,0x80,0x00,0xb8,0xa0,0x01,0xc1 +,0xe8,0x04,0xa3,0x34,0x34,0xa3,0xf2,0x33,0x8e,0xd0,0x8d,0x26,0x80,0x00,0xb8,0x00 +,0x90,0xe7,0x02,0x8d,0x3e,0x70,0x01,0x8b,0xc7,0xc1,0xe8,0x04,0xb9,0x03,0x00,0x89 +,0x45,0x0e,0x89,0x45,0x02,0xc7,0x05,0xff,0xff,0x83,0xc7,0x10,0x05,0x01,0x00,0xe2 +,0xee,0xe8,0x5b,0x01,0xe5,0xce,0xa3,0xb5,0x36,0xe8,0x21,0x00,0xe8,0x45,0x01,0xa1 +,0x32,0x34,0x8c,0xcb,0xcd,0x37,0x0e,0x58,0xa9,0x00,0xf0,0x74,0x07,0x33,0xf6,0x89 +,0x36,0xff,0x34,0xc3,0x8d,0x36,0x30,0x61,0x89,0x36,0xff,0x34,0xc3,0x33,0xc0,0x8b +,0xd0,0x8b,0xf2,0xb9,0x68,0x00,0x2e,0x80,0xbc,0xac,0x17,0x80,0x75,0x01,0xef,0x83 +,0xc2,0x02,0x46,0xe2,0xf1,0xb8,0x02,0x00,0xe7,0x50,0xb9,0x5a,0x00,0x33,0xff,0xc7 +,0x05,0x65,0x18,0x8c,0x4d,0x02,0x83,0xc7,0x04,0xe2,0xf4,0x33,0xc0,0x8e,0xc0,0x8c +,0xc8,0x8e,0xd8,0x8d,0x3e,0x80,0x00,0x8d,0x36,0x9c,0x17,0xb9,0x08,0x00,0xe8,0x37 +,0x00,0x8d,0x36,0x20,0x21,0x8d,0x3e,0xc0,0x00,0xb9,0x0d,0x00,0xe8,0x29,0x00,0x8d +,0x3e,0x40,0x01,0xb9,0x0a,0x00,0xe8,0x1f,0x00,0xe8,0x4b,0x0e,0x33,0xc0,0x8e,0xd8 +,0xc7,0x06,0x4e,0x37,0x6f,0x17,0xe7,0x48,0xe7,0x4c,0xb8,0x40,0x9c,0xe7,0x4a,0xe5 +,0x48,0x90,0xb8,0x00,0x70,0xe7,0x48,0xc3,0xa5,0x83,0xc7,0x02,0xe2,0xfa,0xc3,0xe5 +,0x4c,0xc3,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe5,0x58,0xd1 +,0xe0,0x73,0x11,0x8b,0xf0,0xd1,0xe6,0x33,0xc0,0x8e,0xd8,0x8b,0xb4,0x80,0x00,0x83 +,0xc6,0x0b,0xff,0xe6,0x1f,0x07,0x5a,0x5f,0x5e,0x59,0x58,0xcf,0x58,0x1c,0xe4,0x1c +,0x6c,0x1c,0x8e,0x1a,0xc0,0x1f,0x40,0x1a,0x44,0x1c,0x65,0x18,0x80,0x80,0x80,0xff +,0x80,0x03,0x02,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff +,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff +,0x80,0x03,0x03,0x43,0x80,0x80,0x02,0x80,0x42,0x03,0x02,0xff,0x03,0x01,0x03,0x01 +,0x01,0x03,0x02,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x02,0x03,0x01,0x03 +,0x03,0xff,0x01,0x01,0xff,0x01,0xff,0x01,0x01,0x03,0x03,0x03,0xff,0xff,0xff,0xff +,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff +,0xff,0xff,0xff,0x02,0xb8,0x0f,0x00,0xe7,0x84,0xb8,0x0f,0xf8,0xe7,0x82,0xc3,0xb9 +,0x08,0x00,0x89,0x0e,0xe6,0x3a,0x8d,0x06,0x20,0x03,0x8b,0xd0,0xc1,0xe8,0x04,0xa3 +,0x90,0x01,0x8b,0xc2,0x8b,0xd8,0xc1,0xe8,0x04,0x8e,0xc0,0x05,0x61,0x00,0x26,0xa3 +,0x00,0x00,0xa1,0x30,0x34,0x26,0xa3,0x02,0x00,0x83,0xc3,0x14,0xd1,0xeb,0x26,0x89 +,0x1e,0x08,0x00,0x81,0xc2,0x10,0x06,0xe2,0xd9,0x26,0xc7,0x06,0x00,0x00,0xff,0xff +,0x8c,0x06,0x92,0x01,0xc3,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8 +,0xe7,0x5a,0xff,0x06,0xbe,0x33,0xba,0xd2,0x00,0xed,0xcf,0x00,0x00,0x00,0x00,0x00 +,0x8c,0xcb,0xa1,0x30,0x34,0xcd,0x37,0xe9,0x06,0xed,0xb8,0x32,0x00,0xc3,0xe8,0x8c +,0x01,0xfe,0x06,0xe2,0x34,0xe8,0x21,0x01,0x75,0xf0,0xe8,0x53,0x0e,0x81,0x0e,0xaf +,0x36,0x00,0xc0,0xc7,0x06,0xad,0x36,0x60,0x00,0xf7,0x06,0xe6,0x34,0x80,0x00,0x75 +,0x1a,0xf7,0x06,0xe6,0x34,0x00,0x08,0x74,0x09,0xc7,0x06,0xab,0x36,0x0b,0x00,0xe9 +,0x0f,0x00,0xc7,0x06,0xab,0x36,0x03,0x00,0xe9,0x06,0x00,0xc7,0x06,0xab,0x36,0x11 +,0x9c,0xc7,0x06,0xa9,0x36,0x18,0x00,0xf7,0x06,0xe6,0x34,0x80,0x00,0x75,0x0d,0xf7 +,0x06,0xb5,0x36,0x02,0x00,0x74,0x05,0x83,0x0e,0xa9,0x36,0x20,0xa1,0xa9,0x36,0xe7 +,0x00,0xa1,0xab,0x36,0xe7,0x02,0xf7,0x06,0xe6,0x34,0x80,0x00,0x74,0x2e,0xe8,0xf2 +,0x2f,0x33,0xc0,0x0d,0x41,0x00,0xe7,0x56,0xa1,0xb1,0x36,0x0d,0x00,0x10,0xe7,0x08 +,0xa1,0xb3,0x36,0xe7,0x0a,0xa1,0xaf,0x36,0xe7,0x06,0xb8,0x40,0x00,0xe7,0x4e,0x33 +,0xc0,0xe7,0x0e,0xc7,0x06,0x26,0x02,0x00,0x00,0xe9,0x23,0x00,0xc7,0x06,0x4e,0x37 +,0x3f,0x20,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x80,0x74,0x07,0x26 +,0x81,0x0e,0x08,0x00,0x00,0x80,0xc6,0x06,0xe0,0x34,0x01,0xb8,0x00,0x00,0xc3,0xfe +,0x06,0xe1,0x34,0xc6,0x06,0xe0,0x34,0x00,0xa1,0x26,0x02,0x0b,0xc0,0x74,0x01,0xc3 +,0xe8,0x04,0x00,0xb8,0x00,0x00,0xc3,0xa1,0xa9,0x36,0xe7,0x00,0x8b,0x1e,0xab,0x36 +,0x83,0xe3,0x06,0xe5,0x02,0x25,0xf9,0xff,0x0b,0xc3,0x0d,0x10,0x00,0xe7,0x02,0xa1 +,0xad,0x36,0xe7,0x04,0xc3,0xb8,0x0a,0x00,0xe7,0x84,0xfe,0x06,0xe5,0x34,0xc6,0x06 +,0xe3,0x34,0x01,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x40,0x74,0x07 +,0x26,0x81,0x0e,0x08,0x00,0x00,0x40,0xc3,0xc7,0x06,0x4e,0x37,0x6f,0x17,0xfe,0x06 +,0xe4,0x34,0xc6,0x06,0xe3,0x34,0x00,0xc3,0xc3,0xf6,0x06,0x18,0x34,0x80,0x75,0x0d +,0xa1,0x18,0x34,0x0b,0x06,0x1a,0x34,0x0b,0x06,0x1c,0x34,0x75,0x01,0xc3,0xa1,0x2e +,0x34,0x25,0xff,0xfe,0x8b,0x16,0xe7,0x36,0x81,0xe2,0x00,0x01,0x0b,0xc2,0xa3,0x2e +,0x34,0x8d,0x16,0x10,0x00,0xbf,0x00,0x00,0xb9,0x08,0x00,0x8b,0x85,0x00,0x34,0xef +,0x83,0xc2,0x10,0x8b,0x85,0x02,0x34,0xef,0x83,0xc2,0x10,0x8b,0x85,0x04,0x34,0xef +,0x83,0xc2,0xe2,0x83,0xc7,0x06,0x49,0x75,0xe2,0xb8,0x00,0x00,0x8e,0xc0,0xbe,0x00 +,0x34,0xbf,0xb9,0x36,0xb9,0x18,0x00,0xf3,0xa5,0xb8,0x00,0x00,0xc3,0x33,0xc0,0x8e +,0xc0,0x8d,0x3e,0xb0,0x33,0xb9,0x08,0x00,0xf3,0xab,0x8d,0x3e,0x3e,0x34,0xb9,0x03 +,0x00,0xf3,0xab,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7,0x5a,0xff,0x06,0xba +,0x33,0xe5,0x56,0x0d,0x20,0x00,0xe7,0x56,0xba,0x7a,0x00,0xed,0x08,0x26,0x94,0x36 +,0x33,0xc0,0xb1,0x08,0x32,0xed,0x06,0x8e,0xc0,0x8d,0x3e,0xe0,0xff,0xf3,0xaa,0x8e +,0x06,0x32,0x34,0x26,0x81,0x0e,0x08,0x00,0x00,0x02,0x07,0xe5,0x56,0x25,0xdf,0xff +,0xe7,0x56,0xe9,0xf8,0xfc,0x00,0xbd,0x1b,0x10,0x1b,0xd9,0x1a,0xf3,0x1a,0x50,0x51 +,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7,0x5a,0xff,0x06,0xb6,0x33,0x53 +,0x06,0x51,0xe5,0x80,0xa3,0xb4,0x33,0x8b,0xd8,0x8b,0xc8,0x25,0x10,0x00,0xa3,0xed +,0x34,0x0b,0xc0,0x74,0x14,0xff,0x06,0x80,0x34,0x80,0x3e,0xfe,0x34,0x00,0x74,0x03 +,0xe9,0x06,0x00,0xb8,0x80,0x00,0xe8,0x9d,0x04,0x83,0xe3,0x03,0xd1,0xe3,0x2e,0xff +,0x97,0x86,0x1a,0x59,0x07,0x5b,0xe9,0xa4,0xfc,0xba,0x20,0x00,0x8e,0x06,0x3c,0x34 +,0x83,0x3e,0x3c,0x34,0x00,0x75,0x03,0xe9,0xf0,0x00,0xc7,0x06,0x3c,0x34,0x00,0x00 +,0xe9,0x2a,0x00,0xba,0x10,0x00,0x8e,0x06,0x3a,0x34,0x83,0x3e,0x3a,0x34,0x00,0x75 +,0x03,0xe9,0xd5,0xff,0xc7,0x06,0x3a,0x34,0x00,0x00,0xe8,0x10,0x00,0xe9,0xc9,0xff +,0xba,0x10,0x00,0x8e,0x06,0x3a,0x34,0xc7,0x06,0x3a,0x34,0x00,0x00,0x26,0xa1,0x14 +,0x00,0x26,0xa3,0x0c,0x00,0x26,0xa1,0x16,0x00,0x26,0xa3,0x0e,0x00,0x26,0xc6,0x06 +,0x0a,0x00,0x00,0xc1,0xea,0x02,0x23,0xd1,0x74,0x1c,0xba,0x20,0x00,0x26,0xc7,0x06 +,0x0e,0x00,0xea,0x05,0x26,0x0b,0x16,0x0c,0x00,0x26,0x89,0x16,0x0c,0x00,0xff,0x06 +,0x86,0x34,0xff,0x06,0xdc,0x33,0x26,0xa1,0x0c,0x00,0xa9,0x00,0x37,0x74,0x16,0x26 +,0xc6,0x06,0x0a,0x00,0x02,0xa9,0x00,0x30,0x74,0x04,0xff,0x06,0x7a,0x34,0xff,0x06 +,0xda,0x33,0xe9,0x49,0x00,0xc0,0xec,0x07,0x83,0x16,0x8a,0x34,0x00,0x24,0x07,0x3c +,0x07,0x75,0x04,0xff,0x06,0x8c,0x34,0xff,0x06,0x7e,0x34,0xa1,0x30,0x34,0x8c,0xc3 +,0x8e,0xc0,0x8e,0xdb,0x26,0x83,0x0e,0x08,0x00,0x40,0x8c,0xd8,0x26,0x87,0x06,0x16 +,0x00,0x26,0x83,0x3e,0x14,0x00,0xff,0x74,0x0a,0x8e,0xc0,0x26,0x8c,0x1e,0x00,0x00 +,0xe9,0x05,0x00,0x26,0x8c,0x1e,0x14,0x00,0x33,0xc0,0x8e,0xd8,0xc3,0xc3,0x8c,0xc0 +,0x87,0x06,0x92,0x01,0x3d,0xff,0xff,0x74,0x0d,0x8e,0xd8,0x8c,0x06,0x00,0x00,0x33 +,0xc0,0x8e,0xd8,0xe9,0x04,0x00,0x8c,0x06,0x90,0x01,0xe8,0x01,0x00,0xc3,0x06,0x83 +,0x3e,0x90,0x01,0xff,0x74,0x29,0x83,0x3e,0x3a,0x34,0x00,0x75,0x11,0xba,0x86,0x00 +,0xe8,0x1e,0x00,0x8c,0x06,0x3a,0x34,0x83,0x3e,0x90,0x01,0xff,0x74,0x11,0x83,0x3e +,0x3c,0x34,0x00,0x75,0x0a,0xba,0x88,0x00,0xe8,0x06,0x00,0x8c,0x06,0x3c,0x34,0x07 +,0xc3,0xa1,0x90,0x01,0x8e,0xc0,0x26,0xa1,0x08,0x00,0xef,0x26,0xa1,0x00,0x00,0x26 +,0xc7,0x06,0x00,0x00,0xff,0xff,0xa3,0x90,0x01,0x3d,0xff,0xff,0x75,0x03,0xa3,0x92 +,0x01,0x83,0x3e,0xed,0x34,0x00,0x74,0x0b,0xb8,0x10,0x00,0xe7,0x84,0xc7,0x06,0xed +,0x34,0x00,0x00,0xc3,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7 +,0x5a,0xff,0x06,0xbc,0x33,0xe9,0x25,0xfb,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33 +,0xc0,0x8e,0xd8,0xe7,0x5a,0xff,0x06,0xb0,0x33,0xe9,0x11,0xfb,0x50,0x51,0x56,0x57 +,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7,0x5a,0xff,0x06,0xb4,0x33,0x06,0xff,0x06 +,0x76,0x34,0x80,0x3e,0xfe,0x34,0x00,0x74,0x04,0x07,0xe9,0xf0,0xfa,0xb8,0x80,0x00 +,0xe8,0xd3,0x02,0x07,0xe9,0xe6,0xfa,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0xc6,0x1d,0x08,0x1d,0x91,0x1e,0x5d,0x1e,0x73,0x1e,0x89,0x1e,0x91,0x1e,0xa8,0x1d +,0x91,0x1e,0x91,0x1e,0xaf,0x1e,0xaf,0x1e,0x15,0x1d,0x15,0x1d,0x91,0x1e,0x99,0x1f +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x02,0x00,0x00 +,0x00,0x01,0x00,0x10,0x00,0x01,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00 +,0x07,0xe9,0x99,0xfa,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7 +,0x5a,0xff,0x06,0xb2,0x33,0x06,0x68,0xf6,0x1c,0xe5,0x06,0xa3,0xb2,0x33,0x8b,0xf0 +,0x83,0xe6,0x1e,0x2e,0xff,0xa4,0xa0,0x1c,0xe5,0x0c,0xa9,0x80,0x00,0x74,0x06,0xe8 +,0xa4,0x01,0xe5,0x06,0xc3,0x53,0xe5,0x0c,0x8b,0xd8,0xa9,0x01,0x00,0x74,0x14,0x83 +,0x3e,0xe0,0x3a,0x00,0x74,0x0d,0x8e,0x06,0x38,0x34,0xe8,0xbf,0x06,0xc7,0x06,0xe0 +,0x3a,0x00,0x00,0xe5,0x00,0x0d,0x18,0x00,0xe7,0x00,0xe5,0x02,0x0d,0x11,0x00,0xe7 +,0x02,0x8b,0xc3,0x5b,0xa9,0x01,0x00,0x74,0x01,0xc3,0x8b,0xd0,0xb8,0x00,0x08,0xe7 +,0x84,0x8b,0xc2,0x8e,0x06,0x38,0x34,0x26,0xa3,0x0c,0x00,0x8b,0xd0,0xc1,0xe0,0x03 +,0x83,0x16,0x88,0x34,0x00,0xff,0x06,0x7c,0x34,0x26,0x83,0x3e,0x06,0x00,0x0a,0x75 +,0x21,0x8b,0xc2,0x25,0x40,0x18,0x3d,0x40,0x00,0x74,0x0c,0x3d,0x00,0x10,0x75,0x12 +,0x26,0xfe,0x0e,0x0a,0x00,0x74,0x0b,0xf7,0x06,0xef,0x34,0x20,0x00,0x75,0x03,0xe9 +,0x5a,0x06,0x8c,0xc0,0x26,0x8e,0x06,0x02,0x00,0x26,0x83,0x0e,0x08,0x00,0x20,0x26 +,0xa3,0x12,0x00,0x26,0xa3,0x10,0x00,0xc3,0xff,0x06,0xc4,0x33,0xe5,0x0c,0xa9,0x01 +,0x00,0x75,0x01,0xc3,0xa9,0xf0,0x07,0x74,0x01,0xc3,0xff,0x06,0xd4,0x33,0xe5,0x00 +,0x0d,0x18,0x00,0xe7,0x00,0xc3,0xff,0x06,0xca,0x33,0x80,0x3e,0xa0,0x36,0x08,0x75 +,0x14,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x08,0x74,0x07,0x26,0x81 +,0x0e,0x08,0x00,0x00,0x08,0xe5,0x82,0x25,0xfd,0xff,0xe7,0x82,0xe5,0x0c,0x50,0xe5 +,0x80,0x25,0x00,0x07,0xa3,0xe4,0x3a,0xe5,0x8c,0x25,0x00,0x80,0xa3,0xe2,0x3a,0x58 +,0xa9,0x02,0x00,0x75,0x25,0x83,0x3e,0xe2,0x3a,0x00,0x75,0x1e,0x83,0x3e,0xe4,0x3a +,0x00,0x75,0x17,0xe5,0x08,0x0d,0x00,0x04,0x25,0xff,0x04,0xe7,0x08,0xe8,0x6a,0x01 +,0xe5,0x82,0x0d,0x02,0x00,0xe7,0x82,0xe9,0x21,0x00,0xe8,0x1a,0x06,0x80,0x3e,0xe8 +,0xff,0x00,0x74,0x0a,0x80,0x3e,0xe8,0xff,0x04,0x74,0x03,0xe9,0x0d,0x00,0xc6,0x06 +,0xe8,0xff,0x01,0xba,0x0c,0x01,0xb8,0x08,0x08,0xef,0xed,0x80,0x3e,0x9f,0x36,0x06 +,0x75,0x05,0x83,0x0e,0x99,0x36,0x40,0xb8,0x00,0x01,0xe9,0x09,0x01,0xff,0x06,0xcc +,0x33,0x81,0x26,0xaf,0x36,0xff,0xf7,0xa1,0xaf,0x36,0xe7,0x06,0xff,0x06,0xc6,0x34 +,0xe9,0x1e,0x00,0xff,0x06,0xce,0x33,0xff,0x06,0x95,0x37,0x81,0x26,0xaf,0x36,0xff +,0xef,0xa1,0xaf,0x36,0xe7,0x06,0xe9,0x08,0x00,0xff,0x06,0xd0,0x33,0xff,0x06,0x7a +,0x34,0xff,0x06,0xd2,0x33,0xd1,0xe6,0x8e,0x06,0x30,0x34,0x2e,0x8b,0x84,0xc0,0x1c +,0x26,0x09,0x06,0x08,0x00,0x2e,0x8b,0x84,0xc2,0x1c,0x09,0x06,0x66,0x37,0xc3,0xe5 +,0x0c,0xa9,0x80,0x00,0x74,0x56,0x50,0xe8,0xf0,0x00,0x58,0xa9,0x00,0x01,0x75,0x07 +,0xff,0x06,0xc6,0x33,0xe9,0x08,0x00,0xff,0x06,0x78,0x34,0xff,0x06,0xc8,0x33,0xe5 +,0x82,0x25,0xfd,0xff,0xe7,0x82,0xe8,0x6e,0x05,0xba,0x10,0x01,0xed,0x80,0x3e,0xe8 +,0xff,0x00,0x74,0x0a,0x80,0x3e,0xe8,0xff,0x04,0x74,0x03,0xe9,0x1d,0x00,0xc6,0x06 +,0xe8,0xff,0x01,0xba,0x0c,0x01,0xb8,0x08,0x08,0xef,0xed,0xe9,0x0d,0x00,0xc6,0x06 +,0xe8,0xff,0x03,0xba,0x0c,0x01,0xb8,0x08,0x08,0xef,0xed,0xc3,0xa9,0x01,0x00,0x74 +,0x1c,0xe8,0x2c,0x00,0x83,0x3e,0xe0,0x3a,0x00,0x74,0x0f,0x06,0x8e,0x06,0x38,0x34 +,0xe8,0xc9,0x04,0xc7,0x06,0xe0,0x3a,0x00,0x00,0x07,0xe9,0x5d,0x00,0x8b,0xd0,0x8e +,0x06,0x38,0x34,0x26,0xa3,0x0c,0x00,0xe8,0x06,0x00,0x68,0x69,0x1d,0xe9,0x4a,0x00 +,0xa9,0x00,0x04,0x74,0x0a,0xb8,0x00,0x04,0xff,0x06,0xd8,0x33,0xe9,0x17,0x00,0xa9 +,0x00,0x01,0x74,0x0a,0xff,0x06,0x39,0x37,0xb8,0x00,0x01,0xe9,0x08,0x00,0xa9,0x10 +,0x00,0xb8,0x10,0x00,0x74,0x1d,0x09,0x06,0x66,0x37,0x8c,0xc0,0x8e,0x06,0x30,0x34 +,0x26,0xf7,0x06,0x0a,0x00,0x00,0x01,0x74,0x07,0x26,0x81,0x0e,0x08,0x00,0x00,0x01 +,0x8e,0xc0,0xc3,0xff,0x06,0xc2,0x33,0xe9,0xf8,0xff,0xe5,0x00,0x0d,0x18,0x00,0xe7 +,0x00,0xe5,0x02,0x0d,0x11,0x00,0xe7,0x02,0xc3,0x58,0xe9,0x43,0xfd,0xe5,0x08,0x0d +,0x00,0x04,0x25,0xff,0x04,0xe7,0x08,0xe9,0xe0,0xff,0xe5,0x0e,0xa9,0x00,0x08,0x75 +,0x01,0xc3,0xe9,0xf5,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7,0x5a,0xff,0x06,0xb8 +,0x33,0xe5,0x48,0x06,0x53,0x57,0xff,0x16,0x4e,0x37,0x5f,0x5b,0x83,0x3e,0x80,0x01 +,0xff,0x74,0x58,0x8e,0x06,0x80,0x01,0x26,0xff,0x0e,0x08,0x00,0x75,0x4d,0x26,0xa1 +,0x00,0x00,0xa3,0x80,0x01,0x26,0xc7,0x06,0x00,0x00,0xff,0xff,0x8c,0xc0,0x26,0x8e +,0x06,0x02,0x00,0x26,0x81,0x0e,0x08,0x00,0x80,0x00,0x8b,0xd0,0x26,0x87,0x06,0x1a +,0x00,0x26,0x83,0x3e,0x18,0x00,0xff,0x74,0x0a,0x8e,0xc0,0x26,0x89,0x16,0x00,0x00 +,0xe9,0x05,0x00,0x26,0x89,0x16,0x18,0x00,0x83,0x3e,0x80,0x01,0xff,0x74,0x0c,0x8e +,0x06,0x80,0x01,0x26,0x83,0x3e,0x08,0x00,0x00,0x74,0xb3,0x07,0xe9,0x3e,0xf7,0xe5 +,0x4c,0x90,0xe5,0x02,0xa9,0x00,0x20,0x74,0x0d,0x25,0xff,0xdf,0x0d,0x01,0x00,0xe7 +,0x02,0x0d,0x00,0x20,0xe7,0x02,0xe5,0x0a,0x8b,0xd8,0xa3,0xf4,0x33,0x25,0xc3,0x57 +,0x0d,0x00,0x10,0xe7,0x0a,0xf7,0x06,0x9b,0x36,0x00,0x80,0x74,0x37,0xf7,0xc3,0x00 +,0x80,0x74,0x06,0xf7,0xc3,0x00,0x08,0x74,0x5d,0x81,0x26,0xc2,0x34,0x7f,0xff,0xc7 +,0x06,0x35,0x37,0x05,0x00,0xb8,0x80,0x03,0xcd,0x39,0x81,0x26,0x9b,0x36,0xff,0x7f +,0xc7,0x06,0x0f,0x37,0x04,0x00,0xf7,0x06,0x9b,0x36,0x40,0x00,0x75,0x06,0xc7,0x06 +,0x0f,0x37,0x03,0x00,0xf7,0x06,0x9b,0x36,0x00,0x20,0x74,0x2a,0xf7,0xc3,0x00,0x08 +,0x74,0x24,0x80,0x3e,0x9d,0x36,0x06,0x7c,0x1d,0xff,0x06,0x94,0x34,0x83,0x0e,0x66 +,0x37,0x20,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x01,0x74,0x07,0x26 +,0x81,0x0e,0x08,0x00,0x00,0x01,0xf7,0xc3,0x00,0x20,0x75,0x3b,0xf7,0x06,0x9a,0x37 +,0x80,0x00,0x74,0x0b,0xff,0x06,0x89,0x37,0x33,0xc0,0xe7,0x0e,0xe9,0x04,0x00,0xff +,0x06,0x3b,0x37,0xf7,0x06,0x9b,0x36,0x00,0x20,0x74,0x1c,0x80,0x26,0x9e,0x36,0xff +,0x75,0x15,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x08,0x74,0x07,0x26 +,0x81,0x0e,0x08,0x00,0x00,0x08,0xc3,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x02,0x23,0x02,0x23,0x02,0x23,0x02,0x23,0x03,0x23,0xdd,0x22,0x02,0x23,0xfd,0x21 +,0x02,0x23,0xa4,0x24,0xf3,0x24,0x02,0x23,0x8d,0x22,0x7a,0x23,0x02,0x23,0x97,0x24 +,0x1b,0x24,0x75,0x24,0x02,0x23,0x02,0x23,0x8e,0x25,0xfb,0x8e,0x06,0x7e,0x01,0xfb +,0x26,0x83,0x3e,0x00,0x00,0xff,0x74,0xf2,0x26,0x8e,0x06,0x00,0x00,0xfa,0x26,0x8b +,0x1e,0x08,0x00,0x26,0x23,0x1e,0x0a,0x00,0x74,0xe5,0x8c,0xc0,0x8e,0xd0,0x26,0x8b +,0x26,0x02,0x00,0x8c,0x16,0xf2,0x33,0x22,0xff,0x75,0x6a,0x26,0xa1,0x1c,0x00,0x8a +,0xe3,0x8a,0xdc,0x22,0xd8,0x75,0x0d,0xd0,0xe8,0x24,0xf8,0x0a,0xc0,0x75,0xf2,0xb0 +,0x80,0xe9,0xed,0xff,0xd0,0xe8,0x24,0xf8,0x0a,0xc0,0x75,0x02,0xb0,0x80,0x32,0xe4 +,0x26,0xa3,0x1c,0x00,0xf7,0xc3,0x08,0x00,0x75,0x47,0x2e,0x8a,0x9f,0xc5,0x25,0x2e +,0x8b,0xbf,0xc5,0x26,0x80,0xc3,0x10,0x26,0x8e,0x1d,0x26,0x8c,0x1e,0x06,0x00,0x8b +,0x16,0x00,0x00,0xc7,0x06,0x00,0x00,0xff,0xff,0x26,0x89,0x15,0x83,0xfa,0xff,0x75 +,0x0a,0x2e,0x8b,0x97,0xcd,0x26,0x26,0x21,0x16,0x08,0x00,0x33,0xc0,0x8e,0xd8,0x26 +,0x89,0x1e,0x04,0x00,0xc3,0x8a,0xdf,0xb7,0x00,0x2e,0x8a,0x9f,0xc5,0x25,0xe9,0xe0 +,0xff,0x26,0x83,0x26,0x08,0x00,0xf7,0x83,0xc3,0x10,0xe9,0xde,0xff,0x60,0x06,0x1e +,0x68,0x87,0x25,0x6a,0x00,0x1f,0x8e,0x06,0xf2,0x33,0x8b,0x0e,0x34,0x34,0x39,0x0e +,0xf2,0x33,0x74,0x0e,0x26,0x81,0x0e,0x0a,0x00,0x00,0x02,0x26,0x81,0x0e,0x08,0x00 +,0x00,0x02,0x26,0x89,0x26,0x02,0x00,0xa3,0xf2,0x33,0x8e,0xd0,0x8d,0x26,0x80,0x00 +,0x36,0x89,0x26,0x02,0x00,0x36,0x89,0x1e,0x20,0x00,0x36,0xc7,0x06,0x08,0x00,0x00 +,0x00,0xb9,0x04,0x00,0xbe,0x00,0x00,0x2e,0x8b,0xbc,0xc5,0x26,0x36,0xc7,0x05,0xff +,0xff,0x36,0xc7,0x45,0x02,0xff,0xff,0x83,0xc6,0x02,0xe2,0xeb,0x8e,0x06,0x7e,0x01 +,0x36,0x8b,0x0e,0x22,0x00,0x8c,0xc0,0x26,0x83,0x3e,0x00,0x00,0xff,0x26,0x8e,0x06 +,0x00,0x00,0x74,0x07,0x26,0x3b,0x0e,0x22,0x00,0x7d,0xea,0x36,0x8c,0x06,0x00,0x00 +,0x8e,0xc0,0x26,0x8c,0x16,0x00,0x00,0xfb,0x36,0xff,0x2e,0x1e,0x00,0x06,0x1e,0x68 +,0x8b,0x25,0x6a,0x00,0x1f,0x26,0x09,0x36,0x08,0x00,0xf7,0xc6,0x00,0xff,0x74,0x01 +,0xc3,0x56,0x52,0x2e,0x8b,0xb4,0xc5,0x25,0x81,0xe6,0xff,0x00,0x2e,0x8b,0xb4,0xc5 +,0x26,0x8c,0xc2,0x8e,0xc0,0x26,0xc7,0x06,0x00,0x00,0xff,0xff,0x8e,0xc2,0x26,0x83 +,0x3c,0xff,0x74,0x0f,0x8b,0xd0,0x26,0x87,0x54,0x02,0x8e,0xc2,0x26,0xa3,0x00,0x00 +,0xe9,0x07,0x00,0x26,0x89,0x44,0x02,0x26,0x89,0x04,0x5a,0x5e,0xc3,0x06,0x1e,0x68 +,0x8b,0x25,0x6a,0x00,0x1f,0x8e,0x06,0xf2,0x33,0x26,0xa3,0x0a,0x00,0x26,0x89,0x26 +,0x02,0x00,0xa1,0x34,0x34,0x8e,0xd0,0x8d,0x26,0x80,0x00,0x8c,0x16,0xf2,0x33,0xe9 +,0x4d,0xfe,0xcf,0x50,0x1e,0x52,0x53,0x33,0xc0,0x8e,0xd8,0x26,0x83,0x3e,0x04,0x00 +,0xff,0x26,0xc7,0x06,0x04,0x00,0x00,0x00,0x74,0x03,0xe9,0x1a,0x00,0x83,0x3e,0xe6 +,0x3a,0x02,0x76,0x13,0xff,0x06,0xd6,0x33,0x8c,0xc0,0x8e,0x06,0x32,0x34,0xbe,0x40 +,0x00,0x68,0x3a,0x23,0xe9,0x5e,0xff,0xe8,0x84,0xf8,0x5b,0x5a,0x1f,0x58,0xcf,0xe8 +,0xe1,0x00,0x26,0xc6,0x06,0x18,0x00,0x10,0x26,0x8a,0x1e,0x29,0x00,0x88,0x1e,0x1b +,0x37,0x26,0xc7,0x06,0x0c,0x00,0xff,0x7f,0x26,0xa1,0x0e,0x00,0xe7,0x9c,0x26,0xa1 +,0x08,0x00,0xe7,0x9a,0xe5,0x00,0x80,0xfb,0x08,0x74,0x09,0x0d,0x18,0xac,0xe7,0x00 +,0x07,0x1f,0x58,0xcf,0x0d,0x18,0x00,0xe9,0xf4,0xff,0x50,0x1e,0x06,0x33,0xc0,0x8e +,0xd8,0x83,0x3e,0xa1,0x36,0x00,0x75,0xb7,0x26,0x8b,0x36,0x06,0x00,0x2e,0xff,0x94 +,0xdc,0x23,0x07,0x1f,0x58,0xcf,0xe8,0x8a,0x00,0xe5,0x00,0x0d,0x18,0x00,0xe7,0x00 +,0xe8,0x49,0x00,0xc3,0x53,0xf7,0x06,0xef,0x34,0x20,0x00,0x75,0x2d,0xe5,0x8c,0x25 +,0x00,0x70,0x8b,0xd8,0xe5,0x8c,0x25,0x00,0x70,0x3b,0xc3,0x74,0x05,0x8b,0xd8,0xe9 +,0xf2,0xff,0x3d,0x00,0x30,0x75,0x10,0xe5,0x02,0x25,0xef,0xff,0xe7,0x02,0xc7,0x06 +,0xe0,0x3a,0xff,0xff,0xe9,0x03,0x00,0xe8,0x12,0x00,0x5b,0xc3,0xa3,0x23,0x96,0x23 +,0xa4,0x23,0xa4,0x23,0x96,0x23,0xa4,0x23,0x96,0x23,0x96,0x23,0x26,0xa0,0x29,0x00 +,0xa2,0x1b,0x37,0x26,0xc7,0x06,0x0c,0x00,0xff,0x7f,0x26,0xa1,0x0e,0x00,0xe7,0x9c +,0x26,0xa1,0x08,0x00,0xe7,0x9a,0xe5,0x00,0x25,0xff,0x53,0x26,0x8b,0x36,0x06,0x00 +,0x83,0xe6,0x0e,0x2e,0x0b,0x84,0xad,0x25,0xe7,0x00,0xc3,0x06,0x1e,0x68,0x8b,0x25 +,0x6a,0x00,0x1f,0x83,0x0e,0xef,0x34,0x20,0x83,0x0e,0x9b,0x36,0x08,0xe5,0x00,0x25 +,0xef,0xff,0x0d,0x08,0x00,0xe7,0x00,0xe5,0x00,0xa9,0x10,0x00,0x75,0x01,0xc3,0xe5 +,0x00,0xa9,0x10,0x00,0x75,0xf9,0xc3,0x50,0x53,0x51,0x56,0x06,0x1e,0x33,0xc0,0x8e +,0xd8,0xb8,0x05,0x00,0xe7,0x84,0xe5,0x08,0x0d,0x00,0x04,0x25,0xff,0x04,0xe7,0x08 +,0xe5,0x00,0x0d,0x18,0x00,0xe7,0x00,0xe5,0x02,0x0d,0x11,0x00,0xe7,0x02,0x1f,0x07 +,0x5e,0x59,0x5b,0x58,0xc3,0x50,0x1e,0x33,0xc0,0x8e,0xd8,0xc7,0x06,0xef,0x34,0x00 +,0x00,0x83,0x26,0x9b,0x36,0xf7,0xe5,0x00,0x0d,0x18,0x00,0xe7,0x00,0xe5,0x02,0x0d +,0x11,0x00,0xe7,0x02,0x1f,0x58,0xcf,0x60,0x06,0x1e,0x68,0x87,0x25,0x6a,0x00,0x1f +,0xe8,0x16,0xf5,0xc3,0x06,0x1e,0x68,0x8b,0x25,0x6a,0x00,0x1f,0x8e,0xc0,0x26,0x83 +,0x3e,0x0a,0x00,0x00,0x74,0x03,0xe8,0x43,0x00,0x26,0xc7,0x06,0x0a,0x00,0xff,0xff +,0x26,0x8b,0x16,0x06,0x00,0x8e,0x1e,0x8e,0x01,0x8c,0xd8,0x8b,0xca,0x83,0x3e,0x00 +,0x00,0xff,0x8e,0x1e,0x00,0x00,0x74,0x0a,0x2b,0x16,0x08,0x00,0x73,0xeb,0x29,0x0e +,0x08,0x00,0x26,0x89,0x0e,0x08,0x00,0x26,0x8c,0x1e,0x00,0x00,0x8e,0xd8,0x8c,0x06 +,0x00,0x00,0xc3,0x60,0x06,0x1e,0x68,0x87,0x25,0x6a,0x00,0x1f,0x8e,0xc0,0x8b,0xc8 +,0x8e,0x1e,0x8e,0x01,0x26,0xc7,0x06,0x0a,0x00,0x00,0x00,0x8c,0xd8,0x83,0x3e,0x00 +,0x00,0xff,0x74,0x25,0x3b,0x0e,0x00,0x00,0x8e,0x1e,0x00,0x00,0x75,0xed,0x8e,0xd8 +,0x26,0xa1,0x00,0x00,0xa3,0x00,0x00,0x3d,0xff,0xff,0x74,0x56,0x8e,0xd8,0x26,0xa1 +,0x08,0x00,0x01,0x06,0x08,0x00,0xe9,0x49,0x00,0x26,0x8e,0x1e,0x02,0x00,0xbe,0x18 +,0x00,0x83,0x3c,0xff,0x74,0x3c,0x39,0x0c,0x74,0x19,0x8e,0x1c,0xbe,0x00,0x00,0x83 +,0x3e,0x00,0x00,0xff,0x74,0x2c,0x39,0x0e,0x00,0x00,0x74,0x07,0x8e,0x1e,0x00,0x00 +,0xe9,0xec,0xff,0x26,0xa1,0x00,0x00,0x89,0x04,0x33,0xc9,0x8e,0xd9,0x3d,0xff,0xff +,0x75,0x10,0x83,0xfe,0x18,0x75,0x0b,0x26,0x8e,0x1e,0x02,0x00,0x81,0x26,0x08,0x00 +,0x7f,0xff,0x33,0xc0,0x8e,0xd8,0xc3,0x1f,0x07,0x61,0xcf,0x1f,0x07,0xcf,0x60,0x06 +,0x1e,0x68,0x87,0x25,0x6a,0x00,0x1f,0xe5,0x06,0x25,0x1e,0x00,0x3d,0x1e,0x00,0x75 +,0xf6,0xb9,0x08,0x00,0xe5,0x58,0xe7,0x5a,0x23,0xc0,0xe0,0xf8,0xc3,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0xac,0x00,0x00,0x00,0xa8,0x00,0x8c,0x02,0x04,0x00 +,0x00,0x08,0x10,0x20,0x00,0xff,0x0e,0x0c,0x0c,0x0a,0x0a,0x0a,0x0a,0x08,0x08,0x08 +,0x08,0x08,0x08,0x08,0x08,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06 +,0x06,0x06,0x06,0x06,0x06,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04 +,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04 +,0x04,0x04,0x04,0x04,0x04,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02 +,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02 +,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02 +,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02 +,0x02,0x02,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x14,0x00,0x10,0x00,0x0c,0x00,0xff,0x7f,0xff +,0xbf,0xff,0xdf,0xff,0xef,0xff,0xf7,0xff,0xfb,0xff,0xfd,0xff,0xfe,0x7f,0xff,0xbf +,0xff,0xdf,0xff,0xef,0xff,0xf7,0xff,0xfb,0xff,0xfd,0xff,0xfe,0xff,0x00,0x00,0x00 +,0x80,0x3e,0xe2,0x34,0x01,0x76,0x03,0xe9,0xa5,0x00,0xb8,0x00,0x00,0xe7,0x4e,0xb9 +,0x28,0x00,0xe2,0xfe,0xc6,0x06,0x45,0x37,0x02,0xbf,0x3f,0x28,0x2e,0x8b,0x45,0x08 +,0xe7,0x4e,0xb9,0x28,0x00,0xe2,0xfe,0x2e,0x8b,0x1d,0xc7,0x06,0xb3,0x36,0x40,0x11 +,0xc7,0x06,0xb1,0x36,0x27,0x00,0xc7,0x06,0x46,0x37,0x02,0x00,0xc7,0x06,0x48,0x37 +,0x64,0x00,0xf7,0x06,0xb5,0x36,0x02,0x00,0x75,0x1c,0x2e,0x0b,0x5d,0x02,0x81,0x26 +,0xb3,0x36,0xff,0xfe,0xc7,0x06,0xb1,0x36,0x9c,0x00,0xc7,0x06,0x46,0x37,0x08,0x00 +,0xc7,0x06,0x48,0x37,0x90,0x01,0x89,0x1e,0xb7,0x36,0x89,0x1e,0xfe,0x33,0xbe,0x20 +,0x00,0x8b,0xc3,0xe7,0x4e,0xb9,0x28,0x00,0xe2,0xfe,0x2e,0x8b,0x45,0x04,0xe7,0x4e +,0xb9,0x28,0x00,0xe2,0xfe,0xe5,0x4e,0x8b,0xcb,0x2e,0x23,0x45,0x06,0x2e,0x23,0x4d +,0x06,0x3a,0xc1,0x74,0x36,0x4e,0x75,0xd9,0x80,0x3e,0x45,0x37,0x00,0x74,0x0b,0xc6 +,0x06,0x45,0x37,0x00,0xbf,0x2f,0x28,0xe9,0x72,0xff,0xc6,0x06,0x45,0x37,0x01,0xf7 +,0x06,0xb5,0x36,0x02,0x00,0x74,0x14,0xe5,0xce,0x25,0xfd,0xff,0xe7,0xce,0xe8,0x43 +,0x00,0xe5,0xce,0x0d,0x02,0x00,0xe7,0xce,0xe8,0x39,0x00,0x80,0x3e,0xe2,0x34,0x01 +,0x76,0x01,0xc3,0xb8,0xea,0x05,0xe7,0x8c,0xfa,0xe8,0x12,0xf4,0xfb,0x8d,0x06,0xd0 +,0x39,0x8b,0xd8,0xc1,0xe8,0x04,0xa3,0x38,0x34,0x8e,0xc0,0xa1,0x30,0x34,0x26,0xa3 +,0x02,0x00,0x26,0xc7,0x06,0x00,0x00,0xff,0xff,0x83,0xc3,0x18,0xd1,0xeb,0x26,0x89 +,0x1e,0x08,0x00,0xc3,0xe5,0x02,0x0d,0x00,0x40,0xe7,0x02,0xe5,0x00,0x0d,0x04,0x00 +,0xe7,0x00,0xb8,0x00,0x00,0xe7,0x0a,0xe5,0x0a,0xa9,0x00,0x80,0x75,0x14,0xe5,0x08 +,0x0d,0x00,0x10,0xe7,0x08,0xe5,0x0a,0x0d,0x00,0x08,0xb9,0x05,0x00,0xe7,0x0a,0xe2 +,0xfc,0xc3,0xe5,0x08,0x0d,0x00,0x10,0xb9,0x05,0x00,0xe7,0x08,0xe2,0xfc,0xc3,0x04 +,0x0c,0x20,0x00,0x01,0x0c,0x7e,0xff,0x00,0x0c,0x02,0x00,0x10,0x00,0x40,0x00,0x0c +,0xc6,0x01,0x00,0x00,0xc0,0xf7,0xff,0x00,0xc0,0x02,0x00,0x10,0x00,0x40,0x00,0x00 +,0x33,0xc0,0x8e,0xd8,0x8d,0x3e,0x72,0x49,0x8d,0x36,0xb0,0x37,0xb9,0x14,0x00,0x8b +,0x1e,0x30,0x34,0x89,0x5c,0x02,0x2e,0x8b,0x45,0x02,0x89,0x44,0x06,0x2e,0x8b,0x05 +,0x89,0x44,0x04,0x83,0xc7,0x04,0x83,0xc6,0x10,0xe2,0xe8,0xc6,0x06,0x9e,0x36,0x0e +,0xe8,0xfd,0x26,0x68,0x83,0x28,0xa1,0xaa,0x02,0xcd,0x35,0x83,0x3e,0xa1,0x36,0x00 +,0x74,0x03,0xe9,0x3b,0x27,0x33,0xff,0x8e,0x06,0xa6,0x02,0x8b,0x36,0xa4,0x02,0x2e +,0xff,0xa4,0x2e,0x30,0x83,0x0e,0x99,0x36,0x04,0xc7,0x06,0x37,0x37,0x01,0x00,0xc6 +,0x06,0xca,0x34,0x01,0xe9,0x7d,0x19,0x80,0x3e,0xa0,0x36,0x08,0x74,0xe6,0x80,0x26 +,0x9e,0x36,0xff,0x75,0x1a,0xf7,0x06,0x9b,0x36,0x00,0x20,0x74,0x12,0xf7,0x06,0x9b +,0x36,0x03,0x00,0x75,0x0a,0x83,0x0e,0x66,0x37,0x10,0xc6,0x06,0xa0,0x36,0x08,0xe9 +,0xfb,0x01,0x80,0x3e,0x9e,0x36,0x02,0x75,0xce,0xc6,0x06,0xa0,0x36,0x06,0xe9,0xec +,0x01,0xc3,0xe9,0xe8,0x01,0x26,0xc7,0x06,0x0a,0x00,0x00,0x00,0x26,0xff,0x26,0x04 +,0x00,0xa1,0xd1,0x36,0x26,0x39,0x06,0x1a,0x00,0x75,0x22,0xa1,0xd3,0x36,0x26,0x39 +,0x06,0x1c,0x00,0x75,0x18,0xa1,0xd5,0x36,0x26,0x39,0x06,0x1e,0x00,0x75,0x0e,0x26 +,0xf7,0x06,0x0c,0x00,0x40,0x00,0x74,0x05,0x83,0x0e,0x66,0x37,0x40,0x81,0x0e,0xaf +,0x36,0x00,0x10,0xa1,0xaf,0x36,0xe7,0x06,0x80,0x3e,0x9d,0x36,0x02,0x75,0x06,0xcd +,0x34,0xe9,0xa2,0x1a,0xc3,0xf7,0x06,0x9b,0x36,0x10,0x00,0x75,0x54,0x26,0xf6,0x06 +,0x0a,0x00,0xff,0x75,0x4c,0x26,0xa0,0x19,0x00,0x24,0xc0,0x3c,0x40,0x75,0x11,0x80 +,0x3e,0x95,0x36,0x00,0x74,0x3b,0x26,0xc7,0x06,0x04,0x00,0xff,0xff,0xe9,0x31,0x00 +,0xe8,0xf1,0x04,0xf7,0x06,0x9b,0x36,0x03,0x00,0x74,0x2f,0x8b,0xd8,0xb8,0x7d,0x03 +,0xcd,0x3a,0x8b,0xc3,0xc6,0x06,0xa0,0x36,0x06,0xf7,0x06,0x9b,0x36,0x02,0x00,0x75 +,0x05,0xc6,0x06,0xa0,0x36,0x04,0x81,0x0e,0x9b,0x36,0x80,0x00,0x83,0x26,0x9b,0x36 +,0xfc,0xe9,0x23,0x01,0xe8,0x87,0x1d,0xe9,0x33,0x01,0x50,0x26,0xa1,0x0c,0x00,0x25 +,0x07,0x00,0x3d,0x07,0x00,0x75,0x03,0xe9,0x84,0x00,0x3d,0x05,0x00,0x75,0x03,0xe9 +,0x7c,0x00,0x83,0x3e,0xe8,0x3a,0x04,0x74,0x75,0x83,0x3e,0xe8,0x3a,0x02,0x74,0x6e +,0xf7,0x06,0xe6,0x34,0x18,0x80,0x75,0x03,0xe9,0x6a,0x00,0xf7,0x06,0xe6,0x34,0x00 +,0x80,0x74,0x35,0x26,0x80,0x3e,0x29,0x00,0x02,0x75,0x2d,0x51,0x56,0x57,0x8d,0x36 +,0x3e,0x34,0x8d,0x3e,0x20,0x00,0xb9,0x06,0x00,0xf3,0xa6,0x5f,0x5e,0x59,0x74,0x45 +,0x26,0xa1,0x20,0x00,0xa3,0x3e,0x34,0x26,0xa1,0x22,0x00,0xa3,0x40,0x34,0x26,0xa1 +,0x24,0x00,0xa3,0x42,0x34,0xe9,0x26,0x00,0xf7,0x06,0xe6,0x34,0x08,0x00,0x74,0x0b +,0x26,0x80,0x3e,0x19,0x00,0x00,0x74,0x03,0xe9,0x13,0x00,0xf7,0x06,0xe6,0x34,0x10 +,0x00,0x74,0x12,0x26,0xa0,0x28,0x00,0xc0,0xe8,0x04,0x22,0xc0,0x74,0x07,0x26,0xc7 +,0x06,0x04,0x00,0xff,0xff,0x58,0x23,0xc0,0x74,0x03,0xe9,0x57,0xff,0x81,0x26,0x9b +,0x36,0xff,0xfe,0x83,0xfe,0x06,0x7f,0x24,0x26,0xa1,0x20,0x00,0x3b,0x06,0xd1,0x36 +,0x75,0x1a,0x26,0xa1,0x22,0x00,0x3b,0x06,0xd3,0x36,0x75,0x10,0x26,0xa1,0x24,0x00 +,0x3b,0x06,0xd5,0x36,0x75,0x06,0x81,0x0e,0x9b,0x36,0x00,0x01,0x26,0xa1,0x20,0x00 +,0x25,0x7f,0xff,0xa3,0xb8,0x34,0x26,0xa1,0x22,0x00,0xa3,0xba,0x34,0x26,0xa1,0x24 +,0x00,0xa3,0xbc,0x34,0x8b,0xc6,0x86,0xc4,0xa3,0xc0,0x34,0xd1,0xe6,0x80,0xfc,0x09 +,0x74,0x03,0xe8,0xaa,0x1c,0x8b,0xc6,0x2e,0xff,0xa4,0x30,0x49,0x26,0xa1,0x0c,0x00 +,0x3d,0xff,0x7f,0x74,0x0f,0x26,0xff,0x26,0x04,0x00,0x8e,0x06,0x38,0x34,0xe8,0x36 +,0x06,0xcd,0x50,0xc3,0xe9,0x16,0x00,0xcd,0x34,0xe9,0x11,0x00,0xcd,0x34,0x89,0x36 +,0x3d,0x37,0xa1,0x9d,0x36,0xa3,0x3f,0x37,0xc6,0x06,0xa0,0x36,0x0c,0xe8,0x8e,0x00 +,0xa1,0x9f,0x36,0x22,0xe4,0x75,0x32,0xf7,0x06,0x4c,0x37,0x01,0x00,0x75,0x2a,0xf6 +,0x06,0x9d,0x36,0x80,0x74,0x07,0x88,0x26,0x9e,0x36,0xe9,0x31,0x00,0x3a,0x06,0x9d +,0x36,0xa3,0x9d,0x36,0x74,0x28,0x8b,0xf0,0x2e,0xff,0xa4,0x0d,0x2b,0x44,0x29,0xee +,0x42,0x19,0x44,0xcd,0x44,0x2f,0x45,0x5a,0x45,0x3a,0x26,0x9e,0x36,0x75,0x01,0xc3 +,0x32,0xc0,0x86,0xc4,0x8b,0xf0,0xa2,0x9e,0x36,0x2e,0xff,0xa4,0x20,0x49,0x8b,0x2e +,0x99,0x36,0x23,0xed,0x75,0x01,0xc3,0xbf,0x01,0x00,0xbe,0x00,0x00,0x85,0xfd,0x75 +,0x1a,0x46,0xd1,0xe7,0xe9,0xf6,0xff,0x2a,0x00,0x29,0x00,0x28,0x00,0x27,0x00,0x25 +,0x00,0x05,0x00,0x07,0x00,0x26,0x00,0x06,0x00,0x20,0x00,0xf7,0xd7,0x21,0x3e,0x99 +,0x36,0xd1,0xe6,0x2e,0x8b,0xb4,0x47,0x2b,0xe9,0x4f,0xff,0xe9,0x56,0xff,0x80,0x26 +,0x9e,0x36,0xff,0x75,0x17,0xf7,0x06,0x4c,0x37,0x01,0x00,0x75,0x0f,0xf6,0x06,0x9d +,0x36,0x80,0x74,0x08,0xf7,0x06,0x66,0x37,0xff,0xff,0x75,0x07,0xc7,0x06,0x66,0x37 +,0x00,0x00,0xc3,0xf7,0x06,0x41,0x37,0x01,0x00,0x75,0x0b,0xb8,0x7f,0x03,0xcd,0x39 +,0xc7,0x06,0x41,0x37,0x01,0x00,0x33,0xf6,0xb8,0x00,0x40,0x85,0x06,0x66,0x37,0x74 +,0x21,0x80,0xbc,0x54,0x37,0xff,0x74,0x04,0xfe,0x84,0x54,0x37,0x80,0xbc,0x96,0x34 +,0xff,0x74,0x04,0xfe,0x84,0x96,0x34,0x31,0x06,0x66,0x37,0x83,0x3e,0x66,0x37,0x00 +,0x74,0x05,0x46,0xd1,0xe8,0x73,0xd4,0xc3,0xa1,0xf4,0x33,0xa9,0x00,0x88,0x74,0x0b +,0xa9,0x00,0x10,0x75,0x09,0x8b,0x1e,0x43,0x37,0xff,0xe3,0xe9,0xd7,0x00,0xc7,0x06 +,0x35,0x37,0x05,0x00,0xc7,0x06,0x43,0x37,0x1e,0x2c,0xf7,0x06,0xf4,0x33,0x00,0x08 +,0x74,0x06,0xc7,0x06,0x43,0x37,0x10,0x2c,0xb8,0x80,0x03,0xcd,0x39,0xe9,0xcd,0xfe +,0xa9,0x00,0x08,0x74,0xd9,0xff,0x0e,0x35,0x37,0x75,0xed,0xe9,0x66,0x00,0xa9,0x00 +,0x08,0x75,0xcb,0xff,0x0e,0x35,0x37,0x75,0xdf,0x81,0x0e,0xc2,0x34,0xc0,0x00,0xf6 +,0x06,0x9d,0x36,0x80,0x74,0x48,0x81,0x0e,0x9b,0x36,0x00,0x80,0xf7,0x06,0x9b,0x36 +,0x01,0x00,0x74,0x1e,0xb8,0x7d,0x03,0xcd,0x3a,0x81,0x0e,0x9b,0x36,0x80,0x00,0x83 +,0x26,0x9b,0x36,0xfe,0xc7,0x06,0x0f,0x37,0x02,0x00,0xc6,0x06,0xa0,0x36,0x04,0xe9 +,0x7b,0xfe,0x80,0x3e,0xa0,0x36,0x04,0x75,0x07,0x83,0x3e,0x0f,0x37,0x01,0x75,0x05 +,0xc6,0x06,0xa0,0x36,0x06,0xc7,0x06,0x0f,0x37,0x02,0x00,0xe9,0x5f,0xfe,0xbe,0x02 +,0x00,0xe9,0x4a,0xfe,0x80,0x26,0x9e,0x36,0xff,0x75,0x3a,0xf6,0x06,0x9d,0x36,0x80 +,0x74,0x2d,0xf7,0x06,0x9b,0x36,0x00,0x20,0x75,0x2b,0xc6,0x06,0xa0,0x36,0x06,0xff +,0x06,0x94,0x34,0x83,0x0e,0x66,0x37,0x20,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a +,0x00,0x00,0x01,0x74,0x07,0x26,0x81,0x0e,0x08,0x00,0x00,0x01,0xe9,0x06,0x00,0xbe +,0x04,0x00,0xe9,0x09,0xfe,0x81,0x0e,0xaf,0x36,0x00,0x08,0xa1,0xaf,0x36,0xe7,0x06 +,0xe5,0x0a,0xa9,0x00,0x80,0x74,0x0e,0x81,0x26,0xaf,0x36,0xff,0xf7,0xa1,0xaf,0x36 +,0xe7,0x06,0xe9,0x09,0xff,0xe9,0xf5,0xfd,0xc7,0x06,0x41,0x37,0x00,0x00,0x83,0x0e +,0x99,0x36,0x02,0xe9,0xe7,0xfd,0x80,0x26,0x9e,0x36,0xff,0x75,0x1d,0xf7,0x06,0x9b +,0x36,0x00,0x40,0x75,0x05,0x83,0x0e,0x99,0x36,0x08,0x83,0x0e,0x99,0x36,0x20,0x81 +,0x26,0x9b,0x36,0xff,0xbf,0xb8,0x85,0x03,0xcd,0x39,0xe9,0xc0,0xfd,0x80,0x3e,0x9e +,0x36,0x06,0x74,0x07,0x80,0x3e,0x9e,0x36,0x0a,0x75,0x34,0xf6,0x06,0x9d,0x36,0x80 +,0x75,0x06,0xbe,0x07,0x00,0xe9,0x96,0xfd,0xc6,0x06,0xa0,0x36,0x04,0x83,0x3e,0x0f +,0x37,0x02,0x74,0x1b,0xc7,0x06,0x0f,0x37,0x04,0x00,0x80,0x3e,0x9e,0x36,0x06,0x75 +,0x0e,0xf7,0x06,0x9b,0x36,0x40,0x00,0x75,0x06,0xc7,0x06,0x0f,0x37,0x03,0x00,0xe9 +,0x7b,0xfd,0x80,0x3e,0x9d,0x36,0x04,0x75,0x12,0x81,0x0e,0xc2,0x34,0x00,0x40,0xff +,0x06,0x92,0x34,0xc6,0x06,0xa0,0x36,0x06,0xe9,0x62,0xfd,0xbe,0x05,0x00,0xe9,0x4d +,0xfd,0xf6,0x06,0x9d,0x36,0x80,0x75,0x19,0x83,0x0e,0xc2,0x34,0x04,0xbe,0x06,0x00 +,0xe9,0x3b,0xfd,0x80,0x26,0x9e,0x36,0xff,0x75,0xc5,0xff,0x06,0x31,0x37,0xe9,0x00 +,0x00,0x83,0x26,0xc2,0x34,0xbf,0xc6,0x06,0xa0,0x36,0x06,0xe9,0x2f,0xfd,0xe5,0x0a +,0x50,0x25,0xc3,0xbf,0xe7,0x0a,0x58,0x80,0x26,0x9e,0x36,0xff,0x75,0x0d,0xa9,0x00 +,0x40,0x75,0x08,0xc6,0x06,0xa0,0x36,0x06,0xe9,0x12,0xfd,0xb8,0x83,0x03,0xcd,0x39 +,0xc3,0xb8,0x7c,0x03,0xcd,0x39,0xf7,0x06,0xf4,0x33,0x00,0x10,0x75,0x09,0xc7,0x06 +,0x33,0x37,0x02,0x00,0xe9,0xf6,0xfc,0xff,0x0e,0x33,0x37,0x74,0x03,0xe9,0xed,0xfc +,0xff,0x06,0x8e,0x34,0xe8,0xf7,0x19,0x83,0x0e,0xc2,0x34,0x08,0xbe,0x03,0x00,0xe9 +,0xcc,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x04,0x04,0x05 +,0x04,0x04,0x04,0x00,0x03,0x00,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x04,0x00,0x08,0x08,0x05,0x08,0x08,0x08,0x00,0x03,0x00,0x03,0x03,0x00,0x00 +,0x02,0x04,0x04,0x04,0x04,0x00,0x00,0x08,0x00,0x00,0x0a,0x14,0x00,0x00,0x1a,0x00 +,0x1c,0x00,0x1e,0x20,0x00,0x00,0x04,0x41,0x06,0x0b,0x08,0xc2,0xff,0xe7,0x04,0x03 +,0x06,0x04,0x04,0x05,0x04,0x06,0x04,0x87,0x04,0x03,0x06,0x04,0x04,0x85,0x4e,0xa2 +,0x04,0xcf,0x04,0xcd,0xc7,0x06,0xa2,0x37,0x00,0x00,0xc7,0x06,0xa6,0x37,0x00,0x00 +,0x26,0xa1,0x20,0x00,0x25,0x7f,0xff,0xa3,0xf5,0x36,0x26,0xa1,0x22,0x00,0xa3,0xf7 +,0x36,0x26,0xa1,0x24,0x00,0xa3,0xf9,0x36,0xe8,0x3b,0x19,0x8b,0xf0,0x26,0x8b,0x0e +,0x0e,0x00,0x2b,0xc8,0x83,0xe9,0x0e,0xb8,0x01,0x80,0x83,0xf9,0x04,0x7c,0x51,0x26 +,0x8a,0x54,0x28,0x88,0x16,0x1c,0x37,0x40,0x26,0x8b,0x6c,0x26,0x86,0xcd,0x3b,0xcd +,0x86,0xcd,0x89,0x0e,0xa4,0x37,0x75,0x38,0x40,0x32,0xff,0x26,0x8a,0x5c,0x29,0x80 +,0xfb,0x15,0x77,0x25,0x80,0xfb,0x0a,0x74,0x20,0x80,0xfb,0x01,0x74,0x1b,0xb8,0x04 +,0x80,0x2e,0x3a,0x97,0x02,0x2e,0x74,0x07,0x2e,0x3a,0x97,0x18,0x2e,0x75,0x11,0x33 +,0xc0,0x80,0xfb,0x09,0x75,0x4f,0x8b,0xf3,0xc3,0x26,0xc7,0x06,0x04,0x00,0xff,0xff +,0x50,0x52,0xa1,0xa4,0x37,0x86,0xc4,0x26,0x3b,0x06,0x26,0x00,0x7c,0x32,0x26,0x81 +,0x3e,0x26,0x00,0x00,0x04,0x7e,0x29,0x8d,0x74,0x2a,0x26,0x8b,0x14,0x22,0xd2,0x74 +,0x1f,0x80,0xe6,0xbf,0x80,0xfe,0x09,0x75,0x17,0xc7,0x06,0xa2,0x37,0x01,0x00,0x80 +,0xfa,0x04,0x75,0x0c,0x26,0x8b,0x44,0x02,0xa3,0x03,0x37,0x86,0xc4,0xa3,0xd0,0x34 +,0x5a,0x58,0xe9,0xb1,0xff,0xbd,0x72,0x37,0x2e,0x8a,0x87,0x2e,0x2e,0x22,0xc0,0x74 +,0x16,0x05,0x44,0x2e,0x8b,0xf8,0x2e,0x8b,0x05,0x3e,0x89,0x46,0x00,0x83,0xc5,0x02 +,0x83,0xc7,0x02,0x22,0xe4,0x7d,0xef,0x8d,0x74,0x2a,0x83,0xe9,0x04,0x75,0x03,0xe9 +,0xa1,0x00,0x26,0x8b,0x14,0x22,0xd2,0x75,0x03,0xe9,0x7c,0x00,0xc7,0x06,0xa6,0x37 +,0x01,0x00,0xbf,0x72,0x37,0x8b,0x05,0x83,0xc7,0x02,0x80,0xe6,0xbf,0x80,0xe4,0x3f +,0x80,0xfe,0x09,0x75,0x22,0x80,0xfa,0x04,0x75,0x5e,0xc7,0x06,0xa2,0x37,0x01,0x00 +,0x26,0x8b,0x44,0x02,0xa3,0x03,0x37,0x86,0xc4,0xa3,0xd0,0x34,0x86,0xc4,0xc7,0x06 +,0xa6,0x37,0x00,0x00,0xe9,0x47,0x00,0x3b,0xfd,0x7e,0x15,0x26,0x8b,0x04,0xa8,0x40 +,0x74,0x06,0xb8,0x07,0x80,0xe9,0x38,0xff,0x32,0xc0,0x26,0x8b,0x04,0xe9,0x2e,0x00 +,0x3a,0xf4,0x75,0xb1,0xc7,0x45,0xfe,0x00,0x00,0x80,0xfe,0x22,0x75,0x0d,0x3a,0xd0 +,0x77,0x16,0xc7,0x06,0xa6,0x37,0x00,0x00,0xe9,0x13,0x00,0x3a,0xd0,0x75,0x09,0xc7 +,0x06,0xa6,0x37,0x00,0x00,0xe9,0x06,0x00,0xb8,0x05,0x80,0xe9,0x02,0xff,0x32,0xf6 +,0x03,0xf2,0x2b,0xca,0xb8,0x05,0x80,0x23,0xc9,0x76,0x03,0xe9,0x64,0xff,0x74,0x03 +,0xe9,0xed,0xfe,0x33,0xc0,0xbf,0x72,0x37,0x8b,0x15,0x47,0x47,0x3b,0xfd,0x7f,0x1b +,0xf6,0xc6,0x80,0x74,0x16,0xf7,0x06,0xa6,0x37,0x01,0x00,0x74,0x06,0xb8,0x08,0x80 +,0xe9,0xc3,0xfe,0xf6,0xc6,0x40,0x74,0xe0,0xb8,0x07,0x80,0xe9,0xb8,0xfe,0x7d,0x42 +,0xa3,0x45,0x44,0x29,0x44,0x29,0xb7,0x28,0xe2,0x28,0xee,0x2b,0xf2,0x28,0xf5,0x28 +,0x01,0x29,0xac,0x2a,0x44,0x29,0x44,0x29,0x44,0x29,0x44,0x29,0x44,0x29,0x00,0x00 +,0x73,0x36,0x00,0x00,0x03,0x36,0xc5,0x35,0x83,0x35,0x45,0x35,0x07,0x35,0xd2,0x34 +,0x45,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0xa6,0x38,0x00,0x00,0xe0,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0xf2,0x33,0x00,0x00,0xa6,0x33,0x60,0x33,0xfd,0x32,0xbc,0x32,0x77,0x32,0x3c,0x32 +,0xfb,0x31,0x6a,0x31,0x0a,0x31,0xe0,0xe0,0x10,0x10,0x10,0xe0,0xe0,0xe0,0xe0,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x00,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0 +,0xe0,0x33,0xff,0x26,0xf6,0x06,0x1a,0x00,0x80,0x74,0x1b,0x26,0x80,0x26,0x1a,0x00 +,0x7f,0x26,0x8b,0x3e,0x26,0x00,0x83,0xe7,0x1f,0x74,0x0b,0x26,0x80,0x0e,0x20,0x00 +,0x80,0x26,0x01,0x3e,0x0e,0x00,0xc3,0x60,0x2e,0x8b,0x84,0xa6,0x30,0x26,0xa3,0x18 +,0x00,0xd1,0xe6,0x2e,0xff,0x94,0x50,0x30,0x61,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4 +,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x16,0x00,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26 +,0xc6,0x06,0x19,0x00,0x00,0xe8,0xbf,0x05,0xe8,0x98,0x05,0x26,0xc7,0x06,0x26,0x00 +,0x00,0x08,0x26,0xc6,0x06,0x28,0x00,0x40,0x26,0xc6,0x06,0x29,0x00,0x2a,0xbf,0x2a +,0x00,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x2a,0xa1,0x93,0x37,0x33,0xdb,0xa9 +,0x40,0x00,0x75,0x02,0xb3,0x01,0xa9,0x00,0x10,0x74,0x02,0xb7,0x88,0xa9,0x00,0x08 +,0x74,0x03,0x80,0xcf,0x44,0x26,0x89,0x5d,0x02,0xc3,0x83,0x0e,0xc2,0x34,0x20,0x26 +,0xc7,0x06,0x04,0x00,0x6b,0x2b,0x26,0xc7,0x06,0x0e,0x00,0x30,0x00,0x26,0xc7,0x06 +,0x06,0x00,0x0a,0x00,0x26,0xc7,0x06,0x0a,0x00,0x04,0x00,0x26,0xc6,0x06,0x19,0x00 +,0x00,0xe8,0x69,0x05,0xe8,0x2c,0x05,0x26,0xc7,0x06,0x26,0x00,0x00,0x22,0x26,0xc6 +,0x06,0x28,0x00,0x60,0x26,0xc6,0x06,0x29,0x00,0x29,0xbf,0x2a,0x00,0x26,0xc6,0x05 +,0x08,0x26,0xc6,0x45,0x01,0x2d,0x8d,0x7d,0x02,0xbe,0x54,0x37,0xb9,0x03,0x00,0xf3 +,0xa5,0x26,0xc6,0x05,0x08,0x26,0xc6,0x45,0x01,0x2e,0x8d,0x7d,0x02,0xbe,0x5a,0x37 +,0xb9,0x03,0x00,0xf3,0xa5,0xe8,0xd4,0x05,0xe8,0x64,0x05,0xb9,0x06,0x00,0xbe,0x54 +,0x37,0x8d,0x2e,0x2c,0x00,0x26,0x8b,0x46,0x00,0x29,0x04,0x83,0xc6,0x02,0x83,0xc5 +,0x02,0x83,0xf9,0x04,0x75,0x02,0x45,0x45,0xe2,0xeb,0xc3,0x26,0xc7,0x06,0x04,0x00 +,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x24,0x00,0x26,0xc7,0x06,0x06,0x00,0x06,0x00 +,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0xe4,0x04,0xe8,0xa7,0x04,0x26,0xc7,0x06,0x26 +,0x00,0x00,0x16,0x26,0xc6,0x06,0x28,0x00,0x60,0x26,0xc6,0x06,0x29,0x00,0x28,0xbf +,0x2a,0x00,0xe8,0x5b,0x06,0xe8,0x74,0x05,0xe8,0x04,0x05,0xc3,0x26,0xc7,0x06,0x04 +,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x1a,0x00,0x26,0xc7,0x06,0x06,0x00,0x06 +,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0xa3,0x04,0xe8,0x66,0x04,0x26,0xc7,0x06 +,0x26,0x00,0x00,0x0c,0x26,0xc6,0x06,0x28,0x00,0x60,0x26,0xc6,0x06,0x29,0x00,0x27 +,0xbf,0x2a,0x00,0xe8,0x21,0x05,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7 +,0x06,0x0e,0x00,0x20,0x00,0x26,0xc7,0x06,0x06,0x00,0x0a,0x00,0x26,0xc7,0x06,0x0a +,0x00,0x04,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x4b,0x04,0xe8,0x24,0x04,0x26 +,0xc7,0x06,0x26,0x00,0x00,0x12,0x26,0xc6,0x06,0x28,0x00,0x40,0x26,0xc6,0x06,0x29 +,0x00,0x26,0xbf,0x2a,0x00,0xe8,0xf4,0x04,0xe8,0x84,0x04,0xc3,0x26,0xc7,0x06,0x04 +,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x34,0x00,0x26,0xc7,0x06,0x06,0x00,0x06 +,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x0d,0x04,0xe8,0xe6,0x03,0x26,0xc7,0x06 +,0x26,0x00,0x00,0x26,0x26,0xc6,0x06,0x28,0x00,0x40,0x26,0xc6,0x06,0x29,0x00,0x25 +,0xbf,0x2a,0x00,0xe8,0xb6,0x04,0xe8,0x46,0x04,0xe8,0xfa,0x04,0xc3,0x26,0xc7,0x06 +,0x04,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x38,0x00,0xa1,0xa2,0x37,0x50,0x0b +,0xc0,0x75,0x07,0x26,0xc7,0x06,0x0e,0x00,0x34,0x00,0x26,0xc7,0x06,0x06,0x00,0x06 +,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x99,0x03,0xe8,0xa4,0xfd,0x26,0xc7,0x45 +,0x26,0x00,0x2a,0x58,0x0b,0xc0,0x75,0x06,0x26,0xc7,0x45,0x26,0x00,0x26,0xa1,0x1c +,0x37,0xc1,0xe0,0x04,0x26,0x88,0x45,0x28,0x26,0xc6,0x45,0x29,0x24,0x83,0xc7,0x2a +,0xe8,0x29,0x04,0xe8,0xa0,0x04,0xe8,0x22,0x05,0xe8,0xf8,0x03,0xe8,0x09,0x04,0xc3 +,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x32,0x00,0x26,0xc7 +,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x45,0x03,0xe8,0x50 +,0xfd,0x26,0xc7,0x45,0x26,0x00,0x24,0xa1,0x1c,0x37,0xc1,0xe0,0x04,0x26,0x88,0x45 +,0x28,0x26,0xc6,0x45,0x29,0x23,0x83,0xc7,0x2a,0xe8,0xe0,0x03,0xe8,0x6c,0x04,0xe8 +,0x8a,0x04,0xe8,0x9c,0x04,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7,0x06 +,0x0e,0x00,0x34,0x00,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19,0x00 +,0x00,0xe8,0xff,0x02,0xe8,0x0a,0xfd,0x26,0xc7,0x45,0x26,0x00,0x26,0xa1,0x1c,0x37 +,0xc1,0xe0,0x04,0x26,0x88,0x45,0x28,0x26,0xc6,0x45,0x29,0x22,0x83,0xc7,0x2a,0xe8 +,0x9a,0x03,0xe8,0xc7,0x03,0xe8,0x57,0x03,0xe8,0xf8,0x03,0xe8,0x78,0x04,0xe8,0x8a +,0x04,0xc3,0x26,0xc7,0x06,0x04,0x00,0x74,0x45,0x26,0xc7,0x06,0x0e,0x00,0x3e,0x00 +,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc7,0x06,0x0a,0x00,0x04,0x00,0x26,0xc6 +,0x06,0x19,0x00,0x00,0xe8,0xfc,0x02,0xe8,0xa9,0x02,0x83,0x3e,0x8d,0x37,0x03,0x75 +,0x01,0x90,0x26,0xc7,0x06,0x26,0x00,0x00,0x30,0x26,0xc6,0x06,0x28,0x00,0x50,0x26 +,0xc6,0x06,0x29,0x00,0x20,0xbf,0x2a,0x00,0xe8,0xd0,0x03,0xe8,0x01,0x03,0xe8,0xb5 +,0x03,0xe8,0x9f,0x03,0xc3,0x26,0xc7,0x06,0x04,0x00,0x61,0x43,0xb9,0xf0,0x00,0x83 +,0xe9,0x02,0x26,0x89,0x0e,0x0e,0x00,0x26,0xc7,0x06,0x06,0x00,0x02,0x00,0x26,0xc6 +,0x06,0x19,0x00,0x00,0x26,0xc7,0x06,0x1a,0x00,0x00,0x00,0x26,0xc7,0x06,0x1c,0x00 +,0x00,0x00,0x26,0xc7,0x06,0x1e,0x00,0x00,0x00,0xe8,0x47,0x02,0x83,0xe9,0x0e,0x86 +,0xcd,0x26,0x89,0x0e,0x26,0x00,0x86,0xcd,0x26,0xc6,0x06,0x28,0x00,0x00,0x26,0xc6 +,0x06,0x29,0x00,0x08,0xbf,0x2a,0x00,0x83,0xe9,0x04,0x26,0x89,0x0d,0x26,0xc6,0x45 +,0x01,0x26,0x8d,0x7d,0x02,0x83,0xe9,0x02,0xbb,0x01,0x00,0xb8,0x30,0x30,0x4b,0x75 +,0x17,0xbb,0x0a,0x00,0x8a,0xc4,0x26,0x88,0x05,0xb0,0x31,0x80,0xc4,0x01,0x80,0xfc +,0x3a,0x75,0x0a,0xb4,0x61,0xe9,0x05,0x00,0x26,0x88,0x05,0x04,0x01,0x47,0x49,0x75 +,0xdd,0xc3,0x26,0xc7,0x06,0x04,0x00,0x04,0x45,0x26,0xc7,0x06,0x0e,0x00,0x12,0x00 +,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19,0x00,0x01,0xe8,0xe5,0x01 +,0xe8,0xd0,0x01,0x26,0xc7,0x06,0x26,0x00,0x00,0x04,0x26,0xc6,0x06,0x28,0x00,0x00 +,0x26,0xc6,0x06,0x29,0x00,0x07,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7 +,0x06,0x0e,0x00,0x20,0x00,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19 +,0x00,0x06,0xe8,0x04,0x02,0xe8,0x9b,0x01,0x26,0xc7,0x06,0x26,0x00,0x00,0x12,0x26 +,0xc6,0x06,0x28,0x00,0x00,0x26,0xc6,0x06,0x29,0x00,0x06,0xbf,0x2a,0x00,0xe8,0x6b +,0x02,0xe8,0xfb,0x01,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e +,0x00,0x20,0x00,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19,0x00,0x05 +,0xe8,0xc6,0x01,0xe8,0x5d,0x01,0x26,0xc7,0x06,0x26,0x00,0x00,0x12,0x26,0xc6,0x06 +,0x28,0x00,0x00,0x26,0xc6,0x06,0x29,0x00,0x05,0xbf,0x2a,0x00,0xe8,0x2d,0x02,0xe8 +,0xbd,0x01,0xc3,0xff,0x06,0x82,0x34,0x26,0xc7,0x06,0x04,0x00,0x3d,0x41,0x26,0xc7 +,0x06,0x0e,0x00,0x20,0x00,0x26,0xc7,0x06,0x06,0x00,0x0e,0x00,0x26,0xc6,0x06,0x19 +,0x00,0x04,0xe8,0x84,0x01,0xe8,0x1b,0x01,0x26,0xc7,0x06,0x26,0x00,0x00,0x12,0x26 +,0xc6,0x06,0x28,0x00,0x00,0x26,0xc6,0x06,0x29,0x00,0x04,0xbf,0x2a,0x00,0xe8,0xeb +,0x01,0xe8,0x7b,0x01,0xc3,0x26,0xc7,0x06,0x04,0x00,0x67,0x42,0x26,0xc7,0x06,0x0e +,0x00,0x20,0x00,0x26,0xc7,0x06,0x06,0x00,0x08,0x00,0x26,0xc6,0x06,0x19,0x00,0x03 +,0xe8,0x46,0x01,0xe8,0xdd,0x00,0x26,0xc7,0x06,0x26,0x00,0x00,0x12,0x26,0xc6,0x06 +,0x28,0x00,0x00,0x26,0xc6,0x06,0x29,0x00,0x03,0xbf,0x2a,0x00,0xe8,0xad,0x01,0xe8 +,0x3d,0x01,0xc3,0xff,0x06,0x84,0x34,0x26,0xc7,0x06,0x04,0x00,0x67,0x42,0x26,0xc7 +,0x06,0x0e,0x00,0x24,0x00,0x26,0xc7,0x06,0x06,0x00,0x08,0x00,0x26,0xc6,0x06,0x19 +,0x00,0x02,0xe8,0x04,0x01,0xe8,0x9b,0x00,0x26,0xc7,0x06,0x26,0x00,0x00,0x16,0x26 +,0xc6,0x06,0x28,0x00,0x00,0x26,0xc6,0x06,0x29,0x00,0x02,0xbf,0x2a,0x00,0x26,0xc6 +,0x05,0x04,0x26,0xc6,0x45,0x01,0x01,0xa1,0x0f,0x37,0x86,0xe0,0xf6,0x06,0x6f,0x37 +,0x01,0x75,0x0f,0x39,0x06,0xcc,0x34,0x74,0x09,0x8b,0xd8,0xb8,0x89,0x03,0xcd,0x39 +,0x8b,0xc3,0xa3,0xcc,0x34,0x26,0x89,0x45,0x02,0x8d,0x7d,0x04,0xe8,0x3d,0x01,0xe8 +,0xcd,0x00,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x1c +,0x00,0xa1,0xa2,0x37,0x50,0x0b,0xc0,0x75,0x07,0x26,0xc7,0x06,0x0e,0x00,0x18,0x00 +,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x23,0x00 +,0xe8,0x2e,0xfa,0x26,0xc7,0x45,0x26,0x00,0x0e,0x58,0x0b,0xc0,0x75,0x06,0x26,0xc7 +,0x45,0x26,0x00,0x0a,0x26,0xc6,0x45,0x29,0x00,0x83,0xc7,0x2a,0xe8,0xbd,0x00,0xe8 +,0xff,0x00,0xc3,0x56,0x57,0x51,0xb9,0x03,0x00,0xbe,0xd1,0x36,0xbf,0x20,0x00,0xf3 +,0xa5,0x59,0x5f,0x5e,0xc3,0x56,0x57,0x51,0xb9,0x03,0x00,0xbe,0xd1,0x36,0xbf,0x1a +,0x00,0xf3,0xa5,0x59,0x5f,0x5e,0xc3,0x26,0xc7,0x06,0x1a,0x00,0xc0,0x00,0x26,0xc7 +,0x06,0x1c,0x00,0x00,0x00,0x26,0xc7,0x06,0x1e,0x00,0x00,0x10,0xc3,0x26,0xc7,0x06 +,0x1a,0x00,0xc0,0x00,0x26,0xc7,0x06,0x1c,0x00,0x00,0x00,0x26,0xc7,0x06,0x1e,0x00 +,0x00,0x08,0xc3,0x26,0xc7,0x06,0x1a,0x00,0xc0,0x00,0x26,0xc7,0x06,0x1c,0x00,0x00 +,0x00,0x26,0xc7,0x06,0x1e,0x00,0x00,0x02,0xc3,0x26,0xc7,0x06,0x1a,0x00,0xc0,0x00 +,0x26,0xc7,0x06,0x1c,0x00,0xff,0xff,0x26,0xc7,0x06,0x1e,0x00,0xff,0xff,0xc3,0x26 +,0xc6,0x05,0x08,0x26,0xc6,0x45,0x01,0x02,0x8d,0x7d,0x02,0xbe,0x05,0x37,0xb9,0x03 +,0x00,0xf3,0xa5,0xc3,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x06,0xa1,0x0d,0x37 +,0x26,0x89,0x45,0x02,0x8d,0x7d,0x04,0xc3,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01 +,0x07,0xa1,0x0b,0x37,0x26,0x89,0x45,0x02,0x83,0xc7,0x04,0xc3,0xa1,0xa2,0x37,0x0b +,0xc0,0x74,0x13,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x09,0xa1,0x03,0x37,0x26 +,0x89,0x45,0x02,0x83,0xc7,0x04,0xc3,0x26,0xc6,0x05,0x08,0x26,0xc6,0x45,0x01,0x02 +,0x8d,0x7d,0x02,0xbe,0x05,0x37,0xb9,0x03,0x00,0xf3,0xa5,0xc3,0x26,0xc6,0x05,0x06 +,0x26,0xc6,0x45,0x01,0x0b,0x8d,0x7d,0x02,0xbe,0xef,0x36,0xb9,0x02,0x00,0xf3,0xa5 +,0xc3,0x26,0xc6,0x05,0x06,0x26,0xc6,0x45,0x01,0x20,0xa1,0x68,0x37,0x26,0x89,0x45 +,0x02,0xa1,0x6a,0x37,0x26,0x88,0x65,0x05,0xc1,0xe0,0x04,0x26,0x88,0x45,0x04,0x83 +,0xc7,0x06,0xc3,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x21,0x26,0xc7,0x45,0x02 +,0x00,0x00,0x83,0xc7,0x04,0xc3,0x26,0xc6,0x05,0x14,0x26,0xc6,0x45,0x01,0x22,0x8d +,0x7d,0x02,0xbe,0x1f,0x37,0xb9,0x09,0x00,0xf3,0xa5,0xc3,0x26,0xc6,0x05,0x0c,0x26 +,0xc6,0x45,0x01,0x23,0x8d,0x7d,0x02,0x1e,0x0e,0x1f,0x8d,0x36,0x40,0x54,0xb9,0x03 +,0x00,0xf3,0xa5,0x33,0xc0,0xb9,0x02,0x00,0xf3,0xab,0x1f,0xc3,0x26,0xc6,0x05,0x08 +,0x26,0xc6,0x45,0x01,0x28,0x8d,0x7d,0x02,0xbe,0xd1,0x36,0xb9,0x03,0x00,0xf3,0xa5 +,0xc3,0x26,0xc6,0x05,0x08,0x26,0xc6,0x45,0x01,0x29,0xa1,0xc2,0x34,0x86,0xe0,0x26 +,0x89,0x45,0x02,0xa1,0x9b,0x36,0x26,0x89,0x45,0x04,0x26,0x88,0x45,0x06,0x26,0x88 +,0x45,0x07,0x8d,0x7d,0x08,0xc3,0x26,0xc6,0x05,0x06,0x26,0xc6,0x45,0x01,0x2b,0x8d +,0x7d,0x02,0xbe,0xbb,0x36,0xb9,0x02,0x00,0xf3,0xa5,0xc3,0x26,0xc6,0x05,0x06,0x26 +,0xc6,0x45,0x01,0x2c,0x8d,0x7d,0x02,0xbe,0xe5,0x36,0xb9,0x02,0x00,0xf3,0xa5,0xc3 +,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x30,0xa1,0x37,0x37,0x86,0xe0,0x26,0x89 +,0x45,0x02,0x8d,0x7d,0x04,0xc3,0x26,0xc7,0x06,0x0e,0x00,0x1e,0x00,0x26,0xc7,0x06 +,0x06,0x00,0x02,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x6c,0xfe,0xe8,0x03,0xfe +,0x26,0xc7,0x06,0x26,0x00,0x00,0x10,0x26,0xc6,0x06,0x28,0x00,0x30,0x26,0xc6,0x06 +,0x29,0x00,0x11,0xbf,0x2a,0x00,0xe8,0x35,0x00,0xe8,0x45,0x00,0xe8,0x55,0x00,0xc3 +,0x26,0xc7,0x06,0x0e,0x00,0x12,0x00,0x26,0xc7,0x06,0x06,0x00,0x02,0x00,0x26,0xc6 +,0x06,0x19,0x00,0x00,0xe8,0x32,0xfe,0xe8,0xc9,0xfd,0x26,0xc7,0x06,0x26,0x00,0x00 +,0x04,0x26,0xc6,0x06,0x28,0x00,0x30,0x26,0xc6,0x06,0x29,0x00,0x13,0xc3,0x26,0xc6 +,0x05,0x04,0x26,0xc6,0x45,0x01,0x0c,0x26,0xc7,0x45,0x02,0x00,0x01,0x83,0xc7,0x04 +,0xc3,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x0e,0x26,0xc7,0x45,0x02,0x00,0x02 +,0x83,0xc7,0x04,0xc3,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x21,0x26,0xc7,0x45 +,0x02,0x00,0x00,0x83,0xc7,0x04,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0xb3,0x39,0xc9,0x39,0x83,0x3a,0xb3,0x39,0xb3,0x39,0xb3,0x39,0x1c,0x3a,0x1c,0x3a +,0xa3,0xb6,0x34,0xa1,0xe9,0x36,0xa3,0x11,0x37,0xa3,0xd2,0x34,0xa1,0xeb,0x36,0xa3 +,0x13,0x37,0xa3,0xd4,0x34,0xa1,0xed,0x36,0xa3,0x15,0x37,0xa3,0xd6,0x34,0xa1,0x01 +,0x37,0xa3,0xce,0x34,0xa1,0xf7,0x36,0xa3,0x17,0x37,0xa3,0xdc,0x34,0xa1,0xf9,0x36 +,0xa3,0x19,0x37,0xa3,0xde,0x34,0xf7,0x06,0x9b,0x36,0x02,0x00,0x75,0x0c,0x33,0xc0 +,0xa0,0x9e,0x36,0x8b,0xf0,0x2e,0xff,0xa4,0x50,0x39,0xe9,0x0f,0x01,0xbe,0x07,0x00 +,0xe9,0x19,0xf1,0xf6,0x06,0x9d,0x36,0x80,0x74,0xf3,0xc6,0x06,0xa0,0x36,0x02,0xc6 +,0x06,0x6e,0x37,0x08,0xc6,0x06,0x70,0x37,0x02,0xb8,0x88,0x03,0xcd,0x39,0xf6,0x06 +,0x6f,0x37,0x01,0x75,0x4a,0xa1,0xd1,0x36,0x3a,0x06,0xe9,0x36,0x75,0x41,0x3a,0x26 +,0xea,0x36,0x75,0x3b,0xa1,0xd3,0x36,0x3a,0x06,0xeb,0x36,0x75,0x32,0x3a,0x26,0xec +,0x36,0x75,0x2c,0xa1,0xd5,0x36,0x3a,0x06,0xed,0x36,0x75,0x23,0x3a,0x26,0xee,0x36 +,0x75,0x1d,0xc6,0x06,0x70,0x37,0x02,0xfe,0x0e,0x6e,0x37,0x75,0x0f,0xb8,0x88,0x03 +,0xcd,0x3a,0x83,0x0e,0x9b,0x36,0x12,0xc6,0x06,0xa0,0x36,0x0c,0xe9,0xa8,0xf0,0xa1 +,0x05,0x37,0x26,0x3b,0x06,0x20,0x00,0x75,0x40,0xa1,0x07,0x37,0x26,0x3b,0x06,0x22 +,0x00,0x75,0x36,0xa1,0x09,0x37,0x26,0x3b,0x06,0x24,0x00,0x75,0x2c,0xa0,0x9e,0x36 +,0x3c,0x02,0x75,0x08,0x26,0xf6,0x06,0x18,0x00,0x08,0x75,0x47,0xc6,0x06,0x6e,0x37 +,0x08,0xfe,0x0e,0x70,0x37,0x75,0x1c,0xc6,0x06,0x70,0x37,0x02,0xe5,0x02,0x0d,0x01 +,0x04,0x25,0xef,0xff,0xe7,0x02,0xe9,0x5e,0xf0,0xc6,0x06,0x70,0x37,0x02,0xc6,0x06 +,0x6e,0x37,0x08,0xe5,0x02,0x25,0xff,0xfb,0x0d,0x01,0x00,0x25,0xef,0xff,0xe7,0x02 +,0xe9,0x44,0xf0,0xf7,0x06,0x9b,0x36,0x00,0x01,0x74,0x25,0x26,0xf6,0x06,0x18,0x00 +,0x08,0x75,0xed,0x81,0x26,0x9b,0x36,0x7f,0xff,0xb8,0x89,0x03,0xcd,0x3a,0xb8,0x84 +,0x03,0xcd,0x3a,0xc6,0x06,0xa0,0x36,0x06,0x83,0x26,0xc2,0x34,0xaf,0xe9,0x17,0xf0 +,0xa1,0x01,0x37,0x3a,0x26,0x0f,0x37,0x7f,0xc7,0xe9,0xf7,0xfe,0x83,0x26,0x9b,0x36 +,0xec,0xe8,0x2a,0x0d,0x81,0x0e,0x9b,0x36,0x80,0x00,0xbb,0xff,0x7f,0xcd,0x53,0xc6 +,0x06,0xa0,0x36,0x02,0xe9,0xf0,0xef,0x83,0x0e,0x9b,0x36,0x11,0xc6,0x06,0xa0,0x36 +,0x0c,0xe9,0xf9,0xef,0x44,0x3b,0x2c,0x3b,0xc7,0x2a,0x6b,0x3b,0x44,0x3b,0xc7,0x2a +,0xc7,0x2a,0xc7,0x2a,0xa3,0xb6,0x34,0x81,0x0e,0xc2,0x34,0x00,0x20,0xf7,0x06,0x41 +,0x37,0x01,0x00,0x74,0x1b,0x8c,0xc3,0xc7,0x06,0x41,0x37,0x00,0x00,0xb8,0x7f,0x03 +,0xcd,0x3a,0x33,0xc0,0x8e,0xc0,0xbf,0x54,0x37,0xb9,0x06,0x00,0xf3,0xab,0x8e,0xc3 +,0x33,0xc0,0xa0,0x9e,0x36,0x8b,0xf0,0x2e,0xff,0xa4,0xe4,0x3a,0xf7,0x06,0x9b,0x36 +,0x00,0x01,0x75,0x21,0x83,0x26,0xc2,0x34,0xbf,0xa1,0xa9,0x36,0xe7,0x00,0xa1,0x9b +,0x36,0xe9,0x09,0x00,0xa1,0x9b,0x36,0x81,0x26,0x9b,0x36,0xff,0xdf,0xa9,0x00,0x20 +,0x75,0x06,0xe9,0x6e,0x00,0xe9,0x6f,0xef,0x83,0x0e,0x99,0x36,0x04,0xc7,0x06,0x37 +,0x37,0x01,0x00,0xc6,0x06,0xca,0x34,0x01,0xe9,0x58,0x00,0x83,0x0e,0x9b,0x36,0x40 +,0xe8,0x58,0x00,0xa1,0x05,0x37,0x3b,0x06,0xe9,0x36,0x75,0x37,0xa1,0x07,0x37,0x3b +,0x06,0xeb,0x36,0x75,0x2e,0xa1,0x09,0x37,0x3b,0x06,0xed,0x36,0x75,0x25,0xfe,0x0e +,0x71,0x37,0x75,0x1c,0xb8,0x87,0x03,0xcd,0x3a,0x83,0x0e,0x99,0x36,0x10,0xa1,0x50 +,0x37,0xc7,0x06,0x50,0x37,0x00,0x00,0x09,0x06,0x99,0x36,0xc6,0x06,0xa0,0x36,0x08 +,0xe9,0x14,0xef,0x83,0x0e,0x99,0x36,0x04,0xc7,0x06,0x37,0x37,0x03,0x00,0xc6,0x06 +,0xca,0x34,0x03,0xc6,0x06,0xa0,0x36,0x0a,0xe9,0xfc,0xee,0xa1,0xd1,0x36,0x26,0x3b +,0x06,0x20,0x00,0x75,0x15,0xa1,0xd3,0x36,0x26,0x3b,0x06,0x22,0x00,0x75,0x12,0xa1 +,0xd5,0x36,0x26,0x3b,0x06,0x24,0x00,0x75,0x0f,0xc3,0x8d,0x36,0x20,0x00,0xe9,0x0b +,0x00,0x8d,0x36,0x22,0x00,0xe9,0x04,0x00,0x8d,0x36,0x24,0x00,0x83,0xc4,0x02,0xf7 +,0x06,0xe6,0x34,0x01,0x00,0x74,0x15,0x26,0x3a,0x04,0x77,0x08,0x72,0x0e,0x26,0x3a +,0x64,0x01,0x72,0x08,0xc6,0x06,0xa0,0x36,0x06,0xe9,0xab,0xee,0xe8,0x7c,0x0a,0x8c +,0xc0,0x3d,0xff,0xff,0x74,0x1b,0x26,0xc6,0x06,0x18,0x00,0x10,0x26,0xc7,0x06,0x04 +,0x00,0x49,0x3c,0x26,0xc7,0x06,0x06,0x00,0x0c,0x00,0xcd,0x50,0xb9,0x4e,0x00,0xe2 +,0xfe,0xc6,0x06,0xa0,0x36,0x0a,0xe9,0x94,0xee,0xe9,0x7b,0xee,0x8f,0x3c,0x06,0x3d +,0x06,0x3d,0x06,0x3d,0xd2,0x3c,0xea,0x3c,0x06,0x3d,0x06,0x3d,0xa3,0xb6,0x34,0x81 +,0x26,0xc2,0x34,0xaf,0xdf,0xc7,0x06,0x4c,0x37,0x00,0x00,0xb8,0x8a,0x03,0xcd,0x3a +,0x80,0x3e,0x9d,0x36,0x04,0x75,0x0c,0x80,0x3e,0x9e,0x36,0x06,0x74,0x05,0xc6,0x06 +,0x9f,0x36,0x06,0x33,0xc0,0xa0,0x9e,0x36,0x8b,0xf0,0x2e,0xff,0xa4,0x4c,0x3c,0xf7 +,0x06,0x9b,0x36,0x00,0x20,0x75,0x0e,0x81,0x26,0x9b,0x36,0xff,0xbf,0xb8,0x8b,0x03 +,0xcd,0x3a,0xe9,0x54,0x00,0xf7,0x06,0x9b,0x36,0x00,0x01,0x74,0x03,0xe9,0x17,0xee +,0xc7,0x06,0x37,0x37,0x02,0x00,0xc6,0x06,0xca,0x34,0x02,0x83,0x0e,0x99,0x36,0x04 +,0x83,0x0e,0x50,0x37,0x04,0xf6,0x06,0x9d,0x36,0x80,0x75,0x2a,0xe8,0x1f,0x0b,0xe9 +,0x27,0x00,0xf7,0x06,0x9b,0x36,0x00,0x01,0x75,0xd3,0xc7,0x06,0x37,0x37,0x02,0x00 +,0xc6,0x06,0xca,0x34,0x02,0x83,0x0e,0x99,0x36,0x04,0xc6,0x06,0xa0,0x36,0x00,0xf6 +,0x06,0x9d,0x36,0x80,0x74,0x03,0xe8,0xde,0x0a,0x81,0x26,0x9b,0x36,0x7c,0xff,0xbb +,0xff,0xff,0xcd,0x53,0xcd,0x54,0xe9,0xbe,0xed,0xa3,0xb6,0x34,0xe8,0xad,0x01,0xb8 +,0x86,0x03,0xcd,0x39,0xc7,0x06,0x4c,0x37,0x00,0x00,0x81,0x26,0xc2,0x34,0xaf,0xdf +,0xf6,0x06,0x9d,0x36,0x80,0x74,0x34,0xf7,0x06,0x9b,0x36,0x00,0x20,0x74,0x56,0xf7 +,0x06,0x9b,0x36,0x00,0x01,0x74,0x27,0xe8,0x35,0x01,0x72,0x1c,0xbe,0x00,0x40,0x85 +,0x36,0xc2,0x34,0x75,0x08,0x09,0x36,0xc2,0x34,0xff,0x06,0x92,0x34,0xe8,0x8b,0x01 +,0x73,0x06,0x81,0x0e,0x99,0x36,0x80,0x00,0xe9,0x6c,0xed,0xe9,0xb5,0x00,0xc7,0x06 +,0x37,0x37,0x02,0x00,0xc6,0x06,0xca,0x34,0x02,0x83,0x0e,0x99,0x36,0x04,0x83,0x0e +,0x50,0x37,0x04,0x80,0x3e,0x9e,0x36,0x08,0x74,0x03,0xe8,0x5a,0x0a,0xe8,0xef,0x00 +,0x72,0xd6,0xe9,0xc8,0xff,0x80,0x3e,0x9e,0x36,0x0a,0x75,0x12,0xc6,0x06,0xa0,0x36 +,0x00,0xf7,0x06,0x9b,0x36,0x08,0x00,0x74,0x02,0xcd,0x54,0xe8,0x39,0x0a,0x81,0x26 +,0x9b,0x36,0xff,0xbf,0xe8,0xc8,0x00,0x72,0xaf,0xb8,0x8b,0x03,0xcd,0x39,0xe9,0x9c +,0xff,0xf6,0x06,0x9e,0x36,0xff,0x75,0x58,0xa3,0xb6,0x34,0xe8,0xfe,0x00,0x81,0x26 +,0xc2,0x34,0xff,0xbf,0xf6,0x06,0x9d,0x36,0x80,0x74,0x48,0xf7,0x06,0x9b,0x36,0x00 +,0x20,0x74,0x22,0xf7,0x06,0x9b,0x36,0x00,0x40,0x75,0x08,0xe8,0x91,0x00,0x72,0x30 +,0xe9,0x22,0x00,0x26,0xa1,0x0c,0x00,0xa9,0x60,0x00,0x75,0x24,0x81,0x0e,0x66,0x37 +,0x00,0x08,0xe9,0xd2,0xec,0xc7,0x06,0x4c,0x37,0x00,0x00,0xe8,0x71,0x00,0x72,0x10 +,0xb8,0x8b,0x03,0xcd,0x39,0xe8,0xd3,0x00,0x73,0x06,0x81,0x0e,0x99,0x36,0x80,0x00 +,0xe9,0xb4,0xec,0x80,0x3e,0x9d,0x36,0x04,0x75,0x0c,0x80,0x3e,0x9e,0x36,0x06,0x74 +,0x46,0xc6,0x06,0x9f,0x36,0x06,0xf7,0x06,0x9b,0x36,0x00,0x01,0x74,0x0c,0x80,0x3e +,0x9d,0x36,0x08,0x75,0x05,0xc6,0x06,0x9f,0x36,0x0a,0xe8,0x32,0x00,0x72,0xd1,0xe8 +,0x99,0x00,0x80,0x3e,0x9d,0x36,0x08,0x75,0x13,0x81,0x0e,0x99,0x36,0x80,0x00,0xf7 +,0x06,0x9b,0x36,0x00,0x20,0x75,0x08,0xb8,0x8b,0x03,0xcd,0x39,0xe9,0x68,0xec,0xc6 +,0x06,0x9f,0x36,0x0a,0xe9,0x60,0xec,0xb8,0x86,0x03,0xcd,0x3a,0xe9,0x58,0xec,0x26 +,0xa1,0x0c,0x00,0xa9,0x60,0x00,0x74,0x08,0x81,0x26,0xc2,0x34,0xff,0xbf,0xf9,0xc3 +,0xf7,0x06,0x9b,0x36,0x00,0x40,0x74,0x13,0x81,0x0e,0x66,0x37,0x00,0x08,0xe8,0x4a +,0x00,0x73,0x06,0x81,0x0e,0x99,0x36,0x80,0x00,0xf9,0xc3,0x81,0x0e,0x9b,0x36,0x00 +,0x40,0x80,0x26,0x6f,0x37,0xfe,0x81,0x26,0x9b,0x36,0x7f,0xff,0xc6,0x06,0xa0,0x36 +,0x00,0xf8,0xc3,0x81,0x0e,0x99,0x36,0x00,0x01,0xe9,0x21,0xec,0x26,0xa1,0x20,0x00 +,0xa3,0xfb,0x36,0xa3,0xaa,0x34,0x26,0xa1,0x22,0x00,0xa3,0xfd,0x36,0xa3,0xac,0x34 +,0x26,0xa1,0x24,0x00,0xa3,0xff,0x36,0xa3,0xae,0x34,0xc3,0xa1,0x05,0x37,0x26,0x3b +,0x06,0x20,0x00,0x75,0x19,0xa1,0x07,0x37,0x26,0x3b,0x06,0x22,0x00,0x75,0x0f,0xa1 +,0x09,0x37,0x26,0x3b,0x06,0x24,0x00,0x75,0x05,0xe8,0x02,0x00,0xf8,0xc3,0x51,0x1e +,0x06,0x8b,0xc7,0x8d,0x36,0x20,0x00,0xbf,0x05,0x37,0xb9,0x03,0x00,0x1e,0x06,0x1f +,0x07,0xf3,0xa5,0x8b,0xf8,0x8d,0x36,0x20,0x00,0xbf,0xa0,0x34,0xb9,0x03,0x00,0xf3 +,0xa5,0x07,0x1f,0x59,0x8b,0xf8,0xa1,0x07,0x37,0xa3,0xa6,0x34,0xa1,0x09,0x37,0xa3 +,0xa8,0x34,0xf9,0xc3,0xc6,0x06,0xb6,0x34,0x01,0xe9,0x8b,0xeb,0xe8,0x87,0x08,0x8b +,0xf0,0x05,0x12,0x00,0x26,0x29,0x06,0x0e,0x00,0x26,0x8b,0x44,0x2a,0x26,0x3a,0x06 +,0x0e,0x00,0x75,0x5b,0x26,0x83,0x2e,0x0e,0x00,0x02,0x80,0xfc,0x27,0x75,0x50,0x26 +,0x8b,0x44,0x2c,0xa9,0xff,0xff,0x75,0x47,0x8b,0xfe,0x33,0xc0,0x26,0xf6,0x45,0x3c +,0x80,0x74,0x06,0x26,0x8a,0x45,0x3a,0x24,0x1f,0x03,0xf8,0x26,0x80,0x7d,0x45,0x09 +,0x75,0x2d,0x8c,0xc2,0x8e,0x06,0x38,0x34,0x8e,0xda,0x8b,0x0e,0x0e,0x00,0x26,0x89 +,0x0e,0x0e,0x00,0x8d,0x74,0x2c,0xbf,0x18,0x00,0xf3,0xa4,0x33,0xc0,0x8e,0xd8,0x26 +,0xc7,0x06,0x04,0x00,0xb5,0x3f,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0xcd,0x50,0xb8 +,0x06,0x80,0xe9,0xef,0xe9,0x26,0xa1,0x0c,0x00,0xa3,0x93,0x37,0x83,0x0e,0x99,0x36 +,0x01,0xe9,0x00,0xeb,0x26,0x80,0x3e,0x1c,0x00,0xff,0x75,0x2f,0x26,0x80,0x3e,0x1e +,0x00,0xff,0x75,0x27,0x26,0xf7,0x06,0x0c,0x00,0x40,0x00,0x75,0x1b,0xa1,0xd1,0x36 +,0x26,0xa3,0x1a,0x00,0xa1,0xd3,0x36,0x26,0xa3,0x1c,0x00,0xa1,0xd5,0x36,0x26,0xa3 +,0x1e,0x00,0xb8,0x0a,0x80,0xe8,0x36,0x07,0xe9,0xe2,0xea,0xff,0x06,0x90,0x34,0xbe +,0x0a,0x00,0xc6,0x06,0xb6,0x34,0x01,0xf6,0x06,0x9d,0x36,0x80,0x75,0x05,0x83,0x0e +,0xc2,0x34,0x01,0xe9,0xb6,0xea,0x80,0x3e,0x9d,0x36,0x0a,0x75,0x0f,0x26,0xa1,0x0c +,0x00,0x25,0x07,0x00,0x3d,0x04,0x00,0x75,0x03,0xe8,0x79,0x00,0xa1,0xf3,0x36,0x86 +,0xe0,0xe7,0x1e,0xa3,0xe3,0x36,0x81,0x26,0x0b,0x37,0x00,0x03,0x81,0x26,0x0d,0x37 +,0x7b,0x7f,0x83,0x0e,0x0d,0x37,0x48,0xe8,0x1e,0x00,0x26,0xa1,0x0c,0x00,0x25,0x07 +,0x00,0x3d,0x04,0x00,0x74,0x09,0x26,0xf7,0x06,0x0c,0x00,0x20,0x00,0x75,0x06,0xb8 +,0x01,0x00,0xe9,0x3f,0xe9,0xe9,0x5f,0xea,0xc7,0x06,0x41,0x37,0x00,0x00,0xb8,0x7f +,0x03,0xcd,0x3a,0xa1,0x1d,0x37,0xa3,0xc4,0x34,0x86,0xe0,0x68,0x7f,0x03,0x1f,0xa3 +,0x06,0x00,0x33,0xc0,0x8e,0xd8,0xa1,0x0b,0x37,0xa3,0xb2,0x34,0xa1,0x0d,0x37,0xa3 +,0xb4,0x34,0xa1,0xf3,0x36,0xa3,0xc8,0x34,0xa1,0xef,0x36,0xa3,0x9c,0x34,0xa1,0xf1 +,0x36,0xa3,0x9e,0x34,0xc3,0x80,0x0e,0x9d,0x36,0x80,0xbe,0x00,0x00,0xe8,0xb4,0x07 +,0xb8,0x7b,0x03,0xcd,0x3a,0xb8,0x7c,0x03,0xcd,0x39,0xc7,0x06,0x33,0x37,0x02,0x00 +,0xa1,0xe5,0x36,0xe7,0x2e,0xa1,0xe7,0x36,0xe7,0x3e,0xb8,0x82,0x03,0xcd,0x3a,0xf7 +,0x06,0x9b,0x36,0x00,0x20,0x75,0x03,0xe8,0xfd,0x06,0xa1,0xd3,0x36,0xa3,0xef,0x36 +,0xa3,0x9c,0x34,0xa1,0xd5,0x36,0xa3,0xf1,0x36,0xa3,0x9e,0x34,0xc3,0xf6,0x06,0x9d +,0x36,0x80,0x74,0x31,0xbe,0x22,0x00,0xe9,0x17,0x00,0xf6,0x06,0x9d,0x36,0x80,0x74 +,0x24,0xbe,0x23,0x00,0xe9,0x0a,0x00,0xf6,0x06,0x9d,0x36,0x80,0x74,0x17,0xbe,0x24 +,0x00,0x56,0xe8,0xa8,0x05,0x8c,0xc0,0x3d,0xff,0xff,0x5e,0x74,0x05,0xe8,0xd7,0xef +,0xcd,0x50,0xe9,0x1f,0xe8,0xe9,0x9f,0xe9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0xb8,0x84,0x03,0xcd,0x3a,0xb8,0x8a,0x03,0xcd,0x39,0xe9,0xf7,0x00,0x80,0x3e,0xa0 +,0x36,0x08,0x75,0x2e,0xa9,0xd0,0x07,0x75,0x2c,0xa1,0xb1,0x36,0x0d,0x00,0x04,0xe7 +,0x08,0xe5,0x00,0x25,0xff,0x73,0xe7,0x00,0xb8,0x8a,0x03,0xcd,0x3a,0xe8,0xc3,0x06 +,0x33,0xc0,0xe7,0x0e,0xe5,0x0a,0x25,0xc3,0x17,0xe7,0x0a,0xcd,0x54,0xc6,0x06,0xa0 +,0x36,0x00,0xe9,0x68,0xe9,0xbe,0x04,0x00,0xe9,0x3f,0xe9,0x83,0x26,0x9b,0x36,0xbf +,0xc6,0x06,0x71,0x37,0x03,0xb8,0x86,0x03,0xcd,0x3a,0xb8,0x88,0x03,0xcd,0x3a,0xb8 +,0x83,0x03,0xcd,0x3a,0xb8,0x87,0x03,0xcd,0x39,0x81,0x0e,0xc2,0x34,0x00,0x20,0xe9 +,0x92,0x00,0xe8,0x49,0x06,0xb8,0x87,0x03,0xcd,0x39,0xbb,0xff,0x7f,0xcd,0x53,0xb8 +,0x84,0x03,0xcd,0x3a,0xb8,0x88,0x03,0xcd,0x3a,0xb8,0x8b,0x03,0xcd,0x3a,0xb8,0x83 +,0x03,0xcd,0x3a,0xb8,0x86,0x03,0xcd,0x3a,0xb8,0x85,0x03,0xcd,0x3a,0xc3,0xe5,0x00 +,0x25,0xff,0x53,0xe7,0x00,0x83,0x0e,0xc2,0x34,0x40,0x83,0x26,0xc2,0x34,0xef,0xe8 +,0x0c,0x06,0xbb,0xff,0x7f,0xcd,0x53,0xb8,0x8a,0x03,0xcd,0x3a,0xb8,0x85,0x03,0xcd +,0x3a,0xb8,0x86,0x03,0xcd,0x3a,0xb8,0x83,0x03,0xcd,0x3a,0xb8,0x87,0x03,0xcd,0x3a +,0xb8,0x8b,0x03,0xcd,0x3a,0xb8,0x84,0x03,0xcd,0x3a,0xb8,0x89,0x03,0xcd,0x3a,0xc3 +,0x83,0x0e,0xc2,0x34,0x50,0xe8,0x18,0x04,0xe8,0xd3,0x05,0xf6,0x06,0x6f,0x37,0x01 +,0x75,0x12,0xb8,0x89,0x03,0xcd,0x39,0x83,0x3e,0x0f,0x37,0x00,0x75,0x06,0xc7,0x06 +,0x0f,0x37,0x04,0x00,0xa1,0x9d,0x36,0x80,0xfc,0x08,0x74,0x05,0xb8,0x84,0x03,0xcd +,0x39,0xe5,0x02,0x0d,0x01,0x08,0x25,0xef,0xff,0xe7,0x02,0xa1,0x9d,0x36,0x86,0xe0 +,0x32,0xe4,0x8b,0xf0,0xd1,0xee,0x33,0xc0,0x0d,0x20,0x00,0x09,0x06,0xad,0x36,0xa1 +,0xad,0x36,0xe7,0x04,0xe9,0x53,0xe8,0xe9,0x5a,0xe8,0x33,0xc0,0xa0,0x1b,0x37,0xd1 +,0xe0,0x3a,0x06,0xa0,0x36,0x75,0x03,0xe9,0xba,0xff,0xe9,0x60,0xe8,0xc7,0x06,0x41 +,0x37,0x00,0x00,0xe8,0xc1,0xe1,0xe8,0x6a,0x06,0x33,0xc0,0x0d,0x41,0x00,0xe7,0x56 +,0xa1,0xb1,0x36,0x0d,0x00,0x10,0xe7,0x08,0xe5,0x02,0x25,0xf9,0xff,0x0d,0x03,0x00 +,0xe7,0x02,0xa1,0xb3,0x36,0xe7,0x0a,0xa1,0xaf,0x36,0xe7,0x06,0xa1,0xad,0x36,0xe7 +,0x04,0xe8,0x7c,0x03,0xe8,0x9f,0x03,0xc7,0x06,0x1d,0x37,0x00,0xc8,0xc7,0x06,0x0b +,0x37,0x00,0x03,0xc7,0x06,0x0d,0x37,0x7b,0x7f,0x33,0xc0,0xa3,0x99,0x36,0xa3,0x9b +,0x36,0xa3,0x9d,0x36,0xa3,0x9f,0x36,0xa3,0x4c,0x37,0xa3,0xf3,0x36,0xa3,0xef,0x36 +,0xa3,0xf1,0x36,0xe8,0x82,0xfd,0xc6,0x06,0x9f,0x36,0x02,0xe9,0xef,0xe7,0xe5,0x02 +,0x0d,0x01,0x88,0x25,0xef,0xff,0x0d,0x00,0x40,0x0d,0x00,0x04,0xe7,0x02,0xe8,0xf2 +,0x05,0xe5,0x0a,0x0d,0x40,0x00,0xe7,0x0a,0x33,0xc0,0xa3,0x81,0x37,0xa3,0x85,0x37 +,0xa3,0x83,0x37,0xa3,0x87,0x37,0xa3,0x89,0x37,0xe5,0x00,0x0d,0x00,0x84,0xe7,0x00 +,0xb8,0x8c,0x03,0xcd,0x39,0xb8,0x80,0x00,0xcd,0x35,0xc7,0x06,0xaa,0x02,0xff,0xff +,0xe5,0x00,0x25,0xff,0x7b,0xe7,0x00,0x81,0x0e,0x9a,0x37,0x80,0x00,0xb8,0x7e,0x03 +,0xcd,0x39,0x33,0xc0,0xe7,0x0e,0xbe,0x08,0x00,0x8e,0x06,0x38,0x34,0xe8,0xa7,0xed +,0x83,0x26,0xef,0x34,0xdf,0xff,0x06,0x81,0x37,0xcd,0x50,0x83,0x0e,0xef,0x34,0x20 +,0xc3,0xf7,0x06,0x9a,0x37,0x80,0x00,0x74,0x3d,0xa9,0xd0,0x07,0x74,0x10,0xa9,0x00 +,0x04,0x74,0x12,0x33,0xc0,0xe7,0x0e,0xff,0x06,0x87,0x37,0xe9,0xd2,0xff,0xff,0x06 +,0x85,0x37,0xe9,0xcb,0xff,0xff,0x06,0x83,0x37,0xe9,0xc4,0xff,0x83,0x26,0x9a,0x37 +,0x7f,0xa1,0x89,0x37,0x03,0x06,0x87,0x37,0x3d,0x05,0x00,0x7f,0x01,0xc3,0xbb,0xff +,0x7f,0xcd,0x53,0xe9,0x00,0x00,0xe5,0x02,0x25,0xff,0xfb,0x25,0xef,0xff,0x0d,0x01 +,0x00,0xe7,0x02,0xa1,0x83,0x37,0x3b,0x06,0x46,0x37,0x7f,0x2a,0xa1,0x85,0x37,0x3b +,0x06,0x48,0x37,0x7c,0x21,0xa1,0x89,0x37,0x03,0x06,0x87,0x37,0x3d,0x05,0x00,0x7f +,0x15,0xc6,0x06,0x9f,0x36,0x04,0xe5,0x02,0x25,0xff,0xf7,0x0d,0x01,0x00,0x25,0xef +,0xff,0xe7,0x02,0xe9,0xf7,0xe6,0xbe,0x01,0x00,0xf7,0x06,0x9b,0x36,0x03,0x00,0x74 +,0x0a,0x83,0x26,0x9b,0x36,0xfc,0x83,0x0e,0xc2,0x34,0x04,0xe9,0xd0,0xe6,0xb8,0x7b +,0x03,0xcd,0x39,0xe5,0x02,0x0d,0x01,0x60,0x25,0xef,0xff,0xe7,0x02,0xc7,0x06,0xf1 +,0x34,0x20,0x03,0xb8,0x8e,0x03,0xcd,0x39,0xc3,0x81,0x26,0xc2,0x34,0x7f,0xff,0x80 +,0x0e,0x6f,0x37,0x01,0xf7,0x06,0x9b,0x36,0x03,0x00,0x74,0xd2,0xb8,0x7b,0x03,0xcd +,0x3a,0xb8,0x7d,0x03,0xcd,0x39,0x83,0x26,0x9b,0x36,0xef,0x33,0xc0,0xb0,0x8a,0xa2 +,0x9f,0x36,0xa2,0x9d,0x36,0xc7,0x06,0x4c,0x37,0x01,0x00,0xc7,0x06,0x0f,0x37,0x04 +,0x00,0xf7,0x06,0x9b,0x36,0x40,0x00,0x75,0x06,0xc7,0x06,0x0f,0x37,0x03,0x00,0xb8 +,0x8d,0x03,0xcd,0x39,0xe8,0x00,0xd5,0xe5,0x02,0x0d,0x01,0x40,0x25,0xef,0xff,0x8b +,0xd8,0xb8,0x7c,0x03,0xcd,0x39,0xc7,0x06,0x33,0x37,0x02,0x00,0x8b,0xc3,0x0d,0x00 +,0x20,0x25,0xf9,0xff,0x0b,0x06,0xe8,0x3a,0xe7,0x02,0xc3,0xff,0x0e,0xf1,0x34,0x75 +,0x01,0xc3,0xe5,0x4e,0xa9,0x01,0x00,0x75,0x12,0xe5,0x00,0xa9,0x00,0x04,0x75,0x05 +,0x0d,0x00,0x04,0xe7,0x00,0xb8,0x8e,0x03,0xcd,0x39,0xc3,0xe5,0x00,0xa9,0x00,0x04 +,0x74,0xf3,0x25,0xff,0xfb,0xe7,0x00,0xe9,0xeb,0xff,0xc6,0x06,0xa0,0x36,0x04,0x83 +,0x26,0x9b,0x36,0xfc,0x81,0x0e,0x9b,0x36,0x80,0x00,0xe9,0x10,0xe6,0xb8,0x8e,0x03 +,0xcd,0x3a,0xcd,0x54,0x81,0x0e,0xaf,0x36,0x00,0x18,0xa1,0xaf,0x36,0xe7,0x06,0xb8 +,0x7b,0x03,0xcd,0x39,0xa1,0xd3,0x36,0xa3,0x8f,0x37,0xa1,0xd5,0x36,0xa3,0x91,0x37 +,0xc7,0x06,0x8b,0x37,0x02,0x00,0xc7,0x06,0x8d,0x37,0x02,0x00,0x83,0x0e,0x99,0x36 +,0x40,0xe9,0xd9,0xe5,0x80,0x3e,0x9f,0x36,0x06,0x75,0x15,0xa9,0xd0,0x07,0x75,0xec +,0x25,0x00,0x18,0x75,0x0e,0xff,0x0e,0x8b,0x37,0x75,0xe1,0xc6,0x06,0x9f,0x36,0x08 +,0xe9,0xba,0xe5,0xff,0x0e,0x8d,0x37,0x75,0xd3,0xbe,0x08,0x00,0xe9,0x9f,0xe5,0xb8 +,0x7b,0x03,0xcd,0x39,0xf7,0x06,0x9b,0x36,0x00,0x20,0x74,0x08,0xc6,0x06,0x9f,0x36 +,0x0a,0xe9,0x0d,0x00,0xf7,0x06,0x9b,0x36,0x00,0x40,0x74,0x0b,0xb8,0x8b,0x03,0xcd +,0x39,0x81,0x0e,0x99,0x36,0x80,0x00,0xe9,0x83,0xe5,0xb8,0x7b,0x03,0xcd,0x39,0xc7 +,0x06,0x8b,0x37,0x04,0x00,0xc7,0x06,0x8d,0x37,0x04,0x00,0x81,0x0e,0x99,0x36,0x00 +,0x02,0xe9,0x69,0xe5,0xf6,0x06,0x9d,0x36,0x80,0x75,0x1b,0xa9,0xd0,0x07,0x75,0xeb +,0xa9,0x00,0x18,0x75,0x0c,0xff,0x0e,0x8d,0x37,0x75,0xe0,0xe8,0x17,0xfb,0xe9,0x4c +,0xe5,0xb8,0x82,0x03,0xcd,0x39,0xc3,0xff,0x0e,0x8b,0x37,0x75,0xce,0xbe,0x09,0x00 +,0xe9,0x2b,0xe5,0xc7,0x06,0x3d,0x37,0x00,0x00,0xc7,0x06,0x9b,0x36,0x00,0x00,0xe8 +,0x3c,0x02,0x81,0x26,0xaf,0x36,0xff,0xe7,0xa1,0xaf,0x36,0xe7,0x06,0x81,0x26,0x9b +,0x36,0xff,0x7f,0xe5,0x02,0x0d,0x01,0x00,0x25,0xef,0xff,0x25,0xff,0xdf,0xe7,0x02 +,0xbb,0xff,0x7f,0xcd,0x53,0x33,0xc0,0xa3,0x9d,0x36,0xa3,0x9f,0x36,0xe8,0x50,0x00 +,0xe8,0x73,0x00,0xb8,0x81,0x03,0xcd,0x39,0xc3,0xf7,0x06,0x9b,0x36,0x03,0x00,0x74 +,0x0d,0xc6,0x06,0x9f,0x36,0x02,0xc6,0x06,0xa0,0x36,0x00,0xe9,0xdf,0xe4,0x83,0x0e +,0x9b,0x36,0x10,0xc7,0x06,0x99,0x36,0x00,0x00,0xe8,0xe7,0x02,0xe5,0x56,0x0d,0x02 +,0x00,0xe7,0x56,0xc7,0x06,0xa8,0x02,0x00,0x00,0x8b,0x36,0x3d,0x37,0xe8,0x44,0x02 +,0xc6,0x06,0xa0,0x36,0x0e,0xe9,0xb5,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x06,0xb8,0x8a,0x03,0xcd,0x3a,0xb8,0x85,0x03,0xcd,0x3a,0xb8,0x86,0x03,0xcd,0x3a +,0xb8,0x83,0x03,0xcd,0x3a,0xb8,0x87,0x03,0xcd,0x3a,0xb8,0x8b,0x03,0xcd,0x3a,0xb8 +,0x88,0x03,0xcd,0x3a,0x07,0xc3,0x06,0xb8,0x88,0x03,0xcd,0x3a,0xb8,0x7b,0x03,0xcd +,0x3a,0xb8,0x82,0x03,0xcd,0x3a,0xb8,0x7f,0x03,0xcd,0x3a,0xb8,0x7c,0x03,0xcd,0x3a +,0xb8,0x7e,0x03,0xcd,0x3a,0xb8,0x80,0x03,0xcd,0x3a,0xb8,0x81,0x03,0xcd,0x3a,0xb8 +,0x84,0x03,0xcd,0x3a,0xb8,0x89,0x03,0xcd,0x3a,0xb8,0x7d,0x03,0xcd,0x3a,0xb8,0x8d +,0x03,0xcd,0x3a,0xc7,0x06,0x41,0x37,0x00,0x00,0x07,0xc3,0x06,0x8e,0x06,0x38,0x34 +,0x1f,0x8b,0x0e,0x0e,0x00,0x26,0x89,0x0e,0x0e,0x00,0xbe,0x18,0x00,0xbf,0x18,0x00 +,0xf3,0xa4,0x06,0x1e,0x07,0xcd,0x34,0x07,0x33,0xc0,0x8e,0xd8,0xc3,0x26,0xf6,0x06 +,0x20,0x00,0x80,0x74,0x44,0x33,0xc0,0x26,0xa0,0x26,0x00,0x24,0x1f,0x8b,0xf0,0x26 +,0x8b,0x5c,0x28,0x89,0x1e,0x6a,0x37,0x06,0x8e,0x06,0x38,0x34,0x1f,0xc0,0xe3,0x04 +,0x26,0x88,0x5c,0x28,0x8b,0xc6,0xb9,0x06,0x00,0xbe,0x20,0x00,0xbf,0x1a,0x00,0xf3 +,0xa4,0x8b,0xc8,0x83,0xc7,0x06,0xf3,0xa4,0x26,0x81,0x26,0x26,0x00,0x1f,0x80,0x26 +,0x81,0x36,0x26,0x00,0x00,0x80,0xe9,0xa9,0xff,0x26,0x8b,0x1e,0x28,0x00,0x89,0x1e +,0x6a,0x37,0x06,0x8e,0x06,0x38,0x34,0x1f,0xc0,0xe3,0x04,0x26,0x88,0x1e,0x28,0x00 +,0xb9,0x06,0x00,0xbe,0x20,0x00,0xbf,0x1a,0x00,0xf3,0xa4,0xe9,0x84,0xff,0x86,0xc4 +,0xa3,0x68,0x37,0xe8,0x87,0xff,0xf7,0x06,0x6a,0x37,0x0f,0x00,0x74,0x10,0x80,0x3e +,0x9e,0x36,0x00,0x75,0x09,0xbe,0x00,0x00,0xe8,0xac,0xe9,0xcd,0x50,0xc3,0xc3,0x50 +,0x56,0x06,0x33,0xc0,0x26,0xf6,0x06,0x20,0x00,0x80,0x74,0x06,0x26,0xa0,0x26,0x00 +,0x24,0x1f,0x8b,0xf0,0x26,0x8b,0x5c,0x26,0x86,0xfb,0x83,0xeb,0x04,0x74,0x4f,0x83 +,0xc6,0x2a,0x8c,0xc0,0x8e,0xd8,0xb9,0x07,0x00,0x33,0xc0,0x8e,0xc0,0xbf,0x72,0x37 +,0xf3,0xab,0x33,0xc9,0x8a,0x0c,0x80,0xf9,0x00,0x75,0x03,0xe9,0x30,0x00,0x3b,0xd9 +,0x73,0x03,0xe9,0x29,0x00,0x2b,0xd9,0x8a,0x44,0x01,0x25,0x3f,0x00,0x74,0x19,0x3d +,0x0b,0x00,0x7d,0x14,0xd1,0xe0,0x8b,0xf8,0x2e,0x8b,0xbd,0x5c,0x49,0x8d,0x74,0x02 +,0x83,0xe9,0x02,0xf3,0xa4,0xe9,0x02,0x00,0x03,0xf1,0x23,0xdb,0x75,0xc4,0x33,0xc0 +,0x8e,0xd8,0x07,0x5e,0x58,0xc3,0x33,0xc0,0x26,0xf6,0x06,0x20,0x00,0x80,0x74,0x06 +,0x26,0xa0,0x26,0x00,0x24,0x1f,0xc3,0xe5,0x0a,0x25,0xc3,0xbf,0xe7,0x0a,0xb8,0x86 +,0x03,0xcd,0x39,0xb8,0x83,0x03,0xcd,0x39,0x81,0x26,0x9b,0x36,0x7c,0xdf,0xb8,0x85 +,0x03,0xcd,0x3a,0xe5,0x02,0x25,0xff,0xf3,0x0d,0x01,0x00,0x25,0xef,0xff,0xe7,0x02 +,0xe5,0x00,0x25,0xff,0x53,0xe7,0x00,0xa1,0xe7,0x36,0x25,0xff,0xfe,0xa3,0xe7,0x36 +,0xe7,0x3e,0x83,0x26,0x99,0x36,0xcf,0x81,0x0e,0xaf,0x36,0x00,0x10,0xa1,0xaf,0x36 +,0xe7,0x06,0xc3,0xe5,0x02,0x0d,0x01,0x0c,0x25,0xef,0xff,0xe7,0x02,0xa1,0xe7,0x36 +,0x0d,0x00,0x01,0xe7,0x3e,0xa3,0xe7,0x36,0x81,0x0e,0x9b,0x36,0x00,0x20,0x83,0x0e +,0x99,0x36,0x20,0x81,0x26,0x9b,0x36,0x7c,0xbf,0x81,0x0e,0xaf,0x36,0x00,0x10,0xa1 +,0xaf,0x36,0xe7,0x06,0xb8,0x86,0x03,0xcd,0x39,0xb8,0x85,0x03,0xcd,0x39,0xb8,0x83 +,0x03,0xcd,0x3a,0xc3,0x0b,0xf6,0x75,0x49,0x06,0x8e,0x06,0x32,0x34,0x80,0x3e,0xe0 +,0x34,0x01,0x75,0x1b,0x26,0x89,0x36,0x06,0x00,0x8e,0x06,0x32,0x34,0x26,0xf7,0x06 +,0x0a,0x00,0x00,0x20,0x74,0x07,0x26,0x81,0x0e,0x08,0x00,0x00,0x20,0x07,0xc3,0x80 +,0x3e,0xe3,0x34,0x01,0x75,0x19,0x26,0x89,0x36,0x06,0x00,0x8e,0x06,0x32,0x34,0x26 +,0xf7,0x06,0x0a,0x00,0x00,0x10,0x74,0x07,0x26,0x81,0x0e,0x08,0x00,0x00,0x10,0x07 +,0xc3,0xe9,0xb4,0xff,0x50,0x51,0x57,0x33,0xc0,0xb9,0x06,0x00,0x8e,0xc0,0xbf,0xd1 +,0x36,0xf3,0xae,0x5f,0x74,0x0c,0x26,0xf6,0x06,0x00,0x00,0xc0,0x75,0x04,0xf8,0x59 +,0x58,0xc3,0xf9,0xe9,0xf9,0xff,0x8b,0x05,0x0b,0x45,0x02,0x0b,0x45,0x04,0xc3,0x52 +,0x50,0xe5,0x06,0x25,0x1e,0x00,0x3d,0x1e,0x00,0x75,0xf6,0xb8,0x01,0x80,0xe7,0x5a +,0x58,0x5a,0xc3,0xe8,0xe9,0xff,0x50,0xe5,0x02,0x25,0xff,0x7f,0x0d,0x01,0x00,0x25 +,0xef,0xff,0xe7,0x02,0x0d,0x00,0x80,0xe7,0x02,0xa1,0xad,0x36,0xe7,0x04,0xa1,0xaf +,0x36,0xe7,0x06,0x58,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x2e,0x2b,0xce,0x41,0x10,0x42,0x7b,0x41,0x30,0x41,0xa2,0x41,0xaf,0x45,0x44,0x29 +,0xc7,0x2a,0xc7,0x2a,0x60,0x39,0xf4,0x3a,0x5c,0x3c,0x09,0x3d,0xb1,0x3d,0x34,0x3f +,0xc7,0x2a,0x3c,0x3f,0xc7,0x2a,0xc4,0x3f,0x16,0x40,0x16,0x40,0xed,0x40,0xfa,0x40 +,0x07,0x41,0xc7,0x2a,0xc7,0x2a,0xc7,0x2a,0xc7,0x2a,0xd6,0x52,0x00,0x00,0x01,0x37 +,0xe9,0x36,0xf3,0x36,0xef,0x36,0x1d,0x37,0x0d,0x37,0x0b,0x37,0x9c,0x37,0x03,0x37 +,0xfb,0x36,0x62,0x2d,0x40,0x06,0xd1,0x2d,0xf4,0x01,0xba,0x44,0x40,0x06,0x8c,0x43 +,0x64,0x00,0xe8,0x2c,0xc8,0x00,0xd8,0x2b,0x05,0x00,0xe9,0x45,0x50,0x00,0x97,0x45 +,0xfa,0x00,0xae,0x2d,0x04,0x01,0x6a,0x42,0x02,0x00,0xf6,0x2c,0xbc,0x02,0x93,0x2d +,0xdc,0x05,0x1d,0x2d,0x64,0x00,0xa1,0x2d,0x14,0x00,0xd7,0x3a,0x08,0x07,0x81,0x2d +,0x64,0x00,0xb3,0x3e,0x02,0x00,0x30,0x43,0x64,0x00,0xc5,0x2c,0xf4,0x01,0x8b,0x44 +,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x80,0x3e,0xfd,0x34,0x02,0x74,0x0c,0xe8,0x20,0x05,0xc7,0x06,0xa1,0x36,0x00,0x00 +,0xe9,0x9a,0xf8,0xff,0x06,0xc0,0x33,0xe8,0x10,0x05,0x8b,0x36,0x3d,0x37,0xe8,0x73 +,0xfe,0xc3,0xcd,0x34,0xe9,0xe8,0x05,0xc7,0x06,0xa3,0x36,0x00,0x00,0xc7,0x06,0x41 +,0x37,0x00,0x00,0xe8,0xed,0xfe,0x33,0xc0,0x0d,0x41,0x00,0xe7,0x56,0xa1,0xb1,0x36 +,0x0d,0x00,0x10,0xe7,0x08,0xa1,0xb3,0x36,0xe7,0x0a,0xa1,0xaf,0x36,0xe7,0x06,0xa1 +,0xad,0x36,0xe7,0x04,0xe8,0x2b,0x09,0xc7,0x06,0x1d,0x37,0x00,0xc8,0xc7,0x06,0x0b +,0x37,0x00,0x03,0xc7,0x06,0x0d,0x37,0x7b,0x7f,0x33,0xc0,0xa3,0x9b,0x36,0xa3,0x9d +,0x36,0xc7,0x06,0x4c,0x37,0x01,0x00,0xc6,0x06,0x9e,0x36,0xff,0xc7,0x06,0x05,0x37 +,0x00,0x00,0xc7,0x06,0x07,0x37,0x00,0x00,0xc7,0x06,0x09,0x37,0x00,0x00,0xa3,0xf3 +,0x36,0xa3,0xef,0x36,0xa3,0xf1,0x36,0xe8,0xfe,0xf5,0xe5,0x02,0x25,0xf9,0xff,0x0d +,0x03,0x00,0x0d,0x00,0x88,0x25,0xef,0xff,0x0d,0x00,0x40,0x0d,0x00,0x04,0xe7,0x02 +,0xb8,0x8f,0x03,0xcd,0x39,0xb8,0x80,0x00,0xcd,0x35,0xc7,0x06,0xaa,0x02,0xff,0xff +,0xa1,0xa9,0x36,0xa3,0xa7,0x36,0x0d,0x00,0xa4,0x0d,0x00,0x08,0xe7,0x00,0xa3,0xa9 +,0x36,0xc7,0x06,0xa3,0x36,0x01,0x00,0xc7,0x06,0xa5,0x36,0x0c,0x00,0x83,0x3e,0xa5 +,0x36,0x00,0x75,0x09,0xc7,0x06,0x3d,0x37,0x05,0x00,0xe9,0x13,0xff,0xff,0x0e,0xa5 +,0x36,0xbe,0x11,0x00,0xe8,0x22,0x05,0xb8,0x90,0x03,0xcd,0x39,0xc3,0x83,0x3e,0xa3 +,0x36,0x01,0x74,0xd9,0xc3,0xb8,0x90,0x03,0xcd,0x3a,0x26,0xa0,0x2b,0x00,0x26,0x8b +,0x1e,0x2c,0x00,0xcd,0x34,0x83,0x3e,0xa3,0x36,0x01,0x74,0x03,0xe9,0xf0,0x04,0x3c +,0x0f,0x75,0x1e,0x81,0xfb,0x00,0x02,0x75,0x18,0x26,0xa1,0x20,0x00,0xa3,0x05,0x37 +,0x26,0xa1,0x22,0x00,0xa3,0x07,0x37,0x26,0xa1,0x24,0x00,0xa3,0x09,0x37,0xe9,0x09 +,0x00,0xc7,0x06,0x3d,0x37,0x01,0x00,0xe9,0xb6,0xfe,0xc7,0x06,0xa3,0x36,0x02,0x00 +,0xc6,0x06,0x9e,0x36,0xff,0xe8,0xcb,0xfd,0xe8,0x1c,0xd9,0x33,0xc0,0xa3,0x85,0x37 +,0xa3,0x83,0x37,0xa3,0x87,0x37,0xa3,0x89,0x37,0xb8,0x91,0x03,0xcd,0x39,0xb8,0x80 +,0x00,0xcd,0x35,0xc7,0x06,0xaa,0x02,0xff,0xff,0xe5,0x00,0x25,0xff,0x53,0xe7,0x00 +,0x81,0x0e,0x9a,0x37,0x80,0x00,0xb8,0x92,0x03,0xcd,0x39,0x33,0xc0,0xe7,0x0e,0xbe +,0x08,0x00,0x8e,0x06,0x38,0x34,0xe8,0x8e,0xe5,0x26,0xc7,0x06,0x04,0x00,0x7d,0x4b +,0x83,0x26,0xef,0x34,0xdf,0xcd,0x50,0x83,0x0e,0xef,0x34,0x20,0xc3,0xf7,0x06,0x9a +,0x37,0x80,0x00,0x74,0x32,0xa9,0xd0,0x07,0x74,0x0c,0xa9,0x00,0x04,0x74,0x0e,0x33 +,0xc0,0xe7,0x0e,0xe9,0xda,0xff,0xff,0x06,0x85,0x37,0xe9,0xd3,0xff,0xff,0x06,0x83 +,0x37,0xe9,0xcc,0xff,0xc7,0x06,0x3d,0x37,0x01,0x00,0xe9,0x36,0xfe,0x83,0x26,0x9a +,0x37,0x7f,0xbb,0xff,0x7f,0xcd,0x53,0xe5,0x00,0x0d,0x00,0xac,0xe7,0x00,0xe5,0x02 +,0x25,0xff,0xfb,0x25,0xef,0xff,0x25,0xff,0xf7,0x0d,0x01,0x00,0xe7,0x02,0xa1,0x83 +,0x37,0x3b,0x06,0x46,0x37,0x7f,0xcd,0xa1,0x85,0x37,0x3b,0x06,0x48,0x37,0x7c,0xc4 +,0xc7,0x06,0xa3,0x36,0x03,0x00,0xbe,0x13,0x00,0xe8,0xfd,0x03,0xb8,0x93,0x03,0xcd +,0x39,0xb8,0x94,0x03,0xcd,0x39,0xb8,0x96,0x03,0xcd,0x39,0xb8,0x95,0x03,0xcd,0x39 +,0xbe,0x06,0x00,0xe8,0xe3,0x03,0xe9,0xd6,0x03,0x83,0x3e,0xa3,0x36,0x03,0x74,0x01 +,0xc3,0xbe,0x13,0x00,0xe8,0xd2,0x03,0xb8,0x94,0x03,0xcd,0x39,0xc3,0xb8,0x94,0x03 +,0xcd,0x3a,0x26,0xa0,0x2b,0x00,0x26,0x8b,0x1e,0x2c,0x00,0xcd,0x34,0x83,0x3e,0xa3 +,0x36,0x03,0x74,0x03,0xe9,0xa8,0x03,0x3c,0x0d,0x75,0x3e,0x83,0xfb,0x00,0x75,0x39 +,0xe5,0x02,0x0d,0x00,0x20,0xe7,0x02,0xb8,0x93,0x03,0xcd,0x3a,0xc7,0x06,0xa3,0x36 +,0x04,0x00,0xbe,0x00,0x00,0xe8,0x0c,0xfc,0xc6,0x06,0x9d,0x36,0x80,0xc6,0x06,0x9e +,0x36,0x00,0xc7,0x06,0x33,0x37,0x02,0x00,0xb8,0x9a,0x03,0xcd,0x39,0xe8,0xfc,0x00 +,0xc7,0x06,0x4c,0x37,0x00,0x00,0xe9,0x66,0x03,0xc7,0x06,0x3d,0x37,0x08,0x00,0xe9 +,0x61,0xfd,0x83,0x3e,0xa3,0x36,0x03,0x75,0x09,0xc7,0x06,0x3d,0x37,0x05,0x00,0xe9 +,0x51,0xfd,0xe9,0x4a,0x03,0x83,0x3e,0xa3,0x36,0x04,0x74,0x12,0x83,0x3e,0xa3,0x36 +,0x05,0x74,0x0b,0xcd,0x34,0xc7,0x06,0x3d,0x37,0x07,0x00,0xe9,0x35,0xfd,0xc7,0x06 +,0xa3,0x36,0x06,0x00,0xc6,0x06,0x9e,0x36,0xff,0xb8,0x9a,0x03,0xcd,0x3a,0xb8,0x99 +,0x03,0xcd,0x3a,0xb8,0x96,0x03,0xcd,0x3a,0xb8,0x97,0x03,0xcd,0x39,0xb8,0x98,0x03 +,0xcd,0x39,0xb8,0x9b,0x03,0xcd,0x39,0xe9,0x18,0xfd,0xcd,0x34,0x83,0x3e,0xa3,0x36 +,0x04,0x77,0x18,0x83,0x3e,0xa3,0x36,0x03,0x75,0x08,0xf7,0x06,0x9b,0x36,0x00,0x01 +,0x75,0x09,0xc7,0x06,0x3d,0x37,0x01,0x00,0xe9,0xe8,0xfc,0xe9,0xe1,0x02,0xcd,0x34 +,0x83,0x3e,0xa3,0x36,0x02,0x77,0x09,0xc7,0x06,0x3d,0x37,0x01,0x00,0xe9,0xd3,0xfc +,0x83,0x3e,0xa3,0x36,0x04,0x77,0x05,0xb8,0x96,0x03,0xcd,0x39,0xe9,0xc0,0x02,0x83 +,0x3e,0xa3,0x36,0x03,0x75,0x10,0x26,0xa1,0x0c,0x00,0x25,0x07,0x00,0x50,0x3d,0x04 +,0x00,0x75,0x03,0xe8,0x36,0x00,0xa1,0xf3,0x36,0x86,0xe0,0xe7,0x1e,0xa3,0xe3,0x36 +,0x81,0x26,0x0b,0x37,0x00,0x03,0x81,0x26,0x0d,0x37,0x7b,0x7f,0x83,0x0e,0x0d,0x37 +,0x48,0xe8,0x14,0xf3,0x58,0x3d,0x04,0x00,0x74,0x09,0x26,0xf7,0x06,0x0c,0x00,0x20 +,0x00,0x75,0x06,0xb8,0x01,0x00,0xe9,0x7a,0x02,0xe9,0x86,0xfc,0xa1,0xe5,0x36,0xe7 +,0x2e,0xa1,0xe7,0x36,0xe7,0x3e,0xa1,0xd3,0x36,0xa3,0x9c,0x34,0xa1,0xd5,0x36,0xa3 +,0x9e,0x34,0xc3,0x26,0x80,0x3e,0x1c,0x00,0xff,0x75,0x2f,0x26,0x80,0x3e,0x1e,0x00 +,0xff,0x75,0x27,0x26,0xf7,0x06,0x0c,0x00,0x40,0x00,0x75,0x1b,0xa1,0xd1,0x36,0x26 +,0xa3,0x1a,0x00,0xa1,0xd3,0x36,0x26,0xa3,0x1c,0x00,0xa1,0xd5,0x36,0x26,0xa3,0x1e +,0x00,0xb8,0x0a,0x80,0xe9,0x2c,0x02,0xe9,0x38,0xfc,0xff,0x06,0x90,0x34,0xbe,0x0a +,0x00,0xc6,0x06,0xb6,0x34,0x01,0xf6,0x06,0x9d,0x36,0x80,0x75,0x05,0x83,0x0e,0xc2 +,0x34,0x01,0xcd,0x34,0xe9,0x0c,0xfc,0x83,0x3e,0xa3,0x36,0x03,0x75,0x09,0xc7,0x06 +,0x3d,0x37,0x05,0x00,0xe9,0xfc,0xfb,0xe5,0x02,0x0d,0x03,0x00,0x0d,0x00,0x88,0x0d +,0x00,0x40,0x0d,0x00,0x04,0xe7,0x02,0xc7,0x06,0xa3,0x36,0x05,0x00,0xc6,0x06,0x9e +,0x36,0xff,0xbe,0x02,0x00,0xe8,0xe1,0x01,0xb8,0x89,0x03,0xcd,0x3a,0xb8,0x9a,0x03 +,0xcd,0x3a,0xb8,0x99,0x03,0xcd,0x39,0xb8,0x97,0x03,0xcd,0x39,0xb8,0x98,0x03,0xcd +,0x39,0xe9,0xbb,0x01,0x83,0x3e,0xa3,0x36,0x03,0x74,0x0a,0x83,0x3e,0xa3,0x36,0x04 +,0x74,0x03,0xe9,0xaa,0x01,0xbe,0x06,0x00,0xe8,0xae,0x01,0xb8,0x95,0x03,0xcd,0x39 +,0xe9,0x9c,0x01,0x83,0x3e,0xa3,0x36,0x05,0x74,0x03,0xe9,0x92,0x01,0xbe,0x02,0x00 +,0xe8,0x96,0x01,0xb8,0x99,0x03,0xcd,0x39,0xe9,0x84,0x01,0xc7,0x06,0x0f,0x37,0x05 +,0x00,0xe9,0x7b,0x01,0xe5,0x02,0x25,0xff,0xdf,0xe7,0x02,0xc7,0x06,0xa3,0x36,0x07 +,0x00,0xc7,0x06,0x0f,0x37,0x05,0x00,0xe9,0x65,0x01,0xe8,0xd5,0x04,0xc6,0x06,0x9d +,0x36,0x00,0xc7,0x06,0x9b,0x36,0x00,0x00,0xc7,0x06,0x0f,0x37,0x05,0x00,0xc7,0x06 +,0xa8,0x02,0x00,0x00,0xc7,0x06,0x4c,0x37,0x01,0x00,0xe5,0x02,0x25,0xf9,0xff,0x0d +,0x03,0x00,0x0d,0x00,0x88,0x25,0xef,0xff,0x0d,0x00,0x40,0x0d,0x00,0x04,0xe7,0x02 +,0xe9,0x67,0xfc,0xb8,0x9a,0x03,0xcd,0x39,0xf7,0x06,0xf4,0x33,0x00,0x10,0x75,0x09 +,0xc7,0x06,0x33,0x37,0x02,0x00,0xe9,0x16,0x01,0xff,0x0e,0x33,0x37,0x74,0x03,0xe9 +,0x0d,0x01,0xff,0x06,0x8e,0x34,0x83,0x0e,0xc2,0x34,0x08,0xc7,0x06,0x3d,0x37,0x03 +,0x00,0xe9,0xff,0xfa,0xc3,0x52,0x50,0xba,0xe0,0x00,0xb8,0x00,0x10,0xef,0x58,0x5a +,0xc3,0xc7,0x06,0x3d,0x37,0x00,0x00,0xe9,0xe9,0xfa,0xfa,0xe8,0x54,0x04,0xb8,0x80 +,0x03,0x8e,0xc0,0x26,0xc7,0x06,0x04,0x00,0xd8,0x2b,0xb8,0x7f,0x03,0x8e,0xc0,0x26 +,0xc7,0x06,0x04,0x00,0xe8,0x2c,0x33,0xc0,0x8e,0xc0,0xa1,0xa7,0x36,0xa3,0xa9,0x36 +,0xa1,0xa9,0x36,0xe7,0x00,0xa1,0xab,0x36,0xe7,0x02,0xc7,0x06,0x05,0x37,0x00,0x00 +,0xc7,0x06,0x07,0x37,0x00,0x00,0xc7,0x06,0x09,0x37,0x00,0x00,0xc6,0x06,0x9d,0x36 +,0x00,0xc6,0x06,0x9e,0x36,0xff,0xc7,0x06,0x9b,0x36,0x00,0x00,0xc7,0x06,0xa3,0x36 +,0x00,0x00,0xc7,0x06,0x0f,0x37,0x00,0x00,0xc7,0x06,0xa8,0x02,0x00,0x00,0xc7,0x06 +,0x4c,0x37,0x01,0x00,0x81,0x26,0xaf,0x36,0xff,0xe7,0xa1,0xaf,0x36,0xe7,0x06,0xbb +,0xff,0x7f,0xcd,0x53,0xe8,0x7c,0xf9,0xe5,0x56,0x0d,0x02,0x00,0xe7,0x56,0xfb,0xc3 +,0x8d,0x3e,0xc0,0x53,0x8d,0x36,0xf0,0x38,0xb9,0x0e,0x00,0x8b,0x1e,0x30,0x34,0x89 +,0x5c,0x02,0x2e,0x8b,0x45,0x02,0x89,0x44,0x06,0x2e,0x8b,0x05,0x89,0x44,0x04,0x83 +,0xc7,0x04,0x83,0xc6,0x10,0xe2,0xe8,0xb8,0x80,0x03,0x8e,0xc0,0x26,0xc7,0x06,0x04 +,0x00,0xe2,0x51,0xb8,0x7f,0x03,0x8e,0xc0,0x26,0xc7,0x06,0x04,0x00,0xb2,0x52,0x33 +,0xc0,0x8e,0xc0,0xc7,0x06,0xa1,0x36,0x01,0x00,0xc7,0x06,0x0f,0x37,0x05,0x00,0xc3 +,0x33,0xff,0x8e,0x06,0xa6,0x02,0x8b,0x36,0xa4,0x02,0x2e,0xff,0xa4,0xa0,0x53,0xe8 +,0x8c,0xdb,0xc3,0xe8,0x48,0xf7,0xe9,0xf6,0xff,0x8e,0x06,0x38,0x34,0xe8,0x07,0xe1 +,0x26,0xc7,0x06,0x04,0x00,0xdf,0x4f,0xcd,0x50,0xc3,0x26,0xc7,0x06,0x0a,0x00,0x00 +,0x00,0x26,0xff,0x26,0x04,0x00,0xcd,0x34,0xe9,0xd4,0xff,0xa1,0xd1,0x36,0x26,0x39 +,0x06,0x1a,0x00,0x75,0x22,0xa1,0xd3,0x36,0x26,0x39,0x06,0x1c,0x00,0x75,0x18,0xa1 +,0xd5,0x36,0x26,0x39,0x06,0x1e,0x00,0x75,0x0e,0x26,0xf7,0x06,0x0c,0x00,0x40,0x00 +,0x74,0x05,0x83,0x0e,0x66,0x37,0x40,0x81,0x0e,0xaf,0x36,0x00,0x10,0xa1,0xaf,0x36 +,0xe7,0x06,0x83,0x3e,0xa3,0x36,0x02,0x75,0x05,0xcd,0x34,0xe9,0x56,0xfb,0x83,0x3e +,0xa3,0x36,0x00,0x74,0xb1,0x83,0x3e,0xa3,0x36,0x05,0x77,0xaa,0x26,0xf6,0x06,0x0a +,0x00,0xff,0x75,0xa2,0xe8,0xfd,0xdd,0x50,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xe9 +,0x8c,0x00,0x26,0xa1,0x0c,0x00,0x25,0x07,0x00,0x3d,0x07,0x00,0x75,0x03,0xe9,0x76 +,0x00,0x3d,0x05,0x00,0x75,0x03,0xe9,0x6e,0x00,0xf7,0x06,0xe6,0x34,0x18,0x80,0x75 +,0x03,0xe9,0x6a,0x00,0xf7,0x06,0xe6,0x34,0x00,0x80,0x74,0x35,0x26,0x80,0x3e,0x29 +,0x00,0x02,0x75,0x2d,0x51,0x56,0x57,0x8d,0x36,0x3e,0x34,0x8d,0x3e,0x20,0x00,0xb9 +,0x06,0x00,0xf3,0xa6,0x5f,0x5e,0x59,0x75,0x45,0x26,0xa1,0x20,0x00,0xa3,0x3e,0x34 +,0x26,0xa1,0x22,0x00,0xa3,0x40,0x34,0x26,0xa1,0x24,0x00,0xa3,0x42,0x34,0xe9,0x26 +,0x00,0xf7,0x06,0xe6,0x34,0x08,0x00,0x74,0x0b,0x26,0x80,0x3e,0x19,0x00,0x00,0x74 +,0x03,0xe9,0x13,0x00,0xf7,0x06,0xe6,0x34,0x10,0x00,0x74,0x12,0x26,0xa0,0x28,0x00 +,0xc0,0xe8,0x04,0x22,0xc0,0x74,0x07,0x26,0xc7,0x06,0x04,0x00,0xff,0xff,0x58,0x23 +,0xc0,0x74,0x03,0xe9,0xdd,0xfe,0x81,0x26,0x9b,0x36,0xff,0xfe,0x26,0xa1,0x20,0x00 +,0x3b,0x06,0xd1,0x36,0x75,0x1a,0x26,0xa1,0x22,0x00,0x3b,0x06,0xd3,0x36,0x75,0x10 +,0x26,0xa1,0x24,0x00,0x3b,0x06,0xd5,0x36,0x75,0x06,0x81,0x0e,0x9b,0x36,0x00,0x01 +,0x26,0xa1,0x20,0x00,0x25,0x7f,0xff,0xa3,0xb8,0x34,0x26,0xa1,0x22,0x00,0xa3,0xba +,0x34,0x26,0xa1,0x24,0x00,0xa3,0xbc,0x34,0x8b,0xc6,0x86,0xc4,0xa3,0xc0,0x34,0xd1 +,0xe6,0x80,0xfc,0x09,0x74,0x03,0xe8,0xf6,0xf5,0xa1,0x05,0x37,0x0b,0x06,0x07,0x37 +,0x0b,0x06,0x09,0x37,0x74,0x3e,0x26,0xa1,0x20,0x00,0x3b,0x06,0x05,0x37,0x75,0x17 +,0x26,0xa1,0x22,0x00,0x3b,0x06,0x07,0x37,0x75,0x0d,0x26,0xa1,0x24,0x00,0x3b,0x06 +,0x09,0x37,0x75,0x03,0xe9,0x1d,0x00,0x26,0xa0,0x28,0x00,0x24,0x0f,0x3c,0x03,0x74 +,0x1b,0x3c,0x00,0x75,0x0f,0x83,0x3e,0xa3,0x36,0x04,0x74,0x10,0xf7,0x06,0x9b,0x36 +,0x00,0x01,0x74,0x08,0x2e,0xff,0x94,0xf8,0x53,0xe9,0x33,0xfe,0xcd,0x34,0xc7,0x06 +,0x3d,0x37,0x01,0x00,0xe9,0x2c,0xf8,0x83,0x3e,0xa3,0x36,0x05,0x74,0x10,0x83,0x3e +,0xa3,0x36,0x01,0x7e,0x09,0x83,0xee,0x16,0x2e,0xff,0x94,0x24,0x54,0xc3,0xcd,0x34 +,0xc3,0x26,0xa1,0x0c,0x00,0x3d,0xff,0x7f,0x74,0x05,0x26,0xff,0x26,0x04,0x00,0xe9 +,0xfd,0xfd,0xa1,0xf4,0x33,0xa9,0x00,0x88,0x74,0x0b,0xa9,0x00,0x10,0x75,0x09,0x8b +,0x1e,0x43,0x37,0xff,0xe3,0xe9,0x97,0x00,0xc7,0x06,0x35,0x37,0x05,0x00,0xc7,0x06 +,0x43,0x37,0x28,0x52,0xf7,0x06,0xf4,0x33,0x00,0x08,0x74,0x06,0xc7,0x06,0x43,0x37 +,0x1a,0x52,0xb8,0x80,0x03,0xcd,0x39,0xe9,0xc5,0xfd,0xa9,0x00,0x08,0x74,0xd9,0xff +,0x0e,0x35,0x37,0x75,0xed,0xe9,0x30,0x00,0xa9,0x00,0x08,0x75,0xcb,0xff,0x0e,0x35 +,0x37,0x75,0xdf,0x81,0x0e,0xc2,0x34,0xc0,0x00,0xf6,0x06,0x9d,0x36,0x80,0x74,0x0f +,0x81,0x0e,0x9b,0x36,0x00,0x80,0xc7,0x06,0x0f,0x37,0x02,0x00,0xe9,0x90,0xfd,0xc7 +,0x06,0x3d,0x37,0x02,0x00,0xe9,0x8b,0xf7,0x80,0x26,0x9e,0x36,0xff,0x75,0x30,0xf6 +,0x06,0x9d,0x36,0x80,0x74,0x20,0xff,0x06,0x94,0x34,0x83,0x0e,0x66,0x37,0x20,0x8e +,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x01,0x74,0x07,0x26,0x81,0x0e,0x08 +,0x00,0x00,0x01,0xe9,0x09,0x00,0xc7,0x06,0x3d,0x37,0x04,0x00,0xe9,0x54,0xf7,0x81 +,0x0e,0xaf,0x36,0x00,0x08,0xa1,0xaf,0x36,0xe7,0x06,0xe5,0x0a,0xa9,0x00,0x80,0x74 +,0x0e,0x81,0x26,0xaf,0x36,0xff,0xf7,0xa1,0xaf,0x36,0xe7,0x06,0xe9,0x49,0xff,0xe9 +,0x2d,0xfd,0xc7,0x06,0x41,0x37,0x00,0x00,0xbe,0x29,0x00,0xe8,0x2b,0xfd,0xe9,0x1e +,0xfd,0xcd,0x34,0x83,0x3e,0xa3,0x36,0x04,0x77,0x09,0xc7,0x06,0x3d,0x37,0x01,0x00 +,0xe9,0x10,0xf7,0xe9,0x09,0xfd,0xcd,0x34,0xc3,0xc7,0x06,0x9b,0x36,0x00,0x00,0xe8 +,0x0c,0xf5,0x81,0x26,0xaf,0x36,0xff,0xe7,0xa1,0xaf,0x36,0xe7,0x06,0x81,0x26,0x9b +,0x36,0xff,0x7f,0xe5,0x02,0x0d,0x01,0x00,0x25,0xef,0xff,0x25,0xff,0xdf,0xe7,0x02 +,0xbb,0xff,0x7f,0xcd,0x53,0x33,0xc0,0xa3,0x9d,0x36,0xa3,0x9f,0x36,0xe8,0x20,0xf3 +,0xe8,0x43,0xf3,0x83,0x0e,0x9b,0x36,0x10,0xc7,0x06,0x99,0x36,0x00,0x00,0xe8,0xd2 +,0xf5,0xe5,0x56,0x0d,0x02,0x00,0xe7,0x56,0xc7,0x06,0xa8,0x02,0x00,0x00,0xbe,0x00 +,0x00,0xe8,0x30,0xf5,0xc6,0x06,0xa0,0x36,0x0e,0xb8,0x9c,0x03,0xcd,0x39,0xb8,0x80 +,0x00,0xcd,0x35,0xc7,0x06,0xaa,0x02,0xff,0xff,0xc7,0x06,0xa1,0x36,0x01,0x00,0xe9 +,0xa5,0xf6,0x06,0xb8,0x8f,0x03,0xcd,0x3a,0xb8,0x90,0x03,0xcd,0x3a,0xb8,0x91,0x03 +,0xcd,0x3a,0xb8,0x92,0x03,0xcd,0x3a,0xb8,0x93,0x03,0xcd,0x3a,0xb8,0x94,0x03,0xcd +,0x3a,0xb8,0x95,0x03,0xcd,0x3a,0xb8,0x96,0x03,0xcd,0x3a,0xb8,0x97,0x03,0xcd,0x3a +,0xb8,0x98,0x03,0xcd,0x3a,0xb8,0x99,0x03,0xcd,0x3a,0xb8,0x9a,0x03,0xcd,0x3a,0xb8 +,0x9b,0x03,0xcd,0x3a,0xb8,0x7f,0x03,0xcd,0x3a,0xb8,0x80,0x03,0xcd,0x3a,0x07,0xc3 +,0xf7,0x49,0xf1,0x4e,0xdf,0x4f,0xdf,0x4f,0xdf,0x4f,0xdf,0x4f,0xf8,0x51,0xdf,0x4f +,0xfa,0x4f,0x0b,0x50,0xd1,0x51,0xdf,0x4f,0xdf,0x4f,0xdf,0x4f,0xdf,0x4f,0xdf,0x4f +,0xe4,0x4e,0x06,0x00,0xcd,0x4a,0x04,0x00,0xe4,0x4e,0x19,0x00,0xad,0x4b,0xfa,0x00 +,0x82,0x4c,0x08,0x07,0x09,0x4c,0x14,0x00,0x24,0x4e,0x64,0x00,0xd7,0x4d,0xf4,0x01 +,0x64,0x4e,0xbc,0x02,0x7a,0x4e,0xe8,0x03,0x43,0x4e,0x02,0x00,0xb3,0x4e,0xf4,0x01 +,0x5b,0x4e,0xf4,0x01,0xe5,0x4e,0x14,0x00,0x06,0x50,0x06,0x50,0x95,0x4c,0xc1,0x52 +,0xc1,0x52,0xfe,0x4c,0xda,0x4c,0x06,0x50,0x06,0x50,0x06,0x50,0x06,0x50,0xb7,0x51 +,0xb7,0x51,0xb7,0x51,0xb7,0x51,0xb7,0x51,0xb7,0x51,0x06,0x50,0xd5,0x4a,0x06,0x50 +,0x1d,0x4c,0x06,0x50,0x83,0x4d,0x1f,0x4d,0x1f,0x4d,0xed,0x40,0xfa,0x40,0x07,0x41 +,0x37,0x37,0x2e,0x37,0x37,0x20,0x20,0x79,0x79,0x2f,0x79,0x79,0x2f,0x79,0x79,0x20 +,0x30,0x31,0x2e,0x39,0x30,0x20,0x20,0x30,0x32,0x2f,0x31,0x37,0x2f,0x39,0x39,0x20 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x90,0xea,0xc0,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x06 +} ; +#endif diff -Nru a/drivers/net/tokenring/Config.help b/drivers/net/tokenring/Config.help --- a/drivers/net/tokenring/Config.help Tue Feb 26 11:57:59 2002 +++ b/drivers/net/tokenring/Config.help Tue Feb 26 11:57:59 2002 @@ -129,3 +129,21 @@ The module will be called smctr.o. If you want to compile it as a module, say M here and read . +3COM 3C359 Token Link Velocity XL PCI adapter support +CONFIG_3C359 + This is support for the 3Com PCI Velocity XL cards, specifically + the 3Com 3C359, please note this is not for the 3C339 cards, you + should use the tms380 driver instead. + + If you have such an adapter, say Y and read the Token-Ring + mini-HOWTO, available from . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will will be called 3c359.o. If you want to compile it + as a module, say M here and read Documentation/modules.txt. + + Also read the file or check the + Linux Token Ring Project site for the latest information at + + diff -Nru a/drivers/net/tokenring/Config.in b/drivers/net/tokenring/Config.in --- a/drivers/net/tokenring/Config.in Tue Feb 26 11:57:58 2002 +++ b/drivers/net/tokenring/Config.in Tue Feb 26 11:57:58 2002 @@ -18,6 +18,7 @@ fi dep_tristate ' IBM Olympic chipset PCI adapter support' CONFIG_IBMOL $CONFIG_TR $CONFIG_PCI dep_tristate ' IBM Lanstreamer chipset PCI adapter support' CONFIG_IBMLS $CONFIG_TR $CONFIG_PCI + dep_tristate ' 3Com 3C359 Token Link Velocity XL adapter support' CONFIG_3C359 $CONFIG_TR $CONFIG_PCI tristate ' Generic TMS380 Token Ring ISA/PCI adapter support' CONFIG_TMS380TR if [ "$CONFIG_TMS380TR" != "n" ]; then dep_tristate ' Generic TMS380 PCI support' CONFIG_TMSPCI $CONFIG_PCI diff -Nru a/drivers/net/tokenring/Makefile b/drivers/net/tokenring/Makefile --- a/drivers/net/tokenring/Makefile Tue Feb 26 11:57:57 2002 +++ b/drivers/net/tokenring/Makefile Tue Feb 26 11:57:57 2002 @@ -21,6 +21,7 @@ obj-$(CONFIG_TMSPCI) += tmspci.o obj-$(CONFIG_TMSISA) += tmsisa.o obj-$(CONFIG_SMCTR) += smctr.o +obj-$(CONFIG_3C359) += 3c359.o O_TARGET := tr.o diff -Nru a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c --- a/drivers/net/tokenring/abyss.c Tue Feb 26 11:57:58 2002 +++ b/drivers/net/tokenring/abyss.c Tue Feb 26 11:57:58 2002 @@ -433,7 +433,7 @@ return 0; } -static void __exit abyss_detach (struct pci_dev *pdev) +static void __devexit abyss_detach (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); @@ -451,7 +451,7 @@ name: "abyss", id_table: abyss_pci_tbl, probe: abyss_attach, - remove: abyss_detach, + remove: __devexit_p(abyss_detach), }; static int __init abyss_init (void) diff -Nru a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c --- a/drivers/net/tokenring/lanstreamer.c Tue Feb 26 11:57:59 2002 +++ b/drivers/net/tokenring/lanstreamer.c Tue Feb 26 11:57:59 2002 @@ -1812,7 +1812,7 @@ name: "lanstreamer", id_table: streamer_pci_tbl, probe: streamer_init_one, - remove: streamer_remove_one, + remove: __devexit_p(streamer_remove_one), }; static int __init streamer_init_module(void) { diff -Nru a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c --- a/drivers/net/tokenring/olympic.c Tue Feb 26 11:57:58 2002 +++ b/drivers/net/tokenring/olympic.c Tue Feb 26 11:57:58 2002 @@ -433,8 +433,6 @@ do { int i; - save_flags(flags); - cli(); for(i=0;idev_addr,olympic_priv->olympic_laa,dev->addr_len) ; } writeb(1,init_srb+30); - + + spin_lock_irqsave(&olympic_priv->olympic_lock,flags); olympic_priv->srb_queued=1; writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); + spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags); t = jiffies ; @@ -496,7 +496,6 @@ remove_wait_queue(&olympic_priv->srb_wait,&wait) ; set_current_state(TASK_RUNNING) ; - restore_flags(flags); #if OLYMPIC_DEBUG printk("init_srb(%p): ",init_srb); for(i=0;i<20;i++) @@ -1058,12 +1057,11 @@ writeb(0,srb+1); writeb(OLYMPIC_CLEAR_RET_CODE,srb+2); - save_flags(flags); - cli(); - + spin_lock_irqsave(&olympic_priv->olympic_lock,flags); olympic_priv->srb_queued=1; writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); + spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags); t = jiffies ; @@ -1088,7 +1086,6 @@ remove_wait_queue(&olympic_priv->srb_wait,&wait) ; set_current_state(TASK_RUNNING) ; - restore_flags(flags) ; olympic_priv->rx_status_last_received++; olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1; @@ -1760,7 +1757,7 @@ name: "olympic", id_table: olympic_pci_tbl, probe: olympic_probe, - remove: olympic_remove_one + remove: __devexit_p(olympic_remove_one) }; static int __init olympic_pci_init(void) diff -Nru a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c --- a/drivers/net/tokenring/tmspci.c Tue Feb 26 11:58:00 2002 +++ b/drivers/net/tokenring/tmspci.c Tue Feb 26 11:58:00 2002 @@ -220,7 +220,7 @@ return val; } -static void __exit tms_pci_detach (struct pci_dev *pdev) +static void __devexit tms_pci_detach (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); @@ -238,7 +238,7 @@ name: "tmspci", id_table: tmspci_pci_tbl, probe: tms_pci_attach, - remove: tms_pci_detach, + remove: __devexit_p(tms_pci_detach), }; static int __init tms_pci_init (void) diff -Nru a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c --- a/drivers/net/via-rhine.c Tue Feb 26 11:57:59 2002 +++ b/drivers/net/via-rhine.c Tue Feb 26 11:57:59 2002 @@ -321,6 +321,7 @@ VT86C100A = 0, VT6102, VT3043, + VT6105, }; struct via_rhine_chip_info { @@ -349,7 +350,7 @@ { "VIA VT6102 Rhine-II", RHINE_IOTYPE, 256, CanHaveMII | HasWOL }, { "VIA VT3043 Rhine", RHINE_IOTYPE, 128, - CanHaveMII | ReqTxAlign } + CanHaveMII | ReqTxAlign }, { "VIA VT6105 Rhine-III", RHINE_IOTYPE, 256, CanHaveMII | HasWOL }, }; @@ -1753,7 +1754,7 @@ name: "via-rhine", id_table: via_rhine_pci_tbl, probe: via_rhine_init_one, - remove: via_rhine_remove_one, + remove: __devexit_p(via_rhine_remove_one), }; diff -Nru a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile --- a/drivers/net/wan/Makefile Tue Feb 26 11:57:56 2002 +++ b/drivers/net/wan/Makefile Tue Feb 26 11:57:56 2002 @@ -1,7 +1,7 @@ # # Makefile for the Linux network (wan) device drivers. # -# 3 Aug 2000, Christoph Hellwig +# 3 Aug 2000, Christoph Hellwig # Rewritten to use lists instead of if-statements. # diff -Nru a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c --- a/drivers/net/wan/farsync.c Tue Feb 26 11:57:57 2002 +++ b/drivers/net/wan/farsync.c Tue Feb 26 11:57:57 2002 @@ -1810,7 +1810,7 @@ name: FST_NAME, id_table: fst_pci_dev_id, probe: fst_add_one, - remove: fst_remove_one, + remove: __devexit_p(fst_remove_one), suspend: NULL, resume: NULL, }; diff -Nru a/drivers/net/winbond-840.c b/drivers/net/winbond-840.c --- a/drivers/net/winbond-840.c Tue Feb 26 11:57:57 2002 +++ b/drivers/net/winbond-840.c Tue Feb 26 11:57:57 2002 @@ -1732,7 +1732,7 @@ name: DRV_NAME, id_table: w840_pci_tbl, probe: w840_probe1, - remove: w840_remove1, + remove: __devexit_p(w840_remove1), #ifdef CONFIG_PM suspend: w840_suspend, resume: w840_resume, diff -Nru a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c --- a/drivers/net/wireless/airo.c Tue Feb 26 11:57:57 2002 +++ b/drivers/net/wireless/airo.c Tue Feb 26 11:57:57 2002 @@ -63,7 +63,7 @@ name: "airo", id_table: card_ids, probe: airo_pci_probe, - remove: airo_pci_remove, + remove: __devexit_p(airo_pci_remove), }; #endif /* CONFIG_PCI */ diff -Nru a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c --- a/drivers/net/wireless/netwave_cs.c Tue Feb 26 11:57:59 2002 +++ b/drivers/net/wireless/netwave_cs.c Tue Feb 26 11:57:59 2002 @@ -63,6 +63,9 @@ #ifdef CONFIG_NET_RADIO #include +#if WIRELESS_EXT > 12 +#include +#endif /* WIRELESS_EXT > 12 */ #endif #include @@ -269,6 +272,16 @@ because they generally can't be allocated dynamically. */ +#if WIRELESS_EXT <= 12 +/* Wireless extensions backward compatibility */ + +/* Part of iw_handler prototype we need */ +struct iw_request_info +{ + __u16 cmd; /* Wireless Extension command */ + __u16 flags; /* More to come ;-) */ +}; + /* Wireless Extension Backward compatibility - Jean II * If the new wireless device private ioctl range is not defined, * default to standard device private ioctl range */ @@ -276,8 +289,11 @@ #define SIOCIWFIRSTPRIV SIOCDEVPRIVATE #endif /* SIOCIWFIRSTPRIV */ -#define SIOCGIPSNAP SIOCIWFIRSTPRIV /* Site Survey Snapshot */ -/*#define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1*/ +#else /* WIRELESS_EXT <= 12 */ +static const struct iw_handler_def netwave_handler_def; +#endif /* WIRELESS_EXT <= 12 */ + +#define SIOCGIPSNAP SIOCIWFIRSTPRIV + 1 /* Site Survey Snapshot */ #define MAX_ESA 10 @@ -483,7 +499,10 @@ /* wireless extensions */ #ifdef WIRELESS_EXT dev->get_wireless_stats = &netwave_get_wireless_stats; -#endif +#if WIRELESS_EXT > 12 + dev->wireless_handlers = (struct iw_handler_def *)&netwave_handler_def; +#endif /* WIRELESS_EXT > 12 */ +#endif /* WIRELESS_EXT */ dev->do_ioctl = &netwave_ioctl; dev->tx_timeout = &netwave_watchdog; @@ -596,6 +615,303 @@ } /* netwave_flush_stale_links */ /* + * Wireless Handler : get protocol name + */ +static int netwave_get_name(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + strcpy(wrqu->name, "Netwave"); + return 0; +} + +/* + * Wireless Handler : set Network ID + */ +static int netwave_set_nwid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long flags; + ioaddr_t iobase = dev->base_addr; + netwave_private *priv = (netwave_private *) dev->priv; + u_char *ramBase = priv->ramBase; + + /* Disable interrupts & save flags */ + save_flags(flags); + cli(); + +#if WIRELESS_EXT > 8 + if(!wrqu->nwid.disabled) { + domain = wrqu->nwid.value; +#else /* WIRELESS_EXT > 8 */ + if(wrqu->nwid.on) { + domain = wrqu->nwid.nwid; +#endif /* WIRELESS_EXT > 8 */ + printk( KERN_DEBUG "Setting domain to 0x%x%02x\n", + (domain >> 8) & 0x01, domain & 0xff); + wait_WOC(iobase); + writeb(NETWAVE_CMD_SMD, ramBase + NETWAVE_EREG_CB + 0); + writeb( domain & 0xff, ramBase + NETWAVE_EREG_CB + 1); + writeb((domain >>8 ) & 0x01,ramBase + NETWAVE_EREG_CB+2); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); + } + + /* ReEnable interrupts & restore flags */ + restore_flags(flags); + + return 0; +} + +/* + * Wireless Handler : get Network ID + */ +static int netwave_get_nwid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ +#if WIRELESS_EXT > 8 + wrqu->nwid.value = domain; + wrqu->nwid.disabled = 0; + wrqu->nwid.fixed = 1; +#else /* WIRELESS_EXT > 8 */ + wrqu->nwid.nwid = domain; + wrqu->nwid.on = 1; +#endif /* WIRELESS_EXT > 8 */ + + return 0; +} + +/* + * Wireless Handler : set scramble key + */ +static int netwave_set_scramble(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *key) +{ + unsigned long flags; + ioaddr_t iobase = dev->base_addr; + netwave_private *priv = (netwave_private *) dev->priv; + u_char *ramBase = priv->ramBase; + + /* Disable interrupts & save flags */ + save_flags(flags); + cli(); + + scramble_key = (key[0] << 8) | key[1]; + wait_WOC(iobase); + writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0); + writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1); + writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); + + /* ReEnable interrupts & restore flags */ + restore_flags(flags); + + return 0; +} + +/* + * Wireless Handler : get scramble key + */ +static int netwave_get_scramble(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *key) +{ + key[1] = scramble_key & 0xff; + key[0] = (scramble_key>>8) & 0xff; +#if WIRELESS_EXT > 8 + wrqu->encoding.flags = IW_ENCODE_ENABLED; + wrqu->encoding.length = 2; +#else /* WIRELESS_EXT > 8 */ + wrqu->encoding.method = 1; +#endif /* WIRELESS_EXT > 8 */ + + return 0; +} + +#if WIRELESS_EXT > 8 +/* + * Wireless Handler : get mode + */ +static int netwave_get_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + if(domain & 0x100) + wrqu->mode = IW_MODE_INFRA; + else + wrqu->mode = IW_MODE_ADHOC; + + return 0; +} +#endif /* WIRELESS_EXT > 8 */ + +/* + * Wireless Handler : get range info + */ +static int netwave_get_range(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_range *range = (struct iw_range *) extra; + int ret = 0; + + /* Set the length (very important for backward compatibility) */ + wrqu->data.length = sizeof(struct iw_range); + + /* Set all the info we don't care or don't know about to zero */ + memset(range, 0, sizeof(struct iw_range)); + +#if WIRELESS_EXT > 10 + /* Set the Wireless Extension versions */ + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 9; /* Nothing for us in v10 and v11 */ +#endif /* WIRELESS_EXT > 10 */ + + /* Set information in the range struct */ + range->throughput = 450 * 1000; /* don't argue on this ! */ + range->min_nwid = 0x0000; + range->max_nwid = 0x01FF; + + range->num_channels = range->num_frequency = 0; + + range->sensitivity = 0x3F; + range->max_qual.qual = 255; + range->max_qual.level = 255; + range->max_qual.noise = 0; + +#if WIRELESS_EXT > 7 + range->num_bitrates = 1; + range->bitrate[0] = 1000000; /* 1 Mb/s */ +#endif /* WIRELESS_EXT > 7 */ + +#if WIRELESS_EXT > 8 + range->encoding_size[0] = 2; /* 16 bits scrambling */ + range->num_encoding_sizes = 1; + range->max_encoding_tokens = 1; /* Only one key possible */ +#endif /* WIRELESS_EXT > 8 */ + + return ret; +} + +/* + * Wireless Private Handler : get snapshot + */ +static int netwave_get_snap(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long flags; + ioaddr_t iobase = dev->base_addr; + netwave_private *priv = (netwave_private *) dev->priv; + u_char *ramBase = priv->ramBase; + + /* Disable interrupts & save flags */ + save_flags(flags); + cli(); + + /* Take snapshot of environment */ + netwave_snapshot( priv, ramBase, iobase); + wrqu->data.length = priv->nss.length; + memcpy(extra, (u_char *) &priv->nss, sizeof( struct site_survey)); + + priv->lastExec = jiffies; + + /* ReEnable interrupts & restore flags */ + restore_flags(flags); + + return(0); +} + +/* + * Structures to export the Wireless Handlers + * This is the stuff that are treated the wireless extensions (iwconfig) + */ + +static const struct iw_priv_args netwave_private_args[] = { +/*{ cmd, set_args, get_args, name } */ + { SIOCGIPSNAP, 0, + IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof(struct site_survey), + "getsitesurvey" }, +}; + +#if WIRELESS_EXT > 12 + +static const iw_handler netwave_handler[] = +{ + NULL, /* SIOCSIWNAME */ + netwave_get_name, /* SIOCGIWNAME */ + netwave_set_nwid, /* SIOCSIWNWID */ + netwave_get_nwid, /* SIOCGIWNWID */ + NULL, /* SIOCSIWFREQ */ + NULL, /* SIOCGIWFREQ */ + NULL, /* SIOCSIWMODE */ + netwave_get_mode, /* SIOCGIWMODE */ + NULL, /* SIOCSIWSENS */ + NULL, /* SIOCGIWSENS */ + NULL, /* SIOCSIWRANGE */ + netwave_get_range, /* SIOCGIWRANGE */ + NULL, /* SIOCSIWPRIV */ + NULL, /* SIOCGIWPRIV */ + NULL, /* SIOCSIWSTATS */ + NULL, /* SIOCGIWSTATS */ + NULL, /* SIOCSIWSPY */ + NULL, /* SIOCGIWSPY */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + NULL, /* SIOCSIWAP */ + NULL, /* SIOCGIWAP */ + NULL, /* -- hole -- */ + NULL, /* SIOCGIWAPLIST */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + NULL, /* SIOCSIWESSID */ + NULL, /* SIOCGIWESSID */ + NULL, /* SIOCSIWNICKN */ + NULL, /* SIOCGIWNICKN */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + NULL, /* SIOCSIWRATE */ + NULL, /* SIOCGIWRATE */ + NULL, /* SIOCSIWRTS */ + NULL, /* SIOCGIWRTS */ + NULL, /* SIOCSIWFRAG */ + NULL, /* SIOCGIWFRAG */ + NULL, /* SIOCSIWTXPOW */ + NULL, /* SIOCGIWTXPOW */ + NULL, /* SIOCSIWRETRY */ + NULL, /* SIOCGIWRETRY */ + netwave_set_scramble, /* SIOCSIWENCODE */ + netwave_get_scramble, /* SIOCGIWENCODE */ +}; + +static const iw_handler netwave_private_handler[] = +{ + NULL, /* SIOCIWFIRSTPRIV */ + netwave_get_snap, /* SIOCIWFIRSTPRIV + 1 */ +}; + +static const struct iw_handler_def netwave_handler_def = +{ + num_standard: sizeof(netwave_handler)/sizeof(iw_handler), + num_private: sizeof(netwave_private_handler)/sizeof(iw_handler), + num_private_args: sizeof(netwave_private_args)/sizeof(struct iw_priv_args), + standard: (iw_handler *) netwave_handler, + private: (iw_handler *) netwave_private_handler, + private_args: (struct iw_priv_args *) netwave_private_args, +}; +#endif /* WIRELESS_EXT > 12 */ + +/* * Function netwave_ioctl (dev, rq, cmd) * * Perform ioctl : config & info stuff @@ -606,56 +922,28 @@ struct ifreq *rq, /* Data passed */ int cmd) /* Ioctl number */ { - unsigned long flags; int ret = 0; #ifdef WIRELESS_EXT - ioaddr_t iobase = dev->base_addr; - netwave_private *priv = (netwave_private *) dev->priv; - u_char *ramBase = priv->ramBase; +#if WIRELESS_EXT <= 12 struct iwreq *wrq = (struct iwreq *) rq; #endif +#endif DEBUG(0, "%s: ->netwave_ioctl(cmd=0x%X)\n", dev->name, cmd); - /* Disable interrupts & save flags */ - save_flags(flags); - cli(); - /* Look what is the request */ switch(cmd) { /* --------------- WIRELESS EXTENSIONS --------------- */ #ifdef WIRELESS_EXT +#if WIRELESS_EXT <= 12 case SIOCGIWNAME: - /* Get name */ - strcpy(wrq->u.name, "Netwave"); + netwave_get_name(dev, NULL, &(wrq->u), NULL); break; case SIOCSIWNWID: - /* Set domain */ -#if WIRELESS_EXT > 8 - if(!wrq->u.nwid.disabled) { - domain = wrq->u.nwid.value; -#else /* WIRELESS_EXT > 8 */ - if(wrq->u.nwid.on) { - domain = wrq->u.nwid.nwid; -#endif /* WIRELESS_EXT > 8 */ - printk( KERN_DEBUG "Setting domain to 0x%x%02x\n", - (domain >> 8) & 0x01, domain & 0xff); - wait_WOC(iobase); - writeb(NETWAVE_CMD_SMD, ramBase + NETWAVE_EREG_CB + 0); - writeb( domain & 0xff, ramBase + NETWAVE_EREG_CB + 1); - writeb((domain >>8 ) & 0x01,ramBase + NETWAVE_EREG_CB+2); - writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); - } break; + ret = netwave_set_nwid(dev, NULL, &(wrq->u), NULL); + break; case SIOCGIWNWID: - /* Read domain*/ -#if WIRELESS_EXT > 8 - wrq->u.nwid.value = domain; - wrq->u.nwid.disabled = 0; - wrq->u.nwid.fixed = 1; -#else /* WIRELESS_EXT > 8 */ - wrq->u.nwid.nwid = domain; - wrq->u.nwid.on = 1; -#endif /* WIRELESS_EXT > 8 */ + ret = netwave_get_nwid(dev, NULL, &(wrq->u), NULL); break; #if WIRELESS_EXT > 8 /* Note : The API did change... */ case SIOCGIWENCODE: @@ -663,10 +951,7 @@ if(wrq->u.encoding.pointer != (caddr_t) 0) { char key[2]; - key[1] = scramble_key & 0xff; - key[0] = (scramble_key>>8) & 0xff; - wrq->u.encoding.flags = IW_ENCODE_ENABLED; - wrq->u.encoding.length = 2; + ret = netwave_get_scramble(dev, NULL, &(wrq->u), key); if(copy_to_user(wrq->u.encoding.pointer, key, 2)) ret = -EFAULT; } @@ -681,127 +966,68 @@ ret = -EFAULT; break; } - scramble_key = (key[0] << 8) | key[1]; - wait_WOC(iobase); - writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0); - writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1); - writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2); - writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); + ret = netwave_set_scramble(dev, NULL, &(wrq->u), key); } break; case SIOCGIWMODE: - /* Mode of operation */ - if(domain & 0x100) - wrq->u.mode = IW_MODE_INFRA; - else - wrq->u.mode = IW_MODE_ADHOC; - break; + /* Mode of operation */ + ret = netwave_get_mode(dev, NULL, &(wrq->u), NULL); + break; #else /* WIRELESS_EXT > 8 */ case SIOCGIWENCODE: /* Get scramble key */ - wrq->u.encoding.code = scramble_key; - wrq->u.encoding.method = 1; + ret = netwave_get_scramble(dev, NULL, &(wrq->u), + (char *) &wrq->u.encoding.code); break; case SIOCSIWENCODE: /* Set scramble key */ - scramble_key = wrq->u.encoding.code; - wait_WOC(iobase); - writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0); - writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1); - writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2); - writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); + ret = netwave_set_scramble(dev, NULL, &(wrq->u), + (char *) &wrq->u.encoding.code); break; #endif /* WIRELESS_EXT > 8 */ case SIOCGIWRANGE: /* Basic checking... */ if(wrq->u.data.pointer != (caddr_t) 0) { - struct iw_range range; - - /* Set the length (very important for backward compatibility) */ - wrq->u.data.length = sizeof(struct iw_range); - - /* Set all the info we don't care or don't know about to zero */ - memset(&range, 0, sizeof(range)); - -#if WIRELESS_EXT > 10 - /* Set the Wireless Extension versions */ - range.we_version_compiled = WIRELESS_EXT; - range.we_version_source = 9; /* Nothing for us in v10 and v11 */ -#endif /* WIRELESS_EXT > 10 */ - - /* Set information in the range struct */ - range.throughput = 450 * 1000; /* don't argue on this ! */ - range.min_nwid = 0x0000; - range.max_nwid = 0x01FF; - - range.num_channels = range.num_frequency = 0; - - range.sensitivity = 0x3F; - range.max_qual.qual = 255; - range.max_qual.level = 255; - range.max_qual.noise = 0; - -#if WIRELESS_EXT > 7 - range.num_bitrates = 1; - range.bitrate[0] = 1000000; /* 1 Mb/s */ -#endif /* WIRELESS_EXT > 7 */ - -#if WIRELESS_EXT > 8 - range.encoding_size[0] = 2; /* 16 bits scrambling */ - range.num_encoding_sizes = 1; - range.max_encoding_tokens = 1; /* Only one key possible */ -#endif /* WIRELESS_EXT > 8 */ - - /* Copy structure to the user buffer */ - if(copy_to_user(wrq->u.data.pointer, &range, - sizeof(struct iw_range))) - ret = -EFAULT; + struct iw_range range; + ret = netwave_get_range(dev, NULL, &(wrq->u), (char *) &range); + if (copy_to_user(wrq->u.data.pointer, &range, + sizeof(struct iw_range))) + ret = -EFAULT; } break; case SIOCGIWPRIV: /* Basic checking... */ if(wrq->u.data.pointer != (caddr_t) 0) { - struct iw_priv_args priv[] = - { /* cmd, set_args, get_args, name */ - { SIOCGIPSNAP, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 0, - sizeof(struct site_survey), - "getsitesurvey" }, - }; - /* Set the number of ioctl available */ - wrq->u.data.length = 1; + wrq->u.data.length = sizeof(netwave_private_args) / sizeof(netwave_private_args[0]); /* Copy structure to the user buffer */ - if(copy_to_user(wrq->u.data.pointer, (u_char *) priv, - sizeof(priv))) + if(copy_to_user(wrq->u.data.pointer, + (u_char *) netwave_private_args, + sizeof(netwave_private_args))) ret = -EFAULT; } break; case SIOCGIPSNAP: if(wrq->u.data.pointer != (caddr_t) 0) { - /* Take snapshot of environment */ - netwave_snapshot( priv, ramBase, iobase); - wrq->u.data.length = priv->nss.length; + char buffer[sizeof( struct site_survey)]; + ret = netwave_get_snap(dev, NULL, &(wrq->u), buffer); /* Copy structure to the user buffer */ if(copy_to_user(wrq->u.data.pointer, - (u_char *) &priv->nss, - sizeof( struct site_survey))) + buffer, + sizeof( struct site_survey))) { printk(KERN_DEBUG "Bad buffer!\n"); break; } - - priv->lastExec = jiffies; } break; -#endif +#endif /* WIRELESS_EXT <= 12 */ +#endif /* WIRELESS_EXT */ default: ret = -EOPNOTSUPP; } - /* ReEnable interrupts & restore flags */ - restore_flags(flags); - return ret; } diff -Nru a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c --- a/drivers/net/wireless/orinoco_plx.c Tue Feb 26 11:58:00 2002 +++ b/drivers/net/wireless/orinoco_plx.c Tue Feb 26 11:58:00 2002 @@ -279,7 +279,7 @@ name:"orinoco_plx", id_table:orinoco_plx_pci_id_table, probe:orinoco_plx_init_one, - remove:orinoco_plx_remove_one, + remove:__devexit_p(orinoco_plx_remove_one), suspend:0, resume:0 }; diff -Nru a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c --- a/drivers/net/wireless/wavelan.c Tue Feb 26 11:57:58 2002 +++ b/drivers/net/wireless/wavelan.c Tue Feb 26 11:57:58 2002 @@ -24,28 +24,6 @@ /*------------------------------------------------------------------*/ /* - * Wrapper for disabling interrupts and locking the driver. - * (note : inline, so optimised away) - */ -static inline void wv_splhi(net_local * lp, - unsigned long * pflags) -{ - spin_lock_irqsave(&lp->spinlock, *pflags); - /* Note : above does the cli(); itself */ -} - -/*------------------------------------------------------------------*/ -/* - * Wrapper for re-enabling interrupts and un-locking the driver. - */ -static inline void wv_splx(net_local * lp, - unsigned long * pflags) -{ - spin_unlock_irqrestore(&lp->spinlock, *pflags); -} - -/*------------------------------------------------------------------*/ -/* * Translate irq number to PSA irq parameter */ static u8 wv_irq_to_psa(int irq) @@ -870,10 +848,10 @@ /* Check if we can do it now ! */ if((netif_running(dev)) && !(netif_queue_stopped(dev))) { - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); /* May fail */ wv_82586_config(dev); - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); } else { #ifdef DEBUG_CONFIG_INFO @@ -1786,170 +1764,287 @@ /*------------------------------------------------------------------*/ /* - * Perform ioctl for configuration and information. - * It is here that the wireless extensions are treated (iwconfig). + * Wireless Handler : get protocol name */ -static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is applied */ - struct ifreq *rq, /* data passed */ - int cmd) -{ /* ioctl number */ +static int wavelan_get_name(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + strcpy(wrqu->name, "WaveLAN"); + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set NWID + */ +static int wavelan_set_nwid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ unsigned long ioaddr = dev->base_addr; net_local *lp = (net_local *) dev->priv; /* lp is not unused */ - struct iwreq *wrq = (struct iwreq *) rq; psa_t psa; mm_t m; unsigned long flags; int ret = 0; - int err = 0; -#ifdef DEBUG_IOCTL_TRACE - printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, - cmd); -#endif + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Set NWID in WaveLAN. */ + if (!wrqu->nwid.disabled) { + /* Set NWID in psa */ + psa.psa_nwid[0] = (wrqu->nwid.value & 0xFF00) >> 8; + psa.psa_nwid[1] = wrqu->nwid.value & 0xFF; + psa.psa_nwid_select = 0x01; + psa_write(ioaddr, lp->hacr, + (char *) psa.psa_nwid - (char *) &psa, + (unsigned char *) psa.psa_nwid, 3); + + /* Set NWID in mmc. */ + m.w.mmw_netw_id_l = psa.psa_nwid[1]; + m.w.mmw_netw_id_h = psa.psa_nwid[0]; + mmc_write(ioaddr, + (char *) &m.w.mmw_netw_id_l - + (char *) &m, + (unsigned char *) &m.w.mmw_netw_id_l, 2); + mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), 0x00); + } else { + /* Disable NWID in the psa. */ + psa.psa_nwid_select = 0x00; + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_nwid_select - + (char *) &psa, + (unsigned char *) &psa.psa_nwid_select, + 1); + + /* Disable NWID in the mmc (no filtering). */ + mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), + MMW_LOOPT_SEL_DIS_NWID); + } + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get NWID + */ +static int wavelan_get_nwid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; + int ret = 0; /* Disable interrupts and save flags. */ - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); - /* Look what is the request */ - switch (cmd) { - /* --------------- WIRELESS EXTENSIONS --------------- */ - - case SIOCGIWNAME: - strcpy(wrq->u.name, "WaveLAN"); - break; - - case SIOCSIWNWID: - /* Set NWID in WaveLAN. */ - if (!wrq->u.nwid.disabled) { - /* Set NWID in psa */ - psa.psa_nwid[0] = - (wrq->u.nwid.value & 0xFF00) >> 8; - psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF; - psa.psa_nwid_select = 0x01; - psa_write(ioaddr, lp->hacr, - (char *) psa.psa_nwid - (char *) &psa, - (unsigned char *) psa.psa_nwid, 3); + /* Read the NWID. */ + psa_read(ioaddr, lp->hacr, + (char *) psa.psa_nwid - (char *) &psa, + (unsigned char *) psa.psa_nwid, 3); + wrqu->nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; + wrqu->nwid.disabled = !(psa.psa_nwid_select); + wrqu->nwid.fixed = 1; /* Superfluous */ - /* Set NWID in mmc. */ - m.w.mmw_netw_id_l = psa.psa_nwid[1]; - m.w.mmw_netw_id_h = psa.psa_nwid[0]; - mmc_write(ioaddr, - (char *) &m.w.mmw_netw_id_l - - (char *) &m, - (unsigned char *) &m.w.mmw_netw_id_l, 2); - mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), 0x00); - } else { - /* Disable NWID in the psa. */ - psa.psa_nwid_select = 0x00; - psa_write(ioaddr, lp->hacr, - (char *) &psa.psa_nwid_select - - (char *) &psa, - (unsigned char *) &psa.psa_nwid_select, - 1); + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); - /* Disable NWID in the mmc (no filtering). */ - mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), - MMW_LOOPT_SEL_DIS_NWID); - } - /* update the Wavelan checksum */ - update_psa_checksum(dev, ioaddr, lp->hacr); - break; + return ret; +} - case SIOCGIWNWID: - /* Read the NWID. */ - psa_read(ioaddr, lp->hacr, - (char *) psa.psa_nwid - (char *) &psa, - (unsigned char *) psa.psa_nwid, 3); - wrq->u.nwid.value = - (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; - wrq->u.nwid.disabled = !(psa.psa_nwid_select); - wrq->u.nwid.fixed = 1; /* Superfluous */ - break; - - case SIOCSIWFREQ: - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ - if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) - ret = wv_set_frequency(ioaddr, &(wrq->u.freq)); - else - ret = -EOPNOTSUPP; - break; +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set frequency + */ +static int wavelan_set_freq(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + unsigned long flags; + int ret; - case SIOCGIWFREQ: - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). - * Does it work for everybody, especially old cards? */ - if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { - unsigned short freq; - - /* Ask the EEPROM to read the frequency from the first area. */ - fee_read(ioaddr, 0x00, &freq, 1); - wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000; - wrq->u.freq.e = 1; - } else { - psa_read(ioaddr, lp->hacr, - (char *) &psa.psa_subband - (char *) &psa, - (unsigned char *) &psa.psa_subband, 1); - - if (psa.psa_subband <= 4) { - wrq->u.freq.m = - fixed_bands[psa.psa_subband]; - wrq->u.freq.e = (psa.psa_subband != 0); - } else - ret = -EOPNOTSUPP; - } - break; + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ + if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) + ret = wv_set_frequency(ioaddr, &(wrqu->freq)); + else + ret = -EOPNOTSUPP; - case SIOCSIWSENS: - /* Set the level threshold. */ - /* We should complain loudly if wrq->u.sens.fixed = 0, because we - * can't set auto mode... */ - psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F; - psa_write(ioaddr, lp->hacr, - (char *) &psa.psa_thr_pre_set - (char *) &psa, - (unsigned char *) &psa.psa_thr_pre_set, 1); - /* update the Wavelan checksum */ - update_psa_checksum(dev, ioaddr, lp->hacr); - mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set), - psa.psa_thr_pre_set); - break; + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} - case SIOCGIWSENS: - /* Read the level threshold. */ +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get frequency + */ +static int wavelan_get_freq(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). + * Does it work for everybody, especially old cards? */ + if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { + unsigned short freq; + + /* Ask the EEPROM to read the frequency from the first area. */ + fee_read(ioaddr, 0x00, &freq, 1); + wrqu->freq.m = ((freq >> 5) * 5 + 24000L) * 10000; + wrqu->freq.e = 1; + } else { psa_read(ioaddr, lp->hacr, - (char *) &psa.psa_thr_pre_set - (char *) &psa, - (unsigned char *) &psa.psa_thr_pre_set, 1); - wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F; - wrq->u.sens.fixed = 1; - break; - - case SIOCSIWENCODE: - /* Set encryption key */ - if (!mmc_encr(ioaddr)) { + (char *) &psa.psa_subband - (char *) &psa, + (unsigned char *) &psa.psa_subband, 1); + + if (psa.psa_subband <= 4) { + wrqu->freq.m = fixed_bands[psa.psa_subband]; + wrqu->freq.e = (psa.psa_subband != 0); + } else ret = -EOPNOTSUPP; - break; - } + } - /* Basic checking... */ - if (wrq->u.encoding.pointer != (caddr_t) 0) { - /* Check the size of the key */ - if (wrq->u.encoding.length != 8) { - ret = -EINVAL; - break; - } + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); - /* Copy the key in the driver */ - wv_splx(lp, &flags); - err = copy_from_user(psa.psa_encryption_key, - wrq->u.encoding.pointer, - wrq->u.encoding.length); - wv_splhi(lp, &flags); - if (err) { - ret = -EFAULT; - break; - } + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set level threshold + */ +static int wavelan_set_sens(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Set the level threshold. */ + /* We should complain loudly if wrqu->sens.fixed = 0, because we + * can't set auto mode... */ + psa.psa_thr_pre_set = wrqu->sens.value & 0x3F; + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_thr_pre_set - (char *) &psa, + (unsigned char *) &psa.psa_thr_pre_set, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); + mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set), + psa.psa_thr_pre_set); + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get level threshold + */ +static int wavelan_get_sens(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Read the level threshold. */ + psa_read(ioaddr, lp->hacr, + (char *) &psa.psa_thr_pre_set - (char *) &psa, + (unsigned char *) &psa.psa_thr_pre_set, 1); + wrqu->sens.value = psa.psa_thr_pre_set & 0x3F; + wrqu->sens.fixed = 1; + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set encryption key + */ +static int wavelan_set_encode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + unsigned long flags; + psa_t psa; + int ret = 0; + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Check if capable of encryption */ + if (!mmc_encr(ioaddr)) { + ret = -EOPNOTSUPP; + } + + /* Check the size of the key */ + if((wrqu->encoding.length != 8) && (wrqu->encoding.length != 0)) { + ret = -EINVAL; + } + + if(!ret) { + /* Basic checking... */ + if (wrqu->encoding.length == 8) { + /* Copy the key in the driver */ + memcpy(psa.psa_encryption_key, extra, + wrqu->encoding.length); psa.psa_encryption_select = 1; + psa_write(ioaddr, lp->hacr, (char *) &psa.psa_encryption_select - (char *) &psa, @@ -1963,7 +2058,8 @@ psa_encryption_key, 8); } - if (wrq->u.encoding.flags & IW_ENCODE_DISABLED) { /* disable encryption */ + /* disable encryption */ + if (wrqu->encoding.flags & IW_ENCODE_DISABLED) { psa.psa_encryption_select = 0; psa_write(ioaddr, lp->hacr, (char *) &psa.psa_encryption_select - @@ -1975,350 +2071,430 @@ } /* update the Wavelan checksum */ update_psa_checksum(dev, ioaddr, lp->hacr); - break; + } + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} - case SIOCGIWENCODE: +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get encryption key + */ +static int wavelan_get_encode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Check if encryption is available */ + if (!mmc_encr(ioaddr)) { + ret = -EOPNOTSUPP; + } else { /* Read the encryption key */ - if (!mmc_encr(ioaddr)) { - ret = -EOPNOTSUPP; - break; - } + psa_read(ioaddr, lp->hacr, + (char *) &psa.psa_encryption_select - + (char *) &psa, + (unsigned char *) &psa. + psa_encryption_select, 1 + 8); + + /* encryption is enabled ? */ + if (psa.psa_encryption_select) + wrqu->encoding.flags = IW_ENCODE_ENABLED; + else + wrqu->encoding.flags = IW_ENCODE_DISABLED; + wrqu->encoding.flags |= mmc_encr(ioaddr); - /* only super-user can see encryption key */ - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - break; - } + /* Copy the key to the user buffer */ + wrqu->encoding.length = 8; + memcpy(extra, psa.psa_encryption_key, wrqu->encoding.length); + } - /* Basic checking... */ - if (wrq->u.encoding.pointer != (caddr_t) 0) { - /* Verify the user buffer */ - ret = - verify_area(VERIFY_WRITE, - wrq->u.encoding.pointer, 8); - if (ret) - break; - - psa_read(ioaddr, lp->hacr, - (char *) &psa.psa_encryption_select - - (char *) &psa, - (unsigned char *) &psa. - psa_encryption_select, 1 + 8); - - /* encryption is enabled ? */ - if (psa.psa_encryption_select) - wrq->u.encoding.flags = IW_ENCODE_ENABLED; - else - wrq->u.encoding.flags = IW_ENCODE_DISABLED; - wrq->u.encoding.flags |= mmc_encr(ioaddr); + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); - /* Copy the key to the user buffer */ - wrq->u.encoding.length = 8; - wv_splx(lp, &flags); - if (copy_to_user(wrq->u.encoding.pointer, - psa.psa_encryption_key, 8)) - ret = -EFAULT; - wv_splhi(lp, &flags); - } - break; + return ret; +} - case SIOCGIWRANGE: - /* basic checking */ - if (wrq->u.data.pointer != (caddr_t) 0) { - struct iw_range range; - - /* Set the length (very important for backward - * compatibility) */ - wrq->u.data.length = sizeof(struct iw_range); - - /* Set all the info we don't care or don't know - * about to zero */ - memset(&range, 0, sizeof(range)); - - /* Set the Wireless Extension versions */ - range.we_version_compiled = WIRELESS_EXT; - range.we_version_source = 9; - - /* Set information in the range struct. */ - range.throughput = 1.6 * 1000 * 1000; /* don't argue on this ! */ - range.min_nwid = 0x0000; - range.max_nwid = 0xFFFF; - - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ - if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { - range.num_channels = 10; - range.num_frequency = - wv_frequency_list(ioaddr, range.freq, - IW_MAX_FREQUENCIES); - } else - range.num_channels = range.num_frequency = - 0; - - range.sensitivity = 0x3F; - range.max_qual.qual = MMR_SGNL_QUAL; - range.max_qual.level = MMR_SIGNAL_LVL; - range.max_qual.noise = MMR_SILENCE_LVL; - range.avg_qual.qual = MMR_SGNL_QUAL; /* Always max */ - /* Need to get better values for those two */ - range.avg_qual.level = 30; - range.avg_qual.noise = 8; - - range.num_bitrates = 1; - range.bitrate[0] = 2000000; /* 2 Mb/s */ - - /* Encryption supported ? */ - if (mmc_encr(ioaddr)) { - range.encoding_size[0] = 8; /* DES = 64 bits key */ - range.num_encoding_sizes = 1; - range.max_encoding_tokens = 1; /* Only one key possible */ - } else { - range.num_encoding_sizes = 0; - range.max_encoding_tokens = 0; - } +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get range info + */ +static int wavelan_get_range(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + struct iw_range *range = (struct iw_range *) extra; + unsigned long flags; + int ret = 0; - /* Copy structure to the user buffer. */ - wv_splx(lp, &flags); - if (copy_to_user(wrq->u.data.pointer, - &range, - sizeof(struct iw_range))) - ret = -EFAULT; - wv_splhi(lp, &flags); - } - break; + /* Set the length (very important for backward compatibility) */ + wrqu->data.length = sizeof(struct iw_range); - case SIOCGIWPRIV: - /* Basic checking */ - if (wrq->u.data.pointer != (caddr_t) 0) { - struct iw_priv_args priv[] = { - /* { cmd, - set_args, - get_args, - name } */ - { SIOCSIPQTHR, - IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, - 0, - "setqualthr" }, - { SIOCGIPQTHR, - 0, - IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, - "getqualthr" }, - { SIOCSIPHISTO, - IW_PRIV_TYPE_BYTE | 16, - 0, - "sethisto" }, - { SIOCGIPHISTO, - 0, - IW_PRIV_TYPE_INT | 16, - "gethisto" }, - }; - - /* Set the number of available ioctls. */ - wrq->u.data.length = 4; - - /* Copy structure to the user buffer. */ - wv_splx(lp, &flags); - if (copy_to_user(wrq->u.data.pointer, - (u8 *) priv, - sizeof(priv))) - ret = -EFAULT; - wv_splhi(lp, &flags); - } - break; + /* Set all the info we don't care or don't know about to zero */ + memset(range, 0, sizeof(struct iw_range)); -#ifdef WIRELESS_SPY - case SIOCSIWSPY: - /* Set the spy list */ + /* Set the Wireless Extension versions */ + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 9; + + /* Set information in the range struct. */ + range->throughput = 1.6 * 1000 * 1000; /* don't argue on this ! */ + range->min_nwid = 0x0000; + range->max_nwid = 0xFFFF; + + range->sensitivity = 0x3F; + range->max_qual.qual = MMR_SGNL_QUAL; + range->max_qual.level = MMR_SIGNAL_LVL; + range->max_qual.noise = MMR_SILENCE_LVL; + range->avg_qual.qual = MMR_SGNL_QUAL; /* Always max */ + /* Need to get better values for those two */ + range->avg_qual.level = 30; + range->avg_qual.noise = 8; - /* Check the number of addresses. */ - if (wrq->u.data.length > IW_MAX_SPY) { - ret = -E2BIG; - break; - } - lp->spy_number = wrq->u.data.length; + range->num_bitrates = 1; + range->bitrate[0] = 2000000; /* 2 Mb/s */ - /* Are there are addresses to copy? */ - if (lp->spy_number > 0) { - struct sockaddr address[IW_MAX_SPY]; - int i; - - /* Copy addresses to the driver. */ - wv_splx(lp, &flags); - err = copy_from_user(address, - wrq->u.data.pointer, - sizeof(struct sockaddr) - * lp->spy_number); - wv_splhi(lp, &flags); - if (err) { - ret = -EFAULT; - break; - } + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ + if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { + range->num_channels = 10; + range->num_frequency = wv_frequency_list(ioaddr, range->freq, + IW_MAX_FREQUENCIES); + } else + range->num_channels = range->num_frequency = 0; - /* Copy addresses to the lp structure. */ - for (i = 0; i < lp->spy_number; i++) { - memcpy(lp->spy_address[i], - address[i].sa_data, - WAVELAN_ADDR_SIZE); - } + /* Encryption supported ? */ + if (mmc_encr(ioaddr)) { + range->encoding_size[0] = 8; /* DES = 64 bits key */ + range->num_encoding_sizes = 1; + range->max_encoding_tokens = 1; /* Only one key possible */ + } else { + range->num_encoding_sizes = 0; + range->max_encoding_tokens = 0; + } + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +#ifdef WIRELESS_SPY +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set spy list + */ +static int wavelan_set_spy(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + struct sockaddr *address = (struct sockaddr *) extra; + int i; + int ret = 0; - /* Reset structure. */ - memset(lp->spy_stat, 0x00, - sizeof(iw_qual) * IW_MAX_SPY); + /* Disable spy while we copy the addresses. + * As we don't disable interrupts, we need to do this */ + lp->spy_number = 0; + + /* Are there are addresses to copy? */ + if (wrqu->data.length > 0) { + /* Copy addresses to the lp structure. */ + for (i = 0; i < wrqu->data.length; i++) { + memcpy(lp->spy_address[i], address[i].sa_data, + WAVELAN_ADDR_SIZE); + } + + /* Reset structure. */ + memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY); #ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG + "SetSpy: set of new addresses is: \n"); + for (i = 0; i < wrqu->data.length; i++) printk(KERN_DEBUG - "SetSpy: set of new addresses is: \n"); - for (i = 0; i < wrq->u.data.length; i++) - printk(KERN_DEBUG - "%02X:%02X:%02X:%02X:%02X:%02X \n", - lp->spy_address[i][0], - lp->spy_address[i][1], - lp->spy_address[i][2], - lp->spy_address[i][3], - lp->spy_address[i][4], - lp->spy_address[i][5]); -#endif /* DEBUG_IOCTL_INFO */ - } + "%02X:%02X:%02X:%02X:%02X:%02X \n", + lp->spy_address[i][0], + lp->spy_address[i][1], + lp->spy_address[i][2], + lp->spy_address[i][3], + lp->spy_address[i][4], + lp->spy_address[i][5]); +#endif /* DEBUG_IOCTL_INFO */ + } + + /* Now we can set the number of addresses */ + lp->spy_number = wrqu->data.length; + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get spy list + */ +static int wavelan_get_spy(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + struct sockaddr *address = (struct sockaddr *) extra; + int i; - break; + /* Set the number of addresses */ + wrqu->data.length = lp->spy_number; - case SIOCGIWSPY: - /* Get the spy list and spy stats. */ + /* Copy addresses from the lp structure. */ + for (i = 0; i < lp->spy_number; i++) { + memcpy(address[i].sa_data, + lp->spy_address[i], + WAVELAN_ADDR_SIZE); + address[i].sa_family = AF_UNIX; + } + /* Copy stats to the user buffer (just after). */ + if(lp->spy_number > 0) + memcpy(extra + (sizeof(struct sockaddr) * lp->spy_number), + lp->spy_stat, sizeof(iw_qual) * lp->spy_number); - /* Set the number of addresses */ - wrq->u.data.length = lp->spy_number; + /* Reset updated flags. */ + for (i = 0; i < lp->spy_number; i++) + lp->spy_stat[i].updated = 0x0; - /* Does the user want to have the addresses back? */ - if ((lp->spy_number > 0) - && (wrq->u.data.pointer != (caddr_t) 0)) { - struct sockaddr address[IW_MAX_SPY]; - int i; - - /* Copy addresses from the lp structure. */ - for (i = 0; i < lp->spy_number; i++) { - memcpy(address[i].sa_data, - lp->spy_address[i], - WAVELAN_ADDR_SIZE); - address[i].sa_family = AF_UNIX; - } + return(0); +} +#endif /* WIRELESS_SPY */ - /* Copy addresses to the user buffer. */ - wv_splx(lp, &flags); - err = copy_to_user(wrq->u.data.pointer, - address, - sizeof(struct sockaddr) - * lp->spy_number); - - /* Copy stats to the user buffer (just after). */ - err |= copy_to_user(wrq->u.data.pointer - + (sizeof(struct sockaddr) - * lp->spy_number), - lp->spy_stat, - sizeof(iw_qual) * lp->spy_number); - wv_splhi(lp, &flags); - if (err) { - ret = -EFAULT; - break; - } +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : set quality threshold + */ +static int wavelan_set_qthr(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; - /* Reset updated flags. */ - for (i = 0; i < lp->spy_number; i++) - lp->spy_stat[i].updated = 0x0; - } - /* if(pointer != NULL) */ - break; -#endif /* WIRELESS_SPY */ + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + psa.psa_quality_thr = *(extra) & 0x0F; + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_quality_thr - (char *) &psa, + (unsigned char *) &psa.psa_quality_thr, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); + mmc_out(ioaddr, mmwoff(0, mmw_quality_thr), + psa.psa_quality_thr); - /* ------------------ PRIVATE IOCTL ------------------ */ + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); - case SIOCSIPQTHR: - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - break; - } - psa.psa_quality_thr = *(wrq->u.name) & 0x0F; - psa_write(ioaddr, lp->hacr, - (char *) &psa.psa_quality_thr - (char *) &psa, - (unsigned char *) &psa.psa_quality_thr, 1); - /* update the Wavelan checksum */ - update_psa_checksum(dev, ioaddr, lp->hacr); - mmc_out(ioaddr, mmwoff(0, mmw_quality_thr), - psa.psa_quality_thr); - break; + return 0; +} - case SIOCGIPQTHR: - psa_read(ioaddr, lp->hacr, - (char *) &psa.psa_quality_thr - (char *) &psa, - (unsigned char *) &psa.psa_quality_thr, 1); - *(wrq->u.name) = psa.psa_quality_thr & 0x0F; - break; +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : get quality threshold + */ +static int wavelan_get_qthr(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + psa_read(ioaddr, lp->hacr, + (char *) &psa.psa_quality_thr - (char *) &psa, + (unsigned char *) &psa.psa_quality_thr, 1); + *(extra) = psa.psa_quality_thr & 0x0F; + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return 0; +} #ifdef HISTOGRAM - case SIOCSIPHISTO: - /* Verify that the user is root. */ - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - break; - } +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : set histogram + */ +static int wavelan_set_histo(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ - /* Check the number of intervals. */ - if (wrq->u.data.length > 16) { - ret = -E2BIG; - break; - } - lp->his_number = wrq->u.data.length; + /* Check the number of intervals. */ + if (wrqu->data.length > 16) { + return(-E2BIG); + } - /* Are there addresses to copy? */ - if (lp->his_number > 0) { - /* Copy interval ranges to the driver */ - wv_splx(lp, &flags); - err = copy_from_user(lp->his_range, - wrq->u.data.pointer, - sizeof(char) * lp->his_number); - wv_splhi(lp, &flags); - if (err) { - ret = -EFAULT; - break; - } + /* Disable histo while we copy the addresses. + * As we don't disable interrupts, we need to do this */ + lp->his_number = 0; + + /* Are there ranges to copy? */ + if (wrqu->data.length > 0) { + /* Copy interval ranges to the driver */ + memcpy(lp->his_range, extra, wrqu->data.length); - /* Reset structure. */ - memset(lp->his_sum, 0x00, sizeof(long) * 16); + { + int i; + printk(KERN_DEBUG "Histo :"); + for(i = 0; i < wrqu->data.length; i++) + printk(" %d", lp->his_range[i]); + printk("\n"); } - break; - case SIOCGIPHISTO: - /* Set the number of intervals. */ - wrq->u.data.length = lp->his_number; - - /* Give back the distribution statistics */ - if ((lp->his_number > 0) - && (wrq->u.data.pointer != (caddr_t) 0)) { - /* Copy data to the user buffer. */ - wv_splx(lp, &flags); - if (copy_to_user(wrq->u.data.pointer, - lp->his_sum, - sizeof(long) * lp->his_number); - ret = -EFAULT; - wv_splhi(lp, &flags); + /* Reset result structure. */ + memset(lp->his_sum, 0x00, sizeof(long) * 16); + } - } /* if(pointer != NULL) */ - break; -#endif /* HISTOGRAM */ + /* Now we can set the number of ranges */ + lp->his_number = wrqu->data.length; + + return(0); +} - /* ------------------- OTHER IOCTL ------------------- */ +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : get histogram + */ +static int wavelan_get_histo(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ - default: - ret = -EOPNOTSUPP; - } /* switch (cmd) */ + /* Set the number of intervals. */ + wrqu->data.length = lp->his_number; - /* Enable interrupts and restore flags. */ - wv_splx(lp, &flags); + /* Give back the distribution statistics */ + if(lp->his_number > 0) + memcpy(extra, lp->his_sum, sizeof(long) * lp->his_number); -#ifdef DEBUG_IOCTL_TRACE - printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name); -#endif - return ret; + return(0); } +#endif /* HISTOGRAM */ + +/*------------------------------------------------------------------*/ +/* + * Structures to export the Wireless Handlers + */ + +static const iw_handler wavelan_handler[] = +{ + NULL, /* SIOCSIWNAME */ + wavelan_get_name, /* SIOCGIWNAME */ + wavelan_set_nwid, /* SIOCSIWNWID */ + wavelan_get_nwid, /* SIOCGIWNWID */ + wavelan_set_freq, /* SIOCSIWFREQ */ + wavelan_get_freq, /* SIOCGIWFREQ */ + NULL, /* SIOCSIWMODE */ + NULL, /* SIOCGIWMODE */ + wavelan_set_sens, /* SIOCSIWSENS */ + wavelan_get_sens, /* SIOCGIWSENS */ + NULL, /* SIOCSIWRANGE */ + wavelan_get_range, /* SIOCGIWRANGE */ + NULL, /* SIOCSIWPRIV */ + NULL, /* SIOCGIWPRIV */ + NULL, /* SIOCSIWSTATS */ + NULL, /* SIOCGIWSTATS */ +#ifdef WIRELESS_SPY + wavelan_set_spy, /* SIOCSIWSPY */ + wavelan_get_spy, /* SIOCGIWSPY */ +#else /* WIRELESS_SPY */ + NULL, /* SIOCSIWSPY */ + NULL, /* SIOCGIWSPY */ +#endif /* WIRELESS_SPY */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + NULL, /* SIOCSIWAP */ + NULL, /* SIOCGIWAP */ + NULL, /* -- hole -- */ + NULL, /* SIOCGIWAPLIST */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + NULL, /* SIOCSIWESSID */ + NULL, /* SIOCGIWESSID */ + NULL, /* SIOCSIWNICKN */ + NULL, /* SIOCGIWNICKN */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + NULL, /* SIOCSIWRATE */ + NULL, /* SIOCGIWRATE */ + NULL, /* SIOCSIWRTS */ + NULL, /* SIOCGIWRTS */ + NULL, /* SIOCSIWFRAG */ + NULL, /* SIOCGIWFRAG */ + NULL, /* SIOCSIWTXPOW */ + NULL, /* SIOCGIWTXPOW */ + NULL, /* SIOCSIWRETRY */ + NULL, /* SIOCGIWRETRY */ + /* Bummer ! Why those are only at the end ??? */ + wavelan_set_encode, /* SIOCSIWENCODE */ + wavelan_get_encode, /* SIOCGIWENCODE */ +}; + +static const iw_handler wavelan_private_handler[] = +{ + wavelan_set_qthr, /* SIOCIWFIRSTPRIV */ + wavelan_get_qthr, /* SIOCIWFIRSTPRIV + 1 */ +#ifdef HISTOGRAM + wavelan_set_histo, /* SIOCIWFIRSTPRIV + 2 */ + wavelan_get_histo, /* SIOCIWFIRSTPRIV + 3 */ +#endif /* HISTOGRAM */ +}; + +static const struct iw_priv_args wavelan_private_args[] = { +/*{ cmd, set_args, get_args, name } */ + { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" }, + { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" }, + { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" }, + { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, +}; + +static const struct iw_handler_def wavelan_handler_def = +{ + num_standard: sizeof(wavelan_handler)/sizeof(iw_handler), + num_private: sizeof(wavelan_private_handler)/sizeof(iw_handler), + num_private_args: sizeof(wavelan_private_args)/sizeof(struct iw_priv_args), + standard: (iw_handler *) wavelan_handler, + private: (iw_handler *) wavelan_private_handler, + private_args: (struct iw_priv_args *) wavelan_private_args, +}; /*------------------------------------------------------------------*/ /* @@ -2343,7 +2519,7 @@ return (iw_stats *) NULL; /* Disable interrupts and save flags. */ - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); wstats = &lp->wstats; @@ -2371,7 +2547,7 @@ wstats->discard.misc = 0L; /* Enable interrupts and restore flags. */ - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", @@ -2705,7 +2881,7 @@ if (clen < ETH_ZLEN) clen = ETH_ZLEN; - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); /* Check nothing bad has happened */ if (lp->tx_n_in_use == (NTXBLOCKS - 1)) { @@ -2713,7 +2889,7 @@ printk(KERN_INFO "%s: wv_packet_write(): Tx queue full.\n", dev->name); #endif - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); return 1; } @@ -2791,7 +2967,7 @@ if (lp->tx_n_in_use < NTXBLOCKS - 1) netif_wake_queue(dev); - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); #ifdef DEBUG_TX_INFO wv_packet_info((u8 *) buf, length, dev->name, @@ -2832,9 +3008,9 @@ * we can do it now. */ if (lp->reconfig_82586) { - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); wv_82586_config(dev); - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); /* Check that we can continue */ if (lp->tx_n_in_use == (NTXBLOCKS - 1)) return 1; @@ -3694,7 +3870,7 @@ /* Prevent reentrancy. We need to do that because we may have * multiple interrupt handler running concurrently. - * It is safe because wv_splhi() disables interrupts before acquiring + * It is safe because interrupts are disabled before acquiring * the spinlock. */ spin_lock(&lp->spinlock); @@ -3822,7 +3998,7 @@ return; } - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); /* Try to see if some buffers are not free (in case we missed * an interrupt */ @@ -3862,7 +4038,7 @@ if (lp->tx_n_in_use < NTXBLOCKS - 1) netif_wake_queue(dev); - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); #ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name); @@ -3909,7 +4085,7 @@ return -EAGAIN; } - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); if (wv_hw_reset(dev) != -1) { netif_start_queue(dev); @@ -3920,10 +4096,10 @@ "%s: wavelan_open(): impossible to start the card\n", dev->name); #endif - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); return -EAGAIN; } - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name); @@ -3951,9 +4127,9 @@ /* * Flush the Tx and disable Rx. */ - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); wv_82586_stop(dev); - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); free_irq(dev->irq, dev); @@ -4069,8 +4245,8 @@ #endif /* SET_MAC_ADDRESS */ #ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */ - dev->do_ioctl = wavelan_ioctl; dev->get_wireless_stats = wavelan_get_wireless_stats; + dev->wireless_handlers = (struct iw_handler_def *)&wavelan_handler_def; #endif dev->mtu = WAVELAN_MTU; diff -Nru a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h --- a/drivers/net/wireless/wavelan.p.h Tue Feb 26 11:58:00 2002 +++ b/drivers/net/wireless/wavelan.p.h Tue Feb 26 11:58:00 2002 @@ -345,6 +345,12 @@ * - Fix spinlock stupid bugs that I left in. The driver is now SMP * compliant and doesn't lockup at startup. * + * Changes made for release in 2.5.2 : + * --------------------------------- + * - Use new driver API for Wireless Extensions : + * o got rid of wavelan_ioctl() + * o use a bunch of iw_handler instead + * * Wishes & dreams: * ---------------- * - roaming (see Pcmcia driver) @@ -379,6 +385,7 @@ #include #include /* Wireless extensions */ +#include /* Wireless handlers */ /* WaveLAN declarations */ #include "i82586.h" @@ -436,7 +443,7 @@ /************************ CONSTANTS & MACROS ************************/ #ifdef DEBUG_VERSION_SHOW -static const char *version = "wavelan.c : v23 (SMP + wireless extensions) 05/10/00\n"; +static const char *version = "wavelan.c : v24 (SMP + wireless extensions) 11/12/01\n"; #endif /* Watchdog temporisation */ @@ -449,11 +456,9 @@ #define SIOCSIPQTHR SIOCIWFIRSTPRIV /* Set quality threshold */ #define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1 /* Get quality threshold */ -#define SIOCSIPLTHR SIOCIWFIRSTPRIV + 2 /* Set level threshold */ -#define SIOCGIPLTHR SIOCIWFIRSTPRIV + 3 /* Get level threshold */ -#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 6 /* Set histogram ranges */ -#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 7 /* Get histogram values */ +#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 2 /* Set histogram ranges */ +#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 3 /* Get histogram values */ /****************************** TYPES ******************************/ @@ -516,12 +521,6 @@ /**************************** PROTOTYPES ****************************/ /* ----------------------- MISC. SUBROUTINES ------------------------ */ -static inline void - wv_splhi(net_local *, /* Disable interrupts, lock driver */ - unsigned long *); /* flags */ -static inline void - wv_splx(net_local *, /* Enable interrupts, unlock driver */ - unsigned long *); /* flags */ static u_char wv_irq_to_psa(int); static int diff -Nru a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c --- a/drivers/net/wireless/wavelan_cs.c Tue Feb 26 11:57:59 2002 +++ b/drivers/net/wireless/wavelan_cs.c Tue Feb 26 11:57:59 2002 @@ -66,34 +66,6 @@ /*------------------------------------------------------------------*/ /* - * Wrapper for disabling interrupts. - * (note : inline, so optimised away) - */ -static inline void -wv_splhi(net_local * lp, - unsigned long * pflags) -{ - spin_lock_irqsave(&lp->spinlock, *pflags); - /* Note : above does the cli(); itself */ -} - -/*------------------------------------------------------------------*/ -/* - * Wrapper for re-enabling interrupts. - */ -static inline void -wv_splx(net_local * lp, - unsigned long * pflags) -{ - spin_unlock_irqrestore(&lp->spinlock, *pflags); - - /* Note : enabling interrupts on the hardware is done in wv_ru_start() - * via : outb(OP1_INT_ENABLE, LCCR(base)); - */ -} - -/*------------------------------------------------------------------*/ -/* * Wrapper for reporting error to cardservices */ static void cs_error(client_handle_t handle, int func, int ret) @@ -591,7 +563,7 @@ #endif /* Disable interrupts & save flags */ - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00; mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1); @@ -602,7 +574,7 @@ lp->cell_search=0; /* ReEnable interrupts & restore flags */ - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); } /* Find a record in the WavePoint table matching a given NWID */ @@ -771,7 +743,7 @@ #endif /* Disable interrupts & save flags */ - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF; m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8; @@ -779,7 +751,7 @@ mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2); /* ReEnable interrupts & restore flags */ - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); wv_nwid_filter(!NWID_PROMISC,lp); lp->curr_point=wavepoint; @@ -1049,9 +1021,9 @@ /* Check if we can do it now ! */ if((link->open) && (netif_running(dev)) && !(netif_queue_stopped(dev))) { - wv_splhi(lp, &flags); /* Disable interrupts */ + spin_lock_irqsave(&lp->spinlock, flags); /* Disable interrupts */ wv_82593_config(dev); - wv_splx(lp, &flags); /* Re-enable interrupts */ + spin_unlock_irqrestore(&lp->spinlock, flags); /* Re-enable interrupts */ } else { @@ -1179,7 +1151,7 @@ return; } - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); /* Read the mmc */ mmc_out(base, mmwoff(0, mmw_freeze), 1); @@ -1191,7 +1163,7 @@ lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; #endif /* WIRELESS_EXT */ - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); printk(KERN_DEBUG "##### wavelan modem status registers: #####\n"); #ifdef DEBUG_SHOW_UNUSED @@ -1884,557 +1856,1234 @@ /*------------------------------------------------------------------*/ /* - * Perform ioctl : config & info stuff - * This is here that are treated the wireless extensions (iwconfig) + * Wireless Handler : get protocol name */ -static int -wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */ - struct ifreq * rq, /* Data passed */ - int cmd) /* Ioctl number */ +static int wavelan_get_name(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) { - ioaddr_t base = dev->base_addr; - net_local * lp = (net_local *)dev->priv; /* lp is not unused */ - struct iwreq * wrq = (struct iwreq *) rq; - psa_t psa; - mm_t m; - unsigned long flags; - int ret = 0; - -#ifdef DEBUG_IOCTL_TRACE - printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd); -#endif - - /* Disable interrupts & save flags */ - wv_splhi(lp, &flags); - - /* Look what is the request */ - switch(cmd) - { - /* --------------- WIRELESS EXTENSIONS --------------- */ + strcpy(wrqu->name, "WaveLAN"); + return 0; +} - case SIOCGIWNAME: - strcpy(wrq->u.name, "Wavelan"); - break; +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set NWID + */ +static int wavelan_set_nwid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + ioaddr_t base = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + mm_t m; + unsigned long flags; + int ret = 0; - case SIOCSIWNWID: - /* Set NWID in wavelan */ + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Set NWID in WaveLAN. */ #if WIRELESS_EXT > 8 - if(!wrq->u.nwid.disabled) - { - /* Set NWID in psa */ - psa.psa_nwid[0] = (wrq->u.nwid.value & 0xFF00) >> 8; - psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF; + if (!wrqu->nwid.disabled) { + /* Set NWID in psa */ + psa.psa_nwid[0] = (wrqu->nwid.value & 0xFF00) >> 8; + psa.psa_nwid[1] = wrqu->nwid.value & 0xFF; #else /* WIRELESS_EXT > 8 */ - if(wrq->u.nwid.on) - { - /* Set NWID in psa */ - psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8; - psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF; + if(wrq->u.nwid.on) { + /* Set NWID in psa */ + psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8; + psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF; #endif /* WIRELESS_EXT > 8 */ - psa.psa_nwid_select = 0x01; - psa_write(dev, (char *)psa.psa_nwid - (char *)&psa, - (unsigned char *)psa.psa_nwid, 3); - - /* Set NWID in mmc */ - m.w.mmw_netw_id_l = psa.psa_nwid[1]; - m.w.mmw_netw_id_h = psa.psa_nwid[0]; - mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, - (unsigned char *)&m.w.mmw_netw_id_l, 2); - mmc_out(base, mmwoff(0, mmw_loopt_sel), 0x00); - } - else - { - /* Disable nwid in the psa */ - psa.psa_nwid_select = 0x00; - psa_write(dev, (char *)&psa.psa_nwid_select - (char *)&psa, - (unsigned char *)&psa.psa_nwid_select, 1); - - /* Disable nwid in the mmc (no filtering) */ - mmc_out(base, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID); - } - /* update the Wavelan checksum */ - update_psa_checksum(dev); - break; + psa.psa_nwid_select = 0x01; + psa_write(dev, + (char *) psa.psa_nwid - (char *) &psa, + (unsigned char *) psa.psa_nwid, 3); + + /* Set NWID in mmc. */ + m.w.mmw_netw_id_l = psa.psa_nwid[1]; + m.w.mmw_netw_id_h = psa.psa_nwid[0]; + mmc_write(base, + (char *) &m.w.mmw_netw_id_l - + (char *) &m, + (unsigned char *) &m.w.mmw_netw_id_l, 2); + mmc_out(base, mmwoff(0, mmw_loopt_sel), 0x00); + } else { + /* Disable NWID in the psa. */ + psa.psa_nwid_select = 0x00; + psa_write(dev, + (char *) &psa.psa_nwid_select - + (char *) &psa, + (unsigned char *) &psa.psa_nwid_select, + 1); + + /* Disable NWID in the mmc (no filtering). */ + mmc_out(base, mmwoff(0, mmw_loopt_sel), + MMW_LOOPT_SEL_DIS_NWID); + } + /* update the Wavelan checksum */ + update_psa_checksum(dev); + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} - case SIOCGIWNWID: - /* Read the NWID */ - psa_read(dev, (char *)psa.psa_nwid - (char *)&psa, - (unsigned char *)psa.psa_nwid, 3); +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get NWID + */ +static int wavelan_get_nwid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Read the NWID. */ + psa_read(dev, + (char *) psa.psa_nwid - (char *) &psa, + (unsigned char *) psa.psa_nwid, 3); #if WIRELESS_EXT > 8 - wrq->u.nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; - wrq->u.nwid.disabled = !(psa.psa_nwid_select); - wrq->u.nwid.fixed = 1; /* Superfluous */ + wrqu->nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; + wrqu->nwid.disabled = !(psa.psa_nwid_select); + wrqu->nwid.fixed = 1; /* Superfluous */ #else /* WIRELESS_EXT > 8 */ - wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; - wrq->u.nwid.on = psa.psa_nwid_select; + wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; + wrq->u.nwid.on = psa.psa_nwid_select; #endif /* WIRELESS_EXT > 8 */ - break; - case SIOCSIWFREQ: - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */ - if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) - ret = wv_set_frequency(base, &(wrq->u.freq)); - else - ret = -EOPNOTSUPP; - break; + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); - case SIOCGIWFREQ: - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) - * (does it work for everybody ? - especially old cards...) */ - if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) - { - unsigned short freq; + return ret; +} - /* Ask the EEprom to read the frequency from the first area */ - fee_read(base, 0x00 /* 1st area - frequency... */, - &freq, 1); - wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000; - wrq->u.freq.e = 1; - } - else - { - psa_read(dev, (char *)&psa.psa_subband - (char *)&psa, - (unsigned char *)&psa.psa_subband, 1); +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set frequency + */ +static int wavelan_set_freq(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + ioaddr_t base = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + unsigned long flags; + int ret; - if(psa.psa_subband <= 4) - { - wrq->u.freq.m = fixed_bands[psa.psa_subband]; - wrq->u.freq.e = (psa.psa_subband != 0); - } - else - ret = -EOPNOTSUPP; + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ + if (!(mmc_in(base, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) + ret = wv_set_frequency(base, &(wrqu->freq)); + else + ret = -EOPNOTSUPP; + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get frequency + */ +static int wavelan_get_freq(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + ioaddr_t base = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). + * Does it work for everybody, especially old cards? */ + if (!(mmc_in(base, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { + unsigned short freq; + + /* Ask the EEPROM to read the frequency from the first area. */ + fee_read(base, 0x00, &freq, 1); + wrqu->freq.m = ((freq >> 5) * 5 + 24000L) * 10000; + wrqu->freq.e = 1; + } else { + psa_read(dev, + (char *) &psa.psa_subband - (char *) &psa, + (unsigned char *) &psa.psa_subband, 1); + + if (psa.psa_subband <= 4) { + wrqu->freq.m = fixed_bands[psa.psa_subband]; + wrqu->freq.e = (psa.psa_subband != 0); + } else + ret = -EOPNOTSUPP; } - break; - case SIOCSIWSENS: - /* Set the level threshold */ + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set level threshold + */ +static int wavelan_set_sens(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + ioaddr_t base = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Set the level threshold. */ #if WIRELESS_EXT > 7 - /* We should complain loudly if wrq->u.sens.fixed = 0, because we - * can't set auto mode... */ - psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F; + /* We should complain loudly if wrqu->sens.fixed = 0, because we + * can't set auto mode... */ + psa.psa_thr_pre_set = wrqu->sens.value & 0x3F; #else /* WIRELESS_EXT > 7 */ - psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F; + psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F; #endif /* WIRELESS_EXT > 7 */ - psa_write(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa, - (unsigned char *)&psa.psa_thr_pre_set, 1); - /* update the Wavelan checksum */ - update_psa_checksum(dev); - mmc_out(base, mmwoff(0, mmw_thr_pre_set), psa.psa_thr_pre_set); - break; + psa_write(dev, + (char *) &psa.psa_thr_pre_set - (char *) &psa, + (unsigned char *) &psa.psa_thr_pre_set, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev); + mmc_out(base, mmwoff(0, mmw_thr_pre_set), + psa.psa_thr_pre_set); - case SIOCGIWSENS: - /* Read the level threshold */ - psa_read(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa, - (unsigned char *)&psa.psa_thr_pre_set, 1); + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get level threshold + */ +static int wavelan_get_sens(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Read the level threshold. */ + psa_read(dev, + (char *) &psa.psa_thr_pre_set - (char *) &psa, + (unsigned char *) &psa.psa_thr_pre_set, 1); #if WIRELESS_EXT > 7 - wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F; - wrq->u.sens.fixed = 1; + wrqu->sens.value = psa.psa_thr_pre_set & 0x3F; + wrqu->sens.fixed = 1; #else /* WIRELESS_EXT > 7 */ - wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F; + wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F; #endif /* WIRELESS_EXT > 7 */ - break; -#if WIRELESS_EXT > 8 - case SIOCSIWENCODE: - /* Set encryption key */ - if(!mmc_encr(base)) - { - ret = -EOPNOTSUPP; - break; - } + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); - /* Basic checking... */ - if(wrq->u.encoding.pointer != (caddr_t) 0) - { - /* Check the size of the key */ - if(wrq->u.encoding.length != 8) - { - ret = -EINVAL; - break; - } + return ret; +} - /* Copy the key in the driver */ - if(copy_from_user(psa.psa_encryption_key, wrq->u.encoding.pointer, - wrq->u.encoding.length)) - { - ret = -EFAULT; - break; - } +#if WIRELESS_EXT > 8 +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set encryption key + */ +static int wavelan_set_encode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + ioaddr_t base = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + unsigned long flags; + psa_t psa; + int ret = 0; - psa.psa_encryption_select = 1; - psa_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa, - (unsigned char *) &psa.psa_encryption_select, 8+1); - - mmc_out(base, mmwoff(0, mmw_encr_enable), - MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE); - mmc_write(base, mmwoff(0, mmw_encr_key), - (unsigned char *) &psa.psa_encryption_key, 8); - } - - if(wrq->u.encoding.flags & IW_ENCODE_DISABLED) - { /* disable encryption */ - psa.psa_encryption_select = 0; - psa_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa, - (unsigned char *) &psa.psa_encryption_select, 1); + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); - mmc_out(base, mmwoff(0, mmw_encr_enable), 0); + /* Check if capable of encryption */ + if (!mmc_encr(base)) { + ret = -EOPNOTSUPP; } - /* update the Wavelan checksum */ - update_psa_checksum(dev); - break; - case SIOCGIWENCODE: - /* Read the encryption key */ - if(!mmc_encr(base)) - { - ret = -EOPNOTSUPP; - break; + /* Check the size of the key */ + if((wrqu->encoding.length != 8) && (wrqu->encoding.length != 0)) { + ret = -EINVAL; } - /* only super-user can see encryption key */ - if(!capable(CAP_NET_ADMIN)) - { - ret = -EPERM; - break; + if(!ret) { + /* Basic checking... */ + if (wrqu->encoding.length == 8) { + /* Copy the key in the driver */ + memcpy(psa.psa_encryption_key, extra, + wrqu->encoding.length); + psa.psa_encryption_select = 1; + + psa_write(dev, + (char *) &psa.psa_encryption_select - + (char *) &psa, + (unsigned char *) &psa. + psa_encryption_select, 8 + 1); + + mmc_out(base, mmwoff(0, mmw_encr_enable), + MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE); + mmc_write(base, mmwoff(0, mmw_encr_key), + (unsigned char *) &psa. + psa_encryption_key, 8); + } + + /* disable encryption */ + if (wrqu->encoding.flags & IW_ENCODE_DISABLED) { + psa.psa_encryption_select = 0; + psa_write(dev, + (char *) &psa.psa_encryption_select - + (char *) &psa, + (unsigned char *) &psa. + psa_encryption_select, 1); + + mmc_out(base, mmwoff(0, mmw_encr_enable), 0); + } + /* update the Wavelan checksum */ + update_psa_checksum(dev); } - /* Basic checking... */ - if(wrq->u.encoding.pointer != (caddr_t) 0) - { - psa_read(dev, (char *) &psa.psa_encryption_select - (char *) &psa, - (unsigned char *) &psa.psa_encryption_select, 1+8); + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); - /* encryption is enabled ? */ - if(psa.psa_encryption_select) - wrq->u.encoding.flags = IW_ENCODE_ENABLED; - else - wrq->u.encoding.flags = IW_ENCODE_DISABLED; - wrq->u.encoding.flags |= mmc_encr(base); + return ret; +} - /* Copy the key to the user buffer */ - wrq->u.encoding.length = 8; - if(copy_to_user(wrq->u.encoding.pointer, psa.psa_encryption_key, 8)) - ret = -EFAULT; +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get encryption key + */ +static int wavelan_get_encode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + ioaddr_t base = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Check if encryption is available */ + if (!mmc_encr(base)) { + ret = -EOPNOTSUPP; + } else { + /* Read the encryption key */ + psa_read(dev, + (char *) &psa.psa_encryption_select - + (char *) &psa, + (unsigned char *) &psa. + psa_encryption_select, 1 + 8); + + /* encryption is enabled ? */ + if (psa.psa_encryption_select) + wrqu->encoding.flags = IW_ENCODE_ENABLED; + else + wrqu->encoding.flags = IW_ENCODE_DISABLED; + wrqu->encoding.flags |= mmc_encr(base); + + /* Copy the key to the user buffer */ + wrqu->encoding.length = 8; + memcpy(extra, psa.psa_encryption_key, wrqu->encoding.length); } - break; + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} #endif /* WIRELESS_EXT > 8 */ #ifdef WAVELAN_ROAMING_EXT #if WIRELESS_EXT > 5 - case SIOCSIWESSID: - /* Check if disable */ - if(wrq->u.data.flags == 0) - lp->filter_domains = 0; - else - /* Basic checking... */ - if(wrq->u.data.pointer != (caddr_t) 0) - { - char essid[IW_ESSID_MAX_SIZE + 1]; - char * endp; - - /* Check the size of the string */ - if(wrq->u.data.length > IW_ESSID_MAX_SIZE + 1) - { - ret = -E2BIG; - break; - } - - /* Copy the string in the driver */ - if(copy_from_user(essid, wrq->u.data.pointer, wrq->u.data.length)) - { - ret = -EFAULT; - break; - } - essid[IW_ESSID_MAX_SIZE] = '\0'; +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set ESSID (domain) + */ +static int wavelan_set_essid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Check if disable */ + if(wrqu->data.flags == 0) + lp->filter_domains = 0; + else { + char essid[IW_ESSID_MAX_SIZE + 1]; + char * endp; + + /* Terminate the string */ + memcpy(essid, extra, wrqu->data.length); + essid[IW_ESSID_MAX_SIZE] = '\0'; #ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG "SetEssid : ``%s''\n", essid); + printk(KERN_DEBUG "SetEssid : ``%s''\n", essid); #endif /* DEBUG_IOCTL_INFO */ - /* Convert to a number (note : Wavelan specific) */ - lp->domain_id = simple_strtoul(essid, &endp, 16); - /* Has it worked ? */ - if(endp > essid) - lp->filter_domains = 1; - else - { - lp->filter_domains = 0; - ret = -EINVAL; - } - } - break; + /* Convert to a number (note : Wavelan specific) */ + lp->domain_id = simple_strtoul(essid, &endp, 16); + /* Has it worked ? */ + if(endp > essid) + lp->filter_domains = 1; + else { + lp->filter_domains = 0; + ret = -EINVAL; + } + } - case SIOCGIWESSID: - /* Basic checking... */ - if(wrq->u.data.pointer != (caddr_t) 0) - { - char essid[IW_ESSID_MAX_SIZE + 1]; + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); - /* Is the domain ID active ? */ - wrq->u.data.flags = lp->filter_domains; + return ret; +} - /* Copy Domain ID into a string (Wavelan specific) */ - /* Sound crazy, be we can't have a snprintf in the kernel !!! */ - sprintf(essid, "%lX", lp->domain_id); - essid[IW_ESSID_MAX_SIZE] = '\0'; +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get ESSID (domain) + */ +static int wavelan_get_essid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ - /* Set the length */ - wrq->u.data.length = strlen(essid) + 1; + /* Is the domain ID active ? */ + wrqu->data.flags = lp->filter_domains; - /* Copy structure to the user buffer */ - if(copy_to_user(wrq->u.data.pointer, essid, wrq->u.data.length)) - ret = -EFAULT; - } - break; + /* Copy Domain ID into a string (Wavelan specific) */ + /* Sound crazy, be we can't have a snprintf in the kernel !!! */ + sprintf(extra, "%lX", lp->domain_id); + extra[IW_ESSID_MAX_SIZE] = '\0'; - case SIOCSIWAP: + /* Set the length */ + wrqu->data.length = strlen(extra) + 1; + + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set AP address + */ +static int wavelan_set_wap(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ #ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG "Set AP to : %02X:%02X:%02X:%02X:%02X:%02X\n", - wrq->u.ap_addr.sa_data[0], - wrq->u.ap_addr.sa_data[1], - wrq->u.ap_addr.sa_data[2], - wrq->u.ap_addr.sa_data[3], - wrq->u.ap_addr.sa_data[4], - wrq->u.ap_addr.sa_data[5]); + printk(KERN_DEBUG "Set AP to : %02X:%02X:%02X:%02X:%02X:%02X\n", + wrqu->ap_addr.sa_data[0], + wrqu->ap_addr.sa_data[1], + wrqu->ap_addr.sa_data[2], + wrqu->ap_addr.sa_data[3], + wrqu->ap_addr.sa_data[4], + wrqu->ap_addr.sa_data[5]); #endif /* DEBUG_IOCTL_INFO */ - ret = -EOPNOTSUPP; /* Not supported yet */ - break; + return -EOPNOTSUPP; +} - case SIOCGIWAP: - /* Should get the real McCoy instead of own Ethernet address */ - memcpy(wrq->u.ap_addr.sa_data, dev->dev_addr, WAVELAN_ADDR_SIZE); - wrq->u.ap_addr.sa_family = ARPHRD_ETHER; +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get AP address + */ +static int wavelan_get_wap(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + /* Should get the real McCoy instead of own Ethernet address */ + memcpy(wrqu->ap_addr.sa_data, dev->dev_addr, WAVELAN_ADDR_SIZE); + wrqu->ap_addr.sa_family = ARPHRD_ETHER; - ret = -EOPNOTSUPP; /* Not supported yet */ - break; + return -EOPNOTSUPP; +} #endif /* WIRELESS_EXT > 5 */ #endif /* WAVELAN_ROAMING_EXT */ #if WIRELESS_EXT > 8 #ifdef WAVELAN_ROAMING - case SIOCSIWMODE: - switch(wrq->u.mode) - { +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set mode + */ +static int wavelan_set_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Check mode */ + switch(wrqu->mode) { case IW_MODE_ADHOC: - if(do_roaming) - { - wv_roam_cleanup(dev); - do_roaming = 0; - } - break; + if(do_roaming) { + wv_roam_cleanup(dev); + do_roaming = 0; + } + break; case IW_MODE_INFRA: - if(!do_roaming) - { - wv_roam_init(dev); - do_roaming = 1; - } - break; + if(!do_roaming) { + wv_roam_init(dev); + do_roaming = 1; + } + break; default: - ret = -EINVAL; + ret = -EINVAL; } - break; - case SIOCGIWMODE: - if(do_roaming) - wrq->u.mode = IW_MODE_INFRA; - else - wrq->u.mode = IW_MODE_ADHOC; - break; + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get mode + */ +static int wavelan_get_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + if(do_roaming) + wrqu->mode = IW_MODE_INFRA; + else + wrqu->mode = IW_MODE_ADHOC; + + return 0; +} #endif /* WAVELAN_ROAMING */ #endif /* WIRELESS_EXT > 8 */ - case SIOCGIWRANGE: - /* Basic checking... */ - if(wrq->u.data.pointer != (caddr_t) 0) - { - struct iw_range range; +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get range info + */ +static int wavelan_get_range(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + ioaddr_t base = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + struct iw_range *range = (struct iw_range *) extra; + unsigned long flags; + int ret = 0; - /* Set the length (very important for backward compatibility) */ - wrq->u.data.length = sizeof(struct iw_range); + /* Set the length (very important for backward compatibility) */ + wrqu->data.length = sizeof(struct iw_range); - /* Set all the info we don't care or don't know about to zero */ - memset(&range, 0, sizeof(range)); + /* Set all the info we don't care or don't know about to zero */ + memset(range, 0, sizeof(struct iw_range)); #if WIRELESS_EXT > 10 - /* Set the Wireless Extension versions */ - range.we_version_compiled = WIRELESS_EXT; - range.we_version_source = 9; /* Nothing for us in v10 and v11 */ + /* Set the Wireless Extension versions */ + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 9; #endif /* WIRELESS_EXT > 10 */ - /* Set information in the range struct */ - range.throughput = 1.4 * 1000 * 1000; /* don't argue on this ! */ - range.min_nwid = 0x0000; - range.max_nwid = 0xFFFF; - - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */ - if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) - { - range.num_channels = 10; - range.num_frequency = wv_frequency_list(base, range.freq, - IW_MAX_FREQUENCIES); - } - else - range.num_channels = range.num_frequency = 0; - - range.sensitivity = 0x3F; - range.max_qual.qual = MMR_SGNL_QUAL; - range.max_qual.level = MMR_SIGNAL_LVL; - range.max_qual.noise = MMR_SILENCE_LVL; + /* Set information in the range struct. */ + range->throughput = 1.4 * 1000 * 1000; /* don't argue on this ! */ + range->min_nwid = 0x0000; + range->max_nwid = 0xFFFF; + + range->sensitivity = 0x3F; + range->max_qual.qual = MMR_SGNL_QUAL; + range->max_qual.level = MMR_SIGNAL_LVL; + range->max_qual.noise = MMR_SILENCE_LVL; #if WIRELESS_EXT > 11 - range.avg_qual.qual = MMR_SGNL_QUAL; /* Always max */ - /* Need to get better values for those two */ - range.avg_qual.level = 30; - range.avg_qual.noise = 8; + range->avg_qual.qual = MMR_SGNL_QUAL; /* Always max */ + /* Need to get better values for those two */ + range->avg_qual.level = 30; + range->avg_qual.noise = 8; #endif /* WIRELESS_EXT > 11 */ #if WIRELESS_EXT > 7 - range.num_bitrates = 1; - range.bitrate[0] = 2000000; /* 2 Mb/s */ + range->num_bitrates = 1; + range->bitrate[0] = 2000000; /* 2 Mb/s */ #endif /* WIRELESS_EXT > 7 */ + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ + if (!(mmc_in(base, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { + range->num_channels = 10; + range->num_frequency = wv_frequency_list(base, range->freq, + IW_MAX_FREQUENCIES); + } else + range->num_channels = range->num_frequency = 0; + #if WIRELESS_EXT > 8 - /* Encryption supported ? */ - if(mmc_encr(base)) - { - range.encoding_size[0] = 8; /* DES = 64 bits key */ - range.num_encoding_sizes = 1; - range.max_encoding_tokens = 1; /* Only one key possible */ - } - else - { - range.num_encoding_sizes = 0; - range.max_encoding_tokens = 0; - } + /* Encryption supported ? */ + if (mmc_encr(base)) { + range->encoding_size[0] = 8; /* DES = 64 bits key */ + range->num_encoding_sizes = 1; + range->max_encoding_tokens = 1; /* Only one key possible */ + } else { + range->num_encoding_sizes = 0; + range->max_encoding_tokens = 0; + } #endif /* WIRELESS_EXT > 8 */ - /* Copy structure to the user buffer */ - if(copy_to_user(wrq->u.data.pointer, &range, - sizeof(struct iw_range))) - ret = -EFAULT; + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +#ifdef WIRELESS_SPY +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set spy list + */ +static int wavelan_set_spy(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + struct sockaddr *address = (struct sockaddr *) extra; + int i; + int ret = 0; + + /* Disable spy while we copy the addresses. + * As we don't disable interrupts, we need to do this */ + lp->spy_number = 0; + + /* Are there are addresses to copy? */ + if (wrqu->data.length > 0) { + /* Copy addresses to the lp structure. */ + for (i = 0; i < wrqu->data.length; i++) { + memcpy(lp->spy_address[i], address[i].sa_data, + WAVELAN_ADDR_SIZE); + } + + /* Reset structure. */ + memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY); + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG + "SetSpy: set of new addresses is: \n"); + for (i = 0; i < wrqu->data.length; i++) + printk(KERN_DEBUG + "%02X:%02X:%02X:%02X:%02X:%02X \n", + lp->spy_address[i][0], + lp->spy_address[i][1], + lp->spy_address[i][2], + lp->spy_address[i][3], + lp->spy_address[i][4], + lp->spy_address[i][5]); +#endif /* DEBUG_IOCTL_INFO */ + } + + /* Now we can set the number of addresses */ + lp->spy_number = wrqu->data.length; + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get spy list + */ +static int wavelan_get_spy(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + struct sockaddr *address = (struct sockaddr *) extra; + int i; + + /* Set the number of addresses */ + wrqu->data.length = lp->spy_number; + + /* Copy addresses from the lp structure. */ + for (i = 0; i < lp->spy_number; i++) { + memcpy(address[i].sa_data, + lp->spy_address[i], + WAVELAN_ADDR_SIZE); + address[i].sa_family = AF_UNIX; + } + /* Copy stats to the user buffer (just after). */ + if(lp->spy_number > 0) + memcpy(extra + (sizeof(struct sockaddr) * lp->spy_number), + lp->spy_stat, sizeof(iw_qual) * lp->spy_number); + + /* Reset updated flags. */ + for (i = 0; i < lp->spy_number; i++) + lp->spy_stat[i].updated = 0x0; + + return(0); +} +#endif /* WIRELESS_SPY */ + +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : set quality threshold + */ +static int wavelan_set_qthr(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + ioaddr_t base = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + psa.psa_quality_thr = *(extra) & 0x0F; + psa_write(dev, + (char *) &psa.psa_quality_thr - (char *) &psa, + (unsigned char *) &psa.psa_quality_thr, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev); + mmc_out(base, mmwoff(0, mmw_quality_thr), + psa.psa_quality_thr); + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : get quality threshold + */ +static int wavelan_get_qthr(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + psa_read(dev, + (char *) &psa.psa_quality_thr - (char *) &psa, + (unsigned char *) &psa.psa_quality_thr, 1); + *(extra) = psa.psa_quality_thr & 0x0F; + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return 0; +} + +#ifdef WAVELAN_ROAMING +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : set roaming + */ +static int wavelan_set_roam(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + unsigned long flags; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Note : should check if user == root */ + if(do_roaming && (*extra)==0) + wv_roam_cleanup(dev); + else if(do_roaming==0 && (*extra)!=0) + wv_roam_init(dev); + + do_roaming = (*extra); + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : get quality threshold + */ +static int wavelan_get_roam(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + *(extra) = do_roaming; + + return 0; +} +#endif /* WAVELAN_ROAMING */ + +#ifdef HISTOGRAM +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : set histogram + */ +static int wavelan_set_histo(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + + /* Check the number of intervals. */ + if (wrqu->data.length > 16) { + return(-E2BIG); } + + /* Disable histo while we copy the addresses. + * As we don't disable interrupts, we need to do this */ + lp->his_number = 0; + + /* Are there ranges to copy? */ + if (wrqu->data.length > 0) { + /* Copy interval ranges to the driver */ + memcpy(lp->his_range, extra, wrqu->data.length); + + { + int i; + printk(KERN_DEBUG "Histo :"); + for(i = 0; i < wrqu->data.length; i++) + printk(" %d", lp->his_range[i]); + printk("\n"); + } + + /* Reset result structure. */ + memset(lp->his_sum, 0x00, sizeof(long) * 16); + } + + /* Now we can set the number of ranges */ + lp->his_number = wrqu->data.length; + + return(0); +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : get histogram + */ +static int wavelan_get_histo(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + + /* Set the number of intervals. */ + wrqu->data.length = lp->his_number; + + /* Give back the distribution statistics */ + if(lp->his_number > 0) + memcpy(extra, lp->his_sum, sizeof(long) * lp->his_number); + + return(0); +} +#endif /* HISTOGRAM */ + +/*------------------------------------------------------------------*/ +/* + * Structures to export the Wireless Handlers + */ + +static const struct iw_priv_args wavelan_private_args[] = { +/*{ cmd, set_args, get_args, name } */ + { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" }, + { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" }, + { SIOCSIPROAM, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setroam" }, + { SIOCGIPROAM, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getroam" }, + { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" }, + { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, +}; + +#if WIRELESS_EXT > 12 + +static const iw_handler wavelan_handler[] = +{ + NULL, /* SIOCSIWNAME */ + wavelan_get_name, /* SIOCGIWNAME */ + wavelan_set_nwid, /* SIOCSIWNWID */ + wavelan_get_nwid, /* SIOCGIWNWID */ + wavelan_set_freq, /* SIOCSIWFREQ */ + wavelan_get_freq, /* SIOCGIWFREQ */ +#ifdef WAVELAN_ROAMING + wavelan_set_mode, /* SIOCSIWMODE */ + wavelan_get_mode, /* SIOCGIWMODE */ +#else /* WAVELAN_ROAMING */ + NULL, /* SIOCSIWMODE */ + NULL, /* SIOCGIWMODE */ +#endif /* WAVELAN_ROAMING */ + wavelan_set_sens, /* SIOCSIWSENS */ + wavelan_get_sens, /* SIOCGIWSENS */ + NULL, /* SIOCSIWRANGE */ + wavelan_get_range, /* SIOCGIWRANGE */ + NULL, /* SIOCSIWPRIV */ + NULL, /* SIOCGIWPRIV */ + NULL, /* SIOCSIWSTATS */ + NULL, /* SIOCGIWSTATS */ +#ifdef WIRELESS_SPY + wavelan_set_spy, /* SIOCSIWSPY */ + wavelan_get_spy, /* SIOCGIWSPY */ +#else /* WIRELESS_SPY */ + NULL, /* SIOCSIWSPY */ + NULL, /* SIOCGIWSPY */ +#endif /* WIRELESS_SPY */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ +#ifdef WAVELAN_ROAMING_EXT + wavelan_set_wap, /* SIOCSIWAP */ + wavelan_get_wap, /* SIOCGIWAP */ + NULL, /* -- hole -- */ + NULL, /* SIOCGIWAPLIST */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + wavelan_set_essid, /* SIOCSIWESSID */ + wavelan_get_essid, /* SIOCGIWESSID */ +#else /* WAVELAN_ROAMING_EXT */ + NULL, /* SIOCSIWAP */ + NULL, /* SIOCGIWAP */ + NULL, /* -- hole -- */ + NULL, /* SIOCGIWAPLIST */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + NULL, /* SIOCSIWESSID */ + NULL, /* SIOCGIWESSID */ +#endif /* WAVELAN_ROAMING_EXT */ +#if WIRELESS_EXT > 8 + NULL, /* SIOCSIWNICKN */ + NULL, /* SIOCGIWNICKN */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + NULL, /* SIOCSIWRATE */ + NULL, /* SIOCGIWRATE */ + NULL, /* SIOCSIWRTS */ + NULL, /* SIOCGIWRTS */ + NULL, /* SIOCSIWFRAG */ + NULL, /* SIOCGIWFRAG */ + NULL, /* SIOCSIWTXPOW */ + NULL, /* SIOCGIWTXPOW */ + NULL, /* SIOCSIWRETRY */ + NULL, /* SIOCGIWRETRY */ + wavelan_set_encode, /* SIOCSIWENCODE */ + wavelan_get_encode, /* SIOCGIWENCODE */ +#endif /* WIRELESS_EXT > 8 */ +}; + +static const iw_handler wavelan_private_handler[] = +{ + wavelan_set_qthr, /* SIOCIWFIRSTPRIV */ + wavelan_get_qthr, /* SIOCIWFIRSTPRIV + 1 */ +#ifdef WAVELAN_ROAMING + wavelan_set_roam, /* SIOCIWFIRSTPRIV + 2 */ + wavelan_get_roam, /* SIOCIWFIRSTPRIV + 3 */ +#else /* WAVELAN_ROAMING */ + NULL, /* SIOCIWFIRSTPRIV + 2 */ + NULL, /* SIOCIWFIRSTPRIV + 3 */ +#endif /* WAVELAN_ROAMING */ +#ifdef HISTOGRAM + wavelan_set_histo, /* SIOCIWFIRSTPRIV + 4 */ + wavelan_get_histo, /* SIOCIWFIRSTPRIV + 5 */ +#endif /* HISTOGRAM */ +}; + +static const struct iw_handler_def wavelan_handler_def = +{ + num_standard: sizeof(wavelan_handler)/sizeof(iw_handler), + num_private: sizeof(wavelan_private_handler)/sizeof(iw_handler), + num_private_args: sizeof(wavelan_private_args)/sizeof(struct iw_priv_args), + standard: (iw_handler *) wavelan_handler, + private: (iw_handler *) wavelan_private_handler, + private_args: (struct iw_priv_args *) wavelan_private_args, +}; + +#else /* WIRELESS_EXT > 12 */ +/*------------------------------------------------------------------*/ +/* + * Perform ioctl : config & info stuff + * This is here that are treated the wireless extensions (iwconfig) + */ +static int +wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */ + struct ifreq * rq, /* Data passed */ + int cmd) /* Ioctl number */ +{ + struct iwreq * wrq = (struct iwreq *) rq; + int ret = 0; + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd); +#endif + + /* Look what is the request */ + switch(cmd) + { + /* --------------- WIRELESS EXTENSIONS --------------- */ + + case SIOCGIWNAME: + wavelan_get_name(dev, NULL, &(wrq->u), NULL); break; - case SIOCGIWPRIV: - /* Basic checking... */ - if(wrq->u.data.pointer != (caddr_t) 0) - { - struct iw_priv_args priv[] = - { /* cmd, set_args, get_args, name */ - { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" }, - { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" }, - { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" }, - { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, - { SIOCSIPROAM, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1 , 0, "setroam" }, - { SIOCGIPROAM, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getroam" }, - }; + case SIOCSIWNWID: + ret = wavelan_set_nwid(dev, NULL, &(wrq->u), NULL); + break; - /* Set the number of ioctl available */ - wrq->u.data.length = 6; + case SIOCGIWNWID: + ret = wavelan_get_nwid(dev, NULL, &(wrq->u), NULL); + break; - /* Copy structure to the user buffer */ - if(copy_to_user(wrq->u.data.pointer, (u_char *) priv, - sizeof(priv))) + case SIOCSIWFREQ: + ret = wavelan_set_freq(dev, NULL, &(wrq->u), NULL); + break; + + case SIOCGIWFREQ: + ret = wavelan_get_freq(dev, NULL, &(wrq->u), NULL); + break; + + case SIOCSIWSENS: + ret = wavelan_set_sens(dev, NULL, &(wrq->u), NULL); + break; + + case SIOCGIWSENS: + ret = wavelan_get_sens(dev, NULL, &(wrq->u), NULL); + break; + +#if WIRELESS_EXT > 8 + case SIOCSIWENCODE: + { + char keybuf[8]; + if (wrq->u.encoding.pointer) { + /* We actually have a key to set */ + if (wrq->u.encoding.length != 8) { + ret = -EINVAL; + break; + } + if (copy_from_user(keybuf, + wrq->u.encoding.pointer, + wrq->u.encoding.length)) { ret = -EFAULT; + break; + } + } else if (wrq->u.encoding.length != 0) { + ret = -EINVAL; + break; } + ret = wavelan_set_encode(dev, NULL, &(wrq->u), keybuf); + } break; -#ifdef WIRELESS_SPY - case SIOCSIWSPY: - /* Set the spy list */ + case SIOCGIWENCODE: + if (! capable(CAP_NET_ADMIN)) { + ret = -EPERM; + break; + } + { + char keybuf[8]; + ret = wavelan_get_encode(dev, NULL, + &(wrq->u), + keybuf); + if (wrq->u.encoding.pointer) { + if (copy_to_user(wrq->u.encoding.pointer, + keybuf, + wrq->u.encoding.length)) + ret = -EFAULT; + } + } + break; +#endif /* WIRELESS_EXT > 8 */ - /* Check the number of addresses */ - if(wrq->u.data.length > IW_MAX_SPY) - { +#ifdef WAVELAN_ROAMING_EXT +#if WIRELESS_EXT > 5 + case SIOCSIWESSID: + { + char essidbuf[IW_ESSID_MAX_SIZE+1]; + if (wrq->u.essid.length > IW_ESSID_MAX_SIZE) { ret = -E2BIG; break; } - lp->spy_number = wrq->u.data.length; - - /* If there is some addresses to copy */ - if(lp->spy_number > 0) - { - struct sockaddr address[IW_MAX_SPY]; - int i; - - /* Copy addresses to the driver */ - if(copy_from_user(address, wrq->u.data.pointer, - sizeof(struct sockaddr) * lp->spy_number)) - { - ret = -EFAULT; - break; - } + if (copy_from_user(essidbuf, wrq->u.essid.pointer, + wrq->u.essid.length)) { + ret = -EFAULT; + break; + } + ret = wavelan_set_essid(dev, NULL, + &(wrq->u), + essidbuf); + } + break; - /* Copy addresses to the lp structure */ - for(i = 0; i < lp->spy_number; i++) - { - memcpy(lp->spy_address[i], address[i].sa_data, - WAVELAN_ADDR_SIZE); - } + case SIOCGIWESSID: + { + char essidbuf[IW_ESSID_MAX_SIZE+1]; + ret = wavelan_get_essid(dev, NULL, + &(wrq->u), + essidbuf); + if (wrq->u.essid.pointer) + if ( copy_to_user(wrq->u.essid.pointer, + essidbuf, + wrq->u.essid.length) ) + ret = -EFAULT; + } + break; - /* Reset structure... */ - memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY); + case SIOCSIWAP: + ret = wavelan_set_wap(dev, NULL, &(wrq->u), NULL); + break; -#ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG "SetSpy - Set of new addresses is :\n"); - for(i = 0; i < wrq->u.data.length; i++) - printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X\n", - lp->spy_address[i][0], - lp->spy_address[i][1], - lp->spy_address[i][2], - lp->spy_address[i][3], - lp->spy_address[i][4], - lp->spy_address[i][5]); -#endif /* DEBUG_IOCTL_INFO */ - } + case SIOCGIWAP: + ret = wavelan_get_wap(dev, NULL, &(wrq->u), NULL); + break; +#endif /* WIRELESS_EXT > 5 */ +#endif /* WAVELAN_ROAMING_EXT */ +#if WIRELESS_EXT > 8 +#ifdef WAVELAN_ROAMING + case SIOCSIWMODE: + ret = wavelan_set_mode(dev, NULL, &(wrq->u), NULL); break; - case SIOCGIWSPY: - /* Get the spy list and spy stats */ + case SIOCGIWMODE: + ret = wavelan_get_mode(dev, NULL, &(wrq->u), NULL); + break; +#endif /* WAVELAN_ROAMING */ +#endif /* WIRELESS_EXT > 8 */ - /* Set the number of addresses */ - wrq->u.data.length = lp->spy_number; + case SIOCGIWRANGE: + { + struct iw_range range; + ret = wavelan_get_range(dev, NULL, + &(wrq->u), + (char *) &range); + if (copy_to_user(wrq->u.data.pointer, &range, + sizeof(struct iw_range))) + ret = -EFAULT; + } + break; - /* If the user want to have the addresses back... */ - if((lp->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0)) + case SIOCGIWPRIV: + /* Basic checking... */ + if(wrq->u.data.pointer != (caddr_t) 0) { - struct sockaddr address[IW_MAX_SPY]; - int i; - - /* Copy addresses from the lp structure */ - for(i = 0; i < lp->spy_number; i++) - { - memcpy(address[i].sa_data, lp->spy_address[i], - WAVELAN_ADDR_SIZE); - address[i].sa_family = ARPHRD_ETHER; - } - - /* Copy addresses to the user buffer */ - if(copy_to_user(wrq->u.data.pointer, address, - sizeof(struct sockaddr) * lp->spy_number)) - { - ret = -EFAULT; - break; - } + /* Set the number of ioctl available */ + wrq->u.data.length = sizeof(wavelan_private_args) / sizeof(wavelan_private_args[0]); - /* Copy stats to the user buffer (just after) */ - if(copy_to_user(wrq->u.data.pointer + - (sizeof(struct sockaddr) * lp->spy_number), - lp->spy_stat, sizeof(iw_qual) * lp->spy_number)) - { - ret = -EFAULT; - break; - } + /* Copy structure to the user buffer */ + if(copy_to_user(wrq->u.data.pointer, (u_char *) wavelan_private_args, + sizeof(wavelan_private_args))) + ret = -EFAULT; + } + break; - /* Reset updated flags */ - for(i = 0; i < lp->spy_number; i++) - lp->spy_stat[i].updated = 0x0; - } /* if(pointer != NULL) */ +#ifdef WIRELESS_SPY + case SIOCSIWSPY: + { + struct sockaddr address[IW_MAX_SPY]; + /* Check the number of addresses */ + if (wrq->u.data.length > IW_MAX_SPY) { + ret = -E2BIG; + break; + } + /* Get the data in the driver */ + if (wrq->u.data.pointer) { + if (copy_from_user((char *) address, + wrq->u.data.pointer, + sizeof(struct sockaddr) * + wrq->u.data.length)) { + ret = -EFAULT; + break; + } + } else if (wrq->u.data.length != 0) { + ret = -EINVAL; + break; + } + ret = wavelan_set_spy(dev, NULL, &(wrq->u), + (char *) address); + } + break; + case SIOCGIWSPY: + { + char buffer[IW_MAX_SPY * (sizeof(struct sockaddr) + + sizeof(struct iw_quality))]; + ret = wavelan_get_spy(dev, NULL, &(wrq->u), + buffer); + if (wrq->u.data.pointer) { + if (copy_to_user(wrq->u.data.pointer, + buffer, + (wrq->u.data.length * + (sizeof(struct sockaddr) + + sizeof(struct iw_quality))) + )) + ret = -EFAULT; + } + } break; #endif /* WIRELESS_SPY */ @@ -2446,34 +3095,21 @@ ret = -EPERM; break; } - psa.psa_quality_thr = *(wrq->u.name) & 0x0F; - psa_write(dev, (char *)&psa.psa_quality_thr - (char *)&psa, - (unsigned char *)&psa.psa_quality_thr, 1); - /* update the Wavelan checksum */ - update_psa_checksum(dev); - mmc_out(base, mmwoff(0, mmw_quality_thr), psa.psa_quality_thr); + ret = wavelan_set_qthr(dev, NULL, &(wrq->u), NULL); break; case SIOCGIPQTHR: - psa_read(dev, (char *)&psa.psa_quality_thr - (char *)&psa, - (unsigned char *)&psa.psa_quality_thr, 1); - *(wrq->u.name) = psa.psa_quality_thr & 0x0F; + ret = wavelan_get_qthr(dev, NULL, &(wrq->u), NULL); break; #ifdef WAVELAN_ROAMING case SIOCSIPROAM: /* Note : should check if user == root */ - if(do_roaming && (*wrq->u.name)==0) - wv_roam_cleanup(dev); - else if(do_roaming==0 && (*wrq->u.name)!=0) - wv_roam_init(dev); - - do_roaming = (*wrq->u.name); - + ret = wavelan_set_roam(dev, NULL, &(wrq->u), NULL); break; case SIOCGIPROAM: - *(wrq->u.name) = do_roaming; + ret = wavelan_get_roam(dev, NULL, &(wrq->u), NULL); break; #endif /* WAVELAN_ROAMING */ @@ -2484,44 +3120,44 @@ { ret = -EPERM; } - - /* Check the number of intervals */ - if(wrq->u.data.length > 16) - { - ret = -E2BIG; - break; + { + char buffer[16]; + /* Check the number of intervals */ + if(wrq->u.data.length > 16) + { + ret = -E2BIG; + break; } - lp->his_number = wrq->u.data.length; - - /* If there is some addresses to copy */ - if(lp->his_number > 0) - { - /* Copy interval ranges to the driver */ - if(copy_from_user(lp->his_range, wrq->u.data.pointer, - sizeof(char) * lp->his_number)) - { - ret = -EFAULT; - break; - } - - /* Reset structure... */ - memset(lp->his_sum, 0x00, sizeof(long) * 16); + /* Get the data in the driver */ + if (wrq->u.data.pointer) { + if (copy_from_user(buffer, + wrq->u.data.pointer, + sizeof(struct sockaddr) * + wrq->u.data.length)) { + ret = -EFAULT; + break; + } + } else if (wrq->u.data.length != 0) { + ret = -EINVAL; + break; } + ret = wavelan_set_histo(dev, NULL, &(wrq->u), + buffer); + } break; case SIOCGIPHISTO: - /* Set the number of intervals */ - wrq->u.data.length = lp->his_number; - - /* Give back the distribution statistics */ - if((lp->his_number > 0) && (wrq->u.data.pointer != (caddr_t) 0)) - { - /* Copy data to the user buffer */ - if(copy_to_user(wrq->u.data.pointer, lp->his_sum, - sizeof(long) * lp->his_number)) + { + long buffer[16]; + ret = wavelan_get_histo(dev, NULL, &(wrq->u), + (char *) buffer); + if (wrq->u.data.pointer) { + if (copy_to_user(wrq->u.data.pointer, + buffer, + (wrq->u.data.length * sizeof(long)))) ret = -EFAULT; - - } /* if(pointer != NULL) */ + } + } break; #endif /* HISTOGRAM */ @@ -2531,14 +3167,12 @@ ret = -EOPNOTSUPP; } - /* ReEnable interrupts & restore flags */ - wv_splx(lp, &flags); - #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name); #endif return ret; } +#endif /* WIRELESS_EXT > 12 */ /*------------------------------------------------------------------*/ /* @@ -2559,7 +3193,7 @@ #endif /* Disable interrupts & save flags */ - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); wstats = &lp->wstats; @@ -2585,7 +3219,7 @@ wstats->discard.misc = 0L; /* ReEnable interrupts & restore flags */ - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name); @@ -2921,7 +3555,7 @@ printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length); #endif - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); /* Check if we need some padding */ if(clen < ETH_ZLEN) @@ -2951,7 +3585,7 @@ /* Keep stats up to date */ lp->stats.tx_bytes += length; - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); #ifdef DEBUG_TX_INFO wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write"); @@ -2991,9 +3625,9 @@ * we can do it now */ if(lp->reconfig_82593) { - wv_splhi(lp, &flags); /* Disable interrupts */ + spin_lock_irqsave(&lp->spinlock, flags); /* Disable interrupts */ wv_82593_config(dev); - wv_splx(lp, &flags); /* Re-enable interrupts */ + spin_unlock_irqrestore(&lp->spinlock, flags); /* Re-enable interrupts */ /* Note : the configure procedure was totally synchronous, * so the Tx buffer is now free */ } @@ -3230,7 +3864,7 @@ printk(KERN_DEBUG "%s: ->wv_ru_stop()\n", dev->name); #endif - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); /* First, send the LAN controller a stop receive command */ wv_82593_cmd(dev, "wv_graceful_shutdown(): stop-rcv", @@ -3255,7 +3889,7 @@ } while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0)); - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); /* If there was a problem */ if(spin <= 0) @@ -3299,7 +3933,7 @@ if(!wv_ru_stop(dev)) return FALSE; - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); /* Now we know that no command is being executed. */ @@ -3354,7 +3988,7 @@ } #endif - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name); @@ -3630,7 +4264,7 @@ return FALSE; /* Disable interrupts */ - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); /* Disguised goto ;-) */ do @@ -3695,7 +4329,7 @@ while(0); /* Re-enable interrupts */ - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: <-wv_hw_config()\n", dev->name); @@ -4021,7 +4655,7 @@ /* Prevent reentrancy. We need to do that because we may have * multiple interrupt handler running concurently. - * It is safe because wv_splhi() disable interrupts before aquiring + * It is safe because interrupts are disabled before aquiring * the spinlock. */ spin_lock(&lp->spinlock); @@ -4254,7 +4888,7 @@ dev->name); #endif - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); /* Ask to abort the current command */ outb(OP0_ABORT, LCCR(base)); @@ -4265,7 +4899,7 @@ aborted = TRUE; /* Release spinlock here so that wv_hw_reset() can grab it */ - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); /* Check if we were successful in aborting it */ if(!aborted) @@ -4530,7 +5164,11 @@ dev->watchdog_timeo = WATCHDOG_JIFFIES; #ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ +#if WIRELESS_EXT > 12 + dev->wireless_handlers = (struct iw_handler_def *)&wavelan_handler_def; +#else /* WIRELESS_EXT > 12 */ dev->do_ioctl = wavelan_ioctl; /* wireless extensions */ +#endif /* WIRELESS_EXT > 12 */ dev->get_wireless_stats = wavelan_get_wireless_stats; #endif diff -Nru a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h --- a/drivers/net/wireless/wavelan_cs.p.h Tue Feb 26 11:57:58 2002 +++ b/drivers/net/wireless/wavelan_cs.p.h Tue Feb 26 11:57:58 2002 @@ -394,6 +394,12 @@ * o control first busy loop in wv_82593_cmd() * o Extend spinlock protection in wv_hw_config() * + * Changes made for release in 3.1.33 : + * ---------------------------------- + * - Optional use new driver API for Wireless Extensions : + * o got rid of wavelan_ioctl() + * o use a bunch of iw_handler instead + * * Wishes & dreams: * ---------------- * - Cleanup and integrate the roaming code @@ -430,6 +436,9 @@ #ifdef CONFIG_NET_RADIO #include /* Wireless extensions */ +#if WIRELESS_EXT > 12 +#include +#endif /* WIRELESS_EXT > 12 */ #endif /* Pcmcia headers that we need */ @@ -498,7 +507,7 @@ /************************ CONSTANTS & MACROS ************************/ #ifdef DEBUG_VERSION_SHOW -static const char *version = "wavelan_cs.c : v23 (SMP + wireless extensions) 20/12/00\n"; +static const char *version = "wavelan_cs.c : v24 (SMP + wireless extensions) 11/1/02\n"; #endif /* Watchdog temporisation */ @@ -523,8 +532,8 @@ #define SIOCSIPROAM SIOCIWFIRSTPRIV + 2 /* Set roaming state */ #define SIOCGIPROAM SIOCIWFIRSTPRIV + 3 /* Get roaming state */ -#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 6 /* Set histogram ranges */ -#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 7 /* Get histogram values */ +#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 4 /* Set histogram ranges */ +#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 5 /* Get histogram values */ /*************************** WaveLAN Roaming **************************/ #ifdef WAVELAN_ROAMING /* Conditional compile, see above in options */ @@ -589,6 +598,16 @@ typedef struct net_local net_local; typedef struct timer_list timer_list; +#if WIRELESS_EXT <= 12 +/* Wireless extensions backward compatibility */ +/* Part of iw_handler prototype we need */ +struct iw_request_info +{ + __u16 cmd; /* Wireless Extension command */ + __u16 flags; /* More to come ;-) */ +}; +#endif /* WIRELESS_EXT <= 12 */ + /* Basic types */ typedef u_char mac_addr[WAVELAN_ADDR_SIZE]; /* Hardware address */ @@ -661,12 +680,6 @@ #endif /* WAVELAN_ROAMING */ /* ----------------------- MISC SUBROUTINES ------------------------ */ -static inline void - wv_splhi(net_local *, /* Disable interrupts */ - unsigned long *); /* flags */ -static inline void - wv_splx(net_local *, /* ReEnable interrupts */ - unsigned long *); /* flags */ static void cs_error(client_handle_t, /* Report error to cardmgr */ int, diff -Nru a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c --- a/drivers/net/yellowfin.c Tue Feb 26 11:57:59 2002 +++ b/drivers/net/yellowfin.c Tue Feb 26 11:57:59 2002 @@ -1487,7 +1487,7 @@ name: DRV_NAME, id_table: yellowfin_pci_tbl, probe: yellowfin_init_one, - remove: yellowfin_remove_one, + remove: __devexit_p(yellowfin_remove_one), }; diff -Nru a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c --- a/drivers/parport/parport_serial.c Tue Feb 26 11:58:00 2002 +++ b/drivers/parport/parport_serial.c Tue Feb 26 11:58:00 2002 @@ -331,7 +331,7 @@ name: "parport_serial", id_table: parport_serial_pci_tbl, probe: parport_serial_pci_probe, - remove: parport_serial_pci_remove, + remove: __devexit_p(parport_serial_pci_remove), }; diff -Nru a/drivers/pci/pci.ids b/drivers/pci/pci.ids --- a/drivers/pci/pci.ids Tue Feb 26 11:57:56 2002 +++ b/drivers/pci/pci.ids Tue Feb 26 11:57:56 2002 @@ -3952,6 +3952,7 @@ 9511 16PCI954 Function 1 15ed 2000 Macrolink MCCR Serial p4-7 of 8 15ed 2001 Macrolink MCCR Serial p4-15 of 16 + 9521 Oxford Semi OX16PCI952 PCI/dual 16950 UART 1416 Multiwave Innovation pte Ltd 1417 Convergenet Technologies Inc 1418 Kyushu electronics systems Inc diff -Nru a/drivers/pcmcia/pci_socket.c b/drivers/pcmcia/pci_socket.c --- a/drivers/pcmcia/pci_socket.c Tue Feb 26 11:57:59 2002 +++ b/drivers/pcmcia/pci_socket.c Tue Feb 26 11:57:59 2002 @@ -249,7 +249,7 @@ name: "cardbus", id_table: cardbus_table, probe: cardbus_probe, - remove: cardbus_remove, + remove: __devexit_p(cardbus_remove), suspend: cardbus_suspend, resume: cardbus_resume, }; diff -Nru a/drivers/pnp/isapnp.c b/drivers/pnp/isapnp.c --- a/drivers/pnp/isapnp.c Tue Feb 26 11:57:56 2002 +++ b/drivers/pnp/isapnp.c Tue Feb 26 11:57:56 2002 @@ -21,7 +21,7 @@ * 2000-01-01 Added quirks handling for buggy hardware * Peter Denison * 2000-06-14 Added isapnp_probe_devs() and isapnp_activate_dev() - * Christoph Hellwig + * Christoph Hellwig * 2001-06-03 Added release_region calls to correspond with * request_region calls when a failure occurs. Also * added KERN_* constants to printk() calls. diff -Nru a/drivers/scsi/Makefile b/drivers/scsi/Makefile --- a/drivers/scsi/Makefile Tue Feb 26 11:57:58 2002 +++ b/drivers/scsi/Makefile Tue Feb 26 11:57:58 2002 @@ -1,7 +1,7 @@ # # Makefile for linux/drivers/scsi # -# 30 May 2000, Christoph Hellwig +# 30 May 2000, Christoph Hellwig # Rewritten to use lists instead of if-statements. # # 20 Sep 2000, Torben Mathiasen diff -Nru a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c --- a/drivers/scsi/NCR5380.c Tue Feb 26 11:57:58 2002 +++ b/drivers/scsi/NCR5380.c Tue Feb 26 11:57:58 2002 @@ -83,8 +83,6 @@ * basically, transfer size needs to be reduced by one * and the last byte read as is done with PSEUDO_DMA. * - * 3. Test USLEEP code - * * 4. Test SCSI-II tagged queueing (I have no devices which support * tagged queueing) * @@ -110,6 +108,12 @@ #define READ_OVERRUNS #endif +#ifdef BOARD_REQUIRES_NO_DELAY +#define io_recovery_delay(x) +#else +#define io_recovery_delay(x) udelay(x) +#endif + /* * Design * Issues : @@ -192,9 +196,8 @@ * phase goes through the various phases as instructed by the target. * if the target goes into MSG IN and sends a DISCONNECT message, * the command structure is placed into the per instance disconnected - * queue, and NCR5380_main tries to find more work. If USLEEP - * was defined, and the target is idle for too long, the system - * will try to sleep. + * queue, and NCR5380_main tries to find more work. If the target is + * idle for too long, the system will try to sleep. * * If a command has disconnected, eventually an interrupt will trigger, * calling NCR5380_intr() which will in turn call NCR5380_reselect @@ -244,21 +247,14 @@ * rely on phase mismatch and EOP interrupts to determine end * of phase. * - * SCSI2 - if defined, SCSI-2 tagged queuing is used where possible - * * UNSAFE - leave interrupts enabled during pseudo-DMA transfers. You * only really want to use this if you're having a problem with * dropped characters during high speed communications, and even * then, you're going to be better off twiddling with transfersize * in the high level code. * - * USLEEP - if defined, on devices that aren't disconnecting from the - * bus, we will go to sleep so that the CPU can get real work done - * when we run a command that won't complete immediately. - * - * Defaults for these will be provided if USLEEP is defined, although - * the user may want to adjust these to allocate CPU resources to - * the SCSI driver or "real" code. + * Defaults for these will be provided although the user may want to adjust + * these to allocate CPU resources to the SCSI driver or "real" code. * * USLEEP_SLEEP - amount of time, in jiffies, to sleep * @@ -322,18 +318,13 @@ static void do_reset(struct Scsi_Host *host); static struct Scsi_Host *first_instance = NULL; static Scsi_Host_Template *the_template = NULL; - -#ifdef USLEEP -struct timer_list usleep_timer; -#endif +static struct timer_list usleep_timer; /* - * Function : void initialize_SCp(Scsi_Cmnd *cmd) + * initialize_SCp - init the scsi pointer field + * @cmd: command block to set up * - * Purpose : initialize the saved data pointers for cmd to point to the - * start of the buffer. - * - * Inputs : cmd - Scsi_Cmnd structure to have pointers reset. + * Set up the internal fields in the SCSI command. */ static __inline__ void initialize_SCp(Scsi_Cmnd * cmd) @@ -362,88 +353,49 @@ static struct { unsigned char mask; const char *name; -} signals[] = { { - - SR_DBP, "PARITY" -}, { - SR_RST, "RST" -}, { - SR_BSY, "BSY" -}, -{ - SR_REQ, "REQ" -}, { - SR_MSG, "MSG" -}, { - SR_CD, "CD" -}, { - SR_IO, "IO" -}, -{ - SR_SEL, "SEL" -}, { - 0, NULL -} -}, - -basrs[] = { { - BASR_ATN, "ATN" -}, { - BASR_ACK, "ACK" -}, { - 0, NULL -} -}, - -icrs[] = { { - ICR_ASSERT_RST, "ASSERT RST" -}, { - ICR_ASSERT_ACK, "ASSERT ACK" -}, -{ - ICR_ASSERT_BSY, "ASSERT BSY" -}, { - ICR_ASSERT_SEL, "ASSERT SEL" -}, -{ - ICR_ASSERT_ATN, "ASSERT ATN" -}, { - ICR_ASSERT_DATA, "ASSERT DATA" -}, -{ - 0, NULL -} -}, - -mrs[] = { { - MR_BLOCK_DMA_MODE, "MODE BLOCK DMA" -}, { - MR_TARGET, "MODE TARGET" -}, -{ - MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK" -}, { - MR_ENABLE_PAR_INTR, - "MODE PARITY INTR" -}, { - MR_MONITOR_BSY, "MODE MONITOR BSY" -}, -{ - MR_DMA_MODE, "MODE DMA" -}, { - MR_ARBITRATE, "MODE ARBITRATION" -}, -{ - 0, NULL -} +} signals[] = { + {SR_DBP, "PARITY"}, + {SR_RST, "RST"}, + {SR_BSY, "BSY"}, + {SR_REQ, "REQ"}, + {SR_MSG, "MSG"}, + {SR_CD, "CD"}, + {SR_IO, "IO"}, + {SR_SEL, "SEL"}, + {0, NULL} +}, +basrs[] = { + {BASR_ATN, "ATN"}, + {BASR_ACK, "ACK"}, + {0, NULL} +}, +icrs[] = { + {ICR_ASSERT_RST, "ASSERT RST"}, + {ICR_ASSERT_ACK, "ASSERT ACK"}, + {ICR_ASSERT_BSY, "ASSERT BSY"}, + {ICR_ASSERT_SEL, "ASSERT SEL"}, + {ICR_ASSERT_ATN, "ASSERT ATN"}, + {ICR_ASSERT_DATA, "ASSERT DATA"}, + {0, NULL} +}, +mrs[] = { + {MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, + {MR_TARGET, "MODE TARGET"}, + {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, + {MR_ENABLE_PAR_INTR, "MODE PARITY INTR"}, + {MR_MONITOR_BSY, "MODE MONITOR BSY"}, + {MR_DMA_MODE, "MODE DMA"}, + {MR_ARBITRATE, "MODE ARBITRATION"}, + {0, NULL} }; -/* - * Function : void NCR5380_print(struct Scsi_Host *instance) +/** + * NCR5380_print - print scsi bus signals + * @instance: adapter state to dump * - * Purpose : print the SCSI bus signals for debugging purposes + * Print the SCSI bus signals for debugging purposes * - * Input : instance - which NCR5380 + * Locks: none */ static void NCR5380_print(struct Scsi_Host *instance) @@ -452,6 +404,7 @@ unsigned long flags; unsigned char status, data, basr, mr, icr, i; NCR5380_setup(instance); + /* FIXME - this needs proper locking */ save_flags(flags); cli(); data = NCR5380_read(CURRENT_SCSI_DATA_REG); @@ -483,32 +436,22 @@ unsigned char value; const char *name; } phases[] = { - - { - PHASE_DATAOUT, "DATAOUT" - }, { - PHASE_DATAIN, "DATAIN" - }, { - PHASE_CMDOUT, "CMDOUT" - }, - { - PHASE_STATIN, "STATIN" - }, { - PHASE_MSGOUT, "MSGOUT" - }, { - PHASE_MSGIN, "MSGIN" - }, - { - PHASE_UNKNOWN, "UNKNOWN" - } + {PHASE_DATAOUT, "DATAOUT"}, + {PHASE_DATAIN, "DATAIN"}, + {PHASE_CMDOUT, "CMDOUT"}, + {PHASE_STATIN, "STATIN"}, + {PHASE_MSGOUT, "MSGOUT"}, + {PHASE_MSGIN, "MSGIN"}, + {PHASE_UNKNOWN, "UNKNOWN"} }; /* - * Function : void NCR5380_print_phase(struct Scsi_Host *instance) + * NCR5380_print_phase - show SCSI phase + * @instance: adapter to dump * - * Purpose : print the current SCSI phase for debugging purposes + * Print the current SCSI phase for debugging purposes * - * Input : instance - which NCR5380 + * Locks: none */ static void NCR5380_print_phase(struct Scsi_Host *instance) @@ -520,11 +463,9 @@ status = NCR5380_read(STATUS_REG); if (!(status & SR_REQ)) - printk("scsi%d : REQ not asserted, phase unknown.\n", - instance->host_no); + printk("scsi%d : REQ not asserted, phase unknown.\n", instance->host_no); else { - for (i = 0; (phases[i].value != PHASE_UNKNOWN) && - (phases[i].value != (status & PHASE_MASK)); ++i); + for (i = 0; (phases[i].value != PHASE_UNKNOWN) && (phases[i].value != (status & PHASE_MASK)); ++i); printk("scsi%d : phase %s\n", instance->host_no, phases[i].name); } } @@ -549,7 +490,7 @@ * conditions are possible. */ -static volatile int main_running = 0; +static unsigned long main_running = 0; /* * Function : run_main(void) @@ -563,14 +504,10 @@ static __inline__ void run_main(void) { - if (!main_running) { - main_running = 1; + if (!test_and_set_bit(0, &main_running)) NCR5380_main(); - } } -#ifdef USLEEP - /* * These need tweaking, and would probably work best as per-device * flags initialized differently for disk, tape, cd, etc devices. @@ -621,63 +558,67 @@ static int should_disconnect(unsigned char cmd) { switch (cmd) { - case READ_6: - case WRITE_6: - case SEEK_6: - case READ_10: - case WRITE_10: - case SEEK_10: - return DISCONNECT_TIME_TO_DATA; - case FORMAT_UNIT: - case SEARCH_HIGH: - case SEARCH_LOW: - case SEARCH_EQUAL: - return DISCONNECT_LONG; - default: - return DISCONNECT_NONE; + case READ_6: + case WRITE_6: + case SEEK_6: + case READ_10: + case WRITE_10: + case SEEK_10: + return DISCONNECT_TIME_TO_DATA; + case FORMAT_UNIT: + case SEARCH_HIGH: + case SEARCH_LOW: + case SEARCH_EQUAL: + return DISCONNECT_LONG; + default: + return DISCONNECT_NONE; } } /* * Assumes instance->time_expires has been set in higher level code. + * + * Locks: Caller must hold io_request_lock */ static int NCR5380_set_timer(struct Scsi_Host *instance) { - unsigned long flags; struct Scsi_Host *tmp, **prev; - save_flags(flags); - cli(); if (((struct NCR5380_hostdata *) (instance->hostdata))->next_timer) { - restore_flags(flags); return -1; } - for (prev = &expires_first, tmp = expires_first; tmp; - prev = &(((struct NCR5380_hostdata *) tmp->hostdata)->next_timer), - tmp = ((struct NCR5380_hostdata *) tmp->hostdata)->next_timer) - if (((struct NCR5380_hostdata *)instance->hostdata)->time_expires < - ((struct NCR5380_hostdata *)tmp->hostdata)->time_expires) + for (prev = &expires_first, tmp = expires_first; tmp; prev = &(((struct NCR5380_hostdata *) tmp->hostdata)->next_timer), tmp = ((struct NCR5380_hostdata *) tmp->hostdata)->next_timer) + if (((struct NCR5380_hostdata *) instance->hostdata)->time_expires < ((struct NCR5380_hostdata *) tmp->hostdata)->time_expires) break; ((struct NCR5380_hostdata *) instance->hostdata)->next_timer = tmp; *prev = instance; - + mod_timer(&usleep_timer, ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires); - restore_flags(flags); return 0; } -/* Doing something about unwanted reentrancy here might be useful */ -void NCR5380_timer_fn(unsigned long surplus_to_requirements) +/** + * NCR5380_timer_fn - handle polled timeouts + * @unused: unused + * + * Walk the list of controllers, find which controllers have exceeded + * their expiry timeout and then schedule the processing co-routine to + * do the real work. + * + * Doing something about unwanted reentrancy here might be useful + * + * Locks: disables irqs, takes and frees io_request_lock + */ + +static void NCR5380_timer_fn(unsigned long unused) { - unsigned long flags; struct Scsi_Host *instance; - save_flags(flags); - cli(); - for (; expires_first && - time_before_eq(((struct NCR5380_hostdata *)expires_first->hostdata)->time_expires, jiffies); ) - { + + spin_lock_irq(&io_request_lock); + + for (; expires_first && time_before_eq(((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires, jiffies);) { instance = ((struct NCR5380_hostdata *) expires_first->hostdata)->next_timer; ((struct NCR5380_hostdata *) expires_first->hostdata)->next_timer = NULL; ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires = 0; @@ -685,90 +626,91 @@ } del_timer(&usleep_timer); - if (expires_first) - { - usleep_timer.expires = ((struct NCR5380_hostdata *)expires_first->hostdata)->time_expires; + if (expires_first) { + usleep_timer.expires = ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires; add_timer(&usleep_timer); } - restore_flags(flags); - - spin_lock_irqsave(instance->host_lock, flags); run_main(); - spin_unlock_irqrestore(instance->host_lock, flags); + spin_unlock_irq(&io_request_lock); } -#endif /* def USLEEP */ +/** + * NCR5380_all_init - global setup + * + * Set up the global values and timers needed by the NCR5380 driver + */ + static inline void NCR5380_all_init(void) { static int done = 0; if (!done) { -#if (NDEBUG & NDEBUG_INIT) - printk("scsi : NCR5380_all_init()\n"); -#endif + dprintk(NDEBUG_INIT, ("scsi : NCR5380_all_init()\n")); done = 1; -#ifdef USLEEP init_timer(&usleep_timer); usleep_timer.function = NCR5380_timer_fn; -#endif } } -#ifdef AUTOPROBE_IRQ -/* - * Function : int NCR5380_probe_irq (struct Scsi_Host *instance, int possible) - * - * Purpose : autoprobe for the IRQ line used by the NCR5380. - * - * Inputs : instance - pointer to this instance of the NCR5380 driver, - * possible - bitmask of permissible interrupts. - * - * Returns : number of the IRQ selected, IRQ_NONE if no interrupt fired. - * - * XXX no effort is made to deal with spurious interrupts. - */ - static int probe_irq __initdata = 0; +/** + * probe_intr - helper for IRQ autoprobe + * @irq: interrupt number + * @dev_id: unused + * @regs: unused + * + * Set a flag to indicate the IRQ in question was received. This is + * used by the IRQ probe code. + */ + static void __init probe_intr(int irq, void *dev_id, struct pt_regs *regs) { probe_irq = irq; } +/** + * NCR5380_probe_irq - find the IRQ of an NCR5380 + * @instance: NCR5380 controller + * @possible: bitmask of ISA IRQ lines + * + * Autoprobe for the IRQ line used by the NCR5380 by triggering an IRQ + * and then looking to see what interrupt actually turned up. + * + * Locks: none, irqs must be enabled on entry + */ + static int __init NCR5380_probe_irq(struct Scsi_Host *instance, int possible) { NCR5380_local_declare(); - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; unsigned long timeout; int trying_irqs, i, mask; NCR5380_setup(instance); for (trying_irqs = i = 0, mask = 1; i < 16; ++i, mask <<= 1) - if ((mask & possible) && (request_irq(i, &probe_intr, SA_INTERRUPT, "NCR-probe", instance) - == 0)) + if ((mask & possible) && (request_irq(i, &probe_intr, SA_INTERRUPT, "NCR-probe", NULL) == 0)) trying_irqs |= mask; timeout = jiffies + (250 * HZ / 1000); probe_irq = IRQ_NONE; -/* - * A interrupt is triggered whenever BSY = false, SEL = true - * and a bit set in the SELECT_ENABLE_REG is asserted on the - * SCSI bus. - * - * Note that the bus is only driven when the phase control signals - * (I/O, C/D, and MSG) match those in the TCR, so we must reset that - * to zero. - */ + /* + * A interrupt is triggered whenever BSY = false, SEL = true + * and a bit set in the SELECT_ENABLE_REG is asserted on the + * SCSI bus. + * + * Note that the bus is only driven when the phase control signals + * (I/O, C/D, and MSG) match those in the TCR, so we must reset that + * to zero. + */ NCR5380_write(TARGET_COMMAND_REG, 0); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | - ICR_ASSERT_SEL); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_SEL); - while (probe_irq == IRQ_NONE && time_before(jiffies,timeout)) + while (probe_irq == IRQ_NONE && time_before(jiffies, timeout)) barrier(); NCR5380_write(SELECT_ENABLE_REG, 0); @@ -780,15 +722,16 @@ return probe_irq; } -#endif /* AUTOPROBE_IRQ */ -/* - * Function : void NCR58380_print_options (struct Scsi_Host *instance) - * - * Purpose : called by probe code indicating the NCR5380 driver - * options that were selected. +/** + * NCR58380_print_options - show options + * @instance: unused for now + * + * Called by probe code indicating the NCR5380 driver options that + * were selected. At some point this will switch to runtime options + * read from the adapter in question * - * Inputs : instance, pointer to this instance. Unused. + * Locks: none */ static void __init NCR5380_print_options(struct Scsi_Host *instance) @@ -815,29 +758,25 @@ #ifdef PSEUDO_DMA " PSEUDO DMA" #endif -#ifdef SCSI2 - " SCSI-2" -#endif #ifdef UNSAFE " UNSAFE " #endif ); -#ifdef USLEEP printk(" USLEEP, USLEEP_POLL=%d USLEEP_SLEEP=%d", USLEEP_POLL, USLEEP_SLEEP); -#endif printk(" generic release=%d", NCR5380_PUBLIC_RELEASE); if (((struct NCR5380_hostdata *) instance->hostdata)->flags & FLAG_NCR53C400) { printk(" ncr53c400 release=%d", NCR53C400_PUBLIC_RELEASE); } } -/* - * Function : void NCR5380_print_status (struct Scsi_Host *instance) +/** + * NCR5380_print_status - dump controller info + * @instance: controller to dump * - * Purpose : print commands in the various queues, called from - * NCR5380_abort and NCR5380_debug to aid debugging. + * Print commands in the various queues, called from NCR5380_abort + * and NCR5380_debug to aid debugging. * - * Inputs : instance, pointer to this instance. + * Locks: called functions disable irqs, missing queue lock in proc call */ static void NCR5380_print_status(struct Scsi_Host *instance) @@ -846,16 +785,12 @@ char *start; int len; - printk("NCR5380 : coroutine is%s running.\n", - main_running ? "" : "n't"); + printk("NCR5380 : coroutine is%s running.\n", main_running ? "" : "n't"); -#ifdef NDEBUG - NCR5380_print(instance); - NCR5380_print_phase(instance); -#endif + NCR5380_dprint(NDEBUG_ANY, instance); + NCR5380_dprint_phase(NDEBUG_ANY, instance); - len = NCR5380_proc_info(pr_bfr, &start, 0, sizeof(pr_bfr), - instance->host_no, 0); + len = NCR5380_proc_info(pr_bfr, &start, 0, sizeof(pr_bfr), instance->host_no, 0); pr_bfr[len] = 0; printk("\n%s\n", pr_bfr); } @@ -886,18 +821,14 @@ #ifndef NCR5380_proc_info static #endif -int NCR5380_proc_info( - char *buffer, char **start, off_t offset, - int length, int hostno, int inout) +int NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) { - unsigned long flags; char *pos = buffer; struct Scsi_Host *instance; struct NCR5380_hostdata *hostdata; Scsi_Cmnd *ptr; - for (instance = first_instance; instance && - instance->host_no != hostno; instance = instance->next); + for (instance = first_instance; instance && instance->host_no != hostno; instance = instance->next); if (!instance) return (-ESRCH); hostdata = (struct NCR5380_hostdata *) instance->hostdata; @@ -935,32 +866,27 @@ SPRINTF("IRQ: %d.\n", instance->irq); #ifdef DTC_PUBLIC_RELEASE - SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", - dtc_wmaxi, dtc_maxi); + SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", dtc_wmaxi, dtc_maxi); #endif #ifdef PAS16_PUBLIC_RELEASE - SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", - pas_wmaxi, pas_maxi); + SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", pas_wmaxi, pas_maxi); #endif - save_flags(flags); - cli(); + spin_lock_irq(&io_request_lock); SPRINTF("NCR5380 : coroutine is%s running.\n", main_running ? "" : "n't"); if (!hostdata->connected) SPRINTF("scsi%d: no currently connected command\n", instance->host_no); else - pos = lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected, - pos, buffer, length); + pos = lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected, pos, buffer, length); SPRINTF("scsi%d: issue_queue\n", instance->host_no); - for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; - ptr = (Scsi_Cmnd *) ptr->host_scribble) + for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length); SPRINTF("scsi%d: disconnected_queue\n", instance->host_no); - for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; - ptr = (Scsi_Cmnd *) ptr->host_scribble) + for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length); - restore_flags(flags); + spin_unlock_irq(&io_request_lock); + *start = buffer; if (pos - buffer < offset) return 0; @@ -972,16 +898,14 @@ static char *lprint_Scsi_Cmnd(Scsi_Cmnd * cmd, char *pos, char *buffer, int length) { - SPRINTF("scsi%d : destination target %d, lun %d\n", - cmd->host->host_no, cmd->target, cmd->lun); + SPRINTF("scsi%d : destination target %d, lun %d\n", cmd->host->host_no, cmd->target, cmd->lun); SPRINTF(" command = "); pos = lprint_command(cmd->cmnd, pos, buffer, length); return (pos); } static -char *lprint_command(unsigned char *command, - char *pos, char *buffer, int length) +char *lprint_command(unsigned char *command, char *pos, char *buffer, int length) { int i, s; pos = lprint_opcode(command[0], pos, buffer, length); @@ -999,17 +923,18 @@ } -/* - * Function : void NCR5380_init (struct Scsi_Host *instance, flags) +/** + * NCR5380_init - initialise an NCR5380 + * @instance: adapter to configure + * @flags: control flags * - * Purpose : initializes *instance and corresponding 5380 chip, + * Initializes *instance and corresponding 5380 chip, * with flags OR'd into the initial flags value. * - * Inputs : instance - instantiation of the 5380 driver. - * - * Notes : I assume that the host, hostno, and id bits have been + * Notes : I assume that the host, hostno, and id bits have been * set correctly. I don't care about the irq and other fields. - * + * + * Locks: interrupts must be enabled when we are called */ static void __init NCR5380_init(struct Scsi_Host *instance, int flags) @@ -1017,9 +942,10 @@ NCR5380_local_declare(); int i, pass; unsigned long timeout; - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; + if(in_interrupt()) + printk(KERN_ERR "NCR5380_init called with interrupts off!\n"); /* * On NCR53C400 boards, NCR5380 registers are mapped 8 past * the base address. @@ -1031,7 +957,6 @@ #endif NCR5380_setup(instance); - NCR5380_all_init(); hostdata->aborted = 0; @@ -1070,17 +995,13 @@ the_template = instance->hostt; first_instance = instance; } -#ifdef USLEEP hostdata->time_expires = 0; hostdata->next_timer = NULL; -#endif #ifndef AUTOSENSE if ((instance->cmd_per_lun > 1) || instance->can_queue > 1) - ) - printk("scsi%d : WARNING : support for multiple outstanding commands enabled\n" - " without AUTOSENSE option, contingent allegiance conditions may\n" - " be incorrectly cleared.\n", instance->host_no); + printk(KERN_WARNING "scsi%d : WARNING : support for multiple outstanding commands enabled\n" " without AUTOSENSE option, contingent allegiance conditions may\n" + " be incorrectly cleared.\n", instance->host_no); #endif /* def AUTOSENSE */ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); @@ -1106,50 +1027,40 @@ * failing, do a hard reset of the SCSI bus */ - for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) && - pass <= 6; ++pass) { + for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) && pass <= 6; ++pass) { switch (pass) { case 1: case 3: case 5: - printk("scsi%d: SCSI bus busy, waiting up to five seconds\n", - instance->host_no); + printk("scsi%d: SCSI bus busy, waiting up to five seconds\n", instance->host_no); timeout = jiffies + 5 * HZ; - while (time_before(jiffies,timeout) && (NCR5380_read(STATUS_REG) & SR_BSY)); + while (time_before(jiffies, timeout) && (NCR5380_read(STATUS_REG) & SR_BSY)); break; case 2: - printk("scsi%d: bus busy, attempting abort\n", - instance->host_no); + printk("scsi%d: bus busy, attempting abort\n", instance->host_no); do_abort(instance); break; case 4: - printk("scsi%d: bus busy, attempting reset\n", - instance->host_no); + printk("scsi%d: bus busy, attempting reset\n", instance->host_no); do_reset(instance); break; case 6: - printk("scsi%d: bus locked solid or invalid override\n", - instance->host_no); + printk("scsi%d: bus locked solid or invalid override\n", instance->host_no); } } } -/* - * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, - * void (*done)(Scsi_Cmnd *)) - * - * Purpose : enqueues a SCSI command - * - * Inputs : cmd - SCSI command, done - function called on completion, with - * a pointer to the command descriptor. - * - * Returns : 0 +/** + * NCR5380_queue_command - queue a command + * @cmd: SCSI command + * @done: completion handler * - * Side effects : * cmd is added to the per instance issue_queue, with minor * twiddling done to the host specific fields of cmd. If the * main coroutine is not running, it is restarted. * + * Locks: io_request lock held by caller. Called functions drop and + * retake this lock. Called functions take dma lock. */ /* Only make static if a wrapper function is used */ @@ -1158,16 +1069,14 @@ #endif int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) { struct Scsi_Host *instance = cmd->host; - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; Scsi_Cmnd *tmp; #if (NDEBUG & NDEBUG_NO_WRITE) switch (cmd->cmnd[0]) { - case WRITE_6: - case WRITE_10: - printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n", - instance->host_no); + case WRITE_6: + case WRITE_10: + printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n", instance->host_no); cmd->result = (DID_ERROR << 16); done(cmd); return 0; @@ -1175,31 +1084,22 @@ #endif /* (NDEBUG & NDEBUG_NO_WRITE) */ #ifdef NCR5380_STATS -#if 0 - if (!hostdata->connected && !hostdata->issue_queue && - !hostdata->disconnected_queue) { - hostdata->timebase = jiffies; - } -#endif -#ifdef NCR5380_STAT_LIMIT - if (cmd->request_bufflen > NCR5380_STAT_LIMIT) -#endif - switch (cmd->cmnd[0]) { - case WRITE: - case WRITE_6: - case WRITE_10: - hostdata->time_write[cmd->target] -= (jiffies - hostdata->timebase); + switch (cmd->cmnd[0]) { + case WRITE: + case WRITE_6: + case WRITE_10: + hostdata->time_write[cmd->target] -= (jiffies - hostdata->timebase); hostdata->bytes_write[cmd->target] += cmd->request_bufflen; hostdata->pendingw++; break; - case READ: - case READ_6: - case READ_10: - hostdata->time_read[cmd->target] -= (jiffies - hostdata->timebase); + case READ: + case READ_6: + case READ_10: + hostdata->time_read[cmd->target] -= (jiffies - hostdata->timebase); hostdata->bytes_read[cmd->target] += cmd->request_bufflen; hostdata->pendingr++; break; - } + } #endif /* @@ -1209,10 +1109,8 @@ cmd->host_scribble = NULL; cmd->scsi_done = done; - cmd->result = 0; - /* * Insert the cmd into the issue queue. Note that REQUEST SENSE * commands are added to the head of the queue since any command will @@ -1225,31 +1123,28 @@ cmd->host_scribble = (unsigned char *) hostdata->issue_queue; hostdata->issue_queue = cmd; } else { - for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->host_scribble; - tmp = (Scsi_Cmnd *) tmp->host_scribble); + for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->host_scribble; tmp = (Scsi_Cmnd *) tmp->host_scribble); LIST(cmd, tmp); tmp->host_scribble = (unsigned char *) cmd; } -#if (NDEBUG & NDEBUG_QUEUES) - printk("scsi%d : command added to %s of queue\n", instance->host_no, - (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"); -#endif + dprintk(NDEBUG_QUEUES, ("scsi%d : command added to %s of queue\n", instance->host_no, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail")); -/* Run the coroutine if it isn't already running. */ + /* Run the coroutine if it isn't already running. */ run_main(); return 0; } -/* - * Function : NCR5380_main (void) +/** + * NCR5380_main - NCR state machines * - * Purpose : NCR5380_main is a coroutine that runs as long as more work can + * NCR5380_main is a coroutine that runs as long as more work can * be done on the NCR5380 host adapters in a system. Both * NCR5380_queue_command() and NCR5380_intr() will try to start it * in case it is not running. * - * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should - * reenable them. This prevents reentrancy and kernel stack overflow. + * Locks; The caller must hold the io_request_lock. The lock will still be + * held on return but may be dropped while running. Called functions take + * the DMA lock. */ static void NCR5380_main(void) { @@ -1257,7 +1152,6 @@ struct Scsi_Host *instance; struct NCR5380_hostdata *hostdata; int done; - unsigned long flags; /* * We run (with interrupts disabled) until we're sure that none of @@ -1271,43 +1165,22 @@ * this should prevent any race conditions. */ - spin_unlock_irq(instance->host_lock); - - save_flags(flags); - do { - cli(); /* Freeze request queues */ + /* Lock held here */ done = 1; - for (instance = first_instance; instance && - instance->hostt == the_template; instance = instance->next) { - hostdata = (struct NCR5380_hostdata *) instance->hostdata; - cli(); -#ifdef USLEEP + for (instance = first_instance; instance && instance->hostt == the_template; instance = instance->next) { + hostdata = (struct NCR5380_hostdata *) instance->hostdata; + /* Lock held here */ if (!hostdata->connected && !hostdata->selecting) { -#else - if (!hostdata->connected) { -#endif -#if (NDEBUG & NDEBUG_MAIN) - printk("scsi%d : not connected\n", instance->host_no); -#endif + dprintk(NDEBUG_MAIN, ("scsi%d : not connected\n", instance->host_no)); /* * Search through the issue_queue for a command destined * for a target that's not busy. */ -#if (NDEBUG & NDEBUG_LISTS) - for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; tmp && (tmp != prev); prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble); - /*printk("%p ", tmp); */ - if ((tmp == prev) && tmp) - printk(" LOOP\n"); /* else printk("\n"); */ -#endif - for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, - prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) - tmp->host_scribble) { - -#if (NDEBUG & NDEBUG_LISTS) + for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble) + { if (prev != tmp) - printk("MAIN tmp=%p target=%d busy=%d lun=%d\n", tmp, tmp->target, hostdata->busy[tmp->target], tmp->lun); -#endif + dprintk(NDEBUG_LISTS, ("MAIN tmp=%p target=%d busy=%d lun=%d\n", tmp, tmp->target, hostdata->busy[tmp->target], tmp->lun)); /* When we find one, remove it from the issue queue. */ if (!(hostdata->busy[tmp->target] & (1 << tmp->lun))) { if (prev) { @@ -1319,8 +1192,6 @@ } tmp->host_scribble = NULL; - /* reenable interrupts after finding one */ - restore_flags(flags); /* * Attempt to establish an I_T_L nexus here. @@ -1328,10 +1199,7 @@ * On failure, we must add the command back to the * issue queue so we can keep trying. */ -#if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES)) - printk("scsi%d : main() : command for target %d lun %d removed from issue_queue\n", - instance->host_no, tmp->target, tmp->lun); -#endif + dprintk(NDEBUG_MAIN|NDEBUG_QUEUES, ("scsi%d : main() : command for target %d lun %d removed from issue_queue\n", instance->host_no, tmp->target, tmp->lun)); /* * A successful selection is defined as one that @@ -1343,105 +1211,81 @@ * and see if we can do an information transfer, * with failures we will restart. */ -#ifdef USLEEP - hostdata->selecting = 0; /* RvC: have to preset this - to indicate a new command is being performed */ -#endif + hostdata->selecting = 0; + /* RvC: have to preset this to indicate a new command is being performed */ if (!NCR5380_select(instance, tmp, - /* - * REQUEST SENSE commands are issued without tagged - * queueing, even on SCSI-II devices because the - * contingent allegiance condition exists for the - * entire unit. - */ - (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : - TAG_NEXT)) { + /* + * REQUEST SENSE commands are issued without tagged + * queueing, even on SCSI-II devices because the + * contingent allegiance condition exists for the + * entire unit. + */ + (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT)) { break; } else { - cli(); LIST(tmp, hostdata->issue_queue); - tmp->host_scribble = (unsigned char *) - hostdata->issue_queue; + tmp->host_scribble = (unsigned char *) hostdata->issue_queue; hostdata->issue_queue = tmp; done = 0; - restore_flags(flags); -#if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES)) - printk("scsi%d : main(): select() failed, returned to issue_queue\n", - instance->host_no); -#endif + dprintk(NDEBUG_MAIN|NDEBUG_QUEUES, ("scsi%d : main(): select() failed, returned to issue_queue\n", instance->host_no)); } + /* lock held here still */ } /* if target/lun is not busy */ } /* for */ + /* exited locked */ } /* if (!hostdata->connected) */ -#ifdef USLEEP - if (hostdata->selecting) - { - tmp = (Scsi_Cmnd *)hostdata->selecting; - if (!NCR5380_select(instance, tmp, - (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT)) - { + if (hostdata->selecting) { + tmp = (Scsi_Cmnd *) hostdata->selecting; + /* Selection will drop and retake the lock */ + if (!NCR5380_select(instance, tmp, (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT)) { /* Ok ?? */ - } - else - { + } else { /* RvC: device failed, so we wait a long time - this is needed for Mustek scanners, that - do not respond to commands immediately - after a scan */ - printk(KERN_DEBUG "scsi%d: device %d did not respond in time\n", - instance->host_no, tmp->target); - cli(); + this is needed for Mustek scanners, that + do not respond to commands immediately + after a scan */ + printk(KERN_DEBUG "scsi%d: device %d did not respond in time\n", instance->host_no, tmp->target); + //spin_lock_irq(&io_request_lock); LIST(tmp, hostdata->issue_queue); tmp->host_scribble = (unsigned char *) hostdata->issue_queue; hostdata->issue_queue = tmp; - restore_flags(flags); + //spin_unlock_irq(&io_request_lock); hostdata->time_expires = jiffies + USLEEP_WAITLONG; - NCR5380_set_timer (instance); + NCR5380_set_timer(instance); } - } /* if hostdata->selecting */ -#endif + } /* if hostdata->selecting */ if (hostdata->connected #ifdef REAL_DMA && !hostdata->dmalen #endif -#ifdef USLEEP && (!hostdata->time_expires || time_before_eq(hostdata->time_expires, jiffies)) -#endif ) { - restore_flags(flags); -#if (NDEBUG & NDEBUG_MAIN) - printk("scsi%d : main() : performing information transfer\n", - instance->host_no); -#endif + dprintk(NDEBUG_MAIN, ("scsi%d : main() : performing information transfer\n", instance->host_no)); NCR5380_information_transfer(instance); -#if (NDEBUG & NDEBUG_MAIN) - printk("scsi%d : main() : done set false\n", instance->host_no); -#endif + dprintk(NDEBUG_MAIN, ("scsi%d : main() : done set false\n", instance->host_no)); done = 0; } else break; } /* for instance */ } while (!done); - spin_lock_irq(instance->host_lock); - /* cli();*/ - main_running = 0; + /* Exit lock held */ + clear_bit(0, &main_running); } #ifndef DONT_USE_INTR #include #include -/* - * Function : void NCR5380_intr (int irq) - * - * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses +/** + * NCR5380_intr - generic NCR5380 irq handler + * + * Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses * from the disconnected queue, and restarting NCR5380_main() * as required. * - * Inputs : int irq, irq that caused this interrupt. - * + * Locks: caller must hold the io_request lock. */ static void NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) { @@ -1449,17 +1293,12 @@ struct Scsi_Host *instance; int done; unsigned char basr; - unsigned long flags; - save_flags(flags); - cli(); -#if (NDEBUG & NDEBUG_INTR) - printk("scsi : NCR5380 irq %d triggered\n", irq); -#endif + dprintk(NDEBUG_INTR, ("scsi : NCR5380 irq %d triggered\n", irq)); + do { done = 1; - for (instance = first_instance; instance && (instance->hostt == - the_template); instance = instance->next) + for (instance = first_instance; instance && (instance->hostt == the_template); instance = instance->next) if (instance->irq == irq) { /* Look for pending interrupts */ @@ -1467,34 +1306,19 @@ basr = NCR5380_read(BUS_AND_STATUS_REG); /* XXX dispatch to appropriate routine if found and done=0 */ if (basr & BASR_IRQ) { -#if (NDEBUG & NDEBUG_INTR) - NCR5380_print(instance); -#endif - if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == - (SR_SEL | SR_IO)) { + NCR5380_dprint(NDEBUG_INTR, instance); + if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) { done = 0; - restore_flags(flags); -#if (NDEBUG & NDEBUG_INTR) - printk("scsi%d : SEL interrupt\n", instance->host_no); -#endif + dprintk(NDEBUG_INTR, ("scsi%d : SEL interrupt\n", instance->host_no)); NCR5380_reselect(instance); (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); } else if (basr & BASR_PARITY_ERROR) { -#if (NDEBUG & NDEBUG_INTR) - printk("scsi%d : PARITY interrupt\n", instance->host_no); -#endif + dprintk(NDEBUG_INTR, ("scsi%d : PARITY interrupt\n", instance->host_no)); (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); } else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) { -#if (NDEBUG & NDEBUG_INTR) - printk("scsi%d : RESET interrupt\n", instance->host_no); -#endif + dprintk(NDEBUG_INTR, ("scsi%d : RESET interrupt\n", instance->host_no)); (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); } else { -/* - * XXX the rest of the interrupt conditions should *only* occur during a - * DMA transfer, which I haven't gotten around to fixing yet. - */ - #if defined(REAL_DMA) /* * We should only get PHASE MISMATCH and EOP interrupts @@ -1502,14 +1326,11 @@ * the current setting of the MODE register. */ - if ((NCR5380_read(MODE_REG) & MR_DMA) && ((basr & - BASR_END_DMA_TRANSFER) || - !(basr & BASR_PHASE_MATCH))) { + if ((NCR5380_read(MODE_REG) & MR_DMA) && ((basr & BASR_END_DMA_TRANSFER) || !(basr & BASR_PHASE_MATCH))) { int transfered; if (!hostdata->connected) - panic("scsi%d : received end of DMA interrupt with no connected cmd\n", - instance->hostno); + panic("scsi%d : received end of DMA interrupt with no connected cmd\n", instance->hostno); transfered = (hostdata->dmalen - NCR5380_dma_residual(instance)); hostdata->connected->SCp.this_residual -= transferred; @@ -1521,16 +1342,14 @@ { unsigned long timeout = jiffies + NCR_TIMEOUT; - spin_unlock_irq(instance->host_lock); - while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK - && time_before(jiffies, timeout)); - spin_lock_irq(instance->host_lock); - - if (time_after_eq(jiffies, timeout) ) - printk("scsi%d: timeout at NCR5380.c:%d\n", - host->host_no, __LINE__); + spin_unlock_irq(&io_request_lock); + while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK && time_before(jiffies, timeout)); + spin_lock_irq(&io_request_lock); + + if (time_after_eq(jiffies, timeout)) + printk("scsi%d: timeout at NCR5380.c:%d\n", host->host_no, __LINE__); } -#else /* NCR_TIMEOUT */ +#else /* NCR_TIMEOUT */ while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK); #endif @@ -1538,9 +1357,7 @@ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); } #else -#if (NDEBUG & NDEBUG_INTR) - printk("scsi : unknown interrupt, BASR 0x%X, MR 0x%X, SR 0x%x\n", basr, NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG)); -#endif + dprintk(NDEBUG_INTR, ("scsi : unknown interrupt, BASR 0x%X, MR 0x%X, SR 0x%x\n", basr, NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG))); (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); #endif } @@ -1551,42 +1368,57 @@ } while (!done); } +/** + * do_NCR5380_intr + * @irq: interrupt number + * @dev_id: device info + * @regs: registers (unused) + * + * Takes the io_request_lock and invokes the generic NCR5380 interrupt + * handler code + * + * Locks: takes and releases the io_request lock + */ static void do_NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) { unsigned long flags; - - struct Scsi_Host *dev = dev_id; - - spin_lock_irqsave(dev->host_lock, flags); + + spin_lock_irqsave(&io_request_lock, flags); NCR5380_intr(irq, dev_id, regs); - spin_unlock_irqrestore(dev->host_lock, flags); + spin_unlock_irqrestore(&io_request_lock, flags); } - #endif + +/** + * collect_stats - collect stats on a scsi command + * @hostdata: adapter + * @cmd: command being issued + * + * Update the statistical data by parsing the command in question + */ + +static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) +{ #ifdef NCR5380_STATS -static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) { -#ifdef NCR5380_STAT_LIMIT - if (cmd->request_bufflen > NCR5380_STAT_LIMIT) -#endif - switch (cmd->cmnd[0]) { - case WRITE: - case WRITE_6: - case WRITE_10: - hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase); - /*hostdata->bytes_write[cmd->target] += cmd->request_bufflen; */ - hostdata->pendingw--; - break; - case READ: - case READ_6: - case READ_10: - hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase); - /*hostdata->bytes_read[cmd->target] += cmd->request_bufflen; */ - hostdata->pendingr--; - break; - } -} + switch (cmd->cmnd[0]) { + case WRITE: + case WRITE_6: + case WRITE_10: + hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase); + hostdata->pendingw--; + break; + case READ: + case READ_6: + case READ_10: + hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase); + hostdata->pendingr--; + break; + } #endif +} + + /* * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, * int tag); @@ -1616,69 +1448,58 @@ * * If failed (no target) : cmd->scsi_done() will be called, and the * cmd->result host byte set to DID_BAD_TARGET. + * + * Locks: caller holds io_request_lock */ -static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag) { + +static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag) +{ NCR5380_local_declare(); struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; unsigned char tmp[3], phase; unsigned char *data; int len; unsigned long timeout; - unsigned long flags; -#ifdef USLEEP unsigned char value; -#endif - NCR5380_setup(instance); -#ifdef USLEEP - - if (hostdata->selecting) - { + if (hostdata->selecting) { goto part2; /* RvC: sorry prof. Dijkstra, but it keeps the rest of the code nearly the same */ } -#endif - hostdata->restart_select = 0; -#if defined (NDEBUG) && (NDEBUG & NDEBUG_ARBITRATION) - NCR5380_print(instance); - printk("scsi%d : starting arbitration, id = %d\n", instance->host_no, - instance->this_id); -#endif - save_flags(flags); - cli(); + hostdata->restart_select = 0; + + NCR5380_dprint(NDEBUG_ARBITRATION, instance); + dprintk(NDEBUG_ARBITRATION, ("scsi%d : starting arbitration, id = %d\n", instance->host_no, instance->this_id)); /* * Set the phase bits to 0, otherwise the NCR5380 won't drive the * data bus during SELECTION. */ - NCR5380_write(TARGET_COMMAND_REG, 0); - + NCR5380_write(TARGET_COMMAND_REG, 0); /* * Start arbitration. */ - NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); - NCR5380_write(MODE_REG, MR_ARBITRATE); - - restore_flags(flags); + NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); + NCR5380_write(MODE_REG, MR_ARBITRATE); /* Wait for arbitration logic to complete */ #if NCR_TIMEOUT { unsigned long timeout = jiffies + 2 * NCR_TIMEOUT; - spin_unlock_irq(instance->host_lock); + spin_unlock_irq(&io_request_lock); while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) - && time_before(jiffies,timeout)); + && time_before(jiffies, timeout)); + + spin_lock_irq(&io_request_lock); - spin_lock_irq(instance->host_lock); - - if (time_after_eq(jiffies,timeout)) { + if (time_after_eq(jiffies, timeout)) { printk("scsi: arbitration timeout at %d\n", __LINE__); NCR5380_write(MODE_REG, MR_BASE); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); @@ -1689,11 +1510,7 @@ while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)); #endif -#if (NDEBUG & NDEBUG_ARBITRATION) - printk("scsi%d : arbitration complete\n", instance->host_no); -/* Avoid GCC 2.4.5 asm needs to many reloads error */ - __asm__("nop"); -#endif + dprintk(NDEBUG_ARBITRATION, ("scsi%d : arbitration complete\n", instance->host_no)); /* * The arbitration delay is 2.2us, but this is a minimum and there is @@ -1702,34 +1519,25 @@ * */ - udelay(3); + udelay(3); /* Check for lost arbitration */ - if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || - (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || - (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) { + if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) { NCR5380_write(MODE_REG, MR_BASE); -#if (NDEBUG & NDEBUG_ARBITRATION) - printk("scsi%d : lost arbitration, deasserting MR_ARBITRATE\n", - instance->host_no); -#endif + dprintk(NDEBUG_ARBITRATION, ("scsi%d : lost arbitration, deasserting MR_ARBITRATE\n", instance->host_no)); return -1; } NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL); if (!(hostdata->flags & FLAG_DTC3181E) && - /* RvC: DTC3181E has some trouble with this - * so we simply removed it. Seems to work with - * only Mustek scanner attached - */ - (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) - { + /* RvC: DTC3181E has some trouble with this + * so we simply removed it. Seems to work with + * only Mustek scanner attached + */ + (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) { NCR5380_write(MODE_REG, MR_BASE); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); -#if (NDEBUG & NDEBUG_ARBITRATION) - printk("scsi%d : lost arbitration, deasserting ICR_ASSERT_SEL\n", - instance->host_no); -#endif + dprintk(NDEBUG_ARBITRATION, ("scsi%d : lost arbitration, deasserting ICR_ASSERT_SEL\n", instance->host_no)); return -1; } /* @@ -1739,10 +1547,7 @@ udelay(2); -#if (NDEBUG & NDEBUG_ARBITRATION) - printk("scsi%d : won arbitration\n", instance->host_no); -#endif - + dprintk(NDEBUG_ARBITRATION, ("scsi%d : won arbitration\n", instance->host_no)); /* * Now that we have won arbitration, start Selection process, asserting @@ -1757,8 +1562,7 @@ * phase immediately after selection. */ - NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | - ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL)); + NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL)); NCR5380_write(MODE_REG, MR_BASE); /* @@ -1774,8 +1578,7 @@ udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */ /* Reset BSY */ - NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | - ICR_ASSERT_ATN | ICR_ASSERT_SEL)); + NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL)); /* * Something weird happens when we cease to drive BSY - looks @@ -1796,9 +1599,7 @@ udelay(1); -#if (NDEBUG & NDEBUG_SELECTION) - printk("scsi%d : selecting target %d\n", instance->host_no, cmd->target); -#endif + dprintk(NDEBUG_SELECTION, ("scsi%d : selecting target %d\n", instance->host_no, cmd->target)); /* * The SCSI specification calls for a 250 ms timeout for the actual @@ -1813,40 +1614,30 @@ * and it's detecting as true. Sigh. */ -#ifdef USLEEP - hostdata->select_time = 0; /* we count the clock ticks at which we polled */ + hostdata->select_time = 0; /* we count the clock ticks at which we polled */ hostdata->selecting = cmd; part2: - /* RvC: here we enter after a sleeping period, or immediately after - execution of part 1 - we poll only once ech clock tick */ + /* RvC: here we enter after a sleeping period, or immediately after + execution of part 1 + we poll only once ech clock tick */ value = NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO); - if (!value && (hostdata->select_time < 25)) - { + if (!value && (hostdata->select_time < 25)) { /* RvC: we still must wait for a device response */ - hostdata->select_time++; /* after 25 ticks the device has failed */ + hostdata->select_time++; /* after 25 ticks the device has failed */ hostdata->time_expires = jiffies + 1; NCR5380_set_timer(instance); return 0; /* RvC: we return here with hostdata->selecting set, to go to sleep */ } - hostdata->selecting = 0; /* clear this pointer, because we passed the - waiting period */ -#else - spin_unlock_irq(instance->host_lock); - while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & - (SR_BSY | SR_IO))); - spin_lock_irq(instance->host_lock); -#endif - if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == - (SR_SEL | SR_IO)) { + hostdata->selecting = 0; /* clear this pointer, because we passed the + waiting period */ + if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) { NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); NCR5380_reselect(instance); - printk("scsi%d : reselection after won arbitration?\n", - instance->host_no); + printk("scsi%d : reselection after won arbitration?\n", instance->host_no); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); return -1; } @@ -1866,22 +1657,15 @@ printk("scsi%d : weirdness\n", instance->host_no); if (hostdata->restart_select) printk("\trestart select\n"); -#if (NDEBUG & NDEBUG_SELECTION) - NCR5380_print(instance); -#endif + NCR5380_dprint(NDEBUG_SELECTION, instance); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); return -1; } cmd->result = DID_BAD_TARGET << 16; -#ifdef NCR5380_STATS collect_stats(hostdata, cmd); -#endif cmd->scsi_done(cmd); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); -#if (NDEBUG & NDEBUG_SELECTION) - printk("scsi%d : target did not respond within 250ms\n", - instance->host_no); -#endif + dprintk(NDEBUG_SELECTION, ("scsi%d : target did not respond within 250ms\n", instance->host_no)); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); return 0; } @@ -1907,10 +1691,10 @@ { unsigned long timeout = jiffies + NCR_TIMEOUT; - spin_unlock_irq(instance->host_lock); + spin_unlock_irq(&io_request_lock); while (!(NCR5380_read(STATUS_REG) & SR_REQ) && time_before(jiffies, timeout)); - spin_lock_irq(instance->host_lock); - + spin_lock_irq(&io_request_lock); + if (time_after_eq(jiffies, timeout)) { printk("scsi%d: timeout at NCR5380.c:%d\n", instance->host_no, __LINE__); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); @@ -1921,47 +1705,20 @@ while (!(NCR5380_read(STATUS_REG) & SR_REQ)); #endif /* def NCR_TIMEOUT */ -#if (NDEBUG & NDEBUG_SELECTION) - printk("scsi%d : target %d selected, going into MESSAGE OUT phase.\n", - instance->host_no, cmd->target); -#endif + dprintk(NDEBUG_SELECTION, ("scsi%d : target %d selected, going into MESSAGE OUT phase.\n", instance->host_no, cmd->target)); tmp[0] = IDENTIFY(((instance->irq == IRQ_NONE) ? 0 : 1), cmd->lun); -#ifdef SCSI2 - if (cmd->device->tagged_queue && (tag != TAG_NONE)) { - tmp[1] = SIMPLE_QUEUE_TAG; - if (tag == TAG_NEXT) { - /* 0 is TAG_NONE, used to imply no tag for this command */ - if (cmd->device->current_tag == 0) - cmd->device->current_tag = 1; - - cmd->tag = cmd->device->current_tag; - cmd->device->current_tag++; - } else - cmd->tag = (unsigned char) tag; - - tmp[2] = cmd->tag; - hostdata->last_message = SIMPLE_QUEUE_TAG; - len = 3; - } else -#endif /* def SCSI2 */ - { - len = 1; - cmd->tag = 0; - } + + len = 1; + cmd->tag = 0; /* Send message(s) */ data = tmp; phase = PHASE_MSGOUT; NCR5380_transfer_pio(instance, &phase, &len, &data); -#if (NDEBUG & NDEBUG_SELECTION) - printk("scsi%d : nexus established.\n", instance->host_no); -#endif + dprintk(NDEBUG_SELECTION, ("scsi%d : nexus established.\n", instance->host_no)); /* XXX need to handle errors here */ hostdata->connected = cmd; -#ifdef SCSI2 - if (!cmd->device->tagged_queue) -#endif - hostdata->busy[cmd->target] |= (1 << cmd->lun); + hostdata->busy[cmd->target] |= (1 << cmd->lun); initialize_SCp(cmd); @@ -1994,27 +1751,22 @@ * counts, we will always do a pseudo DMA or DMA transfer. */ -static int NCR5380_transfer_pio(struct Scsi_Host *instance, - unsigned char *phase, int *count, unsigned char **data) { +static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data) { NCR5380_local_declare(); - register unsigned char p = *phase, tmp; - register int c = *count; - register unsigned char *d = *data; -#ifdef USLEEP + unsigned char p = *phase, tmp; + int c = *count; + unsigned char *d = *data; /* - * RvC: some administrative data to process polling time + * RvC: some administrative data to process polling time */ int break_allowed = 0; struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; -#endif NCR5380_setup(instance); -#if (NDEBUG & NDEBUG_PIO) if (!(p & SR_IO)) - printk("scsi%d : pio write %d bytes\n", instance->host_no, c); + dprintk(NDEBUG_PIO, ("scsi%d : pio write %d bytes\n", instance->host_no, c)); else - printk("scsi%d : pio read %d bytes\n", instance->host_no, c); -#endif + dprintk(NDEBUG_PIO, ("scsi%d : pio read %d bytes\n", instance->host_no, c)); /* * The NCR5380 chip will only drive the SCSI bus when the @@ -2024,56 +1776,42 @@ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); -#ifdef USLEEP /* RvC: don't know if this is necessary, but other SCSI I/O is short - * so breaks are not necessary there + * so breaks are not necessary there */ - if ((p == PHASE_DATAIN) || (p == PHASE_DATAOUT)) - { + if ((p == PHASE_DATAIN) || (p == PHASE_DATAOUT)) { break_allowed = 1; } -#endif - - do { /* * Wait for assertion of REQ, after which the phase bits will be * valid */ -#ifdef USLEEP /* RvC: we simply poll once, after that we stop temporarily - * and let the device buffer fill up - * if breaking is not allowed, we keep polling as long as needed + * and let the device buffer fill up + * if breaking is not allowed, we keep polling as long as needed */ - while ( !((tmp = NCR5380_read(STATUS_REG)) & SR_REQ) && - !break_allowed ); - if (!(tmp & SR_REQ)) - { + while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ) && !break_allowed); + if (!(tmp & SR_REQ)) { /* timeout condition */ hostdata->time_expires = jiffies + USLEEP_SLEEP; - NCR5380_set_timer (instance); + NCR5380_set_timer(instance); break; } -#else - while ( !((tmp = NCR5380_read(STATUS_REG)) & SR_REQ) ); -#endif -#if (NDEBUG & NDEBUG_HANDSHAKE) - printk("scsi%d : REQ detected\n", instance->host_no); -#endif + dprintk(NDEBUG_HANDSHAKE, ("scsi%d : REQ detected\n", instance->host_no)); /* Check for phase mismatch */ if ((tmp & PHASE_MASK) != p) { -#if (NDEBUG & NDEBUG_PIO) - printk("scsi%d : phase mismatch\n", instance->host_no); - NCR5380_print_phase(instance); -#endif + dprintk(NDEBUG_HANDSHAKE, ("scsi%d : phase mismatch\n", instance->host_no)); + NCR5380_dprint_phase(NDEBUG_HANDSHAKE, instance); break; } - /* Do actual transfer from SCSI bus to / from memory */ if (!(p & SR_IO)) - NCR5380_write(OUTPUT_DATA_REG, *d); + /* Do actual transfer from SCSI bus to / from memory */ + if (!(p & SR_IO)) + NCR5380_write(OUTPUT_DATA_REG, *d); else *d = NCR5380_read(CURRENT_SCSI_DATA_REG); @@ -2088,34 +1826,22 @@ if (!(p & SR_IO)) { if (!((p & SR_MSG) && c > 1)) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA); -#if (NDEBUG & NDEBUG_PIO) - NCR5380_print(instance); -#endif - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA | ICR_ASSERT_ACK); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); + NCR5380_dprint(NDEBUG_PIO, instance); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ACK); } else { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA | ICR_ASSERT_ATN); -#if (NDEBUG & NDEBUG_PIO) - NCR5380_print(instance); -#endif - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN); + NCR5380_dprint(NDEBUG_PIO, instance); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); } } else { -#if (NDEBUG & NDEBUG_PIO) - NCR5380_print(instance); -#endif + NCR5380_dprint(NDEBUG_PIO, instance); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); } while (NCR5380_read(STATUS_REG) & SR_REQ); -#if (NDEBUG & NDEBUG_HANDSHAKE) - printk("scsi%d : req false, handshake complete\n", instance->host_no); -#endif + dprintk(NDEBUG_HANDSHAKE, ("scsi%d : req false, handshake complete\n", instance->host_no)); /* * We have several special cases to consider during REQ/ACK handshaking : @@ -2136,9 +1862,7 @@ } } while (--c); -#if (NDEBUG & NDEBUG_PIO) - printk("scsi%d : residual %d\n", instance->host_no, c); -#endif + dprintk(NDEBUG_PIO, ("scsi%d : residual %d\n", instance->host_no, c)); *count = c; *data = d; @@ -2154,36 +1878,46 @@ return -1; } +/** + * do_reset - issue a reset command + * @host: adapter to reset + * + * Issue a reset sequence to the NCR5380 and try and get the bus + * back into sane shape. + * + * Locks: caller holds io_request lock + */ + static void do_reset(struct Scsi_Host *host) { - unsigned long flags; - NCR5380_local_declare(); - NCR5380_setup(host); + NCR5380_local_declare(); + NCR5380_setup(host); + + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK)); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST); + udelay(25); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); +} + +/* + * Function : do_abort (Scsi_Host *host) + * + * Purpose : abort the currently established nexus. Should only be + * called from a routine which can drop into a + * + * Returns : 0 on success, -1 on failure. + * + * Locks: io_request lock held by caller + */ - save_flags(flags); - cli(); - NCR5380_write(TARGET_COMMAND_REG, - PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK)); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST); - udelay(25); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - restore_flags(flags); -} /* - - * Function : do_abort (Scsi_Host *host) - * - * Purpose : abort the currently established nexus. Should only be - * called from a routine which can drop into a - * - * Returns : 0 on success, -1 on failure. - */ static int do_abort(struct Scsi_Host *host) { +static int do_abort(struct Scsi_Host *host) { NCR5380_local_declare(); unsigned char tmp, *msgptr, phase; int len; - NCR5380_setup(host); + NCR5380_setup(host); /* Request message out phase */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); /* * Wait for the target to indicate a valid phase by asserting @@ -2197,11 +1931,10 @@ while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ); - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); if ((tmp & PHASE_MASK) != PHASE_MSGOUT) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | - ICR_ASSERT_ACK); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK); while (NCR5380_read(STATUS_REG) & SR_REQ); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); } @@ -2237,54 +1970,46 @@ * * Also, *phase, *count, *data are modified in place. * + * Locks: io_request lock held by caller */ -static int NCR5380_transfer_dma(struct Scsi_Host *instance, - unsigned char *phase, int *count, unsigned char **data) { +static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data) { NCR5380_local_declare(); register int c = *count; register unsigned char p = *phase; register unsigned char *d = *data; unsigned char tmp; -#if defined(PSEUDO_DMA) && !defined(UNSAFE) - unsigned long flags; -#endif int foo; #if defined(REAL_DMA_POLL) int cnt, toPIO; unsigned char saved_data = 0, overrun = 0, residue; #endif - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; - NCR5380_setup(instance); + NCR5380_setup(instance); if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) { *phase = tmp; return -1; } #if defined(REAL_DMA) || defined(REAL_DMA_POLL) -#ifdef READ_OVERRUNS - if (p & SR_IO) { c -= 2; } -#endif -#if (NDEBUG & NDEBUG_DMA) -printk("scsi%d : initializing DMA channel %d for %s, %d bytes %s %0x\n", - instance->host_no, instance->dma_channel, (p & SR_IO) ? "reading" : - "writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d); +#ifdef READ_OVERRUNS + if (p & SR_IO) { + c -= 2; + } #endif -hostdata->dma_len = (p & SR_IO) ? -NCR5380_dma_read_setup(instance, d, c) : -NCR5380_dma_write_setup(instance, d, c); + dprintk(NDEBUG_DMA, ("scsi%d : initializing DMA channel %d for %s, %d bytes %s %0x\n", instance->host_no, instance->dma_channel, (p & SR_IO) ? "reading" : "writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d)); + hostdata->dma_len = (p & SR_IO) ? NCR5380_dma_read_setup(instance, d, c) : NCR5380_dma_write_setup(instance, d, c); #endif -NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); #ifdef REAL_DMA -NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY); + NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY); #elif defined(REAL_DMA_POLL) -NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE); + NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE); #else /* * Note : on my sample board, watch-dog timeouts occurred when interrupts @@ -2292,58 +2017,38 @@ * before the setting of DMA mode to after transfer of the last byte. */ -#if defined(PSEUDO_DMA) && !defined(UNSAFE) -save_flags(flags); -cli(); +#if defined(PSEUDO_DMA) && defined(UNSAFE) + spin_unlock_irq(&io_request_lock); #endif /* KLL May need eop and parity in 53c400 */ -if (hostdata->flags & FLAG_NCR53C400) - NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_PAR_CHECK - | MR_ENABLE_PAR_INTR | MR_ENABLE_EOP_INTR | MR_DMA_MODE - | MR_MONITOR_BSY); -else - NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE); + if (hostdata->flags & FLAG_NCR53C400) + NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_PAR_CHECK | MR_ENABLE_PAR_INTR | MR_ENABLE_EOP_INTR | MR_DMA_MODE | MR_MONITOR_BSY); + else + NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE); #endif /* def REAL_DMA */ -#if (NDEBUG & NDEBUG_DMA) & 0 -printk("scsi%d : mode reg = 0x%X\n", instance->host_no, NCR5380_read(MODE_REG)); -#endif + dprintk(NDEBUG_DMA, ("scsi%d : mode reg = 0x%X\n", instance->host_no, NCR5380_read(MODE_REG))); -/* - * FOO stuff. For some UNAPPARENT reason, I'm getting - * watchdog timers fired on bootup for NO APPARENT REASON, meaning it's - * probably a timing problem. - * - * Since this is the only place I have back-to-back writes, perhaps this - * is the problem? - */ + /* + * On the PAS16 at least I/O recovery delays are not needed here. + * Everyone else seems to want them. + */ -if (p & SR_IO) -{ -#ifndef FOO -udelay(1); -#endif -NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); -} else { -#ifndef FOO - udelay(1); -#endif - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); -#ifndef FOO - udelay(1); -#endif - NCR5380_write(START_DMA_SEND_REG, 0); -#ifndef FOO - udelay(1); -#endif -} + if (p & SR_IO) { + io_recovery_delay(1); + NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); + } else { + io_recovery_delay(1); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); + io_recovery_delay(1); + NCR5380_write(START_DMA_SEND_REG, 0); + io_recovery_delay(1); + } #if defined(REAL_DMA_POLL) -do { - tmp = NCR5380_read(BUS_AND_STATUS_REG); -} while ((tmp & BASR_PHASE_MATCH) && !(tmp & (BASR_BUSY_ERROR | - - BASR_END_DMA_TRANSFER))); + do { + tmp = NCR5380_read(BUS_AND_STATUS_REG); + } while ((tmp & BASR_PHASE_MATCH) && !(tmp & (BASR_BUSY_ERROR | BASR_END_DMA_TRANSFER))); /* At this point, either we've completed DMA, or we have a phase mismatch, @@ -2381,172 +2086,128 @@ request. */ -if (p & SR_IO) { + if (p & SR_IO) { #ifdef READ_OVERRUNS - udelay(10); - if (((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK)) == - (BASR_PHASE_MATCH | BASR_ACK))) { - saved_data = NCR5380_read(INPUT_DATA_REGISTER); - overrun = 1; - } + udelay(10); + if (((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK)) == (BASR_PHASE_MATCH | BASR_ACK))) { + saved_data = NCR5380_read(INPUT_DATA_REGISTER); + overrun = 1; + } #endif -} else { - int limit = 100; - while (((tmp = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_ACK) || - (NCR5380_read(STATUS_REG) & SR_REQ)) { - if (!(tmp & BASR_PHASE_MATCH)) - break; - if (--limit < 0) - break; + } else { + int limit = 100; + while (((tmp = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_ACK) || (NCR5380_read(STATUS_REG) & SR_REQ)) { + if (!(tmp & BASR_PHASE_MATCH)) + break; + if (--limit < 0) + break; + } } -} + dprintk(NDEBUG_DMA, ("scsi%d : polled DMA transfer complete, basr 0x%X, sr 0x%X\n", instance->host_no, tmp, NCR5380_read(STATUS_REG))); -#if (NDEBUG & NDEBUG_DMA) -printk("scsi%d : polled DMA transfer complete, basr 0x%X, sr 0x%X\n", - instance->host_no, tmp, NCR5380_read(STATUS_REG)); -#endif + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); -NCR5380_write(MODE_REG, MR_BASE); -NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - -residue = NCR5380_dma_residual(instance); -c -= residue; -*count -= c; -*data += c; -*phase = NCR5380_read(STATUS_REG) & PHASE_MASK; + residue = NCR5380_dma_residual(instance); + c -= residue; + *count -= c; + *data += c; + *phase = NCR5380_read(STATUS_REG) & PHASE_MASK; #ifdef READ_OVERRUNS -if (*phase == p && (p & SR_IO) && residue == 0) -{ -if (overrun) { -#if (NDEBUG & NDEBUG_DMA) - printk("Got an input overrun, using saved byte\n"); -#endif - **data = saved_data; - *data += 1; - *count -= 1; - cnt = toPIO = 1; -} else { - printk("No overrun??\n"); - cnt = toPIO = 2; -} -#if (NDEBUG & NDEBUG_DMA) -printk("Doing %d-byte PIO to 0x%X\n", cnt, *data); -#endif -NCR5380_transfer_pio(instance, phase, &cnt, data); -*count -= toPIO - cnt; -} + if (*phase == p && (p & SR_IO) && residue == 0) { + if (overrun) { + dprintk(NDEBUG_DMA, ("Got an input overrun, using saved byte\n")); + **data = saved_data; + *data += 1; + *count -= 1; + cnt = toPIO = 1; + } else { + printk("No overrun??\n"); + cnt = toPIO = 2; + } + dprintk(NDEBUG_DMA, ("Doing %d-byte PIO to 0x%X\n", cnt, *data)); + NCR5380_transfer_pio(instance, phase, &cnt, data); + *count -= toPIO - cnt; + } #endif -#if (NDEBUG & NDEBUG_DMA) -printk("Return with data ptr = 0x%X, count %d, last 0x%X, next 0x%X\n", - *data, *count, *(*data + *count - 1), *(*data + *count)); -#endif -return 0; + dprintk(NDEBUG_DMA, ("Return with data ptr = 0x%X, count %d, last 0x%X, next 0x%X\n", *data, *count, *(*data + *count - 1), *(*data + *count))); + return 0; #elif defined(REAL_DMA) -return 0; + return 0; #else /* defined(REAL_DMA_POLL) */ -if (p & SR_IO) { + if (p & SR_IO) { #ifdef DMA_WORKS_RIGHT - foo = NCR5380_pread(instance, d, c); + foo = NCR5380_pread(instance, d, c); #else - int diff = 1; - if (hostdata->flags & FLAG_NCR53C400) { - diff = 0; - } - if (!(foo = NCR5380_pread(instance, d, c - diff))) { - /* - * We can't disable DMA mode after successfully transferring - * what we plan to be the last byte, since that would open up - * a race condition where if the target asserted REQ before - * we got the DMA mode reset, the NCR5380 would have latched - * an additional byte into the INPUT DATA register and we'd - * have dropped it. - * - * The workaround was to transfer one fewer bytes than we - * intended to with the pseudo-DMA read function, wait for - * the chip to latch the last byte, read it, and then disable - * pseudo-DMA mode. - * - * After REQ is asserted, the NCR5380 asserts DRQ and ACK. - * REQ is deasserted when ACK is asserted, and not reasserted - * until ACK goes false. Since the NCR5380 won't lower ACK - * until DACK is asserted, which won't happen unless we twiddle - * the DMA port or we take the NCR5380 out of DMA mode, we - * can guarantee that we won't handshake another extra - * byte. - */ + int diff = 1; + if (hostdata->flags & FLAG_NCR53C400) { + diff = 0; + } + if (!(foo = NCR5380_pread(instance, d, c - diff))) { + /* + * We can't disable DMA mode after successfully transferring + * what we plan to be the last byte, since that would open up + * a race condition where if the target asserted REQ before + * we got the DMA mode reset, the NCR5380 would have latched + * an additional byte into the INPUT DATA register and we'd + * have dropped it. + * + * The workaround was to transfer one fewer bytes than we + * intended to with the pseudo-DMA read function, wait for + * the chip to latch the last byte, read it, and then disable + * pseudo-DMA mode. + * + * After REQ is asserted, the NCR5380 asserts DRQ and ACK. + * REQ is deasserted when ACK is asserted, and not reasserted + * until ACK goes false. Since the NCR5380 won't lower ACK + * until DACK is asserted, which won't happen unless we twiddle + * the DMA port or we take the NCR5380 out of DMA mode, we + * can guarantee that we won't handshake another extra + * byte. + */ - if (!(hostdata->flags & FLAG_NCR53C400)) { - while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)); - /* Wait for clean handshake */ - while (NCR5380_read(STATUS_REG) & SR_REQ); - d[c - 1] = NCR5380_read(INPUT_DATA_REG); + if (!(hostdata->flags & FLAG_NCR53C400)) { + while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)); + /* Wait for clean handshake */ + while (NCR5380_read(STATUS_REG) & SR_REQ); + d[c - 1] = NCR5380_read(INPUT_DATA_REG); + } } - } #endif -} else { + } else { #ifdef DMA_WORKS_RIGHT - foo = NCR5380_pwrite(instance, d, c); -#else - int timeout; -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("About to pwrite %d bytes\n", c); -#endif - if (!(foo = NCR5380_pwrite(instance, d, c))) { - /* - * Wait for the last byte to be sent. If REQ is being asserted for - * the byte we're interested, we'll ACK it and it will go false. - */ - if (!(hostdata->flags & FLAG_HAS_LAST_BYTE_SENT)) { - timeout = 20000; -#if 1 -#if 1 - while (!(NCR5380_read(BUS_AND_STATUS_REG) & - BASR_DRQ) && (NCR5380_read(BUS_AND_STATUS_REG) & - BASR_PHASE_MATCH)); + foo = NCR5380_pwrite(instance, d, c); #else - if (NCR5380_read(STATUS_REG) & SR_REQ) { - for (; timeout && - !(NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK); - --timeout); - for (; timeout && (NCR5380_read(STATUS_REG) & SR_REQ); - --timeout); - } -#endif - - -#if (NDEBUG & NDEBUG_LAST_BYTE_SENT) - if (!timeout) - printk("scsi%d : timed out on last byte\n", - instance->host_no); -#endif - - - if (hostdata->flags & FLAG_CHECK_LAST_BYTE_SENT) { - hostdata->flags &= ~FLAG_CHECK_LAST_BYTE_SENT; - if (NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT) { - hostdata->flags |= FLAG_HAS_LAST_BYTE_SENT; -#if (NDEBUG & NDEBUG_LAST_BYTE_SENT) - printk("scsi%d : last bit sent works\n", - instance->host_no); -#endif + int timeout; + dprintk(NDEBUG_C400_PWRITE, ("About to pwrite %d bytes\n", c)); + if (!(foo = NCR5380_pwrite(instance, d, c))) { + /* + * Wait for the last byte to be sent. If REQ is being asserted for + * the byte we're interested, we'll ACK it and it will go false. + */ + if (!(hostdata->flags & FLAG_HAS_LAST_BYTE_SENT)) { + timeout = 20000; + while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) && (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)); + + if (!timeout) + dprintk(NDEBUG_LAST_BYTE_SENT, ("scsi%d : timed out on last byte\n", instance->host_no)); + + if (hostdata->flags & FLAG_CHECK_LAST_BYTE_SENT) { + hostdata->flags &= ~FLAG_CHECK_LAST_BYTE_SENT; + if (NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT) { + hostdata->flags |= FLAG_HAS_LAST_BYTE_SENT; + dprintk(NDEBUG_LAST_WRITE_SENT, ("scsi%d : last bit sent works\n", instance->host_no)); + } } + } else { + dprintk(NDEBUG_C400_PWRITE, ("Waiting for LASTBYTE\n")); + while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)); + dprintk(NDEBUG_C400_PWRITE, ("Got LASTBYTE\n")); } - } else { -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("Waiting for LASTBYTE\n"); -#endif - while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)); -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("Got LASTBYTE\n"); -#endif - } -#else - udelay(5); -#endif } #endif } @@ -2554,13 +2215,9 @@ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); if ((!(p & SR_IO)) && (hostdata->flags & FLAG_NCR53C400)) { -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: Checking for IRQ\n"); -#endif + dprintk(NDEBUG_C400_PWRITE, ("53C400w: Checking for IRQ\n")); if (NCR5380_read(BUS_AND_STATUS_REG) & BASR_IRQ) { -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: got it, reading reset interrupt reg\n"); -#endif + dprintk(NDEBUG_C400_PWRITE, ("53C400w: got it, reading reset interrupt reg\n")); NCR5380_read(RESET_PARITY_INTERRUPT_REG); } else { printk("53C400w: IRQ NOT THERE!\n"); @@ -2569,11 +2226,8 @@ *data = d + c; *count = 0; *phase = NCR5380_read(STATUS_REG) & PHASE_MASK; -#if 0 - NCR5380_print_phase(instance); -#endif -#if defined(PSEUDO_DMA) && !defined(UNSAFE) - restore_flags(flags); +#if defined(PSEUDO_DMA) && defined(UNSAFE) + spin_lock_irq(&io_request_lock); #endif /* defined(REAL_DMA_POLL) */ return foo; #endif /* def REAL_DMA */ @@ -2595,12 +2249,13 @@ * * XXX Note : we need to watch for bus free or a reset condition here * to recover from an unexpected bus free condition. + * + * Locks: io_request_lock held by caller */ static void NCR5380_information_transfer(struct Scsi_Host *instance) { NCR5380_local_declare(); - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)instance->hostdata; unsigned char msgout = NOP; int sink = 0; int len; @@ -2610,10 +2265,8 @@ unsigned char *data; unsigned char phase, tmp, extended_msg[10], old_phase = 0xff; Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected; -#ifdef USLEEP /* RvC: we need to set the end of the polling time */ unsigned long poll_time = jiffies + USLEEP_POLL; -#endif NCR5380_setup(instance); @@ -2624,27 +2277,22 @@ phase = (tmp & PHASE_MASK); if (phase != old_phase) { old_phase = phase; -#if (NDEBUG & NDEBUG_INFORMATION) - NCR5380_print_phase(instance); -#endif + NCR5380_dprint_phase(NDEBUG_INFORMATION, instance); } if (sink && (phase != PHASE_MSGOUT)) { NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | - ICR_ASSERT_ACK); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK); while (NCR5380_read(STATUS_REG) & SR_REQ); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_ATN); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); sink = 0; continue; } switch (phase) { - case PHASE_DATAIN: - case PHASE_DATAOUT: + case PHASE_DATAIN: + case PHASE_DATAOUT: #if (NDEBUG & NDEBUG_NO_DATAOUT) - printk("scsi%d : NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n", - instance->host_no); + printk("scsi%d : NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n", instance->host_no); sink = 1; do_abort(instance); cmd->result = DID_ERROR << 16; @@ -2661,11 +2309,7 @@ --cmd->SCp.buffers_residual; cmd->SCp.this_residual = cmd->SCp.buffer->length; cmd->SCp.ptr = cmd->SCp.buffer->address; -#if (NDEBUG & NDEBUG_INFORMATION) - printk("scsi%d : %d bytes and %d buffers left\n", - instance->host_no, cmd->SCp.this_residual, - cmd->SCp.buffers_residual); -#endif + dprintk(NDEBUG_INFORMATION, ("scsi%d : %d bytes and %d buffers left\n", instance->host_no, cmd->SCp.this_residual, cmd->SCp.buffers_residual)); } /* * The preferred transfer method is going to be @@ -2686,9 +2330,7 @@ * We supplement these 2 if's with the flag. */ #ifdef NCR5380_dma_xfer_len - if (!cmd->device->borken && - !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && - (transfersize = NCR5380_dma_xfer_len(instance, cmd)) != 0) { + if (!cmd->device->borken && !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && (transfersize = NCR5380_dma_xfer_len(instance, cmd)) != 0) { #else transfersize = cmd->transfersize; @@ -2697,27 +2339,21 @@ transfersize = 512; #endif /* LIMIT_TRANSFERSIZE */ - if (!cmd->device->borken && transfersize && - !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && - cmd->SCp.this_residual && !(cmd->SCp.this_residual % - transfersize)) { + if (!cmd->device->borken && transfersize && !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && cmd->SCp.this_residual && !(cmd->SCp.this_residual % transfersize)) { /* Limit transfers to 32K, for xx400 & xx406 * pseudoDMA that transfers in 128 bytes blocks. */ if (transfersize > 32 * 1024) transfersize = 32 * 1024; #endif len = transfersize; - if (NCR5380_transfer_dma(instance, &phase, - &len, (unsigned char **) &cmd->SCp.ptr)) { + if (NCR5380_transfer_dma(instance, &phase, &len, (unsigned char **) &cmd->SCp.ptr)) { /* * If the watchdog timer fires, all future accesses to this * device will use the polled-IO. */ - printk("scsi%d : switching target %d lun %d to slow handshake\n", - instance->host_no, cmd->target, cmd->lun); + printk("scsi%d : switching target %d lun %d to slow handshake\n", instance->host_no, cmd->target, cmd->lun); cmd->device->borken = 1; - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_ATN); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); sink = 1; do_abort(instance); cmd->result = DID_ERROR << 16; @@ -2727,12 +2363,11 @@ cmd->SCp.this_residual -= transfersize - len; } else #endif /* defined(PSEUDO_DMA) || defined(REAL_DMA_POLL) */ - NCR5380_transfer_pio(instance, &phase, - (int *) &cmd->SCp.this_residual, (unsigned char **) - &cmd->SCp.ptr); + NCR5380_transfer_pio(instance, &phase, (int *) &cmd->SCp.this_residual, (unsigned char **) + &cmd->SCp.ptr); break; - case PHASE_MSGIN: - len = 1; + case PHASE_MSGIN: + len = 1; data = &tmp; NCR5380_transfer_pio(instance, &phase, &len, &data); cmd->SCp.Message = tmp; @@ -2749,24 +2384,18 @@ * next_link, done() is called as with unlinked commands. */ #ifdef LINKED - case LINKED_CMD_COMPLETE: - case LINKED_FLG_CMD_COMPLETE: + case LINKED_CMD_COMPLETE: + case LINKED_FLG_CMD_COMPLETE: /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - -#if (NDEBUG & NDEBUG_LINKED) - printk("scsi%d : target %d lun %d linked command complete.\n", - instance->host_no, cmd->target, cmd->lun); -#endif + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + dprintk(NDEBUG_LINKED, ("scsi%d : target %d lun %d linked command complete.\n", instance->host_no, cmd->target, cmd->lun)); /* * Sanity check : A linked command should only terminate with * one of these messages if there are more linked commands * available. */ - if (!cmd->next_link) { - printk("scsi%d : target %d lun %d linked command complete, no next_link\n" - instance->host_no, cmd->target, cmd->lun); + printk("scsi%d : target %d lun %d linked command complete, no next_link\n" instance->host_no, cmd->target, cmd->lun); sink = 1; do_abort(instance); return; @@ -2775,27 +2404,19 @@ /* The next command is still part of this process */ cmd->next_link->tag = cmd->tag; cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); -#if (NDEBUG & NDEBUG_LINKED) - printk("scsi%d : target %d lun %d linked request done, calling scsi_done().\n", - instance->host_no, cmd->target, cmd->lun); -#endif -#ifdef NCR5380_STATS + dprintk(NDEBUG_LINKED, ("scsi%d : target %d lun %d linked request done, calling scsi_done().\n", instance->host_no, cmd->target, cmd->lun)); collect_stats(hostdata, cmd); -#endif cmd->scsi_done(cmd); cmd = hostdata->connected; break; #endif /* def LINKED */ - case ABORT: - case COMMAND_COMPLETE: + case ABORT: + case COMMAND_COMPLETE: /* Accept message by clearing ACK */ - sink = 1; + sink = 1; NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); hostdata->connected = NULL; -#if (NDEBUG & NDEBUG_QUEUES) - printk("scsi%d : command for target %d, lun %d completed\n", - instance->host_no, cmd->target, cmd->lun); -#endif + dprintk(NDEBUG_QUEUES, ("scsi%d : command for target %d, lun %d completed\n", instance->host_no, cmd->target, cmd->lun)); hostdata->busy[cmd->target] &= ~(1 << cmd->lun); /* @@ -2820,13 +2441,8 @@ cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); #ifdef AUTOSENSE - if ((cmd->cmnd[0] != REQUEST_SENSE) && - (cmd->SCp.Status == CHECK_CONDITION)) { - unsigned long flags; -#if (NDEBUG & NDEBUG_AUTOSENSE) - printk("scsi%d : performing request sense\n", - instance->host_no); -#endif + if ((cmd->cmnd[0] != REQUEST_SENSE) && (cmd->SCp.Status == CHECK_CONDITION)) { + dprintk(NDEBUG_AUTOSENSE, ("scsi%d : performing request sense\n", instance->host_no)); cmd->cmnd[0] = REQUEST_SENSE; cmd->cmnd[1] &= 0xe0; cmd->cmnd[2] = 0; @@ -2839,21 +2455,14 @@ cmd->SCp.ptr = (char *) cmd->sense_buffer; cmd->SCp.this_residual = sizeof(cmd->sense_buffer); - save_flags(flags); - cli(); LIST(cmd, hostdata->issue_queue); cmd->host_scribble = (unsigned char *) hostdata->issue_queue; hostdata->issue_queue = (Scsi_Cmnd *) cmd; - restore_flags(flags); -#if (NDEBUG & NDEBUG_QUEUES) - printk("scsi%d : REQUEST SENSE added to head of issue queue\n", instance->host_no); -#endif + dprintk(NDEBUG_QUEUES, ("scsi%d : REQUEST SENSE added to head of issue queue\n", instance->host_no)); } else { #endif /* def AUTOSENSE */ -#ifdef NCR5380_STATS collect_stats(hostdata, cmd); -#endif cmd->scsi_done(cmd); } @@ -2867,37 +2476,29 @@ while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) barrier(); return; - case MESSAGE_REJECT: + case MESSAGE_REJECT: /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); switch (hostdata->last_message) { - case HEAD_OF_QUEUE_TAG: - case ORDERED_QUEUE_TAG: - case SIMPLE_QUEUE_TAG: - cmd->device->tagged_queue = 0; + case HEAD_OF_QUEUE_TAG: + case ORDERED_QUEUE_TAG: + case SIMPLE_QUEUE_TAG: + cmd->device->tagged_queue = 0; hostdata->busy[cmd->target] |= (1 << cmd->lun); break; - default: - break; + default: + break; } - case DISCONNECT: { - unsigned long flags; + case DISCONNECT:{ /* Accept message by clearing ACK */ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); cmd->device->disconnect = 1; - save_flags(flags); - cli(); LIST(cmd, hostdata->disconnected_queue); cmd->host_scribble = (unsigned char *) hostdata->disconnected_queue; hostdata->connected = NULL; hostdata->disconnected_queue = cmd; - restore_flags(flags); -#if (NDEBUG & NDEBUG_QUEUES) - printk("scsi%d : command for target %d lun %d was moved from connected to" - " the disconnected_queue\n", instance->host_no, - cmd->target, cmd->lun); -#endif + dprintk(NDEBUG_QUEUES, ("scsi%d : command for target %d lun %d was moved from connected to" " the disconnected_queue\n", instance->host_no, cmd->target, cmd->lun)); /* * Restore phase bits to 0 so an interrupted selection, * arbitration can resume. @@ -2909,9 +2510,6 @@ /* Wait for bus free to avoid nasty timeouts */ while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) barrier(); -#if 0 - NCR5380_print_status(instance); -#endif return; } /* @@ -2924,12 +2522,12 @@ * disconnecting, and we have to break spec to remain * compatible. */ - case SAVE_POINTERS: - case RESTORE_POINTERS: + case SAVE_POINTERS: + case RESTORE_POINTERS: /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); break; - case EXTENDED_MESSAGE: + case EXTENDED_MESSAGE: /* * Extended messages are sent in the following format : * Byte @@ -2942,28 +2540,19 @@ * Start the extended message buffer with the EXTENDED_MESSAGE * byte, since print_msg() wants the whole thing. */ - extended_msg[0] = EXTENDED_MESSAGE; + extended_msg[0] = EXTENDED_MESSAGE; /* Accept first byte by clearing ACK */ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - -#if (NDEBUG & NDEBUG_EXTENDED) - printk("scsi%d : receiving extended message\n", - instance->host_no); -#endif + dprintk(NDEBUG_EXTENDED, ("scsi%d : receiving extended message\n", instance->host_no)); len = 2; data = extended_msg + 1; phase = PHASE_MSGIN; NCR5380_transfer_pio(instance, &phase, &len, &data); -#if (NDEBUG & NDEBUG_EXTENDED) - printk("scsi%d : length=%d, code=0x%02x\n", - instance->host_no, (int) extended_msg[1], - (int) extended_msg[2]); -#endif + dprintk(NDEBUG_EXTENDED, ("scsi%d : length=%d, code=0x%02x\n", instance->host_no, (int) extended_msg[1], (int) extended_msg[2])); - if (!len && extended_msg[1] <= - (sizeof(extended_msg) - 1)) { + if (!len && extended_msg[1] <= (sizeof(extended_msg) - 1)) { /* Accept third byte by clearing ACK */ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); len = extended_msg[1] - 1; @@ -2971,26 +2560,20 @@ phase = PHASE_MSGIN; NCR5380_transfer_pio(instance, &phase, &len, &data); - -#if (NDEBUG & NDEBUG_EXTENDED) - printk("scsi%d : message received, residual %d\n", - instance->host_no, len); -#endif + dprintk(NDEBUG_EXTENDED, ("scsi%d : message received, residual %d\n", instance->host_no, len)); switch (extended_msg[2]) { - case EXTENDED_SDTR: - case EXTENDED_WDTR: - case EXTENDED_MODIFY_DATA_POINTER: - case EXTENDED_EXTENDED_IDENTIFY: - tmp = 0; + case EXTENDED_SDTR: + case EXTENDED_WDTR: + case EXTENDED_MODIFY_DATA_POINTER: + case EXTENDED_EXTENDED_IDENTIFY: + tmp = 0; } } else if (len) { - printk("scsi%d: error receiving extended message\n", - instance->host_no); + printk("scsi%d: error receiving extended message\n", instance->host_no); tmp = 0; } else { - printk("scsi%d: extended message code %02x length %d is too long\n", - instance->host_no, extended_msg[2], extended_msg[1]); + printk("scsi%d: extended message code %02x length %d is too long\n", instance->host_no, extended_msg[2], extended_msg[1]); tmp = 0; } /* Fall through to reject message */ @@ -2999,26 +2582,23 @@ * If we get something weird that we aren't expecting, * reject it. */ - default: - if (!tmp) { + default: + if (!tmp) { printk("scsi%d: rejecting message ", instance->host_no); print_msg(extended_msg); printk("\n"); } else if (tmp != EXTENDED_MESSAGE) - printk("scsi%d: rejecting unknown message %02x from target %d, lun %d\n", - instance->host_no, tmp, cmd->target, cmd->lun); + printk("scsi%d: rejecting unknown message %02x from target %d, lun %d\n", instance->host_no, tmp, cmd->target, cmd->lun); else - printk("scsi%d: rejecting unknown extended message code %02x, length %d from target %d, lun %d\n", - instance->host_no, extended_msg[1], extended_msg[0], cmd->target, cmd->lun); + printk("scsi%d: rejecting unknown extended message code %02x, length %d from target %d, lun %d\n", instance->host_no, extended_msg[1], extended_msg[0], cmd->target, cmd->lun); msgout = MESSAGE_REJECT; - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_ATN); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); break; } /* switch (tmp) */ break; - case PHASE_MSGOUT: - len = 1; + case PHASE_MSGOUT: + len = 1; data = &msgout; hostdata->last_message = msgout; NCR5380_transfer_pio(instance, &phase, &len, &data); @@ -3026,69 +2606,50 @@ hostdata->busy[cmd->target] &= ~(1 << cmd->lun); hostdata->connected = NULL; cmd->result = DID_ERROR << 16; -#ifdef NCR5380_STATS collect_stats(hostdata, cmd); -#endif cmd->scsi_done(cmd); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); return; } msgout = NOP; break; - case PHASE_CMDOUT: - len = cmd->cmd_len; + case PHASE_CMDOUT: + len = cmd->cmd_len; data = cmd->cmnd; /* * XXX for performance reasons, on machines with a * PSEUDO-DMA architecture we should probably * use the dma transfer function. */ - NCR5380_transfer_pio(instance, &phase, &len, - &data); -#ifdef USLEEP - if (!cmd->device->disconnect && - should_disconnect(cmd->cmnd[0])) - { + NCR5380_transfer_pio(instance, &phase, &len, &data); + if (!cmd->device->disconnect && should_disconnect(cmd->cmnd[0])) { hostdata->time_expires = jiffies + USLEEP_SLEEP; -#if (NDEBUG & NDEBUG_USLEEP) - printk("scsi%d : issued command, sleeping until %ul\n", instance->host_no, - hostdata->time_expires); -#endif + dprintk(NDEBUG_USLEEP, ("scsi%d : issued command, sleeping until %ul\n", instance->host_no, hostdata->time_expires)); NCR5380_set_timer(instance); return; } -#endif /* def USLEEP */ break; - case PHASE_STATIN: - len = 1; + case PHASE_STATIN: + len = 1; data = &tmp; NCR5380_transfer_pio(instance, &phase, &len, &data); cmd->SCp.Status = tmp; break; - default: - printk("scsi%d : unknown phase\n", instance->host_no); -#ifdef NDEBUG - NCR5380_print(instance); -#endif + default: + printk("scsi%d : unknown phase\n", instance->host_no); + NCR5380_dprint(NDEBUG_ALL, instance); } /* switch(phase) */ } /* if (tmp * SR_REQ) */ -#ifdef USLEEP - else - { + else { /* RvC: go to sleep if polling time expired */ - if (!cmd->device->disconnect && time_after_eq(jiffies, poll_time)) - { + if (!cmd->device->disconnect && time_after_eq(jiffies, poll_time)) { hostdata->time_expires = jiffies + USLEEP_SLEEP; -#if (NDEBUG & NDEBUG_USLEEP) - printk("scsi%d : poll timed out, sleeping until %ul\n", instance->host_no, - hostdata->time_expires); -#endif + dprintk(NDEBUG_USLEEP, ("scsi%d : poll timed out, sleeping until %ul\n", instance->host_no, hostdata->time_expires)); NCR5380_set_timer(instance); return; } } -#endif } /* while (1) */ } @@ -3101,9 +2662,9 @@ * * Inputs : instance - this instance of the NCR5380. * + * Locks: io_request_lock held by caller */ - static void NCR5380_reselect(struct Scsi_Host *instance) { NCR5380_local_declare(); struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) @@ -3111,28 +2672,22 @@ unsigned char target_mask; unsigned char lun, phase; int len; -#ifdef SCSI2 - unsigned char tag; -#endif unsigned char msg[3]; unsigned char *data; Scsi_Cmnd *tmp = NULL, *prev; int abort = 0; - NCR5380_setup(instance); + NCR5380_setup(instance); /* * Disable arbitration, etc. since the host adapter obviously * lost, and tell an interrupted NCR5380_select() to restart. */ - NCR5380_write(MODE_REG, MR_BASE); - hostdata->restart_select = 1; - - target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); + NCR5380_write(MODE_REG, MR_BASE); + hostdata->restart_select = 1; -#if (NDEBUG & NDEBUG_RESELECTION) - printk("scsi%d : reselect\n", instance->host_no); -#endif + target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); + dprintk(NDEBUG_SELECTION, ("scsi%d : reselect\n", instance->host_no)); /* * At this point, we have detected that our SCSI ID is on the bus, @@ -3143,10 +2698,10 @@ * signal. */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); while (NCR5380_read(STATUS_REG) & SR_SEL); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); /* * Wait for target to go into MSGIN. @@ -3154,15 +2709,13 @@ while (!(NCR5380_read(STATUS_REG) & SR_REQ)); - len = 1; - data = msg; - phase = PHASE_MSGIN; - NCR5380_transfer_pio(instance, &phase, &len, &data); - + len = 1; + data = msg; + phase = PHASE_MSGIN; + NCR5380_transfer_pio(instance, &phase, &len, &data); if (!msg[0] & 0x80) { - printk("scsi%d : expecting IDENTIFY message, got ", - instance->host_no); + printk("scsi%d : expecting IDENTIFY message, got ", instance->host_no); print_msg(msg); abort = 1; } else { @@ -3176,22 +2729,14 @@ * nexuses so we can chose to do additional data transfer. */ -#ifdef SCSI2 -#error "SCSI-II tagged queueing is not supported yet" -#endif - /* * Find the command corresponding to the I_T_L or I_T_L_Q nexus we * just reestablished, and remove it from the disconnected queue. */ - for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; - tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble) + for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble) if ((target_mask == (1 << tmp->target)) && (lun == tmp->lun) -#ifdef SCSI2 - && (tag == tmp->tag) -#endif ) { if (prev) { REMOVE(prev, prev->host_scribble, tmp, tmp->host_scribble); @@ -3204,13 +2749,7 @@ break; } if (!tmp) { -#ifdef SCSI2 - printk("scsi%d : warning : target bitmask %02x lun %d tag %d not in disconnect_queue.\n", - instance->host_no, target_mask, lun, tag); -#else - printk("scsi%d : warning : target bitmask %02x lun %d not in disconnect_queue.\n", - instance->host_no, target_mask, lun); -#endif + printk("scsi%d : warning : target bitmask %02x lun %d not in disconnect_queue.\n", instance->host_no, target_mask, lun); /* * Since we have an established nexus that we can't do anything with, * we must abort it. @@ -3223,10 +2762,7 @@ do_abort(instance); } else { hostdata->connected = tmp; -#if (NDEBUG & NDEBUG_RESELECTION) - printk("scsi%d : nexus established, target = %d, lun = %d, tag = %d\n", - instance->host_no, tmp->target, tmp->lun, tmp->tag); -#endif + dprintk(NDEBUG_RESELECTION, ("scsi%d : nexus established, target = %d, lun = %d, tag = %d\n", instance->host_no, tmp->target, tmp->lun, tmp->tag)); } } @@ -3245,8 +2781,7 @@ #ifdef REAL_DMA static void NCR5380_dma_complete(NCR5380_instance * instance) { NCR5380_local_declare(); - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata * - instance->hostdata); + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata * instance->hostdata); int transferred; NCR5380_setup(instance); @@ -3289,10 +2824,12 @@ * * Returns : 0 - success, -1 on failure. * - * XXX - there is no way to abort the command that is currently - * connected, you have to wait for it to complete. If this is - * a problem, we could implement longjmp() / setjmp(), setjmp() - * called where the loop started in NCR5380_main(). + * XXX - there is no way to abort the command that is currently + * connected, you have to wait for it to complete. If this is + * a problem, we could implement longjmp() / setjmp(), setjmp() + * called where the loop started in NCR5380_main(). + * + * Locks: io_request_lock held by caller */ #ifndef NCR5380_abort @@ -3300,10 +2837,8 @@ #endif int NCR5380_abort(Scsi_Cmnd * cmd) { NCR5380_local_declare(); - unsigned long flags; struct Scsi_Host *instance = cmd->host; - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; Scsi_Cmnd *tmp, **prev; printk("scsi%d : aborting command\n", instance->host_no); @@ -3316,15 +2851,10 @@ NCR5380_print_status(instance); - save_flags(flags); - cli(); NCR5380_setup(instance); -#if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : abort called\n", instance->host_no); - printk(" basr 0x%X, sr 0x%X\n", - NCR5380_read(BUS_AND_STATUS_REG), NCR5380_read(STATUS_REG)); -#endif + dprintk(NDEBUG_ABORT, ("scsi%d : abort called\n", instance->host_no)); + dprintk(NDEBUG_ABORT, (" basr 0x%X, sr 0x%X\n", NCR5380_read(BUS_AND_STATUS_REG), NCR5380_read(STATUS_REG))); #if 0 /* @@ -3334,9 +2864,7 @@ */ if (hostdata->connected == cmd) { -#if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : aborting connected command\n", instance->host_no); -#endif + dprintk(NDEBUG_ABORT, ("scsi%d : aborting connected command\n", instance->host_no)); hostdata->aborted = 1; /* * We should perform BSY checking, and make sure we haven't slipped @@ -3363,24 +2891,15 @@ * Case 2 : If the command hasn't been issued yet, we simply remove it * from the issue queue. */ -#if (NDEBUG & NDEBUG_ABORT) /* KLL */ - printk("scsi%d : abort going into loop.\n", instance->host_no); -#endif - for (prev = (Scsi_Cmnd **) & (hostdata->issue_queue), - tmp = (Scsi_Cmnd *) hostdata->issue_queue; - tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = - (Scsi_Cmnd *) tmp->host_scribble) + dprintk(NDEBUG_ABORT, ("scsi%d : abort going into loop.\n", instance->host_no)); + for (prev = (Scsi_Cmnd **) & (hostdata->issue_queue), tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = (Scsi_Cmnd *) tmp->host_scribble) if (cmd == tmp) { REMOVE(5, *prev, tmp, tmp->host_scribble); (*prev) = (Scsi_Cmnd *) tmp->host_scribble; tmp->host_scribble = NULL; tmp->result = DID_ABORT << 16; - restore_flags(flags); -#if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : abort removed command from issue queue.\n", - instance->host_no); -#endif + dprintk(NDEBUG_ABORT, ("scsi%d : abort removed command from issue queue.\n", instance->host_no)); tmp->done(tmp); return SCSI_ABORT_SUCCESS; } @@ -3402,10 +2921,7 @@ */ if (hostdata->connected) { - restore_flags(flags); -#if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : abort failed, command connected.\n", instance->host_no); -#endif + dprintk(NDEBUG_ABORT, ("scsi%d : abort failed, command connected.\n", instance->host_no)); return SCSI_ABORT_NOT_RUNNING; } /* @@ -3433,34 +2949,22 @@ * it from the disconnected queue. */ - for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; - tmp = (Scsi_Cmnd *) tmp->host_scribble) + for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; tmp = (Scsi_Cmnd *) tmp->host_scribble) if (cmd == tmp) { - restore_flags(flags); -#if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : aborting disconnected command.\n", instance->host_no); -#endif + dprintk(NDEBUG_ABORT, ("scsi%d : aborting disconnected command.\n", instance->host_no)); if (NCR5380_select(instance, cmd, (int) cmd->tag)) return SCSI_ABORT_BUSY; - -#if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : nexus reestablished.\n", instance->host_no); -#endif + dprintk(NDEBUG_ABORT, ("scsi%d : nexus reestablished.\n", instance->host_no)); do_abort(instance); - cli(); - for (prev = (Scsi_Cmnd **) & (hostdata->disconnected_queue), - tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; - tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = - (Scsi_Cmnd *) tmp->host_scribble) + for (prev = (Scsi_Cmnd **) & (hostdata->disconnected_queue), tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = (Scsi_Cmnd *) tmp->host_scribble) if (cmd == tmp) { REMOVE(5, *prev, tmp, tmp->host_scribble); *prev = (Scsi_Cmnd *) tmp->host_scribble; tmp->host_scribble = NULL; tmp->result = DID_ABORT << 16; - restore_flags(flags); tmp->done(tmp); return SCSI_ABORT_SUCCESS; } @@ -3474,10 +2978,7 @@ * so we won't panic, but we will notify the user in case something really * broke. */ - - restore_flags(flags); - printk("scsi%d : warning : SCSI command probably completed successfully\n" - " before abortion\n", instance->host_no); + printk("scsi%d : warning : SCSI command probably completed successfully\n" " before abortion\n", instance->host_no); return SCSI_ABORT_NOT_RUNNING; } @@ -3489,6 +2990,7 @@ * * Returns : SCSI_RESET_WAKEUP * + * Locks: io_request_lock held by caller */ #ifndef NCR5380_reset diff -Nru a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h --- a/drivers/scsi/NCR5380.h Tue Feb 26 11:57:59 2002 +++ b/drivers/scsi/NCR5380.h Tue Feb 26 11:57:59 2002 @@ -55,6 +55,8 @@ #define NDEBUG_C400_PWRITE 0x200000 #define NDEBUG_LISTS 0x400000 +#define NDEBUG_ANY 0xFFFFFFFFUL + /* * The contents of the OUTPUT DATA register are asserted on the bus when * either arbitration is occurring or the phase-indicating signals ( @@ -62,8 +64,8 @@ * bit in the INITIATOR COMMAND register is set. */ -#define OUTPUT_DATA_REG 0 /* wo DATA lines on SCSI bus */ -#define CURRENT_SCSI_DATA_REG 0 /* ro same */ +#define OUTPUT_DATA_REG 0 /* wo DATA lines on SCSI bus */ +#define CURRENT_SCSI_DATA_REG 0 /* ro same */ #define INITIATOR_COMMAND_REG 1 /* rw */ #define ICR_ASSERT_RST 0x80 /* rw Set to assert RST */ @@ -91,10 +93,10 @@ */ #define MR_BLOCK_DMA_MODE 0x80 /* rw block mode DMA */ #define MR_TARGET 0x40 /* rw target mode */ -#define MR_ENABLE_PAR_CHECK 0x20 /* rw enable parity checking */ +#define MR_ENABLE_PAR_CHECK 0x20 /* rw enable parity checking */ #define MR_ENABLE_PAR_INTR 0x10 /* rw enable bad parity interrupt */ #define MR_ENABLE_EOP_INTR 0x08 /* rw enable eop interrupt */ -#define MR_MONITOR_BSY 0x04 /* rw enable int on unexpected bsy fail */ +#define MR_MONITOR_BSY 0x04 /* rw enable int on unexpected bsy fail */ #define MR_DMA_MODE 0x02 /* rw DMA / pseudo DMA mode */ #define MR_ARBITRATE 0x01 /* rw start arbitration */ @@ -116,7 +118,7 @@ * Note : a set bit indicates an active signal, driven by us or another * device. */ -#define SR_RST 0x80 +#define SR_RST 0x80 #define SR_BSY 0x40 #define SR_REQ 0x20 #define SR_MSG 0x10 @@ -159,17 +161,17 @@ /* Write any value to this register to start an ini mode DMA receive */ #define START_DMA_INITIATOR_RECEIVE_REG 7 /* wo */ -#define C400_CONTROL_STATUS_REG NCR53C400_register_offset-8 /* rw */ +#define C400_CONTROL_STATUS_REG NCR53C400_register_offset-8 /* rw */ -#define CSR_RESET 0x80 /* wo Resets 53c400 */ -#define CSR_53C80_REG 0x80 /* ro 5380 registers busy */ -#define CSR_TRANS_DIR 0x40 /* rw Data transfer direction */ -#define CSR_SCSI_BUFF_INTR 0x20 /* rw Enable int on transfer ready */ -#define CSR_53C80_INTR 0x10 /* rw Enable 53c80 interrupts */ -#define CSR_SHARED_INTR 0x08 /* rw Interrupt sharing */ -#define CSR_HOST_BUF_NOT_RDY 0x04 /* ro Is Host buffer ready */ -#define CSR_SCSI_BUF_RDY 0x02 /* ro SCSI buffer read */ -#define CSR_GATED_53C80_IRQ 0x01 /* ro Last block xferred */ +#define CSR_RESET 0x80 /* wo Resets 53c400 */ +#define CSR_53C80_REG 0x80 /* ro 5380 registers busy */ +#define CSR_TRANS_DIR 0x40 /* rw Data transfer direction */ +#define CSR_SCSI_BUFF_INTR 0x20 /* rw Enable int on transfer ready */ +#define CSR_53C80_INTR 0x10 /* rw Enable 53c80 interrupts */ +#define CSR_SHARED_INTR 0x08 /* rw Interrupt sharing */ +#define CSR_HOST_BUF_NOT_RDY 0x04 /* ro Is Host buffer ready */ +#define CSR_SCSI_BUF_RDY 0x02 /* ro SCSI buffer read */ +#define CSR_GATED_53C80_IRQ 0x01 /* ro Last block xferred */ #if 0 #define CSR_BASE CSR_SCSI_BUFF_INTR | CSR_53C80_INTR @@ -178,13 +180,13 @@ #endif /* Number of 128-byte blocks to be transferred */ -#define C400_BLOCK_COUNTER_REG NCR53C400_register_offset-7 /* rw */ +#define C400_BLOCK_COUNTER_REG NCR53C400_register_offset-7 /* rw */ /* Resume transfer after disconnect */ -#define C400_RESUME_TRANSFER_REG NCR53C400_register_offset-6 /* wo */ +#define C400_RESUME_TRANSFER_REG NCR53C400_register_offset-6 /* wo */ /* Access to host buffer stack */ -#define C400_HOST_BUFFER NCR53C400_register_offset-4 /* rw */ +#define C400_HOST_BUFFER NCR53C400_register_offset-4 /* rw */ /* Note : PHASE_* macros are based on the values of the STATUS register */ @@ -203,8 +205,8 @@ * the target register so we can get phase mismatch interrupts on DMA * transfers. */ - -#define PHASE_SR_TO_TCR(phase) ((phase) >> 2) + +#define PHASE_SR_TO_TCR(phase) ((phase) >> 2) /* * The internal should_disconnect() function returns these based on the @@ -220,7 +222,7 @@ * These are "special" values for the tag parameter passed to NCR5380_select. */ -#define TAG_NEXT -1 /* Use next free tag */ +#define TAG_NEXT -1 /* Use next free tag */ #define TAG_NONE -2 /* * Establish I_T_L nexus instead of I_T_L_Q * even on SCSI-II devices. @@ -235,7 +237,7 @@ #define DMA_NONE 255 #define IRQ_AUTO 254 #define DMA_AUTO 254 -#define PORT_AUTO 0xffff /* autoprobe io port for 53c400a */ +#define PORT_AUTO 0xffff /* autoprobe io port for 53c400a */ #define FLAG_HAS_LAST_BYTE_SENT 1 /* NCR53c81 or better */ #define FLAG_CHECK_LAST_BYTE_SENT 2 /* Only test once */ @@ -245,134 +247,188 @@ #ifndef ASM struct NCR5380_hostdata { - NCR5380_implementation_fields; /* implementation specific */ - unsigned char id_mask, id_higher_mask; /* 1 << id, all bits greater */ - unsigned char targets_present; /* targets we have connected + NCR5380_implementation_fields; /* implementation specific */ + unsigned char id_mask, id_higher_mask; /* 1 << id, all bits greater */ + unsigned char targets_present; /* targets we have connected to, so we can call a select failure a retryable condition */ - volatile unsigned char busy[8]; /* index = target, bit = lun */ + volatile unsigned char busy[8]; /* index = target, bit = lun */ #if defined(REAL_DMA) || defined(REAL_DMA_POLL) - volatile int dma_len; /* requested length of DMA */ + volatile int dma_len; /* requested length of DMA */ #endif - volatile unsigned char last_message; /* last message OUT */ - volatile Scsi_Cmnd *connected; /* currently connected command */ - volatile Scsi_Cmnd *issue_queue; /* waiting to be issued */ - volatile Scsi_Cmnd *disconnected_queue; /* waiting for reconnect */ - volatile int restart_select; /* we have disconnected, + volatile unsigned char last_message; /* last message OUT */ + volatile Scsi_Cmnd *connected; /* currently connected command */ + volatile Scsi_Cmnd *issue_queue; /* waiting to be issued */ + volatile Scsi_Cmnd *disconnected_queue; /* waiting for reconnect */ + volatile int restart_select; /* we have disconnected, used to restart NCR5380_select() */ - volatile unsigned aborted:1; /* flag, says aborted */ - int flags; -#ifdef USLEEP - unsigned long time_expires; /* in jiffies, set prior to sleeping */ - struct Scsi_Host *next_timer; - int select_time; /* timer in select for target response */ - volatile Scsi_Cmnd *selecting; -#endif + volatile unsigned aborted:1; /* flag, says aborted */ + int flags; + unsigned long time_expires; /* in jiffies, set prior to sleeping */ + struct Scsi_Host *next_timer; + int select_time; /* timer in select for target response */ + volatile Scsi_Cmnd *selecting; #ifdef NCR5380_STATS - unsigned timebase; /* Base for time calcs */ - long time_read[8]; /* time to do reads */ - long time_write[8]; /* time to do writes */ - unsigned long bytes_read[8]; /* bytes read */ - unsigned long bytes_write[8]; /* bytes written */ - unsigned pendingr; - unsigned pendingw; + unsigned timebase; /* Base for time calcs */ + long time_read[8]; /* time to do reads */ + long time_write[8]; /* time to do writes */ + unsigned long bytes_read[8]; /* bytes read */ + unsigned long bytes_write[8]; /* bytes written */ + unsigned pendingr; + unsigned pendingw; #endif }; #ifdef __KERNEL__ -static struct Scsi_Host *first_instance; /* linked list of 5380's */ +static struct Scsi_Host *first_instance; /* linked list of 5380's */ + +#define dprintk(a,b) do {} while(0) +#define NCR5380_dprint(a,b) do {} while(0) +#define NCR5380_dprint_phase(a,b) do {} while(0) #if defined(AUTOPROBE_IRQ) -static int NCR5380_probe_irq (struct Scsi_Host *instance, int possible); +static int NCR5380_probe_irq(struct Scsi_Host *instance, int possible); #endif -static void NCR5380_init (struct Scsi_Host *instance, int flags); -static void NCR5380_information_transfer (struct Scsi_Host *instance); +static void NCR5380_init(struct Scsi_Host *instance, int flags); +static void NCR5380_information_transfer(struct Scsi_Host *instance); #ifndef DONT_USE_INTR -static void NCR5380_intr (int irq, void *dev_id, struct pt_regs * regs); -static void do_NCR5380_intr (int irq, void *dev_id, struct pt_regs * regs); +static void NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs); +static void do_NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs); #endif -static void NCR5380_main (void); -static void NCR5380_print_options (struct Scsi_Host *instance); -static void NCR5380_print_phase (struct Scsi_Host *instance); -static void NCR5380_print (struct Scsi_Host *instance); +static void NCR5380_main(void); +static void NCR5380_print_options(struct Scsi_Host *instance); +static void NCR5380_print_phase(struct Scsi_Host *instance); +static void NCR5380_print(struct Scsi_Host *instance); #ifndef NCR5380_abort static #endif -int NCR5380_abort (Scsi_Cmnd *cmd); +int NCR5380_abort(Scsi_Cmnd * cmd); #ifndef NCR5380_reset static #endif -int NCR5380_reset (Scsi_Cmnd *cmd, unsigned int reset_flags); +int NCR5380_reset(Scsi_Cmnd * cmd, unsigned int reset_flags); #ifndef NCR5380_queue_command -static +static #endif -int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)); +int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)); -static void NCR5380_reselect (struct Scsi_Host *instance); -static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag); +static void NCR5380_reselect(struct Scsi_Host *instance); +static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag); #if defined(PSEUDO_DMA) || defined(REAL_DMA) || defined(REAL_DMA_POLL) -static int NCR5380_transfer_dma (struct Scsi_Host *instance, - unsigned char *phase, int *count, unsigned char **data); +static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data); #endif -static int NCR5380_transfer_pio (struct Scsi_Host *instance, - unsigned char *phase, int *count, unsigned char **data); +static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data); #if (defined(REAL_DMA) || defined(REAL_DMA_POLL)) #if defined(i386) || defined(__alpha__) -static __inline__ int NCR5380_pc_dma_setup (struct Scsi_Host *instance, - unsigned char *ptr, unsigned int count, unsigned char mode) { - unsigned limit; - unsigned long bus_addr = virt_to_bus(ptr); - - if (instance->dma_channel <=3) { - if (count > 65536) - count = 65536; - limit = 65536 - (bus_addr & 0xFFFF); - } else { - if (count > 65536 * 2) - count = 65536 * 2; - limit = 65536* 2 - (bus_addr & 0x1FFFF); - } - - if (count > limit) count = limit; - - if ((count & 1) || (bus_addr & 1)) - panic ("scsi%d : attempted unaligned DMA transfer\n", instance->host_no); - cli(); - disable_dma(instance->dma_channel); - clear_dma_ff(instance->dma_channel); - set_dma_addr(instance->dma_channel, bus_addr); - set_dma_count(instance->dma_channel, count); - set_dma_mode(instance->dma_channel, mode); - enable_dma(instance->dma_channel); - sti(); - return count; +/** + * NCR5380_pc_dma_setup - setup ISA DMA + * @instance: adapter to set up + * @ptr: block to transfer (virtual address) + * @count: number of bytes to transfer + * @mode: DMA controller mode to use + * + * Program the DMA controller ready to perform an ISA DMA transfer + * on this chip. + * + * Locks: takes and releases the ISA DMA lock. + */ + +static __inline__ int NCR5380_pc_dma_setup(struct Scsi_Host *instance, unsigned char *ptr, unsigned int count, unsigned char mode) +{ + unsigned limit; + unsigned long bus_addr = virt_to_bus(ptr); + unsigned long flags; + + if (instance->dma_channel <= 3) { + if (count > 65536) + count = 65536; + limit = 65536 - (bus_addr & 0xFFFF); + } else { + if (count > 65536 * 2) + count = 65536 * 2; + limit = 65536 * 2 - (bus_addr & 0x1FFFF); + } + + if (count > limit) + count = limit; + + if ((count & 1) || (bus_addr & 1)) + panic("scsi%d : attempted unaligned DMA transfer\n", instance->host_no); + + flags=claim_dma_lock(); + disable_dma(instance->dma_channel); + clear_dma_ff(instance->dma_channel); + set_dma_addr(instance->dma_channel, bus_addr); + set_dma_count(instance->dma_channel, count); + set_dma_mode(instance->dma_channel, mode); + enable_dma(instance->dma_channel); + release_dma_lock(flags); + + return count; } -static __inline__ int NCR5380_pc_dma_write_setup (struct Scsi_Host *instance, - unsigned char *src, unsigned int count) { - return NCR5380_pc_dma_setup (instance, src, count, DMA_MODE_WRITE); +/** + * NCR5380_pc_dma_write_setup - setup ISA DMA write + * @instance: adapter to set up + * @ptr: block to transfer (virtual address) + * @count: number of bytes to transfer + * + * Program the DMA controller ready to perform an ISA DMA write to the + * SCSI controller. + * + * Locks: called routines take and release the ISA DMA lock. + */ + +static __inline__ int NCR5380_pc_dma_write_setup(struct Scsi_Host *instance, unsigned char *src, unsigned int count) +{ + return NCR5380_pc_dma_setup(instance, src, count, DMA_MODE_WRITE); } -static __inline__ int NCR5380_pc_dma_read_setup (struct Scsi_Host *instance, - unsigned char *src, unsigned int count) { - return NCR5380_pc_dma_setup (instance, src, count, DMA_MODE_READ); +/** + * NCR5380_pc_dma_read_setup - setup ISA DMA read + * @instance: adapter to set up + * @ptr: block to transfer (virtual address) + * @count: number of bytes to transfer + * + * Program the DMA controller ready to perform an ISA DMA read from the + * SCSI controller. + * + * Locks: called routines take and release the ISA DMA lock. + */ + +static __inline__ int NCR5380_pc_dma_read_setup(struct Scsi_Host *instance, unsigned char *src, unsigned int count) +{ + return NCR5380_pc_dma_setup(instance, src, count, DMA_MODE_READ); } -static __inline__ int NCR5380_pc_dma_residual (struct Scsi_Host *instance) { - register int tmp; - cli(); - clear_dma_ff(instance->dma_channel); - tmp = get_dma_residue(instance->dma_channel); - sti(); - return tmp; +/** + * NCR5380_pc_dma_residual - return bytes left + * @instance: adapter + * + * Reports the number of bytes left over after the DMA was terminated. + * + * Locks: takes and releases the ISA DMA lock. + */ + +static __inline__ int NCR5380_pc_dma_residual(struct Scsi_Host *instance) +{ + unsigned long flags; + int tmp; + + flags = claim_dma_lock(); + clear_dma_ff(instance->dma_channel); + tmp = get_dma_residue(instance->dma_channel); + release_dma_lock(flags); + + return tmp; } -#endif /* defined(i386) || defined(__alpha__) */ -#endif /* defined(REAL_DMA) */ -#endif /* __KERNEL__ */ -#endif /* ndef ASM */ -#endif /* NCR5380_H */ +#endif /* defined(i386) || defined(__alpha__) */ +#endif /* defined(REAL_DMA) */ +#endif /* __KERNEL__ */ +#endif /* ndef ASM */ +#endif /* NCR5380_H */ diff -Nru a/drivers/scsi/eata.c b/drivers/scsi/eata.c --- a/drivers/scsi/eata.c Tue Feb 26 11:57:58 2002 +++ b/drivers/scsi/eata.c Tue Feb 26 11:57:58 2002 @@ -1,6 +1,13 @@ /* * eata.c - Low-level driver for EATA/DMA SCSI host adapters. * + * 20 Feb 2002 Rev. 7.22 for linux 2.5.5 + * + Remove any reference to virt_to_bus(). + * + Fix pio hang while detecting multiple HBAs. + * + Fixed a board detection bug: in a system with + * multiple ISA/EISA boards, all but the first one + * were erroneously detected as PCI. + * * 01 Jan 2002 Rev. 7.20 for linux 2.5.1 * + Use the dynamic DMA mapping API. * @@ -29,7 +36,7 @@ * boot time. * + Improved boot messages: all tagged capable device are * indicated as "tagged" or "soft-tagged" : - * - "soft-tagged" means that the driver is trying to do its + * - "soft-tagged" means that the driver is trying to do its * own tagging (i.e. the tc:y option is in effect); * - "tagged" means that the device supports tagged commands, * but the driver lets the HBA be responsible for tagging @@ -40,7 +47,7 @@ * + When loaded as a module, accepts the new parameter boot_options * which value is a string with the same format of the kernel boot * command line options. A valid example is: - * modprobe eata boot_options=\"0x7410,0x230,lc:y,tc:n,mq:4\" + * modprobe eata 'boot_options="0x7410,0x230,lc:y,tc:n,mq:4"' * * 9 Sep 1999 Rev. 5.10 for linux 2.2.12 and 2.3.17 * + 64bit cleanup for Linux/Alpha platform support @@ -401,8 +408,6 @@ * the driver sets host->wish_block = TRUE for all ISA boards. */ -#error Please convert me to Documentation/DMA-mapping.txt - #include #ifndef LinuxVersionCode @@ -454,7 +459,7 @@ #define ISA 0 #define ESA 1 -#undef FORCE_CONFIG +#undef FORCE_CONFIG #undef DEBUG_LINKED_COMMANDS #undef DEBUG_DETECT @@ -645,11 +650,18 @@ u_int32_t data_address; /* If sg=0 Data Address, if sg=1 sglist address */ u_int32_t sp_dma_addr; /* Address where sp is DMA'ed when cp completes */ u_int32_t sense_addr; /* Address where Sense Data is DMA'ed on error */ + /* Additional fields begin here. */ Scsi_Cmnd *SCpnt; - struct sg_list *sglist; + + /* All the cp structure is zero filled by queuecommand except the + following CP_TAIL_SIZE bytes, initialized by detect */ + dma_addr_t cp_dma_addr; /* dma handle for this cp structure */ + struct sg_list *sglist; /* pointer to the allocated SG list */ }; +#define CP_TAIL_SIZE (sizeof(struct sglist *) + sizeof(dma_addr_t)) + struct hostdata { struct mscp cp[MAX_MAILBOXES]; /* Mailboxes for this board */ unsigned int cp_stat[MAX_MAILBOXES]; /* FREE, IN_USE, LOCKED, IN_RESET */ @@ -657,7 +669,6 @@ unsigned int iocount; /* Total i/o done for this board */ int board_number; /* Number of this board */ char board_name[16]; /* Name of this board */ - char board_id[256]; /* data from INQUIRY on this board */ int in_reset; /* True if board is doing a reset */ int target_to[MAX_TARGET][MAX_CHANNEL]; /* N. of timeout errors on target */ int target_redo[MAX_TARGET][MAX_CHANNEL]; /* If TRUE redo i/o on target */ @@ -675,6 +686,7 @@ static struct Scsi_Host *sh[MAX_BOARDS + 1]; static const char *driver_name = "EATA"; static char sha[MAX_BOARDS]; +static spinlock_t driver_lock = SPIN_LOCK_UNLOCKED; /* Initialize num_boards so that ihdlr can work while detect is in progress */ static unsigned int num_boards = MAX_BOARDS; @@ -710,8 +722,6 @@ #define H2DEV(x) cpu_to_be32(x) #define DEV2H(x) be32_to_cpu(x) -#define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0) - static void do_interrupt_handler(int, void *, struct pt_regs *); static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int); static int do_trace = FALSE; @@ -813,7 +823,7 @@ if (wait_on_busy(iobase, (addr ? MAXLOOP * 100 : MAXLOOP))) return TRUE; - if ((addr = V2DEV(addr))) { + if ((addr = H2DEV(addr))) { outb((char) (addr >> 24), iobase + REG_LOW); outb((char) (addr >> 16), iobase + REG_LM); outb((char) (addr >> 8), iobase + REG_MID); @@ -919,7 +929,8 @@ else protocol_rev = 'C'; - if (!setup_done && j > 0 && j <= MAX_PCI) { + if (protocol_rev != 'A' && info.forcaddr) { + printk("%s: warning, port address has been forced.\n", name); bus_type = "PCI"; is_pci = TRUE; subversion = ESA; @@ -982,7 +993,7 @@ if (is_pci) { pdev = get_pci_dev(port_base); - if (!pdev) + if (!pdev) printk("%s: warning, failed to get pci_dev structure.\n", name); } else @@ -1012,18 +1023,29 @@ #if defined(FORCE_CONFIG) { - struct eata_config config; + struct eata_config *cf; + dma_addr_t cf_dma_addr; + + cf = pci_alloc_consistent(pdev, sizeof(struct eata_config), &cf_dma_addr); + + if (!cf) { + printk("%s: config, pci_alloc_consistent failed, detaching.\n", name); + release_region(port_base, REGION_SIZE); + return FALSE; + } /* Set board configuration */ - memset((char *)&config, 0, sizeof(struct eata_config)); - config.len = (ushort) cpu_to_be16((ushort)510); - config.ocena = TRUE; + memset((char *)cf, 0, sizeof(struct eata_config)); + cf->len = (ushort) cpu_to_be16((ushort)510); + cf->ocena = TRUE; - if (do_dma(port_base, (unsigned long)&config, SET_CONFIG_DMA)) { + if (do_dma(port_base, cf_dma_addr, SET_CONFIG_DMA)) { printk("%s: busy timeout sending configuration, detaching.\n", name); + pci_free_consistent(pdev, sizeof(struct eata_config), cf, cf_dma_addr); release_region(port_base, REGION_SIZE); return FALSE; } + } #endif @@ -1111,6 +1133,10 @@ else sprintf(dma_name, "DMA %u", dma_channel); for (i = 0; i < sh[j]->can_queue; i++) + HD(j)->cp[i].cp_dma_addr = pci_map_single(HD(j)->pdev, + &HD(j)->cp[i], sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL); + + for (i = 0; i < sh[j]->can_queue; i++) if (! ((&HD(j)->cp[i])->sglist = kmalloc( sh[j]->sg_tablesize * sizeof(struct sg_list), (sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) { @@ -1119,7 +1145,7 @@ return FALSE; } - if (! (HD(j)->sp_cpu_addr = pci_alloc_consistent(HD(j)->pdev, + if (! (HD(j)->sp_cpu_addr = pci_alloc_consistent(HD(j)->pdev, sizeof(struct mssp), &HD(j)->sp_dma_addr))) { printk("%s: pci_alloc_consistent failed, detaching.\n", BN(j)); eata2x_release(sh[j]); @@ -1279,6 +1305,9 @@ int eata2x_detect(Scsi_Host_Template *tpnt) { unsigned int j = 0, k; + unsigned long spin_flags; + + spin_lock_irqsave(&driver_lock, spin_flags); tpnt->proc_name = "eata2x"; @@ -1304,6 +1333,7 @@ } num_boards = j; + spin_unlock_irqrestore(&driver_lock, spin_flags); return j; } @@ -1324,10 +1354,10 @@ if (!SCpnt->use_sg) { - if (!SCpnt->request_bufflen) - cpp->data_address = V2DEV(SCpnt->request_buffer); + /* If we get here with PCI_DMA_NONE, pci_map_single triggers a BUG() */ + if (!SCpnt->request_bufflen) pci_dir = PCI_DMA_BIDIRECTIONAL; - else if (SCpnt->request_buffer) + if (SCpnt->request_buffer) cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev, SCpnt->request_buffer, SCpnt->request_bufflen, pci_dir)); @@ -1344,7 +1374,8 @@ } cpp->sg = TRUE; - cpp->data_address = V2DEV(cpp->sglist); + cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev, cpp->sglist, + SCpnt->use_sg * sizeof(struct sg_list), pci_dir)); cpp->data_len = H2DEV((SCpnt->use_sg * sizeof(struct sg_list))); } @@ -1360,13 +1391,14 @@ pci_unmap_single(HD(j)->pdev, DEV2H(cpp->sense_addr), DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); - if (SCpnt->use_sg) + if (SCpnt->use_sg) pci_unmap_sg(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir); - else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len)) - pci_unmap_single(HD(j)->pdev, DEV2H(cpp->data_address), - DEV2H(cpp->data_len), pci_dir); + if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL; + if (DEV2H(cpp->data_address)) + pci_unmap_single(HD(j)->pdev, DEV2H(cpp->data_address), + DEV2H(cpp->data_len), pci_dir); } static void sync_dma(unsigned int i, unsigned int j) { @@ -1381,14 +1413,15 @@ pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->sense_addr), DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); - if (SCpnt->use_sg) - pci_dma_sync_sg(HD(j)->pdev, SCpnt->request_buffer, + if (SCpnt->use_sg) + pci_dma_sync_sg(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir); - else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len)) - pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address), - DEV2H(cpp->data_len), pci_dir); + if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL; + if (DEV2H(cpp->data_address)) + pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address), + DEV2H(cpp->data_len), pci_dir); } static inline void scsi_to_dev_dir(unsigned int i, unsigned int j) { @@ -1409,8 +1442,7 @@ struct mscp *cpp; Scsi_Cmnd *SCpnt; - cpp = &HD(j)->cp[i]; - SCpnt = cpp->SCpnt; + cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt; if (SCpnt->sc_data_direction == SCSI_DATA_READ) { cpp->din = TRUE; @@ -1428,7 +1460,7 @@ return; } - if (SCpnt->sc_data_direction != SCSI_DATA_UNKNOWN) + if (SCpnt->sc_data_direction != SCSI_DATA_UNKNOWN) panic("%s: qcomm, invalid SCpnt->sc_data_direction.\n", BN(j)); for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++) @@ -1479,7 +1511,7 @@ /* Set pointer to control packet structure */ cpp = &HD(j)->cp[i]; - memset(cpp, 0, sizeof(struct mscp) - sizeof(struct sg_list *)); + memset(cpp, 0, sizeof(struct mscp) - CP_TAIL_SIZE); /* Set pointer to status packet structure, Big Endian format */ cpp->sp_dma_addr = H2DEV(HD(j)->sp_dma_addr); @@ -1536,7 +1568,7 @@ } /* Send control packet to the board */ - if (do_dma(sh[j]->io_port, (unsigned long) cpp, SEND_CP_DMA)) { + if (do_dma(sh[j]->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) { unmap_dma(i, j); SCpnt->host_scribble = NULL; printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy.\n", @@ -1935,7 +1967,7 @@ for (n = 0; n < n_ready; n++) { k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; - if (do_dma(sh[j]->io_port, (unsigned long) cpp, SEND_CP_DMA)) { + if (do_dma(sh[j]->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) { printk("%s: %s, target %d.%d:%d, pid %ld, mbox %d, adapter"\ " busy, will abort.\n", BN(j), (ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid, k); @@ -1985,7 +2017,7 @@ reg = inb(sh[j]->io_port + REG_STATUS); /* Reject any sp with supspect data */ - if (spp->eoc == FALSE) + if (spp->eoc == FALSE && HD(j)->iocount > 1) printk("%s: ihdlr, spp->eoc == FALSE, irq %d, reg 0x%x, count %d.\n", BN(j), irq, reg, HD(j)->iocount); if (spp->cpp_index < 0 || spp->cpp_index >= sh[j]->can_queue) @@ -2191,10 +2223,14 @@ for (i = 0; i < sh[j]->can_queue; i++) if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist); - if (HD(j)->sp_cpu_addr) + for (i = 0; i < sh[j]->can_queue; i++) + pci_unmap_single(HD(j)->pdev, HD(j)->cp[i].cp_dma_addr, + sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL); + + if (HD(j)->sp_cpu_addr) pci_free_consistent(HD(j)->pdev, sizeof(struct mssp), HD(j)->sp_cpu_addr, HD(j)->sp_dma_addr); - + free_irq(sh[j]->irq, &sha[j]); if (sh[j]->dma_channel != NO_DMA) free_dma(sh[j]->dma_channel); diff -Nru a/drivers/scsi/eata.h b/drivers/scsi/eata.h --- a/drivers/scsi/eata.h Tue Feb 26 11:57:57 2002 +++ b/drivers/scsi/eata.h Tue Feb 26 11:57:57 2002 @@ -13,7 +13,7 @@ int eata2x_reset(Scsi_Cmnd *); int eata2x_biosparam(Disk *, kdev_t, int *); -#define EATA_VERSION "7.20.00" +#define EATA_VERSION "7.22.00" #define EATA { \ name: "EATA/DMA 2.0x rev. " EATA_VERSION " ", \ diff -Nru a/drivers/scsi/imm.c b/drivers/scsi/imm.c --- a/drivers/scsi/imm.c Tue Feb 26 11:58:00 2002 +++ b/drivers/scsi/imm.c Tue Feb 26 11:58:00 2002 @@ -1007,7 +1007,7 @@ cmd->SCp.this_residual = cmd->request_bufflen; cmd->SCp.ptr = cmd->request_buffer; } - cmd->SCp.buffers_residual = cmd->use_sg; + cmd->SCp.buffers_residual = cmd->use_sg - 1; cmd->SCp.phase++; if (cmd->SCp.this_residual & 0x01) cmd->SCp.this_residual++; diff -Nru a/drivers/scsi/ips.c b/drivers/scsi/ips.c --- a/drivers/scsi/ips.c Tue Feb 26 11:57:56 2002 +++ b/drivers/scsi/ips.c Tue Feb 26 11:57:56 2002 @@ -81,7 +81,7 @@ /* 2.3.18 and later */ /* - Sync with other changes from the 2.3 kernels */ /* 4.00.06 - Fix timeout with initial FFDC command */ -/* 4.00.06a - Port to 2.4 (trivial) -- Christoph Hellwig */ +/* 4.00.06a - Port to 2.4 (trivial) -- Christoph Hellwig */ /* 4.10.00 - Add support for ServeRAID 4M/4L */ /* 4.10.13 - Fix for dynamic unload and proc file system */ /* 4.20.03 - Rename version to coincide with new release schedules */ diff -Nru a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c --- a/drivers/scsi/ppa.c Tue Feb 26 11:57:56 2002 +++ b/drivers/scsi/ppa.c Tue Feb 26 11:57:56 2002 @@ -738,7 +738,7 @@ if (cmd->SCp.buffers_residual--) { cmd->SCp.buffer++; cmd->SCp.this_residual = cmd->SCp.buffer->length; - cmd->SCp.ptr = cmd->SCp.buffer->address; + cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) + cmd->SCp.buffer->offset; } } /* Now check to see if the drive is ready to comunicate */ @@ -923,14 +923,14 @@ /* if many buffers are available, start filling the first */ cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer; cmd->SCp.this_residual = cmd->SCp.buffer->length; - cmd->SCp.ptr = cmd->SCp.buffer->address; + cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) + cmd->SCp.buffer->offset; } else { /* else fill the only available buffer */ cmd->SCp.buffer = NULL; cmd->SCp.this_residual = cmd->request_bufflen; cmd->SCp.ptr = cmd->request_buffer; } - cmd->SCp.buffers_residual = cmd->use_sg; + cmd->SCp.buffers_residual = cmd->use_sg - 1; cmd->SCp.phase++; case 5: /* Phase 5 - Data transfer stage */ diff -Nru a/drivers/scsi/sr.c b/drivers/scsi/sr.c --- a/drivers/scsi/sr.c Tue Feb 26 11:57:58 2002 +++ b/drivers/scsi/sr.c Tue Feb 26 11:57:58 2002 @@ -524,7 +524,7 @@ scsi_CDs[i].needs_sector_size = 1; } else { #if 0 - if (cdrom_get_last_written(MKDEV(MAJOR_NR, i), + if (cdrom_get_last_written(mkdev(MAJOR_NR, i), &scsi_CDs[i].capacity)) #endif scsi_CDs[i].capacity = 1 + ((buffer[0] << 24) | diff -Nru a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c --- a/drivers/scsi/u14-34f.c Tue Feb 26 11:57:58 2002 +++ b/drivers/scsi/u14-34f.c Tue Feb 26 11:57:58 2002 @@ -1,6 +1,10 @@ /* * u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters. * + * 20 Feb 2002 Rev. 7.22 for linux 2.5.5 + * + Remove any reference to virt_to_bus(). + * + Fix pio hang while detecting multiple HBAs. + * * 01 Jan 2002 Rev. 7.20 for linux 2.5.1 * + Use the dynamic DMA mapping API. * @@ -30,7 +34,7 @@ * + When loaded as a module, accepts the new parameter boot_options * which value is a string with the same format of the kernel boot * command line options. A valid example is: - * modprobe u14-34f boot_options=\"0x230,0x340,lc:y,mq:4\" + * modprobe u14-34f 'boot_options="0x230,0x340,lc:y,mq:4"' * * 22 Jul 1999 Rev. 5.00 for linux 2.2.10 and 2.3.11 * + Removed pre-2.2 source code compatibility. @@ -496,11 +500,19 @@ unsigned char adapter_status; /* non-zero indicates HA error */ unsigned char target_status; /* non-zero indicates target error */ unsigned int sense_addr PACKED; + + /* Additional fields begin here. */ Scsi_Cmnd *SCpnt; unsigned int cpp_index; /* cp index */ - struct sg_list *sglist; + + /* All the cp structure is zero filled by queuecommand except the + following CP_TAIL_SIZE bytes, initialized by detect */ + dma_addr_t cp_dma_addr; /* dma handle for this cp structure */ + struct sg_list *sglist; /* pointer to the allocated SG list */ }; +#define CP_TAIL_SIZE (sizeof(struct sglist *) + sizeof(dma_addr_t)) + struct hostdata { struct mscp cp[MAX_MAILBOXES]; /* Mailboxes for this board */ unsigned int cp_stat[MAX_MAILBOXES]; /* FREE, IN_USE, LOCKED, IN_RESET */ @@ -508,7 +520,6 @@ unsigned int iocount; /* Total i/o done for this board */ int board_number; /* Number of this board */ char board_name[16]; /* Name of this board */ - char board_id[256]; /* data from INQUIRY on this board */ int in_reset; /* True if board is doing a reset */ int target_to[MAX_TARGET][MAX_CHANNEL]; /* N. of timeout errors on target */ int target_redo[MAX_TARGET][MAX_CHANNEL]; /* If TRUE redo i/o on target */ @@ -518,14 +529,13 @@ struct pci_dev *pdev; /* Always NULL */ unsigned char heads; unsigned char sectors; - - /* slot != 0 for the U24F, slot == 0 for both the U14F and U34F */ - unsigned char slot; + char board_id[256]; /* data from INQUIRY on this board */ }; static struct Scsi_Host *sh[MAX_BOARDS + 1]; static const char *driver_name = "Ux4F"; static char sha[MAX_BOARDS]; +static spinlock_t driver_lock = SPIN_LOCK_UNLOCKED; /* Initialize num_boards so that ihdlr can work while detect is in progress */ static unsigned int num_boards = MAX_BOARDS; @@ -550,8 +560,6 @@ #define H2DEV(x) cpu_to_le32(x) #define DEV2H(x) le32_to_cpu(x) -#define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0) - static void do_interrupt_handler(int, void *, struct pt_regs *); static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int); static int do_trace = FALSE; @@ -644,13 +652,18 @@ static int board_inquiry(unsigned int j) { struct mscp *cpp; + dma_addr_t id_dma_addr; unsigned int time, limit = 0; + id_dma_addr = pci_map_single(HD(j)->pdev, HD(j)->board_id, + sizeof(HD(j)->board_id), PCI_DMA_BIDIRECTIONAL); cpp = &HD(j)->cp[0]; - memset(cpp, 0, sizeof(struct mscp)); + cpp->cp_dma_addr = pci_map_single(HD(j)->pdev, cpp, sizeof(struct mscp), + PCI_DMA_BIDIRECTIONAL); + memset(cpp, 0, sizeof(struct mscp) - CP_TAIL_SIZE); cpp->opcode = OP_HOST_ADAPTER; cpp->xdir = DTD_IN; - cpp->data_address = V2DEV(HD(j)->board_id); + cpp->data_address = H2DEV(id_dma_addr); cpp->data_len = H2DEV(sizeof(HD(j)->board_id)); cpp->cdb_len = 6; cpp->cdb[0] = HA_CMD_INQUIRY; @@ -666,13 +679,15 @@ outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR); /* Store pointer in OGM address bytes */ - outl(V2DEV(cpp), sh[j]->io_port + REG_OGM); + outl(H2DEV(cpp->cp_dma_addr), sh[j]->io_port + REG_OGM); /* Issue OGM interrupt */ outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR); + spin_unlock_irq(&driver_lock); time = jiffies; while ((jiffies - time) < HZ && limit++ < 20000) udelay(100L); + spin_lock_irq(&driver_lock); if (cpp->adapter_status || HD(j)->cp_stat[0] != FREE) { HD(j)->cp_stat[0] = FREE; @@ -680,6 +695,10 @@ return TRUE; } + pci_unmap_single(HD(j)->pdev, cpp->cp_dma_addr, sizeof(struct mscp), + PCI_DMA_BIDIRECTIONAL); + pci_unmap_single(HD(j)->pdev, id_dma_addr, sizeof(HD(j)->board_id), + PCI_DMA_BIDIRECTIONAL); return FALSE; } @@ -817,6 +836,7 @@ HD(j)->heads = mapping_table[config_2.mapping_mode].heads; HD(j)->sectors = mapping_table[config_2.mapping_mode].sectors; HD(j)->subversion = subversion; + HD(j)->pdev = NULL; HD(j)->board_number = j; if (have_old_firmware) sh[j]->sg_tablesize = MAX_SAFE_SGLIST; @@ -864,6 +884,10 @@ else sprintf(dma_name, "DMA %u", dma_channel); for (i = 0; i < sh[j]->can_queue; i++) + HD(j)->cp[i].cp_dma_addr = pci_map_single(HD(j)->pdev, + &HD(j)->cp[i], sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL); + + for (i = 0; i < sh[j]->can_queue; i++) if (! ((&HD(j)->cp[i])->sglist = kmalloc( sh[j]->sg_tablesize * sizeof(struct sg_list), (sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) { @@ -950,6 +974,9 @@ int u14_34f_detect(Scsi_Host_Template *tpnt) { unsigned int j = 0, k; + unsigned long spin_flags; + + spin_lock_irqsave(&driver_lock, spin_flags); tpnt->proc_name = "u14-34f"; @@ -973,6 +1000,7 @@ } num_boards = j; + spin_unlock_irqrestore(&driver_lock, spin_flags); return j; } @@ -994,10 +1022,10 @@ if (!SCpnt->use_sg) { - if (!SCpnt->request_bufflen) - cpp->data_address = V2DEV(SCpnt->request_buffer); + /* If we get here with PCI_DMA_NONE, pci_map_single triggers a BUG() */ + if (!SCpnt->request_bufflen) pci_dir = PCI_DMA_BIDIRECTIONAL; - else if (SCpnt->request_buffer) + if (SCpnt->request_buffer) cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev, SCpnt->request_buffer, SCpnt->request_bufflen, pci_dir)); @@ -1016,7 +1044,8 @@ cpp->sg = TRUE; cpp->use_sg = SCpnt->use_sg; - cpp->data_address = V2DEV(cpp->sglist); + cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev, cpp->sglist, + SCpnt->use_sg * sizeof(struct sg_list), pci_dir)); cpp->data_len = H2DEV(data_len); } @@ -1032,13 +1061,14 @@ pci_unmap_single(HD(j)->pdev, DEV2H(cpp->sense_addr), DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); - if (SCpnt->use_sg) + if (SCpnt->use_sg) pci_unmap_sg(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir); - else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len)) - pci_unmap_single(HD(j)->pdev, DEV2H(cpp->data_address), - DEV2H(cpp->data_len), pci_dir); + if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL; + if (DEV2H(cpp->data_address)) + pci_unmap_single(HD(j)->pdev, DEV2H(cpp->data_address), + DEV2H(cpp->data_len), pci_dir); } static void sync_dma(unsigned int i, unsigned int j) { @@ -1053,14 +1083,15 @@ pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->sense_addr), DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); - if (SCpnt->use_sg) - pci_dma_sync_sg(HD(j)->pdev, SCpnt->request_buffer, + if (SCpnt->use_sg) + pci_dma_sync_sg(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir); - else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len)) - pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address), - DEV2H(cpp->data_len), pci_dir); + if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL; + if (DEV2H(cpp->data_address)) + pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address), + DEV2H(cpp->data_len), pci_dir); } static inline void scsi_to_dev_dir(unsigned int i, unsigned int j) { @@ -1096,7 +1127,7 @@ return; } - if (SCpnt->sc_data_direction != SCSI_DATA_UNKNOWN) + if (SCpnt->sc_data_direction != SCSI_DATA_UNKNOWN) panic("%s: qcomm, invalid SCpnt->sc_data_direction.\n", BN(j)); cpp->xdir = DTD_IN; @@ -1149,7 +1180,7 @@ /* Set pointer to control packet structure */ cpp = &HD(j)->cp[i]; - memset(cpp, 0, sizeof(struct mscp) - sizeof(struct sg_list *)); + memset(cpp, 0, sizeof(struct mscp) - CP_TAIL_SIZE); SCpnt->scsi_done = done; cpp->cpp_index = i; SCpnt->host_scribble = (unsigned char *) &cpp->cpp_index; @@ -1188,7 +1219,7 @@ } /* Store pointer in OGM address bytes */ - outl(V2DEV(cpp), sh[j]->io_port + REG_OGM); + outl(H2DEV(cpp->cp_dma_addr), sh[j]->io_port + REG_OGM); /* Issue OGM interrupt */ outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR); @@ -1598,7 +1629,7 @@ continue; } - outl(V2DEV(cpp), sh[j]->io_port + REG_OGM); + outl(H2DEV(cpp->cp_dma_addr), sh[j]->io_port + REG_OGM); outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR); HD(j)->cp_stat[k] = IN_USE; } @@ -1636,11 +1667,11 @@ /* Find the mailbox to be serviced on this board */ for (i = 0; i < sh[j]->can_queue; i++) - if (V2DEV(&(HD(j)->cp[i])) == ret) break; + if (H2DEV(HD(j)->cp[i].cp_dma_addr) == ret) break; if (i >= sh[j]->can_queue) panic("%s: ihdlr, invalid mscp bus address %p, cp0 %p.\n", BN(j), - (void *)ret, (void *)V2DEV(HD(j)->cp)); + (void *)ret, (void *)H2DEV(HD(j)->cp[0].cp_dma_addr)); cpp = &(HD(j)->cp[i]); spp = cpp; @@ -1839,6 +1870,10 @@ for (i = 0; i < sh[j]->can_queue; i++) if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist); + + for (i = 0; i < sh[j]->can_queue; i++) + pci_unmap_single(HD(j)->pdev, HD(j)->cp[i].cp_dma_addr, + sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL); free_irq(sh[j]->irq, &sha[j]); diff -Nru a/drivers/scsi/u14-34f.h b/drivers/scsi/u14-34f.h --- a/drivers/scsi/u14-34f.h Tue Feb 26 11:58:00 2002 +++ b/drivers/scsi/u14-34f.h Tue Feb 26 11:58:00 2002 @@ -13,7 +13,7 @@ int u14_34f_reset(Scsi_Cmnd *); int u14_34f_biosparam(Disk *, kdev_t, int *); -#define U14_34F_VERSION "7.20.00" +#define U14_34F_VERSION "7.22.00" #define ULTRASTOR_14_34F { \ name: "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \ diff -Nru a/drivers/usb/hcd/Config.help b/drivers/usb/hcd/Config.help --- a/drivers/usb/hcd/Config.help Tue Feb 26 11:57:56 2002 +++ b/drivers/usb/hcd/Config.help Tue Feb 26 11:57:56 2002 @@ -21,7 +21,6 @@ The module will be called ehci-hcd.o. If you want to compile it as a module, say M here and read . -OHCI (most USB hosts except VIA, Intel PIIX) support CONFIG_USB_OHCI_HCD The Open Host Controller Interface (OHCI) is a standard for accessing USB 1.1 host controller hardware. It does more in hardware than Intel's diff -Nru a/drivers/usb/hub.c b/drivers/usb/hub.c --- a/drivers/usb/hub.c Tue Feb 26 11:57:59 2002 +++ b/drivers/usb/hub.c Tue Feb 26 11:57:59 2002 @@ -644,6 +644,49 @@ port + 1, hub->devpath, ret); } +/* USB 2.0 spec, 7.1.7.3 / fig 7-29: + * + * Between connect detection and reset signaling there must be a delay + * of 100ms at least for debounce and power-settling. The corresponding + * timer shall restart whenever the downstream port detects a disconnect. + * + * Apparently there are some bluetooth and irda-dongles and a number + * of low-speed devices which require longer delays of about 200-400ms. + * Not covered by the spec - but easy to deal with. + * + * This implementation uses 400ms minimum debounce timeout and checks + * every 10ms for transient disconnects to restart the delay. + */ + +#define HUB_DEBOUNCE_TIMEOUT 400 +#define HUB_DEBOUNCE_STEP 10 + +/* return: -1 on error, 0 on success, 1 on disconnect. */ +static int usb_hub_port_debounce(struct usb_device *hub, int port) +{ + int ret; + unsigned delay_time; + u16 portchange, portstatus; + + for (delay_time = 0; delay_time < HUB_DEBOUNCE_TIMEOUT; /* empty */ ) { + + /* wait debounce step increment */ + wait_ms(HUB_DEBOUNCE_STEP); + + ret = usb_hub_port_status(hub, port, &portstatus, &portchange); + if (ret < 0) + return -1; + + if ((portchange & USB_PORT_STAT_C_CONNECTION)) { + usb_clear_port_feature(hub, port+1, USB_PORT_FEAT_C_CONNECTION); + delay_time = 0; + } + else + delay_time += HUB_DEBOUNCE_STEP; + } + return ((portstatus&USB_PORT_STAT_CONNECTION)) ? 0 : 1; +} + static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port, u16 portstatus, u16 portchange) { @@ -671,12 +714,16 @@ return; } + if (usb_hub_port_debounce(hub, port)) { + err("connect-debounce failed, port %d disabled", port+1); + usb_hub_port_disable(hub, port); + return; + } + /* Some low speed devices have problems with the quick delay, so */ /* be a bit pessimistic with those devices. RHbug #23670 */ - if (portstatus & USB_PORT_STAT_LOW_SPEED) { - wait_ms(400); + if (portstatus & USB_PORT_STAT_LOW_SPEED) delay = HUB_LONG_RESET_TIME; - } down(&usb_address0_sem); diff -Nru a/drivers/usb/ov511.c b/drivers/usb/ov511.c --- a/drivers/usb/ov511.c Tue Feb 26 11:57:58 2002 +++ b/drivers/usb/ov511.c Tue Feb 26 11:57:58 2002 @@ -58,7 +58,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.48a for Linux 2.4" +#define DRIVER_VERSION "v1.49 for Linux 2.5" #define EMAIL "mmcclell@bigfoot.com" #define DRIVER_AUTHOR "Mark McClelland & Bret Wallach \ & Orion Sky Lawlor & Kevin Moore & Charl P. Botha \ @@ -309,7 +309,7 @@ static inline int sensor_get_picture(struct usb_ov511 *, struct video_picture *); static int sensor_get_exposure(struct usb_ov511 *, unsigned char *); -static int ov511_control_ioctl(struct inode *, struct file *, unsigned int, +static int ov51x_control_ioctl(struct inode *, struct file *, unsigned int, unsigned long); /********************************************************************** @@ -332,6 +332,7 @@ { 100, "Lifeview RoboCam" }, { 102, "AverMedia InterCam Elite" }, { 112, "MediaForte MV300" }, /* or OV7110 evaluation kit */ + { 192, "Webeye 2000B" }, { -1, NULL } }; @@ -373,17 +374,20 @@ static unsigned char yQuanTable518[] = OV518_YQUANTABLE; static unsigned char uvQuanTable518[] = OV518_UVQUANTABLE; +/********************************************************************** + * Memory management + **********************************************************************/ + /* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = page_address(vmalloc_to_page(va)); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ ret = __pa(kva); return ret; } @@ -392,12 +396,9 @@ rvmalloc(unsigned long size) { void *mem; - unsigned long adr, page; - - /* Round it off to PAGE_SIZE */ - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); + unsigned long adr; + size = PAGE_ALIGN(size); mem = vmalloc_32(size); if (!mem) return NULL; @@ -405,13 +406,9 @@ memset(mem, 0, size); /* Clear the ram out, no junk to the user */ adr = (unsigned long) mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } return mem; @@ -420,23 +417,16 @@ static void rvfree(void *mem, unsigned long size) { - unsigned long adr, page; + unsigned long adr; if (!mem) return; - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); - - adr=(unsigned long) mem; - while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + adr = (unsigned long) mem; + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } vfree(mem); } @@ -452,7 +442,7 @@ extern struct proc_dir_entry *video_proc_entry; static struct file_operations ov511_control_fops = { - ioctl: ov511_control_ioctl, + ioctl: ov51x_control_ioctl, }; #define YES_NO(x) ((x) ? "yes" : "no") @@ -464,29 +454,29 @@ { char *out = page; int i, j, len; - struct usb_ov511 *ov511 = data; + struct usb_ov511 *ov = data; struct video_picture p; unsigned char exp; - if (!ov511 || !ov511->dev) + if (!ov || !ov->dev) return -ENODEV; - sensor_get_picture(ov511, &p); - sensor_get_exposure(ov511, &exp); + sensor_get_picture(ov, &p); + sensor_get_exposure(ov, &exp); /* IMPORTANT: This output MUST be kept under PAGE_SIZE * or we need to get more sophisticated. */ out += sprintf(out, "driver_version : %s\n", DRIVER_VERSION); - out += sprintf(out, "custom_id : %d\n", ov511->customid); - out += sprintf(out, "model : %s\n", ov511->desc ? - clist[ov511->desc].description : "unknown"); - out += sprintf(out, "streaming : %s\n", YES_NO(ov511->streaming)); - out += sprintf(out, "grabbing : %s\n", YES_NO(ov511->grabbing)); - out += sprintf(out, "compress : %s\n", YES_NO(ov511->compress)); - out += sprintf(out, "subcapture : %s\n", YES_NO(ov511->sub_flag)); + out += sprintf(out, "custom_id : %d\n", ov->customid); + out += sprintf(out, "model : %s\n", ov->desc ? + clist[ov->desc].description : "unknown"); + out += sprintf(out, "streaming : %s\n", YES_NO(ov->streaming)); + out += sprintf(out, "grabbing : %s\n", YES_NO(ov->grabbing)); + out += sprintf(out, "compress : %s\n", YES_NO(ov->compress)); + out += sprintf(out, "subcapture : %s\n", YES_NO(ov->sub_flag)); out += sprintf(out, "sub_size : %d %d %d %d\n", - ov511->subx, ov511->suby, ov511->subw, ov511->subh); + ov->subx, ov->suby, ov->subw, ov->subh); out += sprintf(out, "data_format : %s\n", force_rgb ? "RGB" : "BGR"); out += sprintf(out, "brightness : %d\n", p.brightness >> 8); @@ -498,12 +488,12 @@ for (i = 0; i < OV511_NUMFRAMES; i++) { out += sprintf(out, "frame : %d\n", i); out += sprintf(out, " depth : %d\n", - ov511->frame[i].depth); + ov->frame[i].depth); out += sprintf(out, " size : %d %d\n", - ov511->frame[i].width, ov511->frame[i].height); + ov->frame[i].width, ov->frame[i].height); out += sprintf(out, " format : "); for (j = 0; plist[j].num >= 0; j++) { - if (plist[j].num == ov511->frame[i].format) { + if (plist[j].num == ov->frame[i].format) { out += sprintf(out, "%s\n", plist[j].name); break; } @@ -511,29 +501,28 @@ if (plist[j].num < 0) out += sprintf(out, "unknown\n"); out += sprintf(out, " data_buffer : 0x%p\n", - ov511->frame[i].data); + ov->frame[i].data); } - out += sprintf(out, "snap_enabled : %s\n", - YES_NO(ov511->snap_enabled)); + out += sprintf(out, "snap_enabled : %s\n", YES_NO(ov->snap_enabled)); out += sprintf(out, "bridge : %s\n", - ov511->bridge == BRG_OV511 ? "OV511" : - ov511->bridge == BRG_OV511PLUS ? "OV511+" : - ov511->bridge == BRG_OV518 ? "OV518" : - ov511->bridge == BRG_OV518PLUS ? "OV518+" : + ov->bridge == BRG_OV511 ? "OV511" : + ov->bridge == BRG_OV511PLUS ? "OV511+" : + ov->bridge == BRG_OV518 ? "OV518" : + ov->bridge == BRG_OV518PLUS ? "OV518+" : "unknown"); out += sprintf(out, "sensor : %s\n", - ov511->sensor == SEN_OV6620 ? "OV6620" : - ov511->sensor == SEN_OV6630 ? "OV6630" : - ov511->sensor == SEN_OV7610 ? "OV7610" : - ov511->sensor == SEN_OV7620 ? "OV7620" : - ov511->sensor == SEN_OV7620AE ? "OV7620AE" : - ov511->sensor == SEN_OV8600 ? "OV8600" : - ov511->sensor == SEN_KS0127 ? "KS0127" : - ov511->sensor == SEN_KS0127B ? "KS0127B" : - ov511->sensor == SEN_SAA7111A ? "SAA7111A" : + ov->sensor == SEN_OV6620 ? "OV6620" : + ov->sensor == SEN_OV6630 ? "OV6630" : + ov->sensor == SEN_OV7610 ? "OV7610" : + ov->sensor == SEN_OV7620 ? "OV7620" : + ov->sensor == SEN_OV7620AE ? "OV7620AE" : + ov->sensor == SEN_OV8600 ? "OV8600" : + ov->sensor == SEN_KS0127 ? "KS0127" : + ov->sensor == SEN_KS0127B ? "KS0127B" : + ov->sensor == SEN_SAA7111A ? "SAA7111A" : "unknown"); - out += sprintf(out, "packet_size : %d\n", ov511->packet_size); - out += sprintf(out, "framebuffer : 0x%p\n", ov511->fbuf); + out += sprintf(out, "packet_size : %d\n", ov->packet_size); + out += sprintf(out, "framebuffer : 0x%p\n", ov->fbuf); len = out - page; len -= off; @@ -566,16 +555,16 @@ { char *out = page; int len, status; - struct usb_ov511 *ov511 = data; + struct usb_ov511 *ov = data; - if (!ov511 || !ov511->dev) + if (!ov || !ov->dev) return -ENODEV; - status = ov51x_check_snapshot(ov511); + status = ov51x_check_snapshot(ov); out += sprintf(out, "%d", status); if (status) - ov51x_clear_snapshot(ov511); + ov51x_clear_snapshot(ov); len = out - page; len -= off; @@ -717,18 +706,22 @@ * **********************************************************************/ +/* Write an OV51x register */ static int -ov511_reg_write(struct usb_device *dev, unsigned char reg, unsigned char value) +reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value) { int rc; PDEBUG(5, "0x%02X:0x%02X", reg, value); - rc = usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), + down(&ov->cbuf_lock); + ov->cbuf[0] = value; + rc = usb_control_msg(ov->dev, + usb_sndctrlpipe(ov->dev, 0), 2 /* REG_IO */, USB_TYPE_CLASS | USB_RECIP_DEVICE, - 0, (__u16)reg, &value, 1, HZ); + 0, (__u16)reg, &ov->cbuf[0], 1, HZ); + up(&ov->cbuf_lock); if (rc < 0) err("reg write: error %d", rc); @@ -736,45 +729,48 @@ return rc; } +/* Read from an OV51x register */ /* returns: negative is error, pos or zero is data */ static int -ov511_reg_read(struct usb_device *dev, unsigned char reg) +reg_r(struct usb_ov511 *ov, unsigned char reg) { int rc; - unsigned char buffer[1]; - rc = usb_control_msg(dev, - usb_rcvctrlpipe(dev, 0), + down(&ov->cbuf_lock); + rc = usb_control_msg(ov->dev, + usb_rcvctrlpipe(ov->dev, 0), 2 /* REG_IO */, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE, - 0, (__u16)reg, buffer, 1, HZ); + 0, (__u16)reg, &ov->cbuf[0], 1, HZ); - PDEBUG(5, "0x%02X:0x%02X", reg, buffer[0]); + PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]); - if (rc < 0) { + if (rc < 0) err("reg read: error %d", rc); - return rc; - } else { - return buffer[0]; - } + else + rc = ov->cbuf[0]; + + up(&ov->cbuf_lock); + + return rc; } /* - * Writes bits at positions specified by mask to a reg. Bits that are in + * Writes bits at positions specified by mask to an OV51x reg. Bits that are in * the same position as 1's in "mask" are cleared and set to "value". Bits * that are in the same position as 0's in "mask" are preserved, regardless * of their respective state in "value". */ static int -ov511_reg_write_mask(struct usb_device *dev, - unsigned char reg, - unsigned char value, - unsigned char mask) +reg_w_mask(struct usb_ov511 *ov, + unsigned char reg, + unsigned char value, + unsigned char mask) { int ret; unsigned char oldval, newval; - ret = ov511_reg_read(dev, reg); + ret = reg_r(ov, reg); if (ret < 0) return ret; @@ -783,31 +779,30 @@ value &= mask; /* Enforce mask on value */ newval = oldval | value; /* Set the desired bits */ - return (ov511_reg_write(dev, reg, newval)); + return (reg_w(ov, reg, newval)); } -/* Writes multiple (n) values to a single register. Only valid with certain - * registers (0x30 and 0xc4 - 0xce). Used for writing 16 and 24-bit values. */ +/* + * Writes multiple (n) byte value to a single register. Only valid with certain + * registers (0x30 and 0xc4 - 0xce). + */ static int -ov518_reg_write_multi(struct usb_device *dev, - unsigned char reg, - unsigned char *values, - int n) +ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n) { int rc; - PDEBUG(5, "0x%02X:[multiple], n=%d", reg, n); // FIXME + PDEBUG(5, "0x%02X:%7d, n=%d", reg, val, n); - if (values == NULL) { - err("reg write multiple: NULL buffer"); - return -EINVAL; - } + down(&ov->cbuf_lock); - rc = usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), + *((u32 *)ov->cbuf) = __cpu_to_le32(val); + + rc = usb_control_msg(ov->dev, + usb_sndctrlpipe(ov->dev, 0), 2 /* REG_IO */, USB_TYPE_CLASS | USB_RECIP_DEVICE, - 0, (__u16)reg, values, n, HZ); + 0, (__u16)reg, ov->cbuf, n, HZ); + up(&ov->cbuf_lock); if (rc < 0) err("reg write multiple: error %d", rc); @@ -816,12 +811,12 @@ } static int -ov511_upload_quan_tables(struct usb_device *dev) +ov511_upload_quan_tables(struct usb_ov511 *ov) { unsigned char *pYTable = yQuanTable511; unsigned char *pUVTable = uvQuanTable511; unsigned char val0, val1; - int i, rc, reg = OV511_OMNICE_Y_LUT_BEGIN; + int i, rc, reg = R511_COMP_LUT_BEGIN; PDEBUG(4, "Uploading quantization tables"); @@ -834,7 +829,7 @@ val0 &= 0x0f; val1 &= 0x0f; val0 |= val1 << 4; - rc = ov511_reg_write(dev, reg, val0); + rc = reg_w(ov, reg, val0); if (rc < 0) return rc; } @@ -846,8 +841,7 @@ val0 &= 0x0f; val1 &= 0x0f; val0 |= val1 << 4; - rc = ov511_reg_write(dev, reg + OV511_QUANTABLESIZE / 2, - val0); + rc = reg_w(ov, reg + OV511_QUANTABLESIZE/2, val0); if (rc < 0) return rc; } @@ -860,12 +854,12 @@ /* OV518 quantization tables are 8x4 (instead of 8x8) */ static int -ov518_upload_quan_tables(struct usb_device *dev) +ov518_upload_quan_tables(struct usb_ov511 *ov) { unsigned char *pYTable = yQuanTable518; unsigned char *pUVTable = uvQuanTable518; unsigned char val0, val1; - int i, rc, reg = OV511_OMNICE_Y_LUT_BEGIN; + int i, rc, reg = R511_COMP_LUT_BEGIN; PDEBUG(4, "Uploading quantization tables"); @@ -878,7 +872,7 @@ val0 &= 0x0f; val1 &= 0x0f; val0 |= val1 << 4; - rc = ov511_reg_write(dev, reg, val0); + rc = reg_w(ov, reg, val0); if (rc < 0) return rc; } @@ -890,8 +884,7 @@ val0 &= 0x0f; val1 &= 0x0f; val0 |= val1 << 4; - rc = ov511_reg_write(dev, reg + OV518_QUANTABLESIZE / 2, - val0); + rc = reg_w(ov, reg + OV518_QUANTABLESIZE/2, val0); if (rc < 0) return rc; } @@ -902,13 +895,39 @@ return 0; } +static int +ov51x_reset(struct usb_ov511 *ov, unsigned char reset_type) +{ + int rc; + + /* Setting bit 0 not allowed on 518/518Plus */ + if (ov->bclass == BCL_OV518) + reset_type &= 0xfe; + + PDEBUG(4, "Reset: type=0x%X", reset_type); + + rc = reg_w(ov, R51x_SYS_RESET, reset_type); + rc = reg_w(ov, R51x_SYS_RESET, 0); + + if (rc < 0) + err("reset: command failed"); + + return rc; +} + +/********************************************************************** + * + * I2C (sensor) I/O + * + **********************************************************************/ + /* NOTE: Do not call this function directly! * The OV518 I2C I/O procedure is different, hence, this function. - * This is normally only called from ov51x_i2c_write(). Note that this function + * This is normally only called from i2c_w(). Note that this function * always succeeds regardless of whether the sensor is present and working. */ static int -ov518_i2c_write_internal(struct usb_device *dev, +ov518_i2c_write_internal(struct usb_ov511 *ov, unsigned char reg, unsigned char value) { @@ -917,15 +936,15 @@ PDEBUG(5, "0x%02X:0x%02X", reg, value); /* Select camera register */ - rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, reg); + rc = reg_w(ov, R51x_I2C_SADDR_3, reg); if (rc < 0) goto error; /* Write "value" to I2C data port of OV511 */ - rc = ov511_reg_write(dev, OV511_REG_I2C_DATA_PORT, value); + rc = reg_w(ov, R51x_I2C_DATA, value); if (rc < 0) goto error; /* Initiate 3-byte write cycle */ - rc = ov511_reg_write(dev, OV518_REG_I2C_CONTROL, 0x01); + rc = reg_w(ov, R518_I2C_CTL, 0x01); if (rc < 0) goto error; return 0; @@ -937,7 +956,7 @@ /* NOTE: Do not call this function directly! */ static int -ov511_i2c_write_internal(struct usb_device *dev, +ov511_i2c_write_internal(struct usb_ov511 *ov, unsigned char reg, unsigned char value) { @@ -948,19 +967,18 @@ /* Three byte write cycle */ for (retries = OV511_I2C_RETRIES; ; ) { /* Select camera register */ - rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, - reg); + rc = reg_w(ov, R51x_I2C_SADDR_3, reg); if (rc < 0) goto error; /* Write "value" to I2C data port of OV511 */ - rc = ov511_reg_write(dev, OV511_REG_I2C_DATA_PORT, value); + rc = reg_w(ov, R51x_I2C_DATA, value); if (rc < 0) goto error; /* Initiate 3-byte write cycle */ - rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x01); + rc = reg_w(ov, R511_I2C_CTL, 0x01); if (rc < 0) goto error; - do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL); + do rc = reg_r(ov, R511_I2C_CTL); while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */ if (rc < 0) goto error; @@ -968,7 +986,7 @@ break; #if 0 /* I2C abort */ - ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10); + reg_w(ov, R511_I2C_CTL, 0x10); #endif if (--retries < 0) { err("i2c write retries exhausted"); @@ -986,27 +1004,27 @@ /* NOTE: Do not call this function directly! * The OV518 I2C I/O procedure is different, hence, this function. - * This is normally only called from ov51x_i2c_read(). Note that this function + * This is normally only called from i2c_r(). Note that this function * always succeeds regardless of whether the sensor is present and working. */ static int -ov518_i2c_read_internal(struct usb_device *dev, unsigned char reg) +ov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) { int rc, value; /* Select camera register */ - rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, reg); + rc = reg_w(ov, R51x_I2C_SADDR_2, reg); if (rc < 0) goto error; /* Initiate 2-byte write cycle */ - rc = ov511_reg_write(dev, OV518_REG_I2C_CONTROL, 0x03); + rc = reg_w(ov, R518_I2C_CTL, 0x03); if (rc < 0) goto error; /* Initiate 2-byte read cycle */ - rc = ov511_reg_write(dev, OV518_REG_I2C_CONTROL, 0x05); + rc = reg_w(ov, R518_I2C_CTL, 0x05); if (rc < 0) goto error; - value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT); + value = reg_r(ov, R51x_I2C_DATA); PDEBUG(5, "0x%02X:0x%02X", reg, value); @@ -1020,22 +1038,21 @@ /* NOTE: Do not call this function directly! * returns: negative is error, pos or zero is data */ static int -ov511_i2c_read_internal(struct usb_device *dev, unsigned char reg) +ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) { int rc, value, retries; /* Two byte write cycle */ for (retries = OV511_I2C_RETRIES; ; ) { /* Select camera register */ - rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, - reg); + rc = reg_w(ov, R51x_I2C_SADDR_2, reg); if (rc < 0) goto error; /* Initiate 2-byte write cycle */ - rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x03); + rc = reg_w(ov, R511_I2C_CTL, 0x03); if (rc < 0) goto error; - do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL); + do rc = reg_r(ov, R511_I2C_CTL); while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */ if (rc < 0) goto error; @@ -1043,7 +1060,7 @@ break; /* I2C abort */ - ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10); + reg_w(ov, R511_I2C_CTL, 0x10); if (--retries < 0) { err("i2c write retries exhausted"); @@ -1055,10 +1072,10 @@ /* Two byte read cycle */ for (retries = OV511_I2C_RETRIES; ; ) { /* Initiate 2-byte read cycle */ - rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05); + rc = reg_w(ov, R511_I2C_CTL, 0x05); if (rc < 0) goto error; - do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL); + do rc = reg_r(ov, R511_I2C_CTL); while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */ if (rc < 0) goto error; @@ -1066,7 +1083,7 @@ break; /* I2C abort */ - rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10); + rc = reg_w(ov, R511_I2C_CTL, 0x10); if (rc < 0) goto error; if (--retries < 0) { @@ -1076,12 +1093,12 @@ } } - value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT); + value = reg_r(ov, R51x_I2C_DATA); PDEBUG(5, "0x%02X:0x%02X", reg, value); - /* This is needed to make ov51x_i2c_write() work */ - rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05); + /* This is needed to make i2c_w() work */ + rc = reg_w(ov, R511_I2C_CTL, 0x05); if (rc < 0) goto error; @@ -1094,48 +1111,42 @@ /* returns: negative is error, pos or zero is data */ static int -ov51x_i2c_read(struct usb_ov511 *ov511, unsigned char reg) +i2c_r(struct usb_ov511 *ov, unsigned char reg) { int rc; - struct usb_device *dev = ov511->dev; - down(&ov511->i2c_lock); + down(&ov->i2c_lock); - if (dev->descriptor.idProduct == PROD_OV518 || - dev->descriptor.idProduct == PROD_OV518PLUS) - rc = ov518_i2c_read_internal(dev, reg); + if (ov->bclass == BCL_OV518) + rc = ov518_i2c_read_internal(ov, reg); else - rc = ov511_i2c_read_internal(dev, reg); + rc = ov511_i2c_read_internal(ov, reg); - up(&ov511->i2c_lock); + up(&ov->i2c_lock); return rc; } static int -ov51x_i2c_write(struct usb_ov511 *ov511, - unsigned char reg, - unsigned char value) +i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value) { int rc; - struct usb_device *dev = ov511->dev; - down(&ov511->i2c_lock); + down(&ov->i2c_lock); - if (dev->descriptor.idProduct == PROD_OV518 || - dev->descriptor.idProduct == PROD_OV518PLUS) - rc = ov518_i2c_write_internal(dev, reg, value); + if (ov->bclass == BCL_OV518) + rc = ov518_i2c_write_internal(ov, reg, value); else - rc = ov511_i2c_write_internal(dev, reg, value); + rc = ov511_i2c_write_internal(ov, reg, value); - up(&ov511->i2c_lock); + up(&ov->i2c_lock); return rc; } /* Do not call this function directly! */ static int -ov51x_i2c_write_mask_internal(struct usb_device *dev, +ov51x_i2c_write_mask_internal(struct usb_ov511 *ov, unsigned char reg, unsigned char value, unsigned char mask) @@ -1146,11 +1157,10 @@ if (mask == 0xff) { newval = value; } else { - if (dev->descriptor.idProduct == PROD_OV518 || - dev->descriptor.idProduct == PROD_OV518PLUS) - rc = ov518_i2c_read_internal(dev, reg); + if (ov->bclass == BCL_OV518) + rc = ov518_i2c_read_internal(ov, reg); else - rc = ov511_i2c_read_internal(dev, reg); + rc = ov511_i2c_read_internal(ov, reg); if (rc < 0) return rc; @@ -1160,11 +1170,10 @@ newval = oldval | value; /* Set the desired bits */ } - if (dev->descriptor.idProduct == PROD_OV518 || - dev->descriptor.idProduct == PROD_OV518PLUS) - return (ov518_i2c_write_internal(dev, reg, newval)); + if (ov->bclass == BCL_OV518) + return (ov518_i2c_write_internal(ov, reg, newval)); else - return (ov511_i2c_write_internal(dev, reg, newval)); + return (ov511_i2c_write_internal(ov, reg, newval)); } /* Writes bits at positions specified by mask to an I2C reg. Bits that are in @@ -1173,126 +1182,138 @@ * of their respective state in "value". */ static int -ov51x_i2c_write_mask(struct usb_ov511 *ov511, - unsigned char reg, - unsigned char value, - unsigned char mask) +i2c_w_mask(struct usb_ov511 *ov, + unsigned char reg, + unsigned char value, + unsigned char mask) { int rc; - struct usb_device *dev = ov511->dev; - down(&ov511->i2c_lock); - rc = ov51x_i2c_write_mask_internal(dev, reg, value, mask); - up(&ov511->i2c_lock); + down(&ov->i2c_lock); + rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask); + up(&ov->i2c_lock); return rc; } /* Write to a specific I2C slave ID and register, using the specified mask */ static int -ov51x_i2c_write_slave(struct usb_ov511 *ov511, - unsigned char slave, - unsigned char reg, - unsigned char value, - unsigned char mask) +i2c_w_slave(struct usb_ov511 *ov, + unsigned char slave, + unsigned char reg, + unsigned char value, + unsigned char mask) { int rc = 0; - struct usb_device *dev = ov511->dev; - down(&ov511->i2c_lock); + down(&ov->i2c_lock); /* Set new slave IDs */ - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, slave) < 0) { + if (reg_w(ov, R51x_I2C_W_SID, slave) < 0) { rc = -EIO; goto out; } - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, slave + 1) < 0) { + if (reg_w(ov, R51x_I2C_R_SID, slave + 1) < 0) { rc = -EIO; goto out; } - rc = ov51x_i2c_write_mask_internal(dev, reg, value, mask); + rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask); /* Don't bail out yet if error; IDs must be restored */ /* Restore primary IDs */ - slave = ov511->primary_i2c_slave; - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, slave) < 0) { + slave = ov->primary_i2c_slave; + if (reg_w(ov, R51x_I2C_W_SID, slave) < 0) { rc = -EIO; goto out; } - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, slave + 1) < 0) { + if (reg_w(ov, R51x_I2C_R_SID, slave + 1) < 0) { rc = -EIO; goto out; } out: - up(&ov511->i2c_lock); + up(&ov->i2c_lock); return rc; } /* Read from a specific I2C slave ID and register */ static int -ov51x_i2c_read_slave(struct usb_ov511 *ov511, - unsigned char slave, - unsigned char reg) +i2c_r_slave(struct usb_ov511 *ov, + unsigned char slave, + unsigned char reg) { int rc; - struct usb_device *dev = ov511->dev; - down(&ov511->i2c_lock); + down(&ov->i2c_lock); /* Set new slave IDs */ - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, slave) < 0) { + if (reg_w(ov, R51x_I2C_W_SID, slave) < 0) { rc = -EIO; goto out; } - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, slave + 1) < 0) { + if (reg_w(ov, R51x_I2C_R_SID, slave + 1) < 0) { rc = -EIO; goto out; } - if (dev->descriptor.idProduct == PROD_OV518 || - dev->descriptor.idProduct == PROD_OV518PLUS) - rc = ov518_i2c_read_internal(dev, reg); + if (ov->bclass == BCL_OV518) + rc = ov518_i2c_read_internal(ov, reg); else - rc = ov511_i2c_read_internal(dev, reg); + rc = ov511_i2c_read_internal(ov, reg); /* Don't bail out yet if error; IDs must be restored */ /* Restore primary IDs */ - slave = ov511->primary_i2c_slave; - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, slave) < 0) { + slave = ov->primary_i2c_slave; + if (reg_w(ov, R51x_I2C_W_SID, slave) < 0) { rc = -EIO; goto out; } - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, slave + 1) < 0) { + if (reg_w(ov, R51x_I2C_R_SID, slave + 1) < 0) { rc = -EIO; goto out; } out: - up(&ov511->i2c_lock); + up(&ov->i2c_lock); return rc; } +/* Sets I2C read and write slave IDs. Returns <0 for error */ +static int +ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid) +{ + down(&ov->i2c_lock); + + if (reg_w(ov, R51x_I2C_W_SID, sid) < 0) + return -EIO; + + if (reg_w(ov, R51x_I2C_R_SID, sid + 1) < 0) + return -EIO; + + if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) + return -EIO; + + up(&ov->i2c_lock); + + return 0; +} + static int -ov511_write_regvals(struct usb_ov511 *ov511, - struct ov511_regvals * pRegvals) +write_regvals(struct usb_ov511 *ov, struct ov511_regvals * pRegvals) { int rc; - struct usb_device *dev = ov511->dev; while (pRegvals->bus != OV511_DONE_BUS) { if (pRegvals->bus == OV511_REG_BUS) { - if ((rc = ov511_reg_write(dev, pRegvals->reg, - pRegvals->val)) < 0) + if ((rc = reg_w(ov, pRegvals->reg, pRegvals->val)) < 0) goto error; } else if (pRegvals->bus == OV511_I2C_BUS) { - if ((rc = ov51x_i2c_write(ov511, pRegvals->reg, - pRegvals->val)) < 0) + if ((rc = i2c_w(ov, pRegvals->reg, pRegvals->val)) < 0) goto error; } else { err("Bad regval array"); @@ -1310,57 +1331,60 @@ #ifdef OV511_DEBUG static void -ov511_dump_i2c_range(struct usb_ov511 *ov511, int reg1, int regn) +dump_i2c_range(struct usb_ov511 *ov, int reg1, int regn) { int i; int rc; + for (i = reg1; i <= regn; i++) { - rc = ov51x_i2c_read(ov511, i); + rc = i2c_r(ov, i); info("OV7610[0x%X] = 0x%X", i, rc); } } static void -ov51x_dump_i2c_regs(struct usb_ov511 *ov511) +dump_i2c_regs(struct usb_ov511 *ov) { info("I2C REGS"); - ov511_dump_i2c_range(ov511, 0x00, 0x7C); + dump_i2c_range(ov, 0x00, 0x7C); } static void -ov511_dump_reg_range(struct usb_device *dev, int reg1, int regn) +dump_reg_range(struct usb_ov511 *ov, int reg1, int regn) { int i; int rc; + for (i = reg1; i <= regn; i++) { - rc = ov511_reg_read(dev, i); - info("OV511[0x%X] = 0x%X", i, rc); + rc = reg_r(ov, i); + info("OV511[0x%X] = 0x%X", i, rc); } } +/* FIXME: Should there be an OV518 version of this? */ static void -ov511_dump_regs(struct usb_device *dev) +ov511_dump_regs(struct usb_ov511 *ov) { info("CAMERA INTERFACE REGS"); - ov511_dump_reg_range(dev, 0x10, 0x1f); + dump_reg_range(ov, 0x10, 0x1f); info("DRAM INTERFACE REGS"); - ov511_dump_reg_range(dev, 0x20, 0x23); + dump_reg_range(ov, 0x20, 0x23); info("ISO FIFO REGS"); - ov511_dump_reg_range(dev, 0x30, 0x31); + dump_reg_range(ov, 0x30, 0x31); info("PIO REGS"); - ov511_dump_reg_range(dev, 0x38, 0x39); - ov511_dump_reg_range(dev, 0x3e, 0x3e); + dump_reg_range(ov, 0x38, 0x39); + dump_reg_range(ov, 0x3e, 0x3e); info("I2C REGS"); - ov511_dump_reg_range(dev, 0x40, 0x49); + dump_reg_range(ov, 0x40, 0x49); info("SYSTEM CONTROL REGS"); - ov511_dump_reg_range(dev, 0x50, 0x55); - ov511_dump_reg_range(dev, 0x5e, 0x5f); + dump_reg_range(ov, 0x50, 0x55); + dump_reg_range(ov, 0x5e, 0x5f); info("OmniCE REGS"); - ov511_dump_reg_range(dev, 0x70, 0x79); + dump_reg_range(ov, 0x70, 0x79); /* NOTE: Quantization tables are not readable. You will get the value * in reg. 0x79 for every table register */ - ov511_dump_reg_range(dev, 0x80, 0x9f); - ov511_dump_reg_range(dev, 0xa0, 0xbf); + dump_reg_range(ov, 0x80, 0x9f); + dump_reg_range(ov, 0xa0, 0xbf); } #endif @@ -1373,7 +1397,7 @@ /* For as-yet unimplemented I2C interface */ static void -call_i2c_clients(struct usb_ov511 *ov511, unsigned int cmd, +call_i2c_clients(struct usb_ov511 *ov, unsigned int cmd, void *arg) { /* Do nothing */ @@ -1381,59 +1405,33 @@ /*****************************************************************************/ -static int -ov511_reset(struct usb_ov511 *ov511, unsigned char reset_type) -{ - int rc; - - /* Setting bit 0 not allowed on 518/518Plus */ - if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) - reset_type &= 0xfe; - - PDEBUG(4, "Reset: type=0x%X", reset_type); - - rc = ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, reset_type); - rc = ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, 0); - - if (rc < 0) - err("reset: command failed"); - - return rc; -} - /* Temporarily stops OV511 from functioning. Must do this before changing * registers while the camera is streaming */ static inline int -ov511_stop(struct usb_ov511 *ov511) +ov51x_stop(struct usb_ov511 *ov) { PDEBUG(4, "stopping"); - ov511->stopped = 1; - if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) - return (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, - 0x3a)); + ov->stopped = 1; + if (ov->bclass == BCL_OV518) + return (reg_w(ov, R51x_SYS_RESET, 0x3a)); else - return (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, - 0x3d)); + return (reg_w(ov, R51x_SYS_RESET, 0x3d)); } /* Restarts OV511 after ov511_stop() is called. Has no effect if it is not * actually stopped (for performance). */ static inline int -ov511_restart(struct usb_ov511 *ov511) +ov51x_restart(struct usb_ov511 *ov) { - if (ov511->stopped) { + if (ov->stopped) { PDEBUG(4, "restarting"); - ov511->stopped = 0; + ov->stopped = 0; /* Reinitialize the stream */ - if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) - ov511_reg_write(ov511->dev, 0x2f, 0x80); + if (ov->bclass == BCL_OV518) + reg_w(ov, 0x2f, 0x80); - return (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, - 0x00)); + return (reg_w(ov, R51x_SYS_RESET, 0x00)); } return 0; @@ -1441,14 +1439,13 @@ /* Resets the hardware snapshot button */ static void -ov51x_clear_snapshot(struct usb_ov511 *ov511) +ov51x_clear_snapshot(struct usb_ov511 *ov) { - if (ov511->bridge == BRG_OV511 || ov511->bridge == BRG_OV511PLUS) { - ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01); - ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x03); - ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01); - } else if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) { + if (ov->bclass == BCL_OV511) { + reg_w(ov, R51x_SYS_SNAP, 0x01); + reg_w(ov, R51x_SYS_SNAP, 0x03); + reg_w(ov, R51x_SYS_SNAP, 0x01); + } else if (ov->bclass == BCL_OV518) { warn("snapshot reset not supported yet on OV518(+)"); } else { err("clear snap: invalid bridge type"); @@ -1459,19 +1456,18 @@ /* Checks the status of the snapshot button. Returns 1 if it was pressed since * it was last cleared, and zero in all other cases (including errors) */ static int -ov51x_check_snapshot(struct usb_ov511 *ov511) +ov51x_check_snapshot(struct usb_ov511 *ov) { int ret, status = 0; - if (ov511->bridge == BRG_OV511 || ov511->bridge == BRG_OV511PLUS) { - ret = ov511_reg_read(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT); + if (ov->bclass == BCL_OV511) { + ret = reg_r(ov, R51x_SYS_SNAP); if (ret < 0) { err("Error checking snspshot status (%d)", ret); } else if (ret & 0x08) { status = 1; } - } else if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) { + } else if (ov->bclass == BCL_OV518) { warn("snapshot check not supported yet on OV518(+)"); } else { err("check snap: invalid bridge type"); @@ -1480,53 +1476,33 @@ return status; } -/* Sets I2C read and write slave IDs. Returns <0 for error */ -static int -ov51x_set_slave_ids(struct usb_ov511 *ov511, - unsigned char write_id, - unsigned char read_id) -{ - struct usb_device *dev = ov511->dev; - - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, write_id) < 0) - return -EIO; - - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, read_id) < 0) - return -EIO; - - if (ov511_reset(ov511, OV511_RESET_NOREGS) < 0) - return -EIO; - - return 0; -} - /* This does an initial reset of an OmniVision sensor and ensures that I2C * is synchronized. Returns <0 for failure. */ static int -ov51x_init_ov_sensor(struct usb_ov511 *ov511) +init_ov_sensor(struct usb_ov511 *ov) { int i, success; /* Reset the sensor */ - if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) return -EIO; + if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO; /* Wait for it to initialize */ schedule_timeout (1 + 150 * HZ / 1000); for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) { - if ((ov51x_i2c_read(ov511, OV7610_REG_ID_HIGH) == 0x7F) && - (ov51x_i2c_read(ov511, OV7610_REG_ID_LOW) == 0xA2)) { + if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) && + (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) { success = 1; continue; } /* Reset the sensor */ - if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) return -EIO; + if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO; /* Wait for it to initialize */ schedule_timeout(1 + 150 * HZ / 1000); /* Dummy read to sync I2C */ - if (ov51x_i2c_read(ov511, 0x00) < 0) return -EIO; + if (i2c_r(ov, 0x00) < 0) return -EIO; } if (!success) @@ -1538,16 +1514,16 @@ } static int -ov511_set_packet_size(struct usb_ov511 *ov511, int size) +ov51x_set_packet_size(struct usb_ov511 *ov, int size) { int alt, mult; - if (ov511_stop(ov511) < 0) + if (ov51x_stop(ov) < 0) return -EIO; mult = size >> 5; - if (ov511->bridge == BRG_OV511) { + if (ov->bridge == BRG_OV511) { if (size == 0) alt = OV511_ALT_SIZE_0; else if (size == 257) alt = OV511_ALT_SIZE_257; else if (size == 513) alt = OV511_ALT_SIZE_513; @@ -1557,7 +1533,7 @@ err("Set packet size: invalid size (%d)", size); return -EINVAL; } - } else if (ov511->bridge == BRG_OV511PLUS) { + } else if (ov->bridge == BRG_OV511PLUS) { if (size == 0) alt = OV511PLUS_ALT_SIZE_0; else if (size == 33) alt = OV511PLUS_ALT_SIZE_33; else if (size == 129) alt = OV511PLUS_ALT_SIZE_129; @@ -1570,8 +1546,7 @@ err("Set packet size: invalid size (%d)", size); return -EINVAL; } - } else if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) { + } else if (ov->bclass == BCL_OV518) { if (size == 0) alt = OV518_ALT_SIZE_0; else if (size == 128) alt = OV518_ALT_SIZE_128; else if (size == 256) alt = OV518_ALT_SIZE_256; @@ -1592,32 +1567,30 @@ PDEBUG(3, "set packet size: %d, mult=%d, alt=%d", size, mult, alt); // FIXME: Don't know how to do this on OV518 yet - if (ov511->bridge != BRG_OV518 && - ov511->bridge != BRG_OV518PLUS) { - if (ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE, + if (ov->bclass == BCL_OV511) { + if (reg_w(ov, R51x_FIFO_PSIZE, mult) < 0) { return -EIO; } } - if (usb_set_interface(ov511->dev, ov511->iface, alt) < 0) { + if (usb_set_interface(ov->dev, ov->iface, alt) < 0) { err("Set packet size: set interface error"); return -EBUSY; } /* Initialize the stream */ - if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) - if (ov511_reg_write(ov511->dev, 0x2f, 0x80) < 0) + if (ov->bclass == BCL_OV518) + if (reg_w(ov, 0x2f, 0x80) < 0) return -EIO; // FIXME - Should we only reset the FIFO? - if (ov511_reset(ov511, OV511_RESET_NOREGS) < 0) + if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) return -EIO; - ov511->packet_size = size; + ov->packet_size = size; - if (ov511_restart(ov511) < 0) + if (ov51x_restart(ov) < 0) return -EIO; return 0; @@ -1625,51 +1598,49 @@ /* Upload compression params and quantization tables. Returns 0 for success. */ static int -ov511_init_compression(struct usb_ov511 *ov511) +ov511_init_compression(struct usb_ov511 *ov) { - struct usb_device *dev = ov511->dev; int rc = 0; - if (!ov511->compress_inited) { + if (!ov->compress_inited) { - ov511_reg_write(dev, 0x70, phy); - ov511_reg_write(dev, 0x71, phuv); - ov511_reg_write(dev, 0x72, pvy); - ov511_reg_write(dev, 0x73, pvuv); - ov511_reg_write(dev, 0x74, qhy); - ov511_reg_write(dev, 0x75, qhuv); - ov511_reg_write(dev, 0x76, qvy); - ov511_reg_write(dev, 0x77, qvuv); + reg_w(ov, 0x70, phy); + reg_w(ov, 0x71, phuv); + reg_w(ov, 0x72, pvy); + reg_w(ov, 0x73, pvuv); + reg_w(ov, 0x74, qhy); + reg_w(ov, 0x75, qhuv); + reg_w(ov, 0x76, qvy); + reg_w(ov, 0x77, qvuv); - if (ov511_upload_quan_tables(dev) < 0) { + if (ov511_upload_quan_tables(ov) < 0) { err("Error uploading quantization tables"); rc = -EIO; goto out; } } - ov511->compress_inited = 1; + ov->compress_inited = 1; out: return rc; } /* Upload compression params and quantization tables. Returns 0 for success. */ static int -ov518_init_compression(struct usb_ov511 *ov511) +ov518_init_compression(struct usb_ov511 *ov) { - struct usb_device *dev = ov511->dev; int rc = 0; - if (!ov511->compress_inited) { + if (!ov->compress_inited) { - if (ov518_upload_quan_tables(dev) < 0) { + if (ov518_upload_quan_tables(ov) < 0) { err("Error uploading quantization tables"); rc = -EIO; goto out; } } - ov511->compress_inited = 1; + ov->compress_inited = 1; out: return rc; } @@ -1678,22 +1649,22 @@ /* Sets sensor's contrast setting to "val" */ static int -sensor_set_contrast(struct usb_ov511 *ov511, unsigned short val) +sensor_set_contrast(struct usb_ov511 *ov, unsigned short val) { int rc; PDEBUG(3, "%d", val); - if (ov511->stop_during_set) - if (ov511_stop(ov511) < 0) + if (ov->stop_during_set) + if (ov51x_stop(ov) < 0) return -EIO; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV6620: case SEN_OV6630: { - rc = ov51x_i2c_write(ov511, OV7610_REG_CNT, val >> 8); + rc = i2c_w(ov, OV7610_REG_CNT, val >> 8); if (rc < 0) goto out; break; @@ -1706,14 +1677,14 @@ }; /* Use Y gamma control instead. Bit 0 enables it. */ - rc = ov51x_i2c_write(ov511, 0x64, ctab[val>>12]); + rc = i2c_w(ov, 0x64, ctab[val>>12]); if (rc < 0) goto out; break; } case SEN_SAA7111A: { - rc = ov51x_i2c_write(ov511, 0x0b, val >> 9); + rc = i2c_w(ov, 0x0b, val >> 9); if (rc < 0) goto out; break; @@ -1727,9 +1698,9 @@ } rc = 0; /* Success */ - ov511->contrast = val; + ov->contrast = val; out: - if (ov511_restart(ov511) < 0) + if (ov51x_restart(ov) < 0) return -EIO; return rc; @@ -1737,15 +1708,15 @@ /* Gets sensor's contrast setting */ static int -sensor_get_contrast(struct usb_ov511 *ov511, unsigned short *val) +sensor_get_contrast(struct usb_ov511 *ov, unsigned short *val) { int rc; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV6620: case SEN_OV6630: - rc = ov51x_i2c_read(ov511, OV7610_REG_CNT); + rc = i2c_r(ov, OV7610_REG_CNT); if (rc < 0) return rc; else @@ -1753,14 +1724,14 @@ break; case SEN_OV7620: /* Use Y gamma reg instead. Bit 0 is the enable bit. */ - rc = ov51x_i2c_read(ov511, 0x64); + rc = i2c_r(ov, 0x64); if (rc < 0) return rc; else *val = (rc & 0xfe) << 8; break; case SEN_SAA7111A: - *val = ov511->contrast; + *val = ov->contrast; break; default: PDEBUG(3, "Unsupported with this sensor"); @@ -1768,7 +1739,7 @@ } PDEBUG(3, "%d", *val); - ov511->contrast = *val; + ov->contrast = *val; return 0; } @@ -1777,35 +1748,35 @@ /* Sets sensor's brightness setting to "val" */ static int -sensor_set_brightness(struct usb_ov511 *ov511, unsigned short val) +sensor_set_brightness(struct usb_ov511 *ov, unsigned short val) { int rc; PDEBUG(4, "%d", val); - if (ov511->stop_during_set) - if (ov511_stop(ov511) < 0) + if (ov->stop_during_set) + if (ov51x_stop(ov) < 0) return -EIO; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV7620AE: case SEN_OV6620: case SEN_OV6630: - rc = ov51x_i2c_write(ov511, OV7610_REG_BRT, val >> 8); + rc = i2c_w(ov, OV7610_REG_BRT, val >> 8); if (rc < 0) goto out; break; case SEN_OV7620: /* 7620 doesn't like manual changes when in auto mode */ - if (!ov511->auto_brt) { - rc = ov51x_i2c_write(ov511, OV7610_REG_BRT, val >> 8); + if (!ov->auto_brt) { + rc = i2c_w(ov, OV7610_REG_BRT, val >> 8); if (rc < 0) goto out; } break; case SEN_SAA7111A: - rc = ov51x_i2c_write(ov511, 0x0a, val >> 8); + rc = i2c_w(ov, 0x0a, val >> 8); if (rc < 0) goto out; break; @@ -1816,9 +1787,9 @@ } rc = 0; /* Success */ - ov511->brightness = val; + ov->brightness = val; out: - if (ov511_restart(ov511) < 0) + if (ov51x_restart(ov) < 0) return -EIO; return rc; @@ -1826,24 +1797,24 @@ /* Gets sensor's brightness setting */ static int -sensor_get_brightness(struct usb_ov511 *ov511, unsigned short *val) +sensor_get_brightness(struct usb_ov511 *ov, unsigned short *val) { int rc; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV7620AE: case SEN_OV7620: case SEN_OV6620: case SEN_OV6630: - rc = ov51x_i2c_read(ov511, OV7610_REG_BRT); + rc = i2c_r(ov, OV7610_REG_BRT); if (rc < 0) return rc; else *val = rc << 8; break; case SEN_SAA7111A: - *val = ov511->brightness; + *val = ov->brightness; break; default: PDEBUG(3, "Unsupported with this sensor"); @@ -1851,7 +1822,7 @@ } PDEBUG(3, "%d", *val); - ov511->brightness = *val; + ov->brightness = *val; return 0; } @@ -1860,36 +1831,36 @@ /* Sets sensor's saturation (color intensity) setting to "val" */ static int -sensor_set_saturation(struct usb_ov511 *ov511, unsigned short val) +sensor_set_saturation(struct usb_ov511 *ov, unsigned short val) { int rc; PDEBUG(3, "%d", val); - if (ov511->stop_during_set) - if (ov511_stop(ov511) < 0) + if (ov->stop_during_set) + if (ov51x_stop(ov) < 0) return -EIO; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV7620AE: case SEN_OV6620: case SEN_OV6630: - rc = ov51x_i2c_write(ov511, OV7610_REG_SAT, val >> 8); + rc = i2c_w(ov, OV7610_REG_SAT, val >> 8); if (rc < 0) goto out; break; case SEN_OV7620: // /* Use UV gamma control instead. Bits 0 & 7 are reserved. */ -// rc = ov511_i2c_write(ov511->dev, 0x62, (val >> 9) & 0x7e); +// rc = ov_i2c_write(ov->dev, 0x62, (val >> 9) & 0x7e); // if (rc < 0) // goto out; - rc = ov51x_i2c_write(ov511, OV7610_REG_SAT, val >> 8); + rc = i2c_w(ov, OV7610_REG_SAT, val >> 8); if (rc < 0) goto out; break; case SEN_SAA7111A: - rc = ov51x_i2c_write(ov511, 0x0c, val >> 9); + rc = i2c_w(ov, 0x0c, val >> 9); if (rc < 0) goto out; break; @@ -1900,9 +1871,9 @@ } rc = 0; /* Success */ - ov511->colour = val; + ov->colour = val; out: - if (ov511_restart(ov511) < 0) + if (ov51x_restart(ov) < 0) return -EIO; return rc; @@ -1910,16 +1881,16 @@ /* Gets sensor's saturation (color intensity) setting */ static int -sensor_get_saturation(struct usb_ov511 *ov511, unsigned short *val) +sensor_get_saturation(struct usb_ov511 *ov, unsigned short *val) { int rc; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV7620AE: case SEN_OV6620: case SEN_OV6630: - rc = ov51x_i2c_read(ov511, OV7610_REG_SAT); + rc = i2c_r(ov, OV7610_REG_SAT); if (rc < 0) return rc; else @@ -1927,19 +1898,19 @@ break; case SEN_OV7620: // /* Use UV gamma reg instead. Bits 0 & 7 are reserved. */ -// rc = ov51x_i2c_read(ov511, 0x62); +// rc = i2c_r(ov, 0x62); // if (rc < 0) // return rc; // else // *val = (rc & 0x7e) << 9; - rc = ov51x_i2c_read(ov511, OV7610_REG_SAT); + rc = i2c_r(ov, OV7610_REG_SAT); if (rc < 0) return rc; else *val = rc << 8; break; case SEN_SAA7111A: - *val = ov511->colour; + *val = ov->colour; break; default: PDEBUG(3, "Unsupported with this sensor"); @@ -1947,7 +1918,7 @@ } PDEBUG(3, "%d", *val); - ov511->colour = *val; + ov->colour = *val; return 0; } @@ -1956,44 +1927,42 @@ /* Sets sensor's hue (red/blue balance) setting to "val" */ static int -sensor_set_hue(struct usb_ov511 *ov511, unsigned short val) +sensor_set_hue(struct usb_ov511 *ov, unsigned short val) { int rc; PDEBUG(3, "%d", val); - if (ov511->stop_during_set) - if (ov511_stop(ov511) < 0) + if (ov->stop_during_set) + if (ov51x_stop(ov) < 0) return -EIO; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV6620: case SEN_OV6630: - rc = ov51x_i2c_write(ov511, OV7610_REG_RED, 0xFF - (val >> 8)); + rc = i2c_w(ov, OV7610_REG_RED, 0xFF - (val >> 8)); if (rc < 0) goto out; - rc = ov51x_i2c_write(ov511, OV7610_REG_BLUE, val >> 8); + rc = i2c_w(ov, OV7610_REG_BLUE, val >> 8); if (rc < 0) goto out; break; case SEN_OV7620: // Hue control is causing problems. I will enable it once it's fixed. #if 0 - rc = ov51x_i2c_write(ov511, 0x7a, - (unsigned char)(val >> 8) + 0xb); + rc = i2c_w(ov, 0x7a, (unsigned char)(val >> 8) + 0xb); if (rc < 0) goto out; - rc = ov51x_i2c_write(ov511, 0x79, - (unsigned char)(val >> 8) + 0xb); + rc = i2c_w(ov, 0x79, (unsigned char)(val >> 8) + 0xb); if (rc < 0) goto out; #endif break; case SEN_SAA7111A: - rc = ov51x_i2c_write(ov511, 0x0d, (val + 32768) >> 8); + rc = i2c_w(ov, 0x0d, (val + 32768) >> 8); if (rc < 0) goto out; break; @@ -2004,9 +1973,9 @@ } rc = 0; /* Success */ - ov511->hue = val; + ov->hue = val; out: - if (ov511_restart(ov511) < 0) + if (ov51x_restart(ov) < 0) return -EIO; return rc; @@ -2014,29 +1983,29 @@ /* Gets sensor's hue (red/blue balance) setting */ static int -sensor_get_hue(struct usb_ov511 *ov511, unsigned short *val) +sensor_get_hue(struct usb_ov511 *ov, unsigned short *val) { int rc; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV6620: case SEN_OV6630: - rc = ov51x_i2c_read(ov511, OV7610_REG_BLUE); + rc = i2c_r(ov, OV7610_REG_BLUE); if (rc < 0) return rc; else *val = rc << 8; break; case SEN_OV7620: - rc = ov51x_i2c_read(ov511, 0x7a); + rc = i2c_r(ov, 0x7a); if (rc < 0) return rc; else *val = rc << 8; break; case SEN_SAA7111A: - *val = ov511->hue; + *val = ov->hue; break; default: PDEBUG(3, "Unsupported with this sensor"); @@ -2044,7 +2013,7 @@ } PDEBUG(3, "%d", *val); - ov511->hue = *val; + ov->hue = *val; return 0; } @@ -2052,30 +2021,30 @@ /* -------------------------------------------------------------------------- */ static inline int -sensor_set_picture(struct usb_ov511 *ov511, struct video_picture *p) +sensor_set_picture(struct usb_ov511 *ov, struct video_picture *p) { int rc; PDEBUG(4, "sensor_set_picture"); - ov511->whiteness = p->whiteness; + ov->whiteness = p->whiteness; /* Don't return error if a setting is unsupported, or rest of settings * will not be performed */ - rc = sensor_set_contrast(ov511, p->contrast); + rc = sensor_set_contrast(ov, p->contrast); if (FATAL_ERROR(rc)) return rc; - rc = sensor_set_brightness(ov511, p->brightness); + rc = sensor_set_brightness(ov, p->brightness); if (FATAL_ERROR(rc)) return rc; - rc = sensor_set_saturation(ov511, p->colour); + rc = sensor_set_saturation(ov, p->colour); if (FATAL_ERROR(rc)) return rc; - rc = sensor_set_hue(ov511, p->hue); + rc = sensor_set_hue(ov, p->hue); if (FATAL_ERROR(rc)) return rc; @@ -2083,7 +2052,7 @@ } static inline int -sensor_get_picture(struct usb_ov511 *ov511, struct video_picture *p) +sensor_get_picture(struct usb_ov511 *ov, struct video_picture *p) { int rc; @@ -2092,27 +2061,27 @@ /* Don't return error if a setting is unsupported, or rest of settings * will not be performed */ - rc = sensor_get_contrast(ov511, &(p->contrast)); + rc = sensor_get_contrast(ov, &(p->contrast)); if (FATAL_ERROR(rc)) return rc; - rc = sensor_get_brightness(ov511, &(p->brightness)); + rc = sensor_get_brightness(ov, &(p->brightness)); if (FATAL_ERROR(rc)) return rc; - rc = sensor_get_saturation(ov511, &(p->colour)); + rc = sensor_get_saturation(ov, &(p->colour)); if (FATAL_ERROR(rc)) return rc; - rc = sensor_get_hue(ov511, &(p->hue)); + rc = sensor_get_hue(ov, &(p->hue)); if (FATAL_ERROR(rc)) return rc; p->whiteness = 105 << 8; /* Can we get these from frame[0]? -claudio? */ - p->depth = ov511->frame[0].depth; - p->palette = ov511->frame[0].format; + p->depth = ov->frame[0].depth; + p->palette = ov->frame[0].format; return 0; } @@ -2121,24 +2090,24 @@ /* Sets current exposure for sensor. This only has an effect if auto-exposure * is off */ static inline int -sensor_set_exposure(struct usb_ov511 *ov511, unsigned char val) +sensor_set_exposure(struct usb_ov511 *ov, unsigned char val) { int rc; PDEBUG(3, "%d", val); - if (ov511->stop_during_set) - if (ov511_stop(ov511) < 0) + if (ov->stop_during_set) + if (ov51x_stop(ov) < 0) return -EIO; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV6620: case SEN_OV6630: case SEN_OV7610: case SEN_OV7620: case SEN_OV7620AE: case SEN_OV8600: - rc = ov51x_i2c_write(ov511, 0x10, val); + rc = i2c_w(ov, 0x10, val); if (rc < 0) goto out; @@ -2154,9 +2123,9 @@ } rc = 0; /* Success */ - ov511->exposure = val; + ov->exposure = val; out: - if (ov511_restart(ov511) < 0) + if (ov51x_restart(ov) < 0) return -EIO; return rc; @@ -2165,18 +2134,18 @@ /* Gets current exposure level from sensor, regardless of whether it is under * manual control. */ static int -sensor_get_exposure(struct usb_ov511 *ov511, unsigned char *val) +sensor_get_exposure(struct usb_ov511 *ov, unsigned char *val) { int rc; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV6620: case SEN_OV6630: case SEN_OV7620: case SEN_OV7620AE: case SEN_OV8600: - rc = ov51x_i2c_read(ov511, 0x10); + rc = i2c_r(ov, 0x10); if (rc < 0) return rc; else @@ -2194,24 +2163,22 @@ } PDEBUG(3, "%d", *val); - ov511->exposure = *val; + ov->exposure = *val; return 0; } /* Turns on or off the LED. Only has an effect with OV511+/OV518(+) */ static inline void -ov51x_led_control(struct usb_ov511 *ov511, int enable) +ov51x_led_control(struct usb_ov511 *ov, int enable) { PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); - if (ov511->bridge == BRG_OV511PLUS) - ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_LED_CTL, - enable ? 1 : 0); - else if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) - ov511_reg_write_mask(ov511->dev, OV518_REG_GPIO_OUT, - enable ? 0x02 : 0x00, 0x02); + if (ov->bridge == BRG_OV511PLUS) + reg_w(ov, R511_SYS_LED_CTL, enable ? 1 : 0); + else if (ov->bclass == BCL_OV518) + reg_w_mask(ov, R518_GPIO_OUT, enable ? 0x02 : 0x00, 0x02); + return; } @@ -2225,7 +2192,7 @@ * Returns: 0 for success */ static int -sensor_set_light_freq(struct usb_ov511 *ov511, int freq) +sensor_set_light_freq(struct usb_ov511 *ov, int freq) { int sixty; @@ -2240,24 +2207,24 @@ return -EINVAL; } - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: - ov51x_i2c_write_mask(ov511, 0x2a, sixty?0x00:0x80, 0x80); - ov51x_i2c_write(ov511, 0x2b, sixty?0x00:0xac); - ov51x_i2c_write_mask(ov511, 0x13, 0x10, 0x10); - ov51x_i2c_write_mask(ov511, 0x13, 0x00, 0x10); + i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80); + i2c_w(ov, 0x2b, sixty?0x00:0xac); + i2c_w_mask(ov, 0x13, 0x10, 0x10); + i2c_w_mask(ov, 0x13, 0x00, 0x10); break; case SEN_OV7620: case SEN_OV7620AE: case SEN_OV8600: - ov51x_i2c_write_mask(ov511, 0x2a, sixty?0x00:0x80, 0x80); - ov51x_i2c_write(ov511, 0x2b, sixty?0x00:0xac); - ov51x_i2c_write_mask(ov511, 0x76, 0x01, 0x01); + i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80); + i2c_w(ov, 0x2b, sixty?0x00:0xac); + i2c_w_mask(ov, 0x76, 0x01, 0x01); break; case SEN_OV6620: case SEN_OV6630: - ov51x_i2c_write(ov511, 0x2b, sixty?0xa8:0x28); - ov51x_i2c_write(ov511, 0x2a, sixty?0x84:0xa4); + i2c_w(ov, 0x2b, sixty?0xa8:0x28); + i2c_w(ov, 0x2a, sixty?0x84:0xa4); break; case SEN_KS0127: case SEN_KS0127B: @@ -2269,7 +2236,7 @@ return -EINVAL; } - ov511->lightfreq = freq; + ov->lightfreq = freq; return 0; } @@ -2284,23 +2251,23 @@ * Returns: 0 for success */ static inline int -sensor_set_banding_filter(struct usb_ov511 *ov511, int enable) +sensor_set_banding_filter(struct usb_ov511 *ov, int enable) { int rc; PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); - if (ov511->sensor == SEN_KS0127 || ov511->sensor == SEN_KS0127B - || ov511->sensor == SEN_SAA7111A) { + if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B + || ov->sensor == SEN_SAA7111A) { PDEBUG(5, "Unsupported with this sensor"); return -EPERM; } - rc = ov51x_i2c_write_mask(ov511, 0x2d, enable?0x04:0x00, 0x04); + rc = i2c_w_mask(ov, 0x2d, enable?0x04:0x00, 0x04); if (rc < 0) return rc; - ov511->bandfilt = enable; + ov->bandfilt = enable; return 0; } @@ -2312,23 +2279,23 @@ * Returns: 0 for success */ static inline int -sensor_set_auto_brightness(struct usb_ov511 *ov511, int enable) +sensor_set_auto_brightness(struct usb_ov511 *ov, int enable) { int rc; PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); - if (ov511->sensor == SEN_KS0127 || ov511->sensor == SEN_KS0127B - || ov511->sensor == SEN_SAA7111A) { + if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B + || ov->sensor == SEN_SAA7111A) { PDEBUG(5, "Unsupported with this sensor"); return -EPERM; } - rc = ov51x_i2c_write_mask(ov511, 0x2d, enable?0x10:0x00, 0x10); + rc = i2c_w_mask(ov, 0x2d, enable?0x10:0x00, 0x10); if (rc < 0) return rc; - ov511->auto_brt = enable; + ov->auto_brt = enable; return 0; } @@ -2340,22 +2307,22 @@ * Returns: 0 for success */ static inline int -sensor_set_auto_exposure(struct usb_ov511 *ov511, int enable) +sensor_set_auto_exposure(struct usb_ov511 *ov, int enable) { PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: - ov51x_i2c_write_mask(ov511, 0x29, enable?0x00:0x80, 0x80); + i2c_w_mask(ov, 0x29, enable?0x00:0x80, 0x80); break; case SEN_OV6620: case SEN_OV7620: case SEN_OV7620AE: case SEN_OV8600: - ov51x_i2c_write_mask(ov511, 0x13, enable?0x01:0x00, 0x01); + i2c_w_mask(ov, 0x13, enable?0x01:0x00, 0x01); break; case SEN_OV6630: - ov51x_i2c_write_mask(ov511, 0x28, enable?0x00:0x10, 0x10); + i2c_w_mask(ov, 0x28, enable?0x00:0x10, 0x10); break; case SEN_KS0127: case SEN_KS0127B: @@ -2367,7 +2334,7 @@ return -EINVAL; } - ov511->auto_exp = enable; + ov->auto_exp = enable; return 0; } @@ -2380,27 +2347,27 @@ * Returns: 0 for success */ static int -sensor_set_backlight(struct usb_ov511 *ov511, int enable) +sensor_set_backlight(struct usb_ov511 *ov, int enable) { PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7620: case SEN_OV8600: - ov51x_i2c_write_mask(ov511, 0x68, enable?0xe0:0xc0, 0xe0); - ov51x_i2c_write_mask(ov511, 0x29, enable?0x08:0x00, 0x08); - ov51x_i2c_write_mask(ov511, 0x28, enable?0x02:0x00, 0x02); + i2c_w_mask(ov, 0x68, enable?0xe0:0xc0, 0xe0); + i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); + i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02); break; case SEN_OV6620: - ov51x_i2c_write_mask(ov511, 0x4e, enable?0xe0:0xc0, 0xe0); - ov51x_i2c_write_mask(ov511, 0x29, enable?0x08:0x00, 0x08); - ov51x_i2c_write_mask(ov511, 0x0e, enable?0x80:0x00, 0x80); + i2c_w_mask(ov, 0x4e, enable?0xe0:0xc0, 0xe0); + i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); + i2c_w_mask(ov, 0x0e, enable?0x80:0x00, 0x80); break; case SEN_OV6630: - ov51x_i2c_write_mask(ov511, 0x4e, enable?0x80:0x60, 0xe0); - ov51x_i2c_write_mask(ov511, 0x29, enable?0x08:0x00, 0x08); - ov51x_i2c_write_mask(ov511, 0x28, enable?0x02:0x00, 0x02); + i2c_w_mask(ov, 0x4e, enable?0x80:0x60, 0xe0); + i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); + i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02); break; case SEN_OV7610: case SEN_OV7620AE: @@ -2414,7 +2381,7 @@ return -EINVAL; } - ov511->backlight = enable; + ov->backlight = enable; return 0; } @@ -2423,7 +2390,7 @@ * planar or not), or zero for unsupported format. */ static inline int -ov511_get_depth(int palette) +get_depth(int palette) { switch (palette) { case VIDEO_PALETTE_GREY: return 8; @@ -2446,55 +2413,55 @@ return 0; else return ((frame->width * frame->height - * ov511_get_depth(frame->format)) >> 3); + * get_depth(frame->format)) >> 3); } static int -mode_init_ov_sensor_regs(struct usb_ov511 *ov511, int width, int height, +mode_init_ov_sensor_regs(struct usb_ov511 *ov, int width, int height, int mode, int sub_flag, int qvga) { int clock; /******** Mode (VGA/QVGA) and sensor specific regs ********/ - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: - ov51x_i2c_write(ov511, 0x14, qvga?0x24:0x04); + i2c_w(ov, 0x14, qvga?0x24:0x04); // FIXME: Does this improve the image quality or frame rate? #if 0 - ov51x_i2c_write_mask(ov511, 0x28, qvga?0x00:0x20, 0x20); - ov51x_i2c_write(ov511, 0x24, 0x10); - ov51x_i2c_write(ov511, 0x25, qvga?0x40:0x8a); - ov51x_i2c_write(ov511, 0x2f, qvga?0x30:0xb0); - ov51x_i2c_write(ov511, 0x35, qvga?0x1c:0x9c); + i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); + i2c_w(ov, 0x24, 0x10); + i2c_w(ov, 0x25, qvga?0x40:0x8a); + i2c_w(ov, 0x2f, qvga?0x30:0xb0); + i2c_w(ov, 0x35, qvga?0x1c:0x9c); #endif break; case SEN_OV7620: -// ov51x_i2c_write(ov511, 0x2b, 0x00); - ov51x_i2c_write(ov511, 0x14, qvga?0xa4:0x84); - ov51x_i2c_write_mask(ov511, 0x28, qvga?0x00:0x20, 0x20); - ov51x_i2c_write(ov511, 0x24, qvga?0x20:0x3a); - ov51x_i2c_write(ov511, 0x25, qvga?0x30:0x60); - ov51x_i2c_write_mask(ov511, 0x2d, qvga?0x40:0x00, 0x40); - ov51x_i2c_write_mask(ov511, 0x67, qvga?0xf0:0x90, 0xf0); - ov51x_i2c_write_mask(ov511, 0x74, qvga?0x20:0x00, 0x20); +// i2c_w(ov, 0x2b, 0x00); + i2c_w(ov, 0x14, qvga?0xa4:0x84); + i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); + i2c_w(ov, 0x24, qvga?0x20:0x3a); + i2c_w(ov, 0x25, qvga?0x30:0x60); + i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40); + i2c_w_mask(ov, 0x67, qvga?0xf0:0x90, 0xf0); + i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20); break; case SEN_OV7620AE: -// ov51x_i2c_write(ov511, 0x2b, 0x00); - ov51x_i2c_write(ov511, 0x14, qvga?0xa4:0x84); +// i2c_w(ov, 0x2b, 0x00); + i2c_w(ov, 0x14, qvga?0xa4:0x84); // FIXME: Enable this once 7620AE uses 7620 initial settings #if 0 - ov51x_i2c_write_mask(ov511, 0x28, qvga?0x00:0x20, 0x20); - ov51x_i2c_write(ov511, 0x24, qvga?0x20:0x3a); - ov51x_i2c_write(ov511, 0x25, qvga?0x30:0x60); - ov51x_i2c_write_mask(ov511, 0x2d, qvga?0x40:0x00, 0x40); - ov51x_i2c_write_mask(ov511, 0x67, qvga?0xb0:0x90, 0xf0); - ov51x_i2c_write_mask(ov511, 0x74, qvga?0x20:0x00, 0x20); + i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); + i2c_w(ov, 0x24, qvga?0x20:0x3a); + i2c_w(ov, 0x25, qvga?0x30:0x60); + i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40); + i2c_w_mask(ov, 0x67, qvga?0xb0:0x90, 0xf0); + i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20); #endif break; case SEN_OV6620: case SEN_OV6630: - ov51x_i2c_write(ov511, 0x14, qvga?0x24:0x04); + i2c_w(ov, 0x14, qvga?0x24:0x04); /* No special settings yet */ break; default: @@ -2505,19 +2472,17 @@ /******** Palette-specific regs ********/ if (mode == VIDEO_PALETTE_GREY) { - if (ov511->sensor == SEN_OV7610 - || ov511->sensor == SEN_OV7620AE) { + if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV7620AE) { /* these aren't valid on the OV6620/OV7620/6630? */ - ov51x_i2c_write_mask(ov511, 0x0e, 0x40, 0x40); + i2c_w_mask(ov, 0x0e, 0x40, 0x40); } - ov51x_i2c_write_mask(ov511, 0x13, 0x20, 0x20); + i2c_w_mask(ov, 0x13, 0x20, 0x20); } else { - if (ov511->sensor == SEN_OV7610 - || ov511->sensor == SEN_OV7620AE) { + if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV7620AE) { /* not valid on the OV6620/OV7620/6630? */ - ov51x_i2c_write_mask(ov511, 0x0e, 0x00, 0x40); + i2c_w_mask(ov, 0x0e, 0x00, 0x40); } - ov51x_i2c_write_mask(ov511, 0x13, 0x00, 0x20); + i2c_w_mask(ov, 0x13, 0x00, 0x20); } /******** Clock programming ********/ @@ -2526,13 +2491,13 @@ /* The OV6620 needs special handling. This prevents the * severe banding that normally occurs */ - if (ov511->sensor == SEN_OV6620 || ov511->sensor == SEN_OV6630) + if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) { /* Clock down */ - ov51x_i2c_write(ov511, 0x2a, 0x04); + i2c_w(ov, 0x2a, 0x04); - if (ov511->compress) { + if (ov->compress) { // clock = 0; /* This ensures the highest frame rate */ clock = 3; } else if (clockdiv == -1) { /* If user didn't override it */ @@ -2543,21 +2508,21 @@ PDEBUG(4, "Setting clock divisor to %d", clock); - ov51x_i2c_write(ov511, 0x11, clock); + i2c_w(ov, 0x11, clock); - ov51x_i2c_write(ov511, 0x2a, 0x84); + i2c_w(ov, 0x2a, 0x84); /* This next setting is critical. It seems to improve * the gain or the contrast. The "reserved" bits seem * to have some effect in this case. */ - ov51x_i2c_write(ov511, 0x2d, 0x85); + i2c_w(ov, 0x2d, 0x85); } else { - if (ov511->compress) { + if (ov->compress) { clock = 1; /* This ensures the highest frame rate */ } else if (clockdiv == -1) { /* If user didn't override it */ /* Calculate and set the clock divisor */ - clock = ((sub_flag ? ov511->subw * ov511->subh + clock = ((sub_flag ? ov->subw * ov->subh : width * height) * (mode == VIDEO_PALETTE_GREY ? 2 : 3) / 2) / 66000; @@ -2567,45 +2532,44 @@ PDEBUG(4, "Setting clock divisor to %d", clock); - ov51x_i2c_write(ov511, 0x11, clock); + i2c_w(ov, 0x11, clock); } /******** Special Features ********/ if (framedrop >= 0) - ov51x_i2c_write(ov511, 0x16, framedrop); + i2c_w(ov, 0x16, framedrop); /* We only have code to convert GBR -> RGB24 */ if ((mode == VIDEO_PALETTE_RGB24) && sensor_gbr) - ov51x_i2c_write_mask(ov511, 0x12, 0x08, 0x08); + i2c_w_mask(ov, 0x12, 0x08, 0x08); else - ov51x_i2c_write_mask(ov511, 0x12, 0x00, 0x08); + i2c_w_mask(ov, 0x12, 0x00, 0x08); /* Test Pattern */ - ov51x_i2c_write_mask(ov511, 0x12, (testpat?0x02:0x00), 0x02); + i2c_w_mask(ov, 0x12, (testpat?0x02:0x00), 0x02); /* Auto white balance */ // if (awb) - ov51x_i2c_write_mask(ov511, 0x12, 0x04, 0x04); + i2c_w_mask(ov, 0x12, 0x04, 0x04); // else -// ov51x_i2c_write_mask(ov511, 0x12, 0x00, 0x04); +// i2c_w_mask(ov, 0x12, 0x00, 0x04); - // This will go away as soon as ov511_mode_init_sensor_regs() + // This will go away as soon as ov51x_mode_init_sensor_regs() // is fully tested. /* 7620/6620/6630? don't have register 0x35, so play it safe */ - if (ov511->sensor == SEN_OV7610 || - ov511->sensor == SEN_OV7620AE) { + if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV7620AE) { if (width == 640 && height == 480) - ov51x_i2c_write(ov511, 0x35, 0x9e); + i2c_w(ov, 0x35, 0x9e); else - ov51x_i2c_write(ov511, 0x35, 0x1e); + i2c_w(ov, 0x35, 0x1e); } return 0; } static int -set_ov_sensor_window(struct usb_ov511 *ov511, int width, int height, int mode, +set_ov_sensor_window(struct usb_ov511 *ov, int width, int height, int mode, int sub_flag) { int ret; @@ -2614,7 +2578,7 @@ /* The different sensor ICs handle setting up of window differently. * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!!! */ - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV7620AE: hwsbase = 0x38; @@ -2638,9 +2602,9 @@ return -EINVAL; } - if (ov511->sensor == SEN_OV6620 || ov511->sensor == SEN_OV6630) { + if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) { if (width > 176 && height > 144) { /* CIF */ - ret = mode_init_ov_sensor_regs(ov511, width, height, + ret = mode_init_ov_sensor_regs(ov, width, height, mode, sub_flag, 0); if (ret < 0) return ret; @@ -2652,7 +2616,7 @@ err("Illegal dimensions"); return -EINVAL; } else { /* QCIF */ - ret = mode_init_ov_sensor_regs(ov511, width, height, + ret = mode_init_ov_sensor_regs(ov, width, height, mode, sub_flag, 1); if (ret < 0) return ret; @@ -2661,7 +2625,7 @@ } } else { if (width > 320 && height > 240) { /* VGA */ - ret = mode_init_ov_sensor_regs(ov511, width, height, + ret = mode_init_ov_sensor_regs(ov, width, height, mode, sub_flag, 0); if (ret < 0) return ret; @@ -2673,7 +2637,7 @@ err("Illegal dimensions"); return -EINVAL; } else { /* QVGA */ - ret = mode_init_ov_sensor_regs(ov511, width, height, + ret = mode_init_ov_sensor_regs(ov, width, height, mode, sub_flag, 1); if (ret < 0) return ret; @@ -2689,24 +2653,20 @@ /* FIXME! - This needs to be changed to support 160x120 and 6620!!! */ if (sub_flag) { - ov51x_i2c_write(ov511, 0x17, hwsbase+(ov511->subx>>hwscale)); - ov51x_i2c_write(ov511, 0x18, - hwebase+((ov511->subx+ov511->subw)>>hwscale)); - ov51x_i2c_write(ov511, 0x19, vwsbase+(ov511->suby>>vwscale)); - ov51x_i2c_write(ov511, 0x1a, - vwebase+((ov511->suby+ov511->subh)>>vwscale)); + i2c_w(ov, 0x17, hwsbase+(ov->subx>>hwscale)); + i2c_w(ov, 0x18, hwebase+((ov->subx+ov->subw)>>hwscale)); + i2c_w(ov, 0x19, vwsbase+(ov->suby>>vwscale)); + i2c_w(ov, 0x1a, vwebase+((ov->suby+ov->subh)>>vwscale)); } else { - ov51x_i2c_write(ov511, 0x17, hwsbase + hoffset); - ov51x_i2c_write(ov511, 0x18, - hwebase + hoffset + (hwsize>>hwscale)); - ov51x_i2c_write(ov511, 0x19, vwsbase + voffset); - ov51x_i2c_write(ov511, 0x1a, - vwebase + voffset + (vwsize>>vwscale)); + i2c_w(ov, 0x17, hwsbase + hoffset); + i2c_w(ov, 0x18, hwebase + hoffset + (hwsize>>hwscale)); + i2c_w(ov, 0x19, vwsbase + voffset); + i2c_w(ov, 0x1a, vwebase + voffset + (vwsize>>vwscale)); } #ifdef OV511_DEBUG if (dump_sensor) - ov51x_dump_i2c_regs(ov511); + dump_i2c_regs(ov); #endif return 0; @@ -2717,18 +2677,14 @@ * Do not put any sensor-specific code in here (including I2C I/O functions) */ static int -ov511_mode_init_regs(struct usb_ov511 *ov511, +ov511_mode_init_regs(struct usb_ov511 *ov, int width, int height, int mode, int sub_flag) { int lncnt, pxcnt, rc = 0; - struct usb_device *dev = ov511->dev; - - if (!ov511 || !dev) - return -EFAULT; if (sub_flag) { - width = ov511->subw; - height = ov511->subh; + width = ov->subw; + height = ov->subh; } PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d", @@ -2736,7 +2692,7 @@ // FIXME: This should be moved to a 7111a-specific function once // subcapture is dealt with properly - if (ov511->sensor == SEN_SAA7111A) { + if (ov->sensor == SEN_SAA7111A) { if (width == 320 && height == 240) { /* No need to do anything special */ } else if (width == 640 && height == 480) { @@ -2755,26 +2711,22 @@ return -EINVAL; } - if (width < ov511->minwidth || height < ov511->minheight) { + if (width < ov->minwidth || height < ov->minheight) { err("Requested dimensions are too small"); return -EINVAL; } - if (ov511_stop(ov511) < 0) + if (ov51x_stop(ov) < 0) return -EIO; if (mode == VIDEO_PALETTE_GREY) { - ov511_reg_write(dev, 0x16, 0x00); - - /* For snapshot */ - ov511_reg_write(dev, 0x1e, 0x00); - ov511_reg_write(dev, 0x1f, 0x01); + reg_w(ov, R511_CAM_UV_EN, 0x00); + reg_w(ov, R511_SNAP_UV_EN, 0x00); + reg_w(ov, R511_SNAP_OPTS, 0x01); } else { - ov511_reg_write(dev, 0x16, 0x01); - - /* For snapshot */ - ov511_reg_write(dev, 0x1e, 0x01); - ov511_reg_write(dev, 0x1f, 0x03); + reg_w(ov, R511_CAM_UV_EN, 0x01); + reg_w(ov, R511_SNAP_UV_EN, 0x01); + reg_w(ov, R511_SNAP_OPTS, 0x03); } /* Here I'm assuming that snapshot size == image size. @@ -2783,25 +2735,28 @@ pxcnt = (width >> 3) - 1; lncnt = (height >> 3) - 1; - ov511_reg_write(dev, 0x12, pxcnt); - ov511_reg_write(dev, 0x13, lncnt); - ov511_reg_write(dev, 0x14, 0x00); - ov511_reg_write(dev, 0x15, 0x00); - ov511_reg_write(dev, 0x18, 0x03); /* YUV420, low pass filer on */ + reg_w(ov, R511_CAM_PXCNT, pxcnt); + reg_w(ov, R511_CAM_LNCNT, lncnt); + reg_w(ov, R511_CAM_PXDIV, 0x00); + reg_w(ov, R511_CAM_LNDIV, 0x00); + + /* YUV420, low pass filer on */ + reg_w(ov, R511_CAM_OPTS, 0x03); /* Snapshot additions */ - ov511_reg_write(dev, 0x1a, pxcnt); - ov511_reg_write(dev, 0x1b, lncnt); - ov511_reg_write(dev, 0x1c, 0x00); - ov511_reg_write(dev, 0x1d, 0x00); - - if (ov511->compress) { - ov511_reg_write(dev, 0x78, 0x07); // Turn on Y & UV compression - ov511_reg_write(dev, 0x79, 0x03); // Enable LUTs - ov511_reset(ov511, OV511_RESET_OMNICE); + reg_w(ov, R511_SNAP_PXCNT, pxcnt); + reg_w(ov, R511_SNAP_LNCNT, lncnt); + reg_w(ov, R511_SNAP_PXDIV, 0x00); + reg_w(ov, R511_SNAP_LNDIV, 0x00); + + if (ov->compress) { + /* Enable Y and UV quantization and compression */ + reg_w(ov, R511_COMP_EN, 0x07); + reg_w(ov, R511_COMP_LUT_EN, 0x03); + ov51x_reset(ov, OV511_RESET_OMNICE); } //out: - if (ov511_restart(ov511) < 0) + if (ov51x_restart(ov) < 0) return -EIO; return rc; @@ -2825,17 +2780,15 @@ * Do not put any sensor-specific code in here (including I2C I/O functions) */ static int -ov518_mode_init_regs(struct usb_ov511 *ov511, +ov518_mode_init_regs(struct usb_ov511 *ov, int width, int height, int mode, int sub_flag) { int i; - struct usb_device *dev = ov511->dev; - unsigned char b[3]; /* Multiple-value reg buffer */ PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d", width, height, mode, sub_flag); - if (ov511_stop(ov511) < 0) + if (ov51x_stop(ov) < 0) return -EIO; for (i = 0; mlist518[i].width; i++) { @@ -2853,113 +2806,94 @@ // 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); +// reg_w(ov511, 0x12, pxcnt); +// reg_w(ov511, 0x13, lncnt); /******** Set the mode ********/ /* Mode independent regs */ - ov511_reg_write(dev, 0x2b, 0x00); - ov511_reg_write(dev, 0x2d, 0x00); - ov511_reg_write(dev, 0x3b, 0x00); - ov511_reg_write(dev, 0x3d, 0x00); + reg_w(ov, 0x2b, 0x00); + reg_w(ov, 0x2d, 0x00); + reg_w(ov, 0x3b, 0x00); + reg_w(ov, 0x3d, 0x00); /* Mode dependent regs. Regs 38 - 3e are always the same as * regs 28 - 2e */ - ov511_reg_write_mask(dev, 0x28, mlist518[i].reg28 + reg_w_mask(ov, 0x28, mlist518[i].reg28 | (mode == VIDEO_PALETTE_GREY) ? 0x80:0x00, 0x8f); - ov511_reg_write(dev, 0x29, mlist518[i].reg29); - ov511_reg_write(dev, 0x2a, mlist518[i].reg2a); - ov511_reg_write(dev, 0x2c, mlist518[i].reg2c); - ov511_reg_write(dev, 0x2e, mlist518[i].reg2e); - ov511_reg_write_mask(dev, 0x38, mlist518[i].reg28 + reg_w(ov, 0x29, mlist518[i].reg29); + reg_w(ov, 0x2a, mlist518[i].reg2a); + reg_w(ov, 0x2c, mlist518[i].reg2c); + reg_w(ov, 0x2e, mlist518[i].reg2e); + reg_w_mask(ov, 0x38, mlist518[i].reg28 | (mode == VIDEO_PALETTE_GREY) ? 0x80:0x00, 0x8f); - ov511_reg_write(dev, 0x39, mlist518[i].reg29); - ov511_reg_write(dev, 0x3a, mlist518[i].reg2a); - ov511_reg_write(dev, 0x3c, mlist518[i].reg2c); - ov511_reg_write(dev, 0x3e, mlist518[i].reg2e); - ov511_reg_write(dev, 0x24, mlist518[i].reg24); - ov511_reg_write(dev, 0x25, mlist518[i].reg25); + reg_w(ov, 0x39, mlist518[i].reg29); + reg_w(ov, 0x3a, mlist518[i].reg2a); + reg_w(ov, 0x3c, mlist518[i].reg2c); + reg_w(ov, 0x3e, mlist518[i].reg2e); + reg_w(ov, 0x24, mlist518[i].reg24); + reg_w(ov, 0x25, mlist518[i].reg25); /* Windows driver does this here; who knows why */ - ov511_reg_write(dev, 0x2f, 0x80); + reg_w(ov, 0x2f, 0x80); /******** Set the framerate (to 15 FPS) ********/ /* Mode independent, but framerate dependent, regs */ /* These are for 15 FPS only */ - ov511_reg_write(dev, 0x51, 0x08); - ov511_reg_write(dev, 0x22, 0x18); - ov511_reg_write(dev, 0x23, 0xff); - ov511_reg_write(dev, 0x71, 0x19); /* Compression-related? */ + reg_w(ov, 0x51, 0x08); + reg_w(ov, 0x22, 0x18); + reg_w(ov, 0x23, 0xff); + reg_w(ov, 0x71, 0x19); /* Compression-related? */ // FIXME: Sensor-specific /* Bit 5 is what matters here. Of course, it is "reserved" */ - ov51x_i2c_write(ov511, 0x54, 0x23); + i2c_w(ov, 0x54, 0x23); - ov511_reg_write(dev, 0x2f, 0x80); + reg_w(ov, 0x2f, 0x80); /* Mode dependent regs */ if ((width == 352 && height == 288) || (width == 320 && height == 240)) { - b[0]=0x80; b[1]=0x02; - ov518_reg_write_multi(dev, 0x30, b, 2); - b[0]=0x90; b[1]=0x01; - ov518_reg_write_multi(dev, 0xc4, b, 2); - b[0]=0xf4; b[1]=0x01; - ov518_reg_write_multi(dev, 0xc6, b, 2); - b[0]=0xf4; b[1]=0x01; - ov518_reg_write_multi(dev, 0xc7, b, 2); - b[0]=0x8e; b[1]=0x00; - ov518_reg_write_multi(dev, 0xc8, b, 2); - b[0]=0x1a; b[1]=0x00; b[2]=0x02; - ov518_reg_write_multi(dev, 0xca, b, 3); - b[0]=0x14; b[1]=0x02; - ov518_reg_write_multi(dev, 0xcb, b, 2); - b[0]=0xd0; b[1]=0x07; - ov518_reg_write_multi(dev, 0xcc, b, 2); - b[0]=0x20; b[1]=0x00; - ov518_reg_write_multi(dev, 0xcd, b, 2); - b[0]=0x60; b[1]=0x02; - ov518_reg_write_multi(dev, 0xce, b, 2); - + /* 640 (280h) byte iso packets */ + ov518_reg_w32(ov, 0x30, 640, 2); /* 280h */ + ov518_reg_w32(ov, 0xc4, 400, 2); /* 190h */ + ov518_reg_w32(ov, 0xc6, 500, 2); /* 1f4h */ + ov518_reg_w32(ov, 0xc7, 500, 2); /* 1f4h */ + ov518_reg_w32(ov, 0xc8, 142, 2); /* 8eh */ + ov518_reg_w32(ov, 0xca, 131098, 3); /* 2001ah */ + ov518_reg_w32(ov, 0xcb, 532, 2); /* 214h */ + ov518_reg_w32(ov, 0xcc, 2000, 2); /* 7d0h */ + ov518_reg_w32(ov, 0xcd, 32, 2); /* 20h */ + ov518_reg_w32(ov, 0xce, 608, 2); /* 260h */ } else if ((width == 176 && height == 144) || (width == 160 && height == 120)) { - b[0]=0x80; b[1]=0x01; - ov518_reg_write_multi(dev, 0x30, b, 2); - b[0]=0xc8; b[1]=0x00; - ov518_reg_write_multi(dev, 0xc4, b, 2); - b[0]=0x40; b[1]=0x01; - ov518_reg_write_multi(dev, 0xc6, b, 2); - b[0]=0x40; b[1]=0x01; - ov518_reg_write_multi(dev, 0xc7, b, 2); - b[0]=0x60; b[1]=0x00; - ov518_reg_write_multi(dev, 0xc8, b, 2); - b[0]=0x0f; b[1]=0x33; b[2]=0x01; - ov518_reg_write_multi(dev, 0xca, b, 3); - b[0]=0x40; b[1]=0x01; - ov518_reg_write_multi(dev, 0xcb, b, 2); - b[0]=0xec; b[1]=0x04; - ov518_reg_write_multi(dev, 0xcc, b, 2); - b[0]=0x13; b[1]=0x00; - ov518_reg_write_multi(dev, 0xcd, b, 2); - b[0]=0x6d; b[1]=0x01; - ov518_reg_write_multi(dev, 0xce, b, 2); + /* 384 (180h) byte iso packets */ + ov518_reg_w32(ov, 0x30, 384, 2); /* 180h */ + ov518_reg_w32(ov, 0xc4, 200, 2); /* c8h */ + ov518_reg_w32(ov, 0xc6, 320, 2); /* 140h */ + ov518_reg_w32(ov, 0xc7, 320, 2); /* 140h */ + ov518_reg_w32(ov, 0xc8, 96, 2); /* 60h */ + ov518_reg_w32(ov, 0xca, 78607, 3); /* 1330fh */ + ov518_reg_w32(ov, 0xcb, 320, 2); /* 140h */ + ov518_reg_w32(ov, 0xcc, 1260, 2); /* 4ech */ + ov518_reg_w32(ov, 0xcd, 19, 2); /* 13h */ + ov518_reg_w32(ov, 0xce, 365, 2); /* 16dh */ } else { /* Can't happen, since we already handled this case */ err("ov518_mode_init_regs(): **** logic error ****"); } - ov511_reg_write(dev, 0x2f, 0x80); + reg_w(ov, 0x2f, 0x80); break; } - if (ov511_restart(ov511) < 0) + if (ov51x_restart(ov) < 0) return -EIO; /* Reset it just for good measure */ - if (ov511_reset(ov511, OV511_RESET_NOREGS) < 0) + if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) return -EIO; if (mlist518[i].width == 0) { @@ -2972,29 +2906,31 @@ /* This is a wrapper around the OV511, OV518, and sensor specific functions */ static int -mode_init_regs(struct usb_ov511 *ov511, +mode_init_regs(struct usb_ov511 *ov, int width, int height, int mode, int sub_flag) { int rc = 0; - if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) { - rc = ov518_mode_init_regs(ov511, width, height, mode, sub_flag); + if (!ov || !ov->dev) + return -EFAULT; + + if (ov->bclass == BCL_OV518) { + rc = ov518_mode_init_regs(ov, width, height, mode, sub_flag); } else { - rc = ov511_mode_init_regs(ov511, width, height, mode, sub_flag); + rc = ov511_mode_init_regs(ov, width, height, mode, sub_flag); } if (FATAL_ERROR(rc)) return rc; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV7620: case SEN_OV7620AE: case SEN_OV8600: case SEN_OV6620: case SEN_OV6630: - rc = set_ov_sensor_window(ov511, width, height, mode, sub_flag); + rc = set_ov_sensor_window(ov, width, height, mode, sub_flag); break; case SEN_KS0127: case SEN_KS0127B: @@ -3002,10 +2938,10 @@ rc = -EINVAL; break; case SEN_SAA7111A: -// rc = mode_init_saa_sensor_regs(ov511, width, height, mode, +// rc = mode_init_saa_sensor_regs(ov, width, height, mode, // sub_flag); - PDEBUG(1, "SAA status = 0X%x", ov51x_i2c_read(ov511, 0x1f)); + PDEBUG(1, "SAA status = 0X%x", i2c_r(ov, 0x1f)); break; default: err("Unknown sensor"); @@ -3016,25 +2952,25 @@ return rc; /* Sensor-independent settings */ - rc = sensor_set_auto_brightness(ov511, ov511->auto_brt); + rc = sensor_set_auto_brightness(ov, ov->auto_brt); if (FATAL_ERROR(rc)) return rc; - rc = sensor_set_auto_exposure(ov511, ov511->auto_exp); + rc = sensor_set_auto_exposure(ov, ov->auto_exp); if (FATAL_ERROR(rc)) return rc; - rc = sensor_set_banding_filter(ov511, bandingfilter); + rc = sensor_set_banding_filter(ov, bandingfilter); if (FATAL_ERROR(rc)) return rc; - if (ov511->lightfreq) { - rc = sensor_set_light_freq(ov511, lightfreq); + if (ov->lightfreq) { + rc = sensor_set_light_freq(ov, lightfreq); if (FATAL_ERROR(rc)) return rc; } - rc = sensor_set_backlight(ov511, ov511->backlight); + rc = sensor_set_backlight(ov, ov->backlight); if (FATAL_ERROR(rc)) return rc; @@ -3045,28 +2981,28 @@ * useful for apps that use read() and do not set these. */ static int -ov51x_set_default_params(struct usb_ov511 *ov511) +ov51x_set_default_params(struct usb_ov511 *ov) { int i; - PDEBUG(3, "%dx%d, RGB24", ov511->maxwidth, ov511->maxheight); + PDEBUG(3, "%dx%d, RGB24", ov->maxwidth, ov->maxheight); /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used * (using read() instead). */ for (i = 0; i < OV511_NUMFRAMES; i++) { - ov511->frame[i].width = ov511->maxwidth; - ov511->frame[i].height = ov511->maxheight; - ov511->frame[i].bytes_read = 0; + ov->frame[i].width = ov->maxwidth; + ov->frame[i].height = ov->maxheight; + ov->frame[i].bytes_read = 0; if (force_palette) - ov511->frame[i].format = force_palette; + ov->frame[i].format = force_palette; else - ov511->frame[i].format = VIDEO_PALETTE_RGB24; - ov511->frame[i].depth = ov511_get_depth(ov511->frame[i].format); + ov->frame[i].format = VIDEO_PALETTE_RGB24; + ov->frame[i].depth = get_depth(ov->frame[i].format); } /* Initialize to max width/height, RGB24 */ - if (mode_init_regs(ov511, ov511->maxwidth, ov511->maxheight, - ov511->frame[0].format, 0) < 0) + if (mode_init_regs(ov, ov->maxwidth, ov->maxheight, + ov->frame[0].format, 0) < 0) return -EINVAL; return 0; @@ -3080,18 +3016,17 @@ /* Set analog input port of decoder */ static int -decoder_set_input(struct usb_ov511 *ov511, int input) +decoder_set_input(struct usb_ov511 *ov, int input) { PDEBUG(4, "port %d", input); - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_SAA7111A: { /* Select mode */ - ov51x_i2c_write_mask(ov511, 0x02, input, 0x07); + i2c_w_mask(ov, 0x02, input, 0x07); /* Bypass chrominance trap for modes 4..7 */ - ov51x_i2c_write_mask(ov511, 0x09, - (input > 3) ? 0x80:0x00, 0x80); + i2c_w_mask(ov, 0x09, (input > 3) ? 0x80:0x00, 0x80); break; } default: @@ -3103,9 +3038,9 @@ /* Get ASCII name of video input */ static int -decoder_get_input_name(struct usb_ov511 *ov511, int input, char *name) +decoder_get_input_name(struct usb_ov511 *ov, int input, char *name) { - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_SAA7111A: { if (input < 0 || input > 7) @@ -3126,11 +3061,11 @@ /* Set norm (NTSC, PAL, SECAM, AUTO) */ static int -decoder_set_norm(struct usb_ov511 *ov511, int norm) +decoder_set_norm(struct usb_ov511 *ov, int norm) { PDEBUG(4, "%d", norm); - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_SAA7111A: { int reg_8, reg_e; @@ -3151,8 +3086,8 @@ return -EINVAL; } - ov51x_i2c_write_mask(ov511, 0x08, reg_8, 0xc0); - ov51x_i2c_write_mask(ov511, 0x0e, reg_e, 0x70); + i2c_w_mask(ov, 0x08, reg_8, 0xc0); + i2c_w_mask(ov, 0x0e, reg_e, 0x70); break; } default: @@ -3199,8 +3134,8 @@ #define LIMIT(x) ((x)>0xffffff?0xff: ((x)<=0xffff?0:((x)>>16))) static inline void -ov511_move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v, - int rowPixels, unsigned char * rgb, int bits) +move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v, + int rowPixels, unsigned char * rgb, int bits) { const int rvScale = 91881; const int guScale = -22553; @@ -3270,10 +3205,10 @@ **********************************************************************/ /* Copies a 64-byte segment at pIn to an 8x8 block at pOut. The width of the - * array at pOut is specified by w. + * image at pOut is specified by w. */ static inline void -ov511_make_8x8(unsigned char *pIn, unsigned char *pOut, int w) +make_8x8(unsigned char *pIn, unsigned char *pOut, int w) { unsigned char *pOut1 = pOut; int x, y; @@ -3311,7 +3246,7 @@ for (y = 0; y < frame->rawheight - 1; y += 8) { pOut = pOutLine; for (x = 0; x < frame->rawwidth - 1; x += 8) { - ov511_make_8x8(pIn, pOut, frame->rawwidth); + make_8x8(pIn, pOut, frame->rawwidth); pIn += 64; pOut += 8; } @@ -3370,8 +3305,8 @@ for (y = 0; y < frame->rawheight - 1; y += 16) { pOut = pOutLine; for (x = 0; x < frame->rawwidth - 1; x += 16) { - ov511_make_8x8(pIn, pOut, w); - ov511_make_8x8(pIn + 64, pOut + a/4, w); + make_8x8(pIn, pOut, w); + make_8x8(pIn + 64, pOut + a/4, w); pIn += 384; pOut += 8; } @@ -3385,7 +3320,7 @@ for (y = 0; y < frame->rawheight - 1; y += 8) { pOut = pOutLine; for (x = 0; x < frame->rawwidth - 1; x += 8) { - ov511_make_8x8(pIn, pOut, frame->rawwidth); + make_8x8(pIn, pOut, frame->rawwidth); pIn += 64; pOut += 8; if ((++k) > 3) { @@ -3442,17 +3377,17 @@ * **********************************************************************/ -/* Chooses a decompression module, locks it, and sets ov511->decomp_ops +/* Chooses a decompression module, locks it, and sets ov->decomp_ops * accordingly. Returns -ENXIO if decompressor is not available, otherwise * returns 0 if no other error. */ static int -ov51x_request_decompressor(struct usb_ov511 *ov511) +request_decompressor(struct usb_ov511 *ov) { - if (!ov511) + if (!ov) return -ENODEV; - if (ov511->decomp_ops) { + if (ov->decomp_ops) { err("ERROR: Decompressor already requested!"); return -EINVAL; } @@ -3460,24 +3395,23 @@ lock_kernel(); /* Try to get MMX, and fall back on no-MMX if necessary */ - if (ov511->bridge == BRG_OV511 || ov511->bridge == BRG_OV511PLUS) { + if (ov->bclass == BCL_OV511) { if (ov511_mmx_decomp_ops) { PDEBUG(3, "Using OV511 MMX decompressor"); - ov511->decomp_ops = ov511_mmx_decomp_ops; + ov->decomp_ops = ov511_mmx_decomp_ops; } else if (ov511_decomp_ops) { PDEBUG(3, "Using OV511 decompressor"); - ov511->decomp_ops = ov511_decomp_ops; + ov->decomp_ops = ov511_decomp_ops; } else { err("No decompressor available"); } - } else if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) { + } else if (ov->bclass == BCL_OV518) { if (ov518_mmx_decomp_ops) { PDEBUG(3, "Using OV518 MMX decompressor"); - ov511->decomp_ops = ov518_mmx_decomp_ops; + ov->decomp_ops = ov518_mmx_decomp_ops; } else if (ov518_decomp_ops) { PDEBUG(3, "Using OV518 decompressor"); - ov511->decomp_ops = ov518_decomp_ops; + ov->decomp_ops = ov518_decomp_ops; } else { err("No decompressor available"); } @@ -3485,13 +3419,13 @@ err("Unknown bridge"); } - if (ov511->decomp_ops) { - if (!ov511->decomp_ops->decomp_lock) { - ov511->decomp_ops = NULL; + if (ov->decomp_ops) { + if (!ov->decomp_ops->decomp_lock) { + ov->decomp_ops = NULL; unlock_kernel(); return -ENOSYS; } - ov511->decomp_ops->decomp_lock(); + ov->decomp_ops->decomp_lock(); unlock_kernel(); return 0; } else { @@ -3500,25 +3434,25 @@ } } -/* Unlocks decompression module and nulls ov511->decomp_ops. Safe to call even - * if ov511->decomp_ops is NULL. +/* Unlocks decompression module and nulls ov->decomp_ops. Safe to call even + * if ov->decomp_ops is NULL. */ static void -ov51x_release_decompressor(struct usb_ov511 *ov511) +release_decompressor(struct usb_ov511 *ov) { int released = 0; /* Did we actually do anything? */ - if (!ov511) + if (!ov) return; lock_kernel(); - if (ov511->decomp_ops && ov511->decomp_ops->decomp_unlock) { - ov511->decomp_ops->decomp_unlock(); + if (ov->decomp_ops && ov->decomp_ops->decomp_unlock) { + ov->decomp_ops->decomp_unlock(); released = 1; } - ov511->decomp_ops = NULL; + ov->decomp_ops = NULL; unlock_kernel(); @@ -3527,26 +3461,26 @@ } static void -ov51x_decompress(struct usb_ov511 *ov511, struct ov511_frame *frame, - unsigned char *pIn0, unsigned char *pOut0) +decompress(struct usb_ov511 *ov, struct ov511_frame *frame, + unsigned char *pIn0, unsigned char *pOut0) { - if (!ov511->decomp_ops) - if (ov51x_request_decompressor(ov511)) + if (!ov->decomp_ops) + if (request_decompressor(ov)) return; PDEBUG(4, "Decompressing %d bytes", frame->bytes_recvd); if (frame->format == VIDEO_PALETTE_GREY - && ov511->decomp_ops->decomp_400) { - int ret = ov511->decomp_ops->decomp_400( + && ov->decomp_ops->decomp_400) { + int ret = ov->decomp_ops->decomp_400( pIn0, pOut0, frame->rawwidth, frame->rawheight, frame->bytes_recvd); PDEBUG(4, "DEBUG: decomp_400 returned %d", ret); - } else if (ov511->decomp_ops->decomp_420) { - int ret = ov511->decomp_ops->decomp_420( + } else if (ov->decomp_ops->decomp_420) { + int ret = ov->decomp_ops->decomp_420( pIn0, pOut0, frame->rawwidth, @@ -3586,8 +3520,8 @@ u = (*pU++) - 128; v = (*pV++) - 128; - ov511_move_420_block(y00, y01, y10, y11, u, v, - frame->width, pOut, bits); + move_420_block(y00, y01, y10, y11, u, v, + frame->width, pOut, bits); pY += 2; pOut += 2 * bytes; @@ -3742,11 +3676,11 @@ * 4. Fix the RGB offset, if necessary */ static void -ov511_postprocess(struct usb_ov511 *ov511, struct ov511_frame *frame) +ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame) { if (dumppix) { memset(frame->data, 0, - MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight)); + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)); PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd); memmove(frame->data, frame->rawdata, frame->bytes_recvd); return; @@ -3755,9 +3689,9 @@ /* YUV400 must be handled separately */ if (frame->format == VIDEO_PALETTE_GREY) { /* Deinterlace frame, if necessary */ - if (ov511->sensor == SEN_SAA7111A && frame->rawheight == 480) { + if (ov->sensor == SEN_SAA7111A && frame->rawheight == 480) { if (frame->compressed) - ov51x_decompress(ov511, frame, frame->rawdata, + decompress(ov, frame, frame->rawdata, frame->tempdata); else yuv400raw_to_yuv400p(frame, frame->rawdata, @@ -3767,7 +3701,7 @@ frame->data); } else { if (frame->compressed) - ov51x_decompress(ov511, frame, frame->rawdata, + decompress(ov, frame, frame->rawdata, frame->data); else yuv400raw_to_yuv400p(frame, frame->rawdata, @@ -3779,12 +3713,12 @@ /* Process frame->data to frame->rawdata */ if (frame->compressed) - ov51x_decompress(ov511, frame, frame->rawdata, frame->tempdata); + decompress(ov, frame, frame->rawdata, frame->tempdata); else yuv420raw_to_yuv420p(frame, frame->rawdata, frame->tempdata); /* Deinterlace frame, if necessary */ - if (ov511->sensor == SEN_SAA7111A && frame->rawheight == 480) { + if (ov->sensor == SEN_SAA7111A && frame->rawheight == 480) { memmove(frame->rawdata, frame->tempdata, MAX_RAW_DATA_SIZE(frame->width, frame->height)); deinterlace(frame, RAWFMT_YUV420, frame->rawdata, @@ -3838,7 +3772,7 @@ **********************************************************************/ static int -ov511_move_data(struct usb_ov511 *ov511, struct urb *urb) +ov511_move_data(struct usb_ov511 *ov, struct urb *urb) { unsigned char *cdata; int data_size, num, offset, i, totlen = 0; @@ -3848,7 +3782,7 @@ PDEBUG(5, "Moving %d packets", urb->number_of_packets); - data_size = ov511->packet_size - 1; + data_size = ov->packet_size - 1; for (i = 0; i < urb->number_of_packets; i++) { int n = urb->iso_frame_desc[i].actual_length; @@ -3859,15 +3793,15 @@ cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - aPackNum[i] = n ? cdata[ov511->packet_size - 1] : -1; + aPackNum[i] = n ? cdata[ov->packet_size - 1] : -1; - if (!n || ov511->curframe == -1) + if (!n || ov->curframe == -1) continue; if (st) PDEBUG(2, "data error: [%d] len=%d, status=%d", i, n, st); - frame = &ov511->frame[ov511->curframe]; + frame = &ov->frame[ov->curframe]; /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th * byte non-zero. The EOF packet has image width/height in the @@ -3885,7 +3819,7 @@ if (printph) { info("packet header (%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x", - cdata[ov511->packet_size - 1], + cdata[ov->packet_size - 1], cdata[0], cdata[1], cdata[2], cdata[3], cdata[4], cdata[5], cdata[6], cdata[7], cdata[8], cdata[9], cdata[10], cdata[11]); } @@ -3899,7 +3833,7 @@ /* Frame end */ if (cdata[8] & 0x80) { ts = (struct timeval *)(frame->data - + MAX_FRAME_SIZE(ov511->maxwidth, ov511->maxheight)); + + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight)); do_gettimeofday(ts); /* Get the actual frame size from the EOF header */ @@ -3907,21 +3841,21 @@ frame->rawheight = ((int)(cdata[10]) + 1) * 8; PDEBUG(4, "Frame end, curframe = %d, packnum=%d, hw=%d, vw=%d, recvd=%d", - ov511->curframe, - (int)(cdata[ov511->packet_size - 1]), + ov->curframe, + (int)(cdata[ov->packet_size - 1]), frame->rawwidth, frame->rawheight, frame->bytes_recvd); /* Validate the header data */ - RESTRICT_TO_RANGE(frame->rawwidth, ov511->minwidth, ov511->maxwidth); - RESTRICT_TO_RANGE(frame->rawheight, ov511->minheight, ov511->maxheight); + RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth); + RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight); /* Don't allow byte count to exceed buffer size */ RESTRICT_TO_RANGE(frame->bytes_recvd, 8, - MAX_RAW_DATA_SIZE(ov511->maxwidth, - ov511->maxheight)); + MAX_RAW_DATA_SIZE(ov->maxwidth, + ov->maxheight)); if (frame->scanstate == STATE_LINES) { int iFrameNext; @@ -3935,20 +3869,20 @@ /* If next frame is ready or grabbing, * point to it */ - iFrameNext = (ov511->curframe + 1) % OV511_NUMFRAMES; - if (ov511->frame[iFrameNext].grabstate == FRAME_READY - || ov511->frame[iFrameNext].grabstate == FRAME_GRABBING) { - ov511->curframe = iFrameNext; - ov511->frame[iFrameNext].scanstate = STATE_SCANNING; + iFrameNext = (ov->curframe + 1) % OV511_NUMFRAMES; + if (ov->frame[iFrameNext].grabstate == FRAME_READY + || ov->frame[iFrameNext].grabstate == FRAME_GRABBING) { + ov->curframe = iFrameNext; + ov->frame[iFrameNext].scanstate = STATE_SCANNING; } else { if (frame->grabstate == FRAME_DONE) { PDEBUG(4, "Frame done! congratulations"); } else { PDEBUG(4, "Frame not ready? state = %d", - ov511->frame[iFrameNext].grabstate); + ov->frame[iFrameNext].grabstate); } - ov511->curframe = -1; + ov->curframe = -1; } } else { PDEBUG(5, "Frame done, but not scanning"); @@ -3958,7 +3892,7 @@ */ } else { /* Frame start */ - PDEBUG(4, "Frame start, framenum = %d", ov511->curframe); + PDEBUG(4, "Frame start, framenum = %d", ov->curframe); /* Check to see if it's a snapshot frame */ /* FIXME?? Should the snapshot reset go here? Performance? */ @@ -4007,24 +3941,24 @@ /* Dump all data exactly as received */ if (dumppix == 2) { frame->bytes_recvd += n - 1; - if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight)) + if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)) memmove(frame->rawdata + frame->bytes_recvd - (n - 1), &cdata[0], n - 1); else PDEBUG(3, "Raw data buffer overrun!! (%d)", frame->bytes_recvd - - MAX_RAW_DATA_SIZE(ov511->maxwidth, - ov511->maxheight)); + - MAX_RAW_DATA_SIZE(ov->maxwidth, + ov->maxheight)); } else if (!frame->compressed && !remove_zeros) { frame->bytes_recvd += num; - if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight)) + if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)) memmove(frame->rawdata + frame->bytes_recvd - num, &cdata[offset], num); else PDEBUG(3, "Raw data buffer overrun!! (%d)", frame->bytes_recvd - - MAX_RAW_DATA_SIZE(ov511->maxwidth, - ov511->maxheight)); + - MAX_RAW_DATA_SIZE(ov->maxwidth, + ov->maxheight)); } else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */ int b, in = 0, allzero, copied=0; if (offset) { @@ -4047,7 +3981,7 @@ /* Don't copy it */ } else { if (frame->bytes_recvd + copied + 32 - <= MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight)) { + <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)) { memmove(frame->rawdata + frame->bytes_recvd + copied, &cdata[in], 32); copied += 32; @@ -4071,7 +4005,7 @@ } static int -ov518_move_data(struct usb_ov511 *ov511, struct urb *urb) +ov518_move_data(struct usb_ov511 *ov, struct urb *urb) { unsigned char *cdata; int i, data_size, totlen = 0; @@ -4081,7 +4015,7 @@ PDEBUG(5, "Moving %d packets", urb->number_of_packets); /* OV518(+) has no packet numbering */ - data_size = ov511->packet_size; + data_size = ov->packet_size; for (i = 0; i < urb->number_of_packets; i++) { int n = urb->iso_frame_desc[i].actual_length; @@ -4097,7 +4031,7 @@ continue; } - if (ov511->curframe == -1) { + if (ov->curframe == -1) { PDEBUG(4, "No frame currently active"); continue; } @@ -4105,21 +4039,7 @@ if (st) PDEBUG(2, "data error: [%d] len=%d, status=%d", i, n, st); - frame = &ov511->frame[ov511->curframe]; - -#if 0 - { - int d; - /* Print all data */ - for (d = 0; d <= data_size - 16; d += 16) { - info("%4x: %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x", d, - cdata[d], cdata[d+1], cdata[d+2], cdata[d+3], - cdata[d+4], cdata[d+5], cdata[d+6], cdata[d+7], - cdata[d+8], cdata[d+9], cdata[d+10], cdata[d+11], - cdata[d+12], cdata[d+13], cdata[d+14], cdata[d+15]); - } - } -#endif + frame = &ov->frame[ov->curframe]; if (printph) { info("packet header: %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x", @@ -4137,7 +4057,7 @@ goto eof; } else { //scanstate == STATE_SCANNING /* Frame start */ - PDEBUG(4, "Frame start, framenum = %d", ov511->curframe); + PDEBUG(4, "Frame start, framenum = %d", ov->curframe); goto sof; } } else { @@ -4146,11 +4066,11 @@ eof: ts = (struct timeval *)(frame->data - + MAX_FRAME_SIZE(ov511->maxwidth, ov511->maxheight)); + + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight)); do_gettimeofday(ts); PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d", - ov511->curframe, + ov->curframe, (int)(cdata[9]), (int)(cdata[10]), frame->bytes_recvd); // FIXME: Since we don't know the header formats yet, @@ -4159,13 +4079,13 @@ frame->rawheight = frame->height; /* Validate the header data */ - RESTRICT_TO_RANGE(frame->rawwidth, ov511->minwidth, ov511->maxwidth); - RESTRICT_TO_RANGE(frame->rawheight, ov511->minheight, ov511->maxheight); + RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth); + RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight); /* Don't allow byte count to exceed buffer size */ RESTRICT_TO_RANGE(frame->bytes_recvd, 8, - MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight)); + MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)); if (frame->scanstate == STATE_LINES) { int iFrameNext; @@ -4179,21 +4099,21 @@ /* If next frame is ready or grabbing, * point to it */ - iFrameNext = (ov511->curframe + 1) % OV511_NUMFRAMES; - if (ov511->frame[iFrameNext].grabstate == FRAME_READY - || ov511->frame[iFrameNext].grabstate == FRAME_GRABBING) { - ov511->curframe = iFrameNext; - ov511->frame[iFrameNext].scanstate = STATE_SCANNING; - frame = &ov511->frame[iFrameNext]; + iFrameNext = (ov->curframe + 1) % OV511_NUMFRAMES; + if (ov->frame[iFrameNext].grabstate == FRAME_READY + || ov->frame[iFrameNext].grabstate == FRAME_GRABBING) { + ov->curframe = iFrameNext; + ov->frame[iFrameNext].scanstate = STATE_SCANNING; + frame = &ov->frame[iFrameNext]; } else { if (frame->grabstate == FRAME_DONE) { PDEBUG(4, "Frame done! congratulations"); } else { PDEBUG(4, "Frame not ready? state = %d", - ov511->frame[iFrameNext].grabstate); + ov->frame[iFrameNext].grabstate); } - ov511->curframe = -1; + ov->curframe = -1; PDEBUG(4, "SOF dropped (no active frame)"); continue; /* Nowhere to store this frame */ } @@ -4226,31 +4146,26 @@ /* Dump all data exactly as received */ if (dumppix == 2) { frame->bytes_recvd += n; - if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight)) + if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)) memmove(frame->rawdata + frame->bytes_recvd - n, &cdata[0], n); else PDEBUG(3, "Raw data buffer overrun!! (%d)", frame->bytes_recvd - - MAX_RAW_DATA_SIZE(ov511->maxwidth, - ov511->maxheight)); + - MAX_RAW_DATA_SIZE(ov->maxwidth, + ov->maxheight)); } else { /* All incoming data are divided into 8-byte segments. If the * segment contains all zero bytes, it must be skipped. These * zero-segments allow the OV518 to mainain a constant data rate * regardless of the effectiveness of the compression. Segments * are aligned relative to the beginning of each isochronous - * packet. The first segment is a header. + * packet. The first segment is a header (the decompressor + * skips it later). */ int b, in = 0, allzero, copied=0; -// Decompressor expects the header -#if 0 - if (frame->bytes_recvd == 0) - in += 8; /* Skip header */ -#endif - while (in < n) { allzero = 1; for (b = 0; b < 8; b++) { @@ -4264,7 +4179,7 @@ /* Don't copy it */ } else { if (frame->bytes_recvd + copied + 8 - <= MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight)) { + <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)) { memmove(frame->rawdata + frame->bytes_recvd + copied, &cdata[in], 8); copied += 8; @@ -4282,43 +4197,41 @@ } static void -ov511_isoc_irq(struct urb *urb) +ov51x_isoc_irq(struct urb *urb) { int len; - struct usb_ov511 *ov511; + struct usb_ov511 *ov; if (!urb->context) { PDEBUG(4, "no context"); return; } - ov511 = (struct usb_ov511 *) urb->context; + ov = (struct usb_ov511 *) urb->context; - if (!ov511->dev || !ov511->user) { + if (!ov || !ov->dev || !ov->user) { PDEBUG(4, "no device, or not open"); return; } - if (!ov511->streaming) { + if (!ov->streaming) { PDEBUG(4, "hmmm... not streaming, but got interrupt"); return; } /* Copy the data received into our frame buffer */ - if (ov511->curframe >= 0) { - if (ov511->bridge == BRG_OV511 || - ov511->bridge == BRG_OV511PLUS) - len = ov511_move_data(ov511, urb); - else if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) - len = ov518_move_data(ov511, urb); + if (ov->curframe >= 0) { + if (ov->bclass == BCL_OV511) + len = ov511_move_data(ov, urb); + else if (ov->bclass == BCL_OV518) + len = ov518_move_data(ov, urb); else - err("Unknown bridge device (%d)", ov511->bridge); - } else if (waitqueue_active(&ov511->wq)) { - wake_up_interruptible(&ov511->wq); + err("Unknown bridge device (%d)", ov->bridge); + } else if (waitqueue_active(&ov->wq)) { + wake_up_interruptible(&ov->wq); } - urb->dev = ov511->dev; + urb->dev = ov->dev; return; } @@ -4330,16 +4243,16 @@ ***************************************************************************/ static int -ov511_init_isoc(struct usb_ov511 *ov511) +ov51x_init_isoc(struct usb_ov511 *ov) { struct urb *urb; int fx, err, n, size; PDEBUG(3, "*** Initializing capture ***"); - ov511->curframe = -1; + ov->curframe = -1; - if (ov511->bridge == BRG_OV511) { + if (ov->bridge == BRG_OV511) { if (cams == 1) size = 993; else if (cams == 2) size = 513; else if (cams == 3 || cams == 4) size = 257; @@ -4347,7 +4260,7 @@ err("\"cams\" parameter too high!"); return -1; } - } else if (ov511->bridge == BRG_OV511PLUS) { + } else if (ov->bridge == BRG_OV511PLUS) { if (cams == 1) size = 961; else if (cams == 2) size = 513; else if (cams == 3 || cams == 4) size = 257; @@ -4357,8 +4270,7 @@ err("\"cams\" parameter too high!"); return -1; } - } else if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) { + } else if (ov->bclass == BCL_OV518) { if (cams == 1) size = 896; else if (cams == 2) size = 512; else if (cams == 3 || cams == 4) size = 256; @@ -4374,14 +4286,13 @@ if (packetsize == -1) { // FIXME: OV518 is hardcoded to 15 FPS (alternate 5) for now - if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) - ov511_set_packet_size(ov511, 640); + if (ov->bclass == BCL_OV518) + ov51x_set_packet_size(ov, 640); else - ov511_set_packet_size(ov511, size); + ov51x_set_packet_size(ov, size); } else { info("Forcing packet size to %d", packetsize); - ov511_set_packet_size(ov511, packetsize); + ov51x_set_packet_size(ov, packetsize); } for (n = 0; n < OV511_NUMSBUF; n++) { @@ -4391,32 +4302,30 @@ err("init isoc: usb_alloc_urb ret. NULL"); return -ENOMEM; } - ov511->sbuf[n].urb = urb; - urb->dev = ov511->dev; - urb->context = ov511; - urb->pipe = usb_rcvisocpipe(ov511->dev, OV511_ENDPOINT_ADDRESS); + ov->sbuf[n].urb = urb; + urb->dev = ov->dev; + urb->context = ov; + urb->pipe = usb_rcvisocpipe(ov->dev, OV511_ENDPOINT_ADDRESS); urb->transfer_flags = USB_ISO_ASAP; - urb->transfer_buffer = ov511->sbuf[n].data; - urb->complete = ov511_isoc_irq; + urb->transfer_buffer = ov->sbuf[n].data; + urb->complete = ov51x_isoc_irq; urb->number_of_packets = FRAMES_PER_DESC; - urb->transfer_buffer_length = - ov511->packet_size * FRAMES_PER_DESC; + urb->transfer_buffer_length = ov->packet_size * FRAMES_PER_DESC; for (fx = 0; fx < FRAMES_PER_DESC; fx++) { - urb->iso_frame_desc[fx].offset = - ov511->packet_size * fx; - urb->iso_frame_desc[fx].length = ov511->packet_size; + urb->iso_frame_desc[fx].offset = ov->packet_size * fx; + urb->iso_frame_desc[fx].length = ov->packet_size; } } - ov511->streaming = 1; + ov->streaming = 1; - ov511->sbuf[OV511_NUMSBUF - 1].urb->next = ov511->sbuf[0].urb; + ov->sbuf[OV511_NUMSBUF - 1].urb->next = ov->sbuf[0].urb; for (n = 0; n < OV511_NUMSBUF - 1; n++) - ov511->sbuf[n].urb->next = ov511->sbuf[n+1].urb; + ov->sbuf[n].urb->next = ov->sbuf[n+1].urb; for (n = 0; n < OV511_NUMSBUF; n++) { - ov511->sbuf[n].urb->dev = ov511->dev; - err = usb_submit_urb(ov511->sbuf[n].urb, GFP_KERNEL); + ov->sbuf[n].urb->dev = ov->dev; + err = usb_submit_urb(ov->sbuf[n].urb, GFP_KERNEL); if (err) err("init isoc: usb_submit_urb(%d) ret %d", n, err); } @@ -4425,51 +4334,51 @@ } static void -ov511_stop_isoc(struct usb_ov511 *ov511) +ov51x_stop_isoc(struct usb_ov511 *ov) { int n; - if (!ov511->streaming || !ov511->dev) + if (!ov->streaming || !ov->dev) return; PDEBUG(3, "*** Stopping capture ***"); - ov511_set_packet_size(ov511, 0); + ov51x_set_packet_size(ov, 0); - ov511->streaming = 0; + ov->streaming = 0; /* Unschedule all of the iso td's */ for (n = OV511_NUMSBUF - 1; n >= 0; n--) { - if (ov511->sbuf[n].urb) { - ov511->sbuf[n].urb->next = NULL; - usb_unlink_urb(ov511->sbuf[n].urb); - usb_free_urb(ov511->sbuf[n].urb); - ov511->sbuf[n].urb = NULL; + if (ov->sbuf[n].urb) { + ov->sbuf[n].urb->next = NULL; + usb_unlink_urb(ov->sbuf[n].urb); + usb_free_urb(ov->sbuf[n].urb); + ov->sbuf[n].urb = NULL; } } } static int -ov511_new_frame(struct usb_ov511 *ov511, int framenum) +ov51x_new_frame(struct usb_ov511 *ov, int framenum) { struct ov511_frame *frame; int newnum; - PDEBUG(4, "ov511->curframe = %d, framenum = %d", ov511->curframe, - framenum); - if (!ov511->dev) + PDEBUG(4, "ov->curframe = %d, framenum = %d", ov->curframe, framenum); + + if (!ov->dev) return -1; /* If we're not grabbing a frame right now and the other frame is */ /* ready to be grabbed into, then use it instead */ - if (ov511->curframe == -1) { + if (ov->curframe == -1) { newnum = (framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES; - if (ov511->frame[newnum].grabstate == FRAME_READY) + if (ov->frame[newnum].grabstate == FRAME_READY) framenum = newnum; } else return 0; - frame = &ov511->frame[framenum]; + frame = &ov->frame[framenum]; PDEBUG(4, "framenum = %d, width = %d, height = %d", framenum, frame->width, frame->height); @@ -4478,16 +4387,16 @@ frame->scanstate = STATE_SCANNING; frame->snapshot = 0; - ov511->curframe = framenum; + ov->curframe = framenum; /* Make sure it's not too big */ - if (frame->width > ov511->maxwidth) - frame->width = ov511->maxwidth; + if (frame->width > ov->maxwidth) + frame->width = ov->maxwidth; frame->width &= ~7L; /* Multiple of 8 */ - if (frame->height > ov511->maxheight) - frame->height = ov511->maxheight; + if (frame->height > ov->maxheight) + frame->height = ov->maxheight; frame->height &= ~3L; /* Multiple of 4 */ @@ -4499,84 +4408,86 @@ * Buffer management * ***************************************************************************/ + static int -ov511_alloc(struct usb_ov511 *ov511) +ov51x_alloc(struct usb_ov511 *ov) { int i; - int w = ov511->maxwidth; - int h = ov511->maxheight; + const int w = ov->maxwidth; + const int h = ov->maxheight; + const int data_bufsize = OV511_NUMFRAMES * MAX_DATA_SIZE(w, h); + const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h); PDEBUG(4, "entered"); - down(&ov511->buf_lock); + down(&ov->buf_lock); - if (ov511->buf_state == BUF_PEND_DEALLOC) { - ov511->buf_state = BUF_ALLOCATED; - del_timer(&ov511->buf_timer); + if (ov->buf_state == BUF_PEND_DEALLOC) { + ov->buf_state = BUF_ALLOCATED; + del_timer(&ov->buf_timer); } - if (ov511->buf_state == BUF_ALLOCATED) + if (ov->buf_state == BUF_ALLOCATED) goto out; - ov511->fbuf = rvmalloc(OV511_NUMFRAMES * MAX_DATA_SIZE(w, h)); - if (!ov511->fbuf) + ov->fbuf = rvmalloc(data_bufsize); + if (!ov->fbuf) goto error; - ov511->rawfbuf = vmalloc(OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h)); - if (!ov511->rawfbuf) { - rvfree(ov511->fbuf, OV511_NUMFRAMES * MAX_DATA_SIZE(w, h)); - ov511->fbuf = NULL; + ov->rawfbuf = vmalloc(raw_bufsize); + if (!ov->rawfbuf) { + rvfree(ov->fbuf, data_bufsize); + ov->fbuf = NULL; goto error; } - memset(ov511->rawfbuf, 0, OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h)); + memset(ov->rawfbuf, 0, raw_bufsize); - ov511->tempfbuf = vmalloc(OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h)); - if (!ov511->tempfbuf) { - vfree(ov511->rawfbuf); - ov511->rawfbuf = NULL; - rvfree(ov511->fbuf, OV511_NUMFRAMES * MAX_DATA_SIZE(w, h)); - ov511->fbuf = NULL; + ov->tempfbuf = vmalloc(raw_bufsize); + if (!ov->tempfbuf) { + vfree(ov->rawfbuf); + ov->rawfbuf = NULL; + rvfree(ov->fbuf, data_bufsize); + ov->fbuf = NULL; goto error; } - memset(ov511->tempfbuf, 0, OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h)); + memset(ov->tempfbuf, 0, raw_bufsize); for (i = 0; i < OV511_NUMSBUF; i++) { - ov511->sbuf[i].data = kmalloc(FRAMES_PER_DESC * + ov->sbuf[i].data = kmalloc(FRAMES_PER_DESC * MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL); - if (!ov511->sbuf[i].data) { + if (!ov->sbuf[i].data) { while (--i) { - kfree(ov511->sbuf[i].data); - ov511->sbuf[i].data = NULL; + kfree(ov->sbuf[i].data); + ov->sbuf[i].data = NULL; } - vfree(ov511->tempfbuf); - ov511->tempfbuf = NULL; - vfree(ov511->rawfbuf); - ov511->rawfbuf = NULL; - rvfree(ov511->fbuf, - OV511_NUMFRAMES * MAX_DATA_SIZE(w, h)); - ov511->fbuf = NULL; + vfree(ov->tempfbuf); + ov->tempfbuf = NULL; + vfree(ov->rawfbuf); + ov->rawfbuf = NULL; + rvfree(ov->fbuf, data_bufsize); + ov->fbuf = NULL; goto error; } - PDEBUG(4, "sbuf[%d] @ %p", i, ov511->sbuf[i].data); + PDEBUG(4, "sbuf[%d] @ %p", i, ov->sbuf[i].data); } for (i = 0; i < OV511_NUMFRAMES; i++) { - ov511->frame[i].data = ov511->fbuf + i * MAX_DATA_SIZE(w, h); - ov511->frame[i].rawdata = ov511->rawfbuf + ov->frame[i].data = ov->fbuf + i * MAX_DATA_SIZE(w, h); + ov->frame[i].rawdata = ov->rawfbuf + i * MAX_RAW_DATA_SIZE(w, h); - ov511->frame[i].tempdata = ov511->tempfbuf + ov->frame[i].tempdata = ov->tempfbuf + i * MAX_RAW_DATA_SIZE(w, h); - PDEBUG(4, "frame[%d] @ %p", i, ov511->frame[i].data); + PDEBUG(4, "frame[%d] @ %p", i, ov->frame[i].data); } - ov511->buf_state = BUF_ALLOCATED; + ov->buf_state = BUF_ALLOCATED; out: - up(&ov511->buf_lock); + up(&ov->buf_lock); PDEBUG(4, "leaving"); return 0; error: - ov511->buf_state = BUF_NOT_ALLOCATED; - up(&ov511->buf_lock); + ov->buf_state = BUF_NOT_ALLOCATED; + up(&ov->buf_lock); PDEBUG(4, "errored"); return -ENOMEM; } @@ -4587,206 +4498,211 @@ * them if you explicitly free them somewhere else! */ static void -ov511_do_dealloc(struct usb_ov511 *ov511) +ov51x_do_dealloc(struct usb_ov511 *ov) { int i; PDEBUG(4, "entered"); - if (ov511->fbuf) { - rvfree(ov511->fbuf, OV511_NUMFRAMES - * MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight)); - ov511->fbuf = NULL; + if (ov->fbuf) { + rvfree(ov->fbuf, OV511_NUMFRAMES + * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)); + ov->fbuf = NULL; } - if (ov511->rawfbuf) { - vfree(ov511->rawfbuf); - ov511->rawfbuf = NULL; + if (ov->rawfbuf) { + vfree(ov->rawfbuf); + ov->rawfbuf = NULL; } - if (ov511->tempfbuf) { - vfree(ov511->tempfbuf); - ov511->tempfbuf = NULL; + if (ov->tempfbuf) { + vfree(ov->tempfbuf); + ov->tempfbuf = NULL; } for (i = 0; i < OV511_NUMSBUF; i++) { - if (ov511->sbuf[i].data) { - kfree(ov511->sbuf[i].data); - ov511->sbuf[i].data = NULL; + if (ov->sbuf[i].data) { + kfree(ov->sbuf[i].data); + ov->sbuf[i].data = NULL; } } for (i = 0; i < OV511_NUMFRAMES; i++) { - ov511->frame[i].data = NULL; - ov511->frame[i].rawdata = NULL; - ov511->frame[i].tempdata = NULL; + ov->frame[i].data = NULL; + ov->frame[i].rawdata = NULL; + ov->frame[i].tempdata = NULL; } PDEBUG(4, "buffer memory deallocated"); - ov511->buf_state = BUF_NOT_ALLOCATED; + ov->buf_state = BUF_NOT_ALLOCATED; PDEBUG(4, "leaving"); } static void -ov511_buf_callback(unsigned long data) +ov51x_buf_callback(unsigned long data) { - struct usb_ov511 *ov511 = (struct usb_ov511 *)data; + struct usb_ov511 *ov = (struct usb_ov511 *)data; PDEBUG(4, "entered"); - down(&ov511->buf_lock); + down(&ov->buf_lock); - if (ov511->buf_state == BUF_PEND_DEALLOC) - ov511_do_dealloc(ov511); + if (ov->buf_state == BUF_PEND_DEALLOC) + ov51x_do_dealloc(ov); - up(&ov511->buf_lock); + up(&ov->buf_lock); PDEBUG(4, "leaving"); } static void -ov511_dealloc(struct usb_ov511 *ov511, int now) +ov51x_dealloc(struct usb_ov511 *ov, int now) { - struct timer_list *bt = &(ov511->buf_timer); + struct timer_list *bt = &(ov->buf_timer); PDEBUG(4, "entered"); - down(&ov511->buf_lock); + down(&ov->buf_lock); PDEBUG(4, "deallocating buffer memory %s", now ? "now" : "later"); - if (ov511->buf_state == BUF_PEND_DEALLOC) { - ov511->buf_state = BUF_ALLOCATED; + if (ov->buf_state == BUF_PEND_DEALLOC) { + ov->buf_state = BUF_ALLOCATED; del_timer(bt); } if (now) - ov511_do_dealloc(ov511); + ov51x_do_dealloc(ov); else { - ov511->buf_state = BUF_PEND_DEALLOC; + ov->buf_state = BUF_PEND_DEALLOC; init_timer(bt); - bt->function = ov511_buf_callback; - bt->data = (unsigned long)ov511; + bt->function = ov51x_buf_callback; + bt->data = (unsigned long)ov; bt->expires = jiffies + buf_timeout * HZ; add_timer(bt); } - up(&ov511->buf_lock); + up(&ov->buf_lock); PDEBUG(4, "leaving"); } /**************************************************************************** * - * V4L API + * V4L 1 API * ***************************************************************************/ static int -ov511_open(struct video_device *vdev, int flags) +ov51x_v4l1_open(struct video_device *vdev, int flags) { - struct usb_ov511 *ov511 = vdev->priv; + struct usb_ov511 *ov = vdev->priv; int err, i; PDEBUG(4, "opening"); - down(&ov511->lock); + down(&ov->lock); err = -EBUSY; - if (ov511->user) + if (ov->user) goto out; err = -ENOMEM; - if (ov511_alloc(ov511)) + if (ov51x_alloc(ov)) goto out; - ov511->sub_flag = 0; + ov->sub_flag = 0; /* In case app doesn't set them... */ - if (ov51x_set_default_params(ov511) < 0) + if (ov51x_set_default_params(ov) < 0) goto out; /* Make sure frames are reset */ for (i = 0; i < OV511_NUMFRAMES; i++) { - ov511->frame[i].grabstate = FRAME_UNUSED; - ov511->frame[i].bytes_read = 0; + ov->frame[i].grabstate = FRAME_UNUSED; + ov->frame[i].bytes_read = 0; } /* If compression is on, make sure now that a * decompressor can be loaded */ - if (ov511->compress && !ov511->decomp_ops) { - err = ov51x_request_decompressor(ov511); - if (err) + if (ov->compress && !ov->decomp_ops) { + err = request_decompressor(ov); + if (err && !dumppix) goto out; } - err = ov511_init_isoc(ov511); + err = ov51x_init_isoc(ov); if (err) { - ov511_dealloc(ov511, 0); + ov51x_dealloc(ov, 0); goto out; } - ov511->user++; + ov->user++; - if (ov511->led_policy == LED_AUTO) - ov51x_led_control(ov511, 1); + if (ov->led_policy == LED_AUTO) + ov51x_led_control(ov, 1); out: - up(&ov511->lock); - + up(&ov->lock); return err; } static void -ov511_close(struct video_device *dev) +ov51x_v4l1_close(struct video_device *vdev) { - struct usb_ov511 *ov511 = (struct usb_ov511 *)dev; + struct usb_ov511 *ov = vdev->priv; PDEBUG(4, "ov511_close"); - down(&ov511->lock); + down(&ov->lock); - ov511->user--; - ov511_stop_isoc(ov511); + ov->user--; + ov51x_stop_isoc(ov); - ov51x_release_decompressor(ov511); + release_decompressor(ov); - if (ov511->led_policy == LED_AUTO) - ov51x_led_control(ov511, 0); + if (ov->led_policy == LED_AUTO) + ov51x_led_control(ov, 0); - if (ov511->dev) - ov511_dealloc(ov511, 0); + if (ov->dev) + ov51x_dealloc(ov, 0); - up(&ov511->lock); + up(&ov->lock); /* Device unplugged while open. Only a minimum of unregistration is done * here; the disconnect callback already did the rest. */ - if (!ov511->dev) { - ov511_dealloc(ov511, 1); - video_unregister_device(&ov511->vdev); - kfree(ov511); - ov511 = NULL; + if (!ov->dev) { + down(&ov->cbuf_lock); + kfree(ov->cbuf); + ov->cbuf = NULL; + up(&ov->cbuf_lock); + + ov51x_dealloc(ov, 1); + video_unregister_device(&ov->vdev); + kfree(ov); + ov = NULL; } } static int -ov511_init_done(struct video_device *vdev) +ov51x_v4l1_init_done(struct video_device *vdev) { #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - create_proc_ov511_cam((struct usb_ov511 *)vdev); + create_proc_ov511_cam(vdev->priv); #endif return 0; } static long -ov511_write(struct video_device *vdev, const char *buf, - unsigned long count, int noblock) +ov51x_v4l1_write(struct video_device *vdev, const char *buf, + unsigned long count, int noblock) { return -EINVAL; } /* Do not call this function directly! */ static int -ov511_ioctl_internal(struct video_device *vdev, unsigned int cmd, void *arg) +ov51x_v4l1_ioctl_internal(struct video_device *vdev, unsigned int cmd, + void *arg) { - struct usb_ov511 *ov511 = (struct usb_ov511 *)vdev; + struct usb_ov511 *ov = vdev->priv; PDEBUG(5, "IOCtl: 0x%X", cmd); - if (!ov511->dev) + if (!ov->dev) return -EIO; switch (cmd) { @@ -4798,20 +4714,20 @@ memset(&b, 0, sizeof(b)); sprintf(b.name, "%s USB Camera", - ov511->bridge == BRG_OV511 ? "OV511" : - ov511->bridge == BRG_OV511PLUS ? "OV511+" : - ov511->bridge == BRG_OV518 ? "OV518" : - ov511->bridge == BRG_OV518PLUS ? "OV518+" : + ov->bridge == BRG_OV511 ? "OV511" : + ov->bridge == BRG_OV511PLUS ? "OV511+" : + ov->bridge == BRG_OV518 ? "OV518" : + ov->bridge == BRG_OV518PLUS ? "OV518+" : "unknown"); b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE; - if (ov511->has_tuner) + if (ov->has_tuner) b.type |= VID_TYPE_TUNER; - b.channels = ov511->num_inputs; - b.audios = ov511->has_audio_proc ? 1:0; - b.maxwidth = ov511->maxwidth; - b.maxheight = ov511->maxheight; - b.minwidth = ov511->minwidth; - b.minheight = ov511->minheight; + b.channels = ov->num_inputs; + b.audios = ov->has_audio_proc ? 1:0; + b.maxwidth = ov->maxwidth; + b.maxheight = ov->maxheight; + b.minwidth = ov->minwidth; + b.minheight = ov->minheight; if (copy_to_user(arg, &b, sizeof(b))) return -EFAULT; @@ -4827,18 +4743,18 @@ if (copy_from_user(&v, arg, sizeof(v))) return -EFAULT; - if ((unsigned)(v.channel) >= ov511->num_inputs) { + if ((unsigned)(v.channel) >= ov->num_inputs) { err("Invalid channel (%d)", v.channel); return -EINVAL; } - v.norm = ov511->norm; - v.type = (ov511->has_tuner) ? VIDEO_TYPE_TV : VIDEO_TYPE_CAMERA; - v.flags = (ov511->has_tuner) ? VIDEO_VC_TUNER : 0; - v.flags |= (ov511->has_audio_proc) ? VIDEO_VC_AUDIO : 0; -// v.flags |= (ov511->has_decoder) ? VIDEO_VC_NORM : 0; - v.tuners = (ov511->has_tuner) ? 1:0; - decoder_get_input_name(ov511, v.channel, v.name); + v.norm = ov->norm; + v.type = (ov->has_tuner) ? VIDEO_TYPE_TV : VIDEO_TYPE_CAMERA; + v.flags = (ov->has_tuner) ? VIDEO_VC_TUNER : 0; + v.flags |= (ov->has_audio_proc) ? VIDEO_VC_AUDIO : 0; +// v.flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0; + v.tuners = (ov->has_tuner) ? 1:0; + decoder_get_input_name(ov, v.channel, v.name); if (copy_to_user(arg, &v, sizeof(v))) return -EFAULT; @@ -4856,7 +4772,7 @@ return -EFAULT; /* Make sure it's not a camera */ - if (!ov511->has_decoder) { + if (!ov->has_decoder) { if (v.channel == 0) return 0; else @@ -4871,16 +4787,16 @@ return -EINVAL; } - if ((unsigned)(v.channel) >= ov511->num_inputs) { + if ((unsigned)(v.channel) >= ov->num_inputs) { err("Invalid channel (%d)", v.channel); return -EINVAL; } - err = decoder_set_input(ov511, v.channel); + err = decoder_set_input(ov, v.channel); if (err) return err; - err = decoder_set_norm(ov511, v.norm); + err = decoder_set_norm(ov, v.norm); if (err) return err; @@ -4894,7 +4810,7 @@ memset(&p, 0, sizeof(p)); - if (sensor_get_picture(ov511, &p)) + if (sensor_get_picture(ov, &p)) return -EIO; if (copy_to_user(arg, &p, sizeof(p))) @@ -4912,10 +4828,10 @@ if (copy_from_user(&p, arg, sizeof(p))) return -EFAULT; - if (!ov511_get_depth(p.palette)) + if (!get_depth(p.palette)) return -EINVAL; - if (sensor_set_picture(ov511, &p)) + if (sensor_set_picture(ov, &p)) return -EIO; if (force_palette && p.palette != force_palette) { @@ -4924,23 +4840,22 @@ } // FIXME: Format should be independent of frames - if (p.palette != ov511->frame[0].format) { + if (p.palette != ov->frame[0].format) { PDEBUG(4, "Detected format change"); /* If we're collecting previous frame wait before changing modes */ - interruptible_sleep_on(&ov511->wq); + interruptible_sleep_on(&ov->wq); if (signal_pending(current)) return -EINTR; - mode_init_regs(ov511, ov511->frame[0].width, - ov511->frame[0].height, p.palette, - ov511->sub_flag); + mode_init_regs(ov, ov->frame[0].width, + ov->frame[0].height, p.palette, ov->sub_flag); } PDEBUG(4, "Setting depth=%d, palette=%d", p.depth, p.palette); for (i = 0; i < OV511_NUMFRAMES; i++) { - ov511->frame[i].depth = p.depth; - ov511->frame[i].format = p.palette; + ov->frame[i].depth = p.depth; + ov->frame[i].format = p.palette; } return 0; @@ -4953,7 +4868,7 @@ if (copy_from_user(&vf, arg, sizeof(vf))) return -EFAULT; - ov511->sub_flag = vf; + ov->sub_flag = vf; return 0; } case VIDIOCSCAPTURE: @@ -4981,10 +4896,10 @@ if (vc.height == 0) vc.height = 16; - ov511->subx = vc.x; - ov511->suby = vc.y; - ov511->subw = vc.width; - ov511->subh = vc.height; + ov->subx = vc.x; + ov->suby = vc.y; + ov->subw = vc.width; + ov->subh = vc.height; return 0; } @@ -5004,25 +4919,25 @@ return -EINVAL; if (vw.clipcount) return -EINVAL; - if (vw.height != ov511->maxheight) + if (vw.height != ov->maxheight) return -EINVAL; - if (vw.width != ov511->maxwidth) + if (vw.width != ov->maxwidth) return -EINVAL; #endif /* If we're collecting previous frame wait before changing modes */ - interruptible_sleep_on(&ov511->wq); + interruptible_sleep_on(&ov->wq); if (signal_pending(current)) return -EINTR; - result = mode_init_regs(ov511, vw.width, vw.height, - ov511->frame[0].format, ov511->sub_flag); + result = mode_init_regs(ov, vw.width, vw.height, + ov->frame[0].format, ov->sub_flag); if (result < 0) return result; for (i = 0; i < OV511_NUMFRAMES; i++) { - ov511->frame[i].width = vw.width; - ov511->frame[i].height = vw.height; + ov->frame[i].width = vw.width; + ov->frame[i].height = vw.height; } return 0; @@ -5034,8 +4949,8 @@ memset(&vw, 0, sizeof(vw)); vw.x = 0; /* FIXME */ vw.y = 0; - vw.width = ov511->frame[0].width; - vw.height = ov511->frame[0].height; + vw.width = ov->frame[0].width; + vw.height = ov->frame[0].height; vw.flags = 30; PDEBUG(4, "VIDIOCGWIN: %dx%d", vw.width, vw.height); @@ -5054,13 +4969,13 @@ memset(&vm, 0, sizeof(vm)); vm.size = OV511_NUMFRAMES - * MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight); + * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight); vm.frames = OV511_NUMFRAMES; vm.offsets[0] = 0; for (i = 1; i < OV511_NUMFRAMES; i++) { vm.offsets[i] = vm.offsets[i-1] - + MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight); + + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight); } if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) @@ -5080,7 +4995,7 @@ PDEBUG(4, "frame: %d, size: %dx%d, format: %d", vm.frame, vm.width, vm.height, vm.format); - depth = ov511_get_depth(vm.format); + depth = get_depth(vm.format); if (!depth) { err("VIDIOCMCAPTURE: invalid format (%d)", vm.format); return -EINVAL; @@ -5091,13 +5006,13 @@ return -EINVAL; } - if (vm.width > ov511->maxwidth - || vm.height > ov511->maxheight) { + if (vm.width > ov->maxwidth + || vm.height > ov->maxheight) { err("VIDIOCMCAPTURE: requested dimensions too big"); return -EINVAL; } - if (ov511->frame[vm.frame].grabstate == FRAME_GRABBING) { + if (ov->frame[vm.frame].grabstate == FRAME_GRABBING) { PDEBUG(4, "VIDIOCMCAPTURE: already grabbing"); return -EBUSY; } @@ -5107,38 +5022,38 @@ return -EINVAL; } - if ((ov511->frame[vm.frame].width != vm.width) || - (ov511->frame[vm.frame].height != vm.height) || - (ov511->frame[vm.frame].format != vm.format) || - (ov511->frame[vm.frame].sub_flag != ov511->sub_flag) || - (ov511->frame[vm.frame].depth != depth)) { + if ((ov->frame[vm.frame].width != vm.width) || + (ov->frame[vm.frame].height != vm.height) || + (ov->frame[vm.frame].format != vm.format) || + (ov->frame[vm.frame].sub_flag != ov->sub_flag) || + (ov->frame[vm.frame].depth != depth)) { PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters"); /* If we're collecting previous frame wait before changing modes */ - interruptible_sleep_on(&ov511->wq); + interruptible_sleep_on(&ov->wq); if (signal_pending(current)) return -EINTR; - ret = mode_init_regs(ov511, vm.width, vm.height, - vm.format, ov511->sub_flag); + ret = mode_init_regs(ov, vm.width, vm.height, + vm.format, ov->sub_flag); #if 0 if (ret < 0) { PDEBUG(1, "Got error while initializing regs "); return ret; } #endif - ov511->frame[vm.frame].width = vm.width; - ov511->frame[vm.frame].height = vm.height; - ov511->frame[vm.frame].format = vm.format; - ov511->frame[vm.frame].sub_flag = ov511->sub_flag; - ov511->frame[vm.frame].depth = depth; + ov->frame[vm.frame].width = vm.width; + ov->frame[vm.frame].height = vm.height; + ov->frame[vm.frame].format = vm.format; + ov->frame[vm.frame].sub_flag = ov->sub_flag; + ov->frame[vm.frame].depth = depth; } /* Mark it as ready */ - ov511->frame[vm.frame].grabstate = FRAME_READY; + ov->frame[vm.frame].grabstate = FRAME_READY; PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", vm.frame); - return ov511_new_frame(ov511, vm.frame); + return ov51x_new_frame(ov, vm.frame); } case VIDIOCSYNC: { @@ -5153,7 +5068,7 @@ return -EINVAL; } - frame = &ov511->frame[fnum]; + frame = &ov->frame[fnum]; PDEBUG(4, "syncing to frame %d, grabstate = %d", fnum, frame->grabstate); @@ -5165,7 +5080,7 @@ case FRAME_GRABBING: case FRAME_ERROR: redo: - if (!ov511->dev) + if (!ov->dev) return -EIO; rc = wait_event_interruptible(frame->wq, @@ -5178,15 +5093,15 @@ if (frame->grabstate == FRAME_ERROR) { int ret; - if ((ret = ov511_new_frame(ov511, fnum)) < 0) + if ((ret = ov51x_new_frame(ov, fnum)) < 0) return ret; goto redo; } /* Fall through */ case FRAME_DONE: - if (ov511->snap_enabled && !frame->snapshot) { + if (ov->snap_enabled && !frame->snapshot) { int ret; - if ((ret = ov511_new_frame(ov511, fnum)) < 0) + if ((ret = ov51x_new_frame(ov, fnum)) < 0) return ret; goto redo; } @@ -5195,13 +5110,13 @@ /* Reset the hardware snapshot button */ /* FIXME - Is this the best place for this? */ - if ((ov511->snap_enabled) && (frame->snapshot)) { + if ((ov->snap_enabled) && (frame->snapshot)) { frame->snapshot = 0; - ov51x_clear_snapshot(ov511); + ov51x_clear_snapshot(ov); } /* Decompression, format conversion, etc... */ - ov511_postprocess(ov511, frame); + ov51x_postprocess(ov, frame); break; } /* end switch */ @@ -5230,7 +5145,7 @@ memset(&vu, 0, sizeof(vu)); - vu.video = ov511->vdev.minor; /* Video minor */ + vu.video = ov->vdev.minor; /* Video minor */ vu.vbi = VIDEO_NO_UNIT; /* VBI minor */ vu.radio = VIDEO_NO_UNIT; /* Radio minor */ vu.audio = VIDEO_NO_UNIT; /* Audio minor */ @@ -5250,7 +5165,7 @@ if (copy_from_user(&v, arg, sizeof(v))) return -EFAULT; - if (!ov511->has_tuner || v.tuner) // Only tuner 0 + if (!ov->has_tuner || v.tuner) // Only tuner 0 return -EINVAL; strcpy(v.name, "Television"); @@ -5264,7 +5179,7 @@ v.mode = 0; /* FIXME: Not sure what this is yet */ v.signal = 0xFFFF; /* unknown */ - call_i2c_clients(ov511, cmd, &v); + call_i2c_clients(ov, cmd, &v); if (copy_to_user(arg, &v, sizeof(v))) return -EFAULT; @@ -5282,7 +5197,7 @@ return -EFAULT; /* Only no or one tuner for now */ - if (!ov511->has_tuner || v.tuner) + if (!ov->has_tuner || v.tuner) return -EINVAL; /* and it only has certain valid modes */ @@ -5291,21 +5206,21 @@ v.mode != VIDEO_MODE_SECAM) return -EOPNOTSUPP; /* Is this right/necessary? */ - err = decoder_set_norm(ov511, v.mode); + err = decoder_set_norm(ov, v.mode); if (err) return err; - call_i2c_clients(ov511, cmd, &v); + call_i2c_clients(ov, cmd, &v); return 0; } case VIDIOCGFREQ: { - unsigned long v = ov511->freq; + unsigned long v = ov->freq; PDEBUG(4, "VIDIOCGFREQ"); - if (!ov511->has_tuner) + if (!ov->has_tuner) return -EINVAL; #if 0 /* FIXME: this is necessary for testing */ @@ -5320,7 +5235,7 @@ { unsigned long v; - if (!ov511->has_tuner) + if (!ov->has_tuner) return -EINVAL; if (copy_from_user(&v, arg, sizeof(v))) @@ -5328,8 +5243,8 @@ PDEBUG(4, "VIDIOCSFREQ: %lx", v); - ov511->freq = v; - call_i2c_clients(ov511, cmd, &v); + ov->freq = v; + call_i2c_clients(ov, cmd, &v); return 0; } @@ -5348,29 +5263,29 @@ } static int -ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg) +ov51x_v4l1_ioctl(struct video_device *vdev, unsigned int cmd, void *arg) { int rc; - struct usb_ov511 *ov511 = vdev->priv; + struct usb_ov511 *ov = vdev->priv; - if (down_interruptible(&ov511->lock)) + if (down_interruptible(&ov->lock)) return -EINTR; - rc = ov511_ioctl_internal(vdev, cmd, arg); + rc = ov51x_v4l1_ioctl_internal(vdev, cmd, arg); - up(&ov511->lock); + up(&ov->lock); return rc; } static inline long -ov511_read(struct video_device *vdev, char *buf, unsigned long count, - int noblock) +ov51x_v4l1_read(struct video_device *vdev, char *buf, unsigned long count, + int noblock) { - struct usb_ov511 *ov511 = vdev->priv; + struct usb_ov511 *ov = vdev->priv; int i, rc = 0, frmx = -1; struct ov511_frame *frame; - if (down_interruptible(&ov511->lock)) + if (down_interruptible(&ov->lock)) return -EINTR; PDEBUG(4, "%ld bytes, noblock=%d", count, noblock); @@ -5380,16 +5295,16 @@ goto error; } - if (!ov511->dev) { + if (!ov->dev) { rc = -EIO; goto error; } // FIXME: Only supports two frames /* See if a frame is completed, then use it. */ - if (ov511->frame[0].grabstate >= FRAME_DONE) /* _DONE or _ERROR */ + if (ov->frame[0].grabstate >= FRAME_DONE) /* _DONE or _ERROR */ frmx = 0; - else if (ov511->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */ + else if (ov->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */ frmx = 1; /* If nonblocking we return immediately */ @@ -5401,24 +5316,24 @@ /* If no FRAME_DONE, look for a FRAME_GRABBING state. */ /* See if a frame is in process (grabbing), then use it. */ if (frmx == -1) { - if (ov511->frame[0].grabstate == FRAME_GRABBING) + if (ov->frame[0].grabstate == FRAME_GRABBING) frmx = 0; - else if (ov511->frame[1].grabstate == FRAME_GRABBING) + else if (ov->frame[1].grabstate == FRAME_GRABBING) frmx = 1; } /* If no frame is active, start one. */ if (frmx == -1) { - if ((rc = ov511_new_frame(ov511, frmx = 0))) { - err("read: ov511_new_frame error"); + if ((rc = ov51x_new_frame(ov, frmx = 0))) { + err("read: ov51x_new_frame error"); goto error; } } - frame = &ov511->frame[frmx]; + frame = &ov->frame[frmx]; restart: - if (!ov511->dev) { + if (!ov->dev) { rc = -EIO; goto error; } @@ -5437,9 +5352,9 @@ if (frame->grabstate == FRAME_ERROR) { frame->bytes_read = 0; - err("** ick! ** Errored frame %d", ov511->curframe); - if (ov511_new_frame(ov511, frmx)) { - err("read: ov511_new_frame error"); + err("** ick! ** Errored frame %d", ov->curframe); + if (ov51x_new_frame(ov, frmx)) { + err("read: ov51x_new_frame error"); goto error; } goto restart; @@ -5447,25 +5362,25 @@ /* Repeat until we get a snapshot frame */ - if (ov511->snap_enabled) + if (ov->snap_enabled) PDEBUG(4, "Waiting snapshot frame"); - if (ov511->snap_enabled && !frame->snapshot) { + if (ov->snap_enabled && !frame->snapshot) { frame->bytes_read = 0; - if ((rc = ov511_new_frame(ov511, frmx))) { - err("read: ov511_new_frame error"); + if ((rc = ov51x_new_frame(ov, frmx))) { + err("read: ov51x_new_frame error"); goto error; } goto restart; } /* Clear the snapshot */ - if (ov511->snap_enabled && frame->snapshot) { + if (ov->snap_enabled && frame->snapshot) { frame->snapshot = 0; - ov51x_clear_snapshot(ov511); + ov51x_clear_snapshot(ov); } /* Decompression, format conversion, etc... */ - ov511_postprocess(ov511, frame); + ov51x_postprocess(ov, frame); PDEBUG(4, "frmx=%d, bytes_read=%ld, length=%ld", frmx, frame->bytes_read, @@ -5497,48 +5412,49 @@ // FIXME: Only supports two frames /* Mark it as available to be used again. */ - ov511->frame[frmx].grabstate = FRAME_UNUSED; - if ((rc = ov511_new_frame(ov511, !frmx))) { - err("ov511_new_frame returned error"); + ov->frame[frmx].grabstate = FRAME_UNUSED; + if ((rc = ov51x_new_frame(ov, !frmx))) { + err("ov51x_new_frame returned error"); goto error; } } PDEBUG(4, "read finished, returning %ld (sweet)", count); - up(&ov511->lock); + up(&ov->lock); return count; error: - up(&ov511->lock); + up(&ov->lock); return rc; } static int -ov511_mmap(struct vm_area_struct *vma, struct video_device *vdev, const char *adr, unsigned long size) +ov51x_v4l1_mmap(struct vm_area_struct *vma, struct video_device *vdev, + const char *adr, unsigned long size) { - struct usb_ov511 *ov511 = vdev->priv; + struct usb_ov511 *ov = vdev->priv; unsigned long start = (unsigned long)adr; unsigned long page, pos; - if (ov511->dev == NULL) + if (ov->dev == NULL) return -EIO; PDEBUG(4, "mmap: %ld (%lX) bytes", size, size); if (size > (((OV511_NUMFRAMES - * MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight) + * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))) return -EINVAL; - if (down_interruptible(&ov511->lock)) + if (down_interruptible(&ov->lock)) return -EINTR; - pos = (unsigned long)ov511->fbuf; + pos = (unsigned long)ov->fbuf; while (size > 0) { page = kvirt_to_pa(pos); if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { - up(&ov511->lock); + up(&ov->lock); return -EAGAIN; } start += PAGE_SIZE; @@ -5549,31 +5465,31 @@ size = 0; } - up(&ov511->lock); + up(&ov->lock); return 0; } -static struct video_device ov511_template = { +static struct video_device vdev_template = { owner: THIS_MODULE, name: "OV511 USB Camera", type: VID_TYPE_CAPTURE, hardware: VID_HARDWARE_OV511, - open: ov511_open, - close: ov511_close, - read: ov511_read, - write: ov511_write, - ioctl: ov511_ioctl, - mmap: ov511_mmap, - initialize: ov511_init_done, + open: ov51x_v4l1_open, + close: ov51x_v4l1_close, + read: ov51x_v4l1_read, + write: ov51x_v4l1_write, + ioctl: ov51x_v4l1_ioctl, + mmap: ov51x_v4l1_mmap, + initialize: ov51x_v4l1_init_done, }; #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) static int -ov511_control_ioctl(struct inode *inode, struct file *file, unsigned int cmd, +ov51x_control_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long ularg) { struct proc_dir_entry *pde; - struct usb_ov511 *ov511; + struct usb_ov511 *ov; void *arg = (void *) ularg; int rc; @@ -5581,11 +5497,11 @@ if (!pde) return -ENOENT; - ov511 = (struct usb_ov511 *) pde->data; - if (!ov511) + ov = (struct usb_ov511 *) pde->data; + if (!ov) return -ENODEV; - if (!ov511->dev) + if (!ov->dev) return -EIO; /* Should we pass through standard V4L IOCTLs? */ @@ -5610,19 +5526,19 @@ switch (opt.optnum) { case OV511_USOPT_BRIGHT: - rc = sensor_get_brightness(ov511, &(opt.val)); + rc = sensor_get_brightness(ov, &(opt.val)); if (rc) return rc; break; case OV511_USOPT_SAT: - rc = sensor_get_saturation(ov511, &(opt.val)); + rc = sensor_get_saturation(ov, &(opt.val)); if (rc) return rc; break; case OV511_USOPT_HUE: - rc = sensor_get_hue(ov511, &(opt.val)); + rc = sensor_get_hue(ov, &(opt.val)); if (rc) return rc; break; case OV511_USOPT_CONTRAST: - rc = sensor_get_contrast(ov511, &(opt.val)); + rc = sensor_get_contrast(ov, &(opt.val)); if (rc) return rc; break; default: @@ -5644,19 +5560,19 @@ switch (opt.optnum) { case OV511_USOPT_BRIGHT: - rc = sensor_set_brightness(ov511, opt.val); + rc = sensor_set_brightness(ov, opt.val); if (rc) return rc; break; case OV511_USOPT_SAT: - rc = sensor_set_saturation(ov511, opt.val); + rc = sensor_set_saturation(ov, opt.val); if (rc) return rc; break; case OV511_USOPT_HUE: - rc = sensor_set_hue(ov511, opt.val); + rc = sensor_set_hue(ov, opt.val); if (rc) return rc; break; case OV511_USOPT_CONTRAST: - rc = sensor_set_contrast(ov511, opt.val); + rc = sensor_set_contrast(ov, opt.val); if (rc) return rc; break; default: @@ -5675,19 +5591,19 @@ switch (opt.optnum) { case OV511_UIOPT_POWER_FREQ: - opt.val = ov511->lightfreq; + opt.val = ov->lightfreq; break; case OV511_UIOPT_BFILTER: - opt.val = ov511->bandfilt; + opt.val = ov->bandfilt; break; case OV511_UIOPT_LED: - opt.val = ov511->led_policy; + opt.val = ov->led_policy; break; case OV511_UIOPT_DEBUG: opt.val = debug; break; case OV511_UIOPT_COMPRESS: - opt.val = ov511->compress; + opt.val = ov->compress; break; default: err("Invalid get int option number"); @@ -5708,20 +5624,20 @@ switch (opt.optnum) { case OV511_UIOPT_POWER_FREQ: - rc = sensor_set_light_freq(ov511, opt.val); + rc = sensor_set_light_freq(ov, opt.val); if (rc) return rc; break; case OV511_UIOPT_BFILTER: - rc = sensor_set_banding_filter(ov511, opt.val); + rc = sensor_set_banding_filter(ov, opt.val); if (rc) return rc; break; case OV511_UIOPT_LED: if (opt.val <= 2) { - ov511->led_policy = opt.val; - if (ov511->led_policy == LED_OFF) - ov51x_led_control(ov511, 0); - else if (ov511->led_policy == LED_ON) - ov51x_led_control(ov511, 1); + ov->led_policy = opt.val; + if (ov->led_policy == LED_OFF) + ov51x_led_control(ov, 0); + else if (ov->led_policy == LED_ON) + ov51x_led_control(ov, 1); } else { return -EINVAL; } @@ -5733,14 +5649,12 @@ return -EINVAL; break; case OV511_UIOPT_COMPRESS: - ov511->compress = opt.val; - if (ov511->compress) { - if (ov511->bridge == BRG_OV511 || - ov511->bridge == BRG_OV511PLUS) - ov511_init_compression(ov511); - else if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) - ov518_init_compression(ov511); + ov->compress = opt.val; + if (ov->compress) { + if (ov->bclass == BCL_OV511) + ov511_init_compression(ov); + else if (ov->bclass == BCL_OV518) + ov518_init_compression(ov); } break; default: @@ -5757,7 +5671,7 @@ if (copy_from_user(&w, arg, sizeof(w))) return -EFAULT; - return ov51x_i2c_write_slave(ov511, w.slave, w.reg, w.value, + return i2c_w_slave(ov, w.slave, w.reg, w.value, w.mask); } case OV511IOC_RI2C: @@ -5767,7 +5681,7 @@ if (copy_from_user(&r, arg, sizeof(r))) return -EFAULT; - rc = ov51x_i2c_read_slave(ov511, r.slave, r.reg); + rc = i2c_r_slave(ov, r.slave, r.reg); if (rc < 0) return rc; @@ -5796,7 +5710,7 @@ * the same register settings as the OV7610, since they are very similar. */ static int -ov7xx0_configure(struct usb_ov511 *ov511) +ov7xx0_configure(struct usb_ov511 *ov) { int i, success; int rc; @@ -5913,16 +5827,15 @@ PDEBUG(4, "starting configuration"); /* This looks redundant, but is necessary for WebCam 3 */ - ov511->primary_i2c_slave = OV7xx0_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, OV7xx0_I2C_WRITE_ID, - OV7xx0_I2C_READ_ID) < 0) + ov->primary_i2c_slave = OV7xx0_SID; + if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) return -1; - if (ov51x_init_ov_sensor(ov511) >= 0) { + if (init_ov_sensor(ov) >= 0) { PDEBUG(1, "OV7xx0 sensor initalized (method 1)"); } else { /* Reset the 76xx */ - if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) return -1; + if (i2c_w(ov, 0x12, 0x80) < 0) return -1; /* Wait for it to initialize */ schedule_timeout(1 + 150 * HZ / 1000); @@ -5930,10 +5843,8 @@ i = 0; success = 0; while (i <= i2c_detect_tries) { - if ((ov51x_i2c_read(ov511, - OV7610_REG_ID_HIGH) == 0x7F) && - (ov51x_i2c_read(ov511, - OV7610_REG_ID_LOW) == 0xA2)) { + if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) && + (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) { success = 1; break; } else { @@ -5957,17 +5868,17 @@ } /* Detect sensor (sub)type */ - rc = ov51x_i2c_read(ov511, OV7610_REG_COM_I); + rc = i2c_r(ov, OV7610_REG_COM_I); if (rc < 0) { err("Error detecting sensor type"); return -1; } else if ((rc & 3) == 3) { info("Sensor is an OV7610"); - ov511->sensor = SEN_OV7610; + ov->sensor = SEN_OV7610; } else if ((rc & 3) == 1) { /* I don't know what's different about the 76BE yet */ - if (ov51x_i2c_read(ov511, 0x15) & 1) + if (i2c_r(ov, 0x15) & 1) info("Sensor is an OV7620AE"); else info("Sensor is an OV76BE"); @@ -5975,48 +5886,48 @@ /* OV511+ will return all zero isoc data unless we * configure the sensor as a 7620. Someone needs to * find the exact reg. setting that causes this. */ - if (ov511->bridge == BRG_OV511PLUS) { + if (ov->bridge == BRG_OV511PLUS) { info("Enabling 511+/7620AE workaround"); - ov511->sensor = SEN_OV7620; + ov->sensor = SEN_OV7620; } else { - ov511->sensor = SEN_OV7620AE; + ov->sensor = SEN_OV7620AE; } } else if ((rc & 3) == 0) { info("Sensor is an OV7620"); - ov511->sensor = SEN_OV7620; + ov->sensor = SEN_OV7620; } else { err("Unknown image sensor version: %d", rc & 3); return -1; } - if (ov511->sensor == SEN_OV7620) { + if (ov->sensor == SEN_OV7620) { PDEBUG(4, "Writing 7620 registers"); - if (ov511_write_regvals(ov511, aRegvalsNorm7620)) + if (write_regvals(ov, aRegvalsNorm7620)) return -1; } else { PDEBUG(4, "Writing 7610 registers"); - if (ov511_write_regvals(ov511, aRegvalsNorm7610)) + if (write_regvals(ov, aRegvalsNorm7610)) return -1; } /* Set sensor-specific vars */ - ov511->maxwidth = 640; - ov511->maxheight = 480; - ov511->minwidth = 64; - ov511->minheight = 48; + ov->maxwidth = 640; + ov->maxheight = 480; + ov->minwidth = 64; + ov->minheight = 48; // FIXME: These do not match the actual settings yet - ov511->brightness = 0x80 << 8; - ov511->contrast = 0x80 << 8; - ov511->colour = 0x80 << 8; - ov511->hue = 0x80 << 8; + ov->brightness = 0x80 << 8; + ov->contrast = 0x80 << 8; + ov->colour = 0x80 << 8; + ov->hue = 0x80 << 8; return 0; } /* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */ static int -ov6xx0_configure(struct usb_ov511 *ov511) +ov6xx0_configure(struct usb_ov511 *ov) { int rc; @@ -6142,7 +6053,7 @@ PDEBUG(4, "starting sensor configuration"); - if (ov51x_init_ov_sensor(ov511) < 0) { + if (init_ov_sensor(ov) < 0) { err("Failed to read sensor ID. You might not have an OV6xx0,"); err("or it may be not responding. Report this to " EMAIL); return -1; @@ -6151,50 +6062,44 @@ } /* Detect sensor (sub)type */ - rc = ov51x_i2c_read(ov511, OV7610_REG_COM_I); + rc = i2c_r(ov, OV7610_REG_COM_I); if (rc < 0) { err("Error detecting sensor type"); return -1; } else if ((rc & 3) == 0) { info("Sensor is an OV6630"); - ov511->sensor = SEN_OV6630; + ov->sensor = SEN_OV6630; } else if ((rc & 3) == 1) { info("Sensor is an OV6620"); - ov511->sensor = SEN_OV6620; + ov->sensor = SEN_OV6620; } else if ((rc & 3) == 2) { info("Sensor is an OV6630AE"); - ov511->sensor = SEN_OV6630; + ov->sensor = SEN_OV6630; } else if ((rc & 3) == 3) { info("Sensor is an OV6630AF"); - ov511->sensor = SEN_OV6630; + ov->sensor = SEN_OV6630; } /* Set sensor-specific vars */ - if (ov511->sensor == SEN_OV6620) { - ov511->maxwidth = 352; - ov511->maxheight = 288; - } else { - /* 352x288 not working with OV518 yet */ - ov511->maxwidth = 320; - ov511->maxheight = 240; - } - ov511->minwidth = 64; - ov511->minheight = 48; + ov->maxwidth = 352; + ov->maxheight = 288; + ov->minwidth = 64; + ov->minheight = 48; // FIXME: These do not match the actual settings yet - ov511->brightness = 0x80 << 8; - ov511->contrast = 0x80 << 8; - ov511->colour = 0x80 << 8; - ov511->hue = 0x80 << 8; + ov->brightness = 0x80 << 8; + ov->contrast = 0x80 << 8; + ov->colour = 0x80 << 8; + ov->hue = 0x80 << 8; - if (ov511->sensor == SEN_OV6620) { + if (ov->sensor == SEN_OV6620) { PDEBUG(4, "Writing 6x20 registers"); - if (ov511_write_regvals(ov511, aRegvalsNorm6x20)) + if (write_regvals(ov, aRegvalsNorm6x20)) return -1; } else { PDEBUG(4, "Writing 6x30 registers"); - if (ov511_write_regvals(ov511, aRegvalsNorm6x30)) + if (write_regvals(ov, aRegvalsNorm6x30)) return -1; } @@ -6203,13 +6108,13 @@ /* This initializes the KS0127 and KS0127B video decoders. */ static int -ks0127_configure(struct usb_ov511 *ov511) +ks0127_configure(struct usb_ov511 *ov) { int rc; // FIXME: I don't know how to sync or reset it yet #if 0 - if (ov51x_init_ks_sensor(ov511) < 0) { + if (ov51x_init_ks_sensor(ov) < 0) { err("Failed to initialize the KS0127"); return -1; } else { @@ -6218,21 +6123,21 @@ #endif /* Detect decoder subtype */ - rc = ov51x_i2c_read(ov511, 0x00); + rc = i2c_r(ov, 0x00); if (rc < 0) { err("Error detecting sensor type"); return -1; } else if (rc & 0x08) { - rc = ov51x_i2c_read(ov511, 0x3d); + rc = i2c_r(ov, 0x3d); if (rc < 0) { err("Error detecting sensor type"); return -1; } else if ((rc & 0x0f) == 0) { info("Sensor is a KS0127"); - ov511->sensor = SEN_KS0127; + ov->sensor = SEN_KS0127; } else if ((rc & 0x0f) == 9) { info("Sensor is a KS0127B Rev. A"); - ov511->sensor = SEN_KS0127B; + ov->sensor = SEN_KS0127B; } } else { err("Error: Sensor is an unsupported KS0122"); @@ -6240,16 +6145,16 @@ } /* Set sensor-specific vars */ - ov511->maxwidth = 640; - ov511->maxheight = 480; - ov511->minwidth = 64; - ov511->minheight = 48; + ov->maxwidth = 640; + ov->maxheight = 480; + ov->minwidth = 64; + ov->minheight = 48; // FIXME: These do not match the actual settings yet - ov511->brightness = 0x80 << 8; - ov511->contrast = 0x80 << 8; - ov511->colour = 0x80 << 8; - ov511->hue = 0x80 << 8; + ov->brightness = 0x80 << 8; + ov->contrast = 0x80 << 8; + ov->colour = 0x80 << 8; + ov->hue = 0x80 << 8; /* This device is not supported yet. Bail out now... */ err("This sensor is not supported yet."); @@ -6262,7 +6167,6 @@ static int saa7111a_configure(struct usb_ov511 *ov511) { - struct usb_device *dev = ov511->dev; int rc; /* Since there is no register reset command, all registers must be @@ -6297,7 +6201,7 @@ // FIXME: I don't know how to sync or reset it yet #if 0 - if (ov51x_init_saa_sensor(ov511) < 0) { + if (ov51x_init_saa_sensor(ov) < 0) { err("Failed to initialize the SAA7111A"); return -1; } else { @@ -6324,12 +6228,12 @@ ov511->hue = 32768; PDEBUG(4, "Writing SAA7111A registers"); - if (ov511_write_regvals(ov511, aRegvalsNormSAA7111A)) + if (write_regvals(ov511, aRegvalsNormSAA7111A)) return -1; /* Detect version of decoder. This must be done after writing the * initial regs or the decoder will lock up. */ - rc = ov51x_i2c_read(ov511, 0x00); + rc = i2c_r(ov511, 0x00); if (rc < 0) { err("Error detecting sensor version"); @@ -6342,8 +6246,8 @@ // FIXME: Fix this for OV518(+) /* Latch to negative edge of clock. Otherwise, we get incorrect * colors and jitter in the digital signal. */ - if (ov511->bridge == BRG_OV511 || ov511->bridge == BRG_OV511PLUS) - ov511_reg_write(dev, 0x11, 0x00); + if (ov511->bclass == BCL_OV511) + reg_w(ov511, 0x11, 0x00); else warn("SAA7111A not yet supported with OV518/OV518+"); @@ -6352,144 +6256,138 @@ /* This initializes the OV511/OV511+ and the sensor */ static int -ov511_configure(struct usb_ov511 *ov511) +ov511_configure(struct usb_ov511 *ov) { - struct usb_device *dev = ov511->dev; int i; static struct ov511_regvals aRegvalsInit511[] = { - { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x7f }, - { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x7f }, - { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3f }, - { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3d }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x7f }, + { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x7f }, + { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x3f }, + { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x3d }, { OV511_DONE_BUS, 0x0, 0x00}, }; static struct ov511_regvals aRegvalsNorm511[] = { - { OV511_REG_BUS, OV511_REG_DRAM_ENABLE_FLOW_CONTROL, 0x01 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x01 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x03 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x01 }, - { OV511_REG_BUS, OV511_REG_FIFO_BITMASK, 0x1f }, - { OV511_REG_BUS, OV511_OMNICE_ENABLE, 0x00 }, - { OV511_REG_BUS, OV511_OMNICE_LUT_ENABLE, 0x03 }, + { OV511_REG_BUS, R511_DRAM_FLOW_CTL, 0x01 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x03 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, + { OV511_REG_BUS, R511_FIFO_OPTS, 0x1f }, + { OV511_REG_BUS, R511_COMP_EN, 0x00 }, + { OV511_REG_BUS, R511_COMP_LUT_EN, 0x03 }, { OV511_DONE_BUS, 0x0, 0x00 }, }; static struct ov511_regvals aRegvalsNorm511Plus[] = { - { OV511_REG_BUS, OV511_REG_DRAM_ENABLE_FLOW_CONTROL, 0xff }, - { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x01 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x03 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x01 }, - { OV511_REG_BUS, OV511_REG_FIFO_BITMASK, 0xff }, - { OV511_REG_BUS, OV511_OMNICE_ENABLE, 0x00 }, - { OV511_REG_BUS, OV511_OMNICE_LUT_ENABLE, 0x03 }, + { OV511_REG_BUS, R511_DRAM_FLOW_CTL, 0xff }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x03 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, + { OV511_REG_BUS, R511_FIFO_OPTS, 0xff }, + { OV511_REG_BUS, R511_COMP_EN, 0x00 }, + { OV511_REG_BUS, R511_COMP_LUT_EN, 0x03 }, { OV511_DONE_BUS, 0x0, 0x00 }, }; PDEBUG(4, ""); - ov511->customid = ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID); - if (ov511->customid < 0) { + ov->customid = reg_r(ov, R511_SYS_CUST_ID); + if (ov->customid < 0) { err("Unable to read camera bridge registers"); goto error; } - ov511->desc = -1; - PDEBUG (1, "CustomID = %d", ov511->customid); + ov->desc = -1; + PDEBUG (1, "CustomID = %d", ov->customid); for (i = 0; clist[i].id >= 0; i++) { - if (ov511->customid == clist[i].id) { + if (ov->customid == clist[i].id) { info("model: %s", clist[i].description); - ov511->desc = i; + ov->desc = i; break; } } if (clist[i].id == -1) { - err("Camera type (%d) not recognized", ov511->customid); + err("Camera type (%d) not recognized", ov->customid); err("Please notify " EMAIL " of the name,"); err("manufacturer, model, and this number of your camera."); err("Also include the output of the detection process."); } if (clist[i].id == 6) { /* USB Life TV (NTSC) */ - ov511->tuner_type = 8; /* Temic 4036FY5 3X 1981 */ + ov->tuner_type = 8; /* Temic 4036FY5 3X 1981 */ } - if (ov511_write_regvals(ov511, aRegvalsInit511)) goto error; + if (write_regvals(ov, aRegvalsInit511)) goto error; - if (ov511->led_policy == LED_OFF || ov511->led_policy == LED_AUTO) - ov51x_led_control(ov511, 0); + if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO) + ov51x_led_control(ov, 0); /* The OV511+ has undocumented bits in the flow control register. * Setting it to 0xff fixes the corruption with moving objects. */ - if (ov511->bridge == BRG_OV511) { - if (ov511_write_regvals(ov511, aRegvalsNorm511)) goto error; - } else if (ov511->bridge == BRG_OV511PLUS) { - if (ov511_write_regvals(ov511, aRegvalsNorm511Plus)) goto error; + if (ov->bridge == BRG_OV511) { + if (write_regvals(ov, aRegvalsNorm511)) goto error; + } else if (ov->bridge == BRG_OV511PLUS) { + if (write_regvals(ov, aRegvalsNorm511Plus)) goto error; } else { err("Invalid bridge"); } - if (ov511_init_compression(ov511)) goto error; + if (ov511_init_compression(ov)) goto error; - ov511_set_packet_size(ov511, 0); + ov51x_set_packet_size(ov, 0); - ov511->snap_enabled = snapshot; + ov->snap_enabled = snapshot; /* Test for 7xx0 */ PDEBUG(3, "Testing for 0V7xx0"); - ov511->primary_i2c_slave = OV7xx0_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, OV7xx0_I2C_WRITE_ID, - OV7xx0_I2C_READ_ID) < 0) + ov->primary_i2c_slave = OV7xx0_SID; + if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) goto error; - if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) { + if (i2c_w(ov, 0x12, 0x80) < 0) { /* Test for 6xx0 */ PDEBUG(3, "Testing for 0V6xx0"); - ov511->primary_i2c_slave = OV6xx0_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, OV6xx0_I2C_WRITE_ID, - OV6xx0_I2C_READ_ID) < 0) + ov->primary_i2c_slave = OV6xx0_SID; + if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0) goto error; - if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) { + if (i2c_w(ov, 0x12, 0x80) < 0) { /* Test for 8xx0 */ PDEBUG(3, "Testing for 0V8xx0"); - ov511->primary_i2c_slave = OV8xx0_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, OV8xx0_I2C_WRITE_ID, - OV8xx0_I2C_READ_ID)) + ov->primary_i2c_slave = OV8xx0_SID; + if (ov51x_set_slave_ids(ov, OV8xx0_SID)) goto error; - if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) { + if (i2c_w(ov, 0x12, 0x80) < 0) { /* Test for SAA7111A */ PDEBUG(3, "Testing for SAA7111A"); - ov511->primary_i2c_slave = SAA7111A_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, SAA7111A_I2C_WRITE_ID, - SAA7111A_I2C_READ_ID)) + ov->primary_i2c_slave = SAA7111A_SID; + if (ov51x_set_slave_ids(ov, SAA7111A_SID)) goto error; - if (ov51x_i2c_write(ov511, 0x0d, 0x00) < 0) { + if (i2c_w(ov, 0x0d, 0x00) < 0) { /* Test for KS0127 */ PDEBUG(3, "Testing for KS0127"); - ov511->primary_i2c_slave = KS0127_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, KS0127_I2C_WRITE_ID, - KS0127_I2C_READ_ID)) + ov->primary_i2c_slave = KS0127_SID; + if (ov51x_set_slave_ids(ov, KS0127_SID)) goto error; - if (ov51x_i2c_write(ov511, 0x10, 0x00) < 0) { + if (i2c_w(ov, 0x10, 0x00) < 0) { err("Can't determine sensor slave IDs"); goto error; } else { - if(ks0127_configure(ov511) < 0) { + if (ks0127_configure(ov) < 0) { err("Failed to configure KS0127"); goto error; } } } else { - if(saa7111a_configure(ov511) < 0) { + if (saa7111a_configure(ov) < 0) { err("Failed to configure SAA7111A"); goto error; } @@ -6499,13 +6397,13 @@ goto error; } } else { - if(ov6xx0_configure(ov511) < 0) { + if (ov6xx0_configure(ov) < 0) { err("Failed to configure OV6xx0"); goto error; } } } else { - if(ov7xx0_configure(ov511) < 0) { + if (ov7xx0_configure(ov) < 0) { err("Failed to configure OV7xx0"); goto error; } @@ -6521,96 +6419,90 @@ /* This initializes the OV518/OV518+ and the sensor */ static int -ov518_configure(struct usb_ov511 *ov511) +ov518_configure(struct usb_ov511 *ov) { - struct usb_device *dev = ov511->dev; - static struct ov511_regvals aRegvalsInit518[] = { - { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x40 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0xe1 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3e }, - { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0xe1 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x00 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0xe1 }, - { OV511_REG_BUS, 0x46, 0x00 }, - { OV511_REG_BUS, 0x5d, 0x03 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x40 }, + { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x3e }, + { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x00 }, + { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, + { OV511_REG_BUS, 0x46, 0x00 }, + { OV511_REG_BUS, 0x5d, 0x03 }, { OV511_DONE_BUS, 0x0, 0x00}, }; /* New values, based on Windows driver. Since what they do is not * known yet, this may be incorrect. */ static struct ov511_regvals aRegvalsNorm518[] = { - { OV511_REG_BUS, 0x52, 0x02 }, /* Reset snapshot */ - { OV511_REG_BUS, 0x52, 0x01 }, /* Enable snapshot */ - { OV511_REG_BUS, 0x31, 0x0f }, - { OV511_REG_BUS, 0x5d, 0x03 }, - { OV511_REG_BUS, 0x24, 0x9f }, - { OV511_REG_BUS, 0x25, 0x90 }, - { OV511_REG_BUS, 0x20, 0x00 }, /* Was 0x08 */ - { OV511_REG_BUS, 0x51, 0x04 }, - { OV511_REG_BUS, 0x71, 0x19 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, /* Reset */ + { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, /* Enable */ + { OV511_REG_BUS, 0x31, 0x0f }, + { OV511_REG_BUS, 0x5d, 0x03 }, + { OV511_REG_BUS, 0x24, 0x9f }, + { OV511_REG_BUS, 0x25, 0x90 }, + { OV511_REG_BUS, 0x20, 0x00 }, /* Was 0x08 */ + { OV511_REG_BUS, 0x51, 0x04 }, + { OV511_REG_BUS, 0x71, 0x19 }, { OV511_DONE_BUS, 0x0, 0x00 }, }; PDEBUG(4, ""); /* First 5 bits of custom ID reg are a revision ID on OV518 */ - info("Device revision %d", - 0x1F & ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID)); + info("Device revision %d", 0x1F & reg_r(ov, R511_SYS_CUST_ID)); - if (ov511_write_regvals(ov511, aRegvalsInit518)) goto error; + if (write_regvals(ov, aRegvalsInit518)) goto error; /* Set LED GPIO pin to output mode */ - if (ov511_reg_write_mask(dev, 0x57,0x00, 0x02) < 0) goto error; + if (reg_w_mask(ov, 0x57, 0x00, 0x02) < 0) goto error; /* LED is off by default with OV518; have to explicitly turn it on */ - if (ov511->led_policy == LED_OFF || ov511->led_policy == LED_AUTO) - ov51x_led_control(ov511, 0); + if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO) + ov51x_led_control(ov, 0); else - ov51x_led_control(ov511, 1); + ov51x_led_control(ov, 1); /* Don't require compression if dumppix is enabled; otherwise it's * required. OV518 has no uncompressed mode, to save RAM. */ - if (!dumppix && !ov511->compress) { - ov511->compress = 1; + if (!dumppix && !ov->compress) { + ov->compress = 1; warn("Compression required with OV518...enabling"); } - if (ov511_write_regvals(ov511, aRegvalsNorm518)) goto error; + if (write_regvals(ov, aRegvalsNorm518)) goto error; - if (ov511_reg_write(dev, 0x2f,0x80) < 0) goto error; + if (reg_w(ov, 0x2f, 0x80) < 0) goto error; - if (ov518_init_compression(ov511)) goto error; + if (ov518_init_compression(ov)) goto error; - ov511_set_packet_size(ov511, 0); + ov51x_set_packet_size(ov, 0); - ov511->snap_enabled = snapshot; + ov->snap_enabled = snapshot; /* Test for 76xx */ - ov511->primary_i2c_slave = OV7xx0_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, OV7xx0_I2C_WRITE_ID, - OV7xx0_I2C_READ_ID) < 0) + ov->primary_i2c_slave = OV7xx0_SID; + if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) goto error; /* The OV518 must be more aggressive about sensor detection since * I2C write will never fail if the sensor is not present. We have * to try to initialize the sensor to detect its presence */ - if (ov51x_init_ov_sensor(ov511) < 0) { + if (init_ov_sensor(ov) < 0) { /* Test for 6xx0 */ - ov511->primary_i2c_slave = OV6xx0_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, OV6xx0_I2C_WRITE_ID, - OV6xx0_I2C_READ_ID) < 0) + ov->primary_i2c_slave = OV6xx0_SID; + if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0) goto error; - if (ov51x_init_ov_sensor(ov511) < 0) { + if (init_ov_sensor(ov) < 0) { /* Test for 8xx0 */ - ov511->primary_i2c_slave = OV8xx0_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, OV8xx0_I2C_WRITE_ID, - OV8xx0_I2C_READ_ID) < 0) + ov->primary_i2c_slave = OV8xx0_SID; + if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0) goto error; - if (ov51x_init_ov_sensor(ov511) < 0) { + if (init_ov_sensor(ov) < 0) { err("Can't determine sensor slave IDs"); goto error; } else { @@ -6618,21 +6510,25 @@ goto error; } } else { - if (ov6xx0_configure(ov511) < 0) { + if (ov6xx0_configure(ov) < 0) { err("Failed to configure OV6xx0"); goto error; } } } else { - if (ov7xx0_configure(ov511) < 0) { + if (ov7xx0_configure(ov) < 0) { err("Failed to configure OV7xx0"); goto error; } } + // FIXME: Sizes > 320x240 are not working yet + ov->maxwidth = 320; + ov->maxheight = 240; + // The OV518 cannot go as low as the sensor can - ov511->minwidth = 160; - ov511->minheight = 120; + ov->minwidth = 160; + ov->minheight = 120; return 0; @@ -6649,12 +6545,13 @@ * ***************************************************************************/ +/* 2.2.x compatibility */ static void * ov51x_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id) { struct usb_interface_descriptor *interface; - struct usb_ov511 *ov511; + struct usb_ov511 *ov; int i; int registered = 0; @@ -6672,57 +6569,54 @@ 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"); - goto error_unlock; - } - - memset(ov511, 0, sizeof(*ov511)); - - ov511->dev = dev; - ov511->iface = interface->bInterfaceNumber; - ov511->led_policy = led; - ov511->compress = compress; - ov511->lightfreq = lightfreq; - ov511->num_inputs = 1; /* Video decoder init functs. change this */ - ov511->stop_during_set = !fastset; - ov511->tuner_type = tuner; - ov511->backlight = backlight; - - ov511->auto_brt = autobright; - ov511->auto_gain = autogain; - ov511->auto_exp = autoexp; + if ((ov = kmalloc(sizeof(*ov), GFP_KERNEL)) == NULL) { + err("couldn't kmalloc ov struct"); + goto error_out; + } + + memset(ov, 0, sizeof(*ov)); + + ov->dev = dev; + ov->iface = interface->bInterfaceNumber; + ov->led_policy = led; + ov->compress = compress; + ov->lightfreq = lightfreq; + ov->num_inputs = 1; /* Video decoder init functs. change this */ + ov->stop_during_set = !fastset; + ov->tuner_type = tuner; + ov->backlight = backlight; + + ov->auto_brt = autobright; + ov->auto_gain = autogain; + ov->auto_exp = autoexp; switch (dev->descriptor.idProduct) { case PROD_OV511: info("USB OV511 camera found"); - ov511->bridge = BRG_OV511; - ov511->bclass = BCL_OV511; + ov->bridge = BRG_OV511; + ov->bclass = BCL_OV511; break; case PROD_OV511PLUS: info("USB OV511+ camera found"); - ov511->bridge = BRG_OV511PLUS; - ov511->bclass = BCL_OV511; + ov->bridge = BRG_OV511PLUS; + ov->bclass = BCL_OV511; break; case PROD_OV518: info("USB OV518 camera found"); - ov511->bridge = BRG_OV518; - ov511->bclass = BCL_OV518; + ov->bridge = BRG_OV518; + ov->bclass = BCL_OV518; break; case PROD_OV518PLUS: info("USB OV518+ camera found"); - ov511->bridge = BRG_OV518PLUS; - ov511->bclass = BCL_OV518; + ov->bridge = BRG_OV518PLUS; + ov->bclass = BCL_OV518; break; case PROD_ME2CAM: if (dev->descriptor.idVendor != VEND_MATTEL) goto error; info("Intel Play Me2Cam (OV511+) found"); - ov511->bridge = BRG_OV511PLUS; - ov511->bclass = BCL_OV511; + ov->bridge = BRG_OV511PLUS; + ov->bclass = BCL_OV511; break; default: err("Unknown product ID 0x%x", dev->descriptor.idProduct); @@ -6734,47 +6628,53 @@ if (force_rgb) info("data format set to RGB"); - init_waitqueue_head(&ov511->wq); + init_waitqueue_head(&ov->wq); + + init_MUTEX(&ov->lock); /* to 1 == available */ + init_MUTEX(&ov->buf_lock); + init_MUTEX(&ov->param_lock); + init_MUTEX(&ov->i2c_lock); + init_MUTEX(&ov->cbuf_lock); + + ov->buf_state = BUF_NOT_ALLOCATED; + + /* Must be kmalloc()'ed, for DMA accessibility */ + ov->cbuf = kmalloc(OV511_CBUF_SIZE, GFP_KERNEL); + if (!ov->cbuf) + goto error; - init_MUTEX(&ov511->lock); /* to 1 == available */ - init_MUTEX(&ov511->buf_lock); - init_MUTEX(&ov511->param_lock); - init_MUTEX(&ov511->i2c_lock); - ov511->buf_state = BUF_NOT_ALLOCATED; - - if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) { - if (ov518_configure(ov511) < 0) + if (ov->bclass == BCL_OV518) { + if (ov518_configure(ov) < 0) goto error; } else { - if (ov511_configure(ov511) < 0) + if (ov511_configure(ov) < 0) goto error; } for (i = 0; i < OV511_NUMFRAMES; i++) { - ov511->frame[i].framenum = i; - init_waitqueue_head(&ov511->frame[i].wq); + ov->frame[i].framenum = i; + init_waitqueue_head(&ov->frame[i].wq); } /* Unnecessary? (This is done on open(). Need to make sure variables * are properly initialized without this before removing it, though). */ - if (ov51x_set_default_params(ov511) < 0) + if (ov51x_set_default_params(ov) < 0) goto error; #ifdef OV511_DEBUG if (dump_bridge) - ov511_dump_regs(dev); + ov511_dump_regs(ov); #endif - memcpy(&ov511->vdev, &ov511_template, sizeof(ov511_template)); - ov511->vdev.priv = ov511; + memcpy(&ov->vdev, &vdev_template, sizeof(vdev_template)); + ov->vdev.priv = ov; for (i = 0; i < OV511_MAX_UNIT_VIDEO; i++) { /* Minor 0 cannot be specified; assume user wants autodetect */ if (unit_video[i] == 0) break; - if (video_register_device(&ov511->vdev, VFL_TYPE_GRABBER, + if (video_register_device(&ov->vdev, VFL_TYPE_GRABBER, unit_video[i]) >= 0) { registered = 1; break; @@ -6783,35 +6683,40 @@ /* Use the next available one */ if (!registered && - video_register_device(&ov511->vdev, VFL_TYPE_GRABBER, -1) < 0) { + video_register_device(&ov->vdev, VFL_TYPE_GRABBER, -1) < 0) { err("video_register_device failed"); goto error; } - info("Device registered on minor %d", ov511->vdev.minor); + info("Device registered on minor %d", ov->vdev.minor); - MOD_DEC_USE_COUNT; - return ov511; + return ov; error: err("Camera initialization failed"); #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) /* Safe to call even if entry doesn't exist */ - destroy_proc_ov511_cam(ov511); + destroy_proc_ov511_cam(ov); #endif + if (ov->cbuf) { + down(&ov->cbuf_lock); + kfree(ov->cbuf); + ov->cbuf = NULL; + up(&ov->cbuf_lock); + } + usb_driver_release_interface(&ov511_driver, - &dev->actconfig->interface[ov511->iface]); + &dev->actconfig->interface[ov->iface]); error_dealloc: - if (ov511) { - kfree(ov511); - ov511 = NULL; + if (ov) { + kfree(ov); + ov = NULL; } -error_unlock: - MOD_DEC_USE_COUNT; +error_out: return NULL; } @@ -6819,62 +6724,64 @@ static void ov51x_disconnect(struct usb_device *dev, void *ptr) { - struct usb_ov511 *ov511 = (struct usb_ov511 *) ptr; + struct usb_ov511 *ov = (struct usb_ov511 *) ptr; int n; - MOD_INC_USE_COUNT; - PDEBUG(3, ""); /* We don't want people trying to open up the device */ - if (!ov511->user) - video_unregister_device(&ov511->vdev); + if (!ov->user) + video_unregister_device(&ov->vdev); else PDEBUG(3, "Device open...deferring video_unregister_device"); for (n = 0; n < OV511_NUMFRAMES; n++) - ov511->frame[n].grabstate = FRAME_ERROR; + ov->frame[n].grabstate = FRAME_ERROR; - ov511->curframe = -1; + ov->curframe = -1; /* This will cause the process to request another frame */ for (n = 0; n < OV511_NUMFRAMES; n++) - if (waitqueue_active(&ov511->frame[n].wq)) - wake_up_interruptible(&ov511->frame[n].wq); - if (waitqueue_active(&ov511->wq)) - wake_up_interruptible(&ov511->wq); + if (waitqueue_active(&ov->frame[n].wq)) + wake_up_interruptible(&ov->frame[n].wq); + if (waitqueue_active(&ov->wq)) + wake_up_interruptible(&ov->wq); - ov511->streaming = 0; + ov->streaming = 0; /* Unschedule all of the iso td's */ for (n = OV511_NUMSBUF - 1; n >= 0; n--) { - if (ov511->sbuf[n].urb) { - ov511->sbuf[n].urb->next = NULL; - usb_unlink_urb(ov511->sbuf[n].urb); - usb_free_urb(ov511->sbuf[n].urb); - ov511->sbuf[n].urb = NULL; + if (ov->sbuf[n].urb) { + ov->sbuf[n].urb->next = NULL; + usb_unlink_urb(ov->sbuf[n].urb); + usb_free_urb(ov->sbuf[n].urb); + ov->sbuf[n].urb = NULL; } } #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - destroy_proc_ov511_cam(ov511); + destroy_proc_ov511_cam(ov); #endif usb_driver_release_interface(&ov511_driver, - &ov511->dev->actconfig->interface[ov511->iface]); - ov511->dev = NULL; + &ov->dev->actconfig->interface[ov->iface]); + ov->dev = NULL; /* Free the memory */ - if (ov511 && !ov511->user) { - ov511_dealloc(ov511, 1); - kfree(ov511); - ov511 = NULL; + if (ov && !ov->user) { + down(&ov->cbuf_lock); + kfree(ov->cbuf); + ov->cbuf = NULL; + up(&ov->cbuf_lock); + + ov51x_dealloc(ov, 1); + kfree(ov); + ov = NULL; } - - MOD_DEC_USE_COUNT; } static struct usb_driver ov511_driver = { + owner: THIS_MODULE, name: "ov511", id_table: device_table, probe: ov51x_probe, diff -Nru a/drivers/usb/ov511.h b/drivers/usb/ov511.h --- a/drivers/usb/ov511.h Tue Feb 26 11:57:59 2002 +++ b/drivers/usb/ov511.h Tue Feb 26 11:57:59 2002 @@ -9,11 +9,11 @@ #define OV511_DEBUG /* Turn on debug messages */ #ifdef OV511_DEBUG -# define PDEBUG(level, fmt, args...) \ -if (debug >= (level)) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , \ - ## args) + #define PDEBUG(level, fmt, args...) \ + if (debug >= (level)) info("[" __PRETTY_FUNCTION__ ":%d] " fmt,\ + __LINE__ , ## args) #else -# define PDEBUG(level, fmt, args...) do {} while(0) + #define PDEBUG(level, fmt, args...) do {} while(0) #endif /* This macro restricts an int variable to an inclusive range */ @@ -36,98 +36,105 @@ #define VEND_MATTEL 0x0813 #define PROD_ME2CAM 0x0002 +/* --------------------------------- */ +/* OV51x REGISTER MNEMONICS */ +/* --------------------------------- */ + /* Camera interface register numbers */ -#define OV511_REG_CAMERA_DELAY_MODE 0x10 -#define OV511_REG_CAMERA_EDGE_MODE 0x11 -#define OV511_REG_CAMERA_CLAMPED_PIXEL_NUM 0x12 -#define OV511_REG_CAMERA_CLAMPED_LINE_NUM 0x13 -#define OV511_REG_CAMERA_PIXEL_DIVISOR 0x14 -#define OV511_REG_CAMERA_LINE_DIVISOR 0x15 -#define OV511_REG_CAMERA_DATA_INPUT_SELECT 0x16 -#define OV511_REG_CAMERA_RESERVED_LINE_MODE 0x17 -#define OV511_REG_CAMERA_BITMASK 0x18 +#define R511_CAM_DELAY 0x10 +#define R511_CAM_EDGE 0x11 +#define R511_CAM_PXCNT 0x12 +#define R511_CAM_LNCNT 0x13 +#define R511_CAM_PXDIV 0x14 +#define R511_CAM_LNDIV 0x15 +#define R511_CAM_UV_EN 0x16 +#define R511_CAM_LINE_MODE 0x17 +#define R511_CAM_OPTS 0x18 /* Snapshot mode camera interface register numbers */ -#define OV511_REG_SNAP_CAPTURED_FRAME 0x19 -#define OV511_REG_SNAP_CLAMPED_PIXEL_NUM 0x1A -#define OV511_REG_SNAP_CLAMPED_LINE_NUM 0x1B -#define OV511_REG_SNAP_PIXEL_DIVISOR 0x1C -#define OV511_REG_SNAP_LINE_DIVISOR 0x1D -#define OV511_REG_SNAP_DATA_INPUT_SELECT 0x1E -#define OV511_REG_SNAP_BITMASK 0x1F +#define R511_SNAP_FRAME 0x19 +#define R511_SNAP_PXCNT 0x1A +#define R511_SNAP_LNCNT 0x1B +#define R511_SNAP_PXDIV 0x1C +#define R511_SNAP_LNDIV 0x1D +#define R511_SNAP_UV_EN 0x1E +#define R511_SNAP_OPTS 0x1F /* DRAM register numbers */ -#define OV511_REG_DRAM_ENABLE_FLOW_CONTROL 0x20 -#define OV511_REG_DRAM_READ_CYCLE_PREDICT 0x21 -#define OV511_REG_DRAM_MANUAL_READ_CYCLE 0x22 -#define OV511_REG_DRAM_REFRESH_COUNTER 0x23 +#define R511_DRAM_FLOW_CTL 0x20 +#define R511_DRAM_ARCP 0x21 +#define R511_DRAM_MRC 0x22 +#define R511_DRAM_RFC 0x23 /* ISO FIFO register numbers */ -#define OV511_REG_FIFO_PACKET_SIZE 0x30 -#define OV511_REG_FIFO_BITMASK 0x31 +#define R51x_FIFO_PSIZE 0x30 /* 2 bytes wide w/ OV518(+) */ +#define R511_FIFO_OPTS 0x31 -/* PIO register numbers */ -#define OV511_REG_PIO_BITMASK 0x38 -#define OV511_REG_PIO_DATA_PORT 0x39 -#define OV511_REG_PIO_BIST 0x3E - -/* I2C register numbers */ -#define OV511_REG_I2C_CONTROL 0x40 -#define OV518_REG_I2C_CONTROL 0x47 /* OV518(+) only */ -#define OV511_REG_I2C_SLAVE_ID_WRITE 0x41 -#define OV511_REG_I2C_SUB_ADDRESS_3_BYTE 0x42 -#define OV511_REG_I2C_SUB_ADDRESS_2_BYTE 0x43 -#define OV511_REG_I2C_SLAVE_ID_READ 0x44 -#define OV511_REG_I2C_DATA_PORT 0x45 -#define OV511_REG_I2C_CLOCK_PRESCALER 0x46 -#define OV511_REG_I2C_TIME_OUT_COUNTER 0x47 - -/* I2C snapshot register numbers */ -#define OV511_REG_I2C_SNAP_SUB_ADDRESS 0x48 -#define OV511_REG_I2C_SNAP_DATA_PORT 0x49 - -/* System control register numbers */ -#define OV511_REG_SYSTEM_RESET 0x50 -#define OV511_RESET_UDC 0x01 -#define OV511_RESET_I2C 0x02 -#define OV511_RESET_FIFO 0x04 -#define OV511_RESET_OMNICE 0x08 -#define OV511_RESET_DRAM_INTF 0x10 -#define OV511_RESET_CAMERA_INTF 0x20 -#define OV511_RESET_OV511 0x40 -#define OV511_RESET_NOREGS 0x3F /* All but OV511 & regs */ -#define OV511_RESET_ALL 0x7F -#define OV511_REG_SYSTEM_CLOCK_DIVISOR 0x51 -#define OV511_REG_SYSTEM_SNAPSHOT 0x52 -#define OV511_REG_SYSTEM_INIT 0x53 -#define OV511_REG_SYSTEM_PWR_CLK 0x54 /* OV511+/OV518(+) only */ -#define OV511_REG_SYSTEM_LED_CTL 0x55 /* OV511+ only */ -#define OV518_REG_GPIO_IN 0x55 /* OV518(+) only */ -#define OV518_REG_GPIO_OUT 0x56 /* OV518(+) only */ -#define OV518_REG_GPIO_CTL 0x57 /* OV518(+) only */ -#define OV518_REG_GPIO_PULSE_IN 0x58 /* OV518(+) only */ -#define OV518_REG_GPIO_PULSE_CLEAR 0x59 /* OV518(+) only */ -#define OV518_REG_GPIO_PULSE_POLARITY 0x5a /* OV518(+) only */ -#define OV518_REG_GPIO_PULSE_EN 0x5b /* OV518(+) only */ -#define OV518_REG_GPIO_RESET 0x5c /* OV518(+) only */ -#define OV511_REG_SYSTEM_USER_DEFINED 0x5E -#define OV511_REG_SYSTEM_CUSTOM_ID 0x5F - -/* OmniCE register numbers */ -#define OV511_OMNICE_PREDICTION_HORIZ_Y 0x70 -#define OV511_OMNICE_PREDICTION_HORIZ_UV 0x71 -#define OV511_OMNICE_PREDICTION_VERT_Y 0x72 -#define OV511_OMNICE_PREDICTION_VERT_UV 0x73 -#define OV511_OMNICE_QUANTIZATION_HORIZ_Y 0x74 -#define OV511_OMNICE_QUANTIZATION_HORIZ_UV 0x75 -#define OV511_OMNICE_QUANTIZATION_VERT_Y 0x76 -#define OV511_OMNICE_QUANTIZATION_VERT_UV 0x77 -#define OV511_OMNICE_ENABLE 0x78 -#define OV511_OMNICE_LUT_ENABLE 0x79 -#define OV511_OMNICE_Y_LUT_BEGIN 0x80 -#define OV511_OMNICE_Y_LUT_END 0x9F -#define OV511_OMNICE_UV_LUT_BEGIN 0xA0 -#define OV511_OMNICE_UV_LUT_END 0xBF +/* Parallel IO register numbers */ +#define R511_PIO_OPTS 0x38 +#define R511_PIO_DATA 0x39 +#define R511_PIO_BIST 0x3E +#define R518_GPIO_IN 0x55 /* OV518(+) only */ +#define R518_GPIO_OUT 0x56 /* OV518(+) only */ +#define R518_GPIO_CTL 0x57 /* OV518(+) only */ +#define R518_GPIO_PULSE_IN 0x58 /* OV518(+) only */ +#define R518_GPIO_PULSE_CLEAR 0x59 /* OV518(+) only */ +#define R518_GPIO_PULSE_POL 0x5a /* OV518(+) only */ +#define R518_GPIO_PULSE_EN 0x5b /* OV518(+) only */ +#define R518_GPIO_RESET 0x5c /* OV518(+) only */ + +/* I2C registers */ +#define R511_I2C_CTL 0x40 +#define R518_I2C_CTL 0x47 /* OV518(+) only */ +#define R51x_I2C_W_SID 0x41 +#define R51x_I2C_SADDR_3 0x42 +#define R51x_I2C_SADDR_2 0x43 +#define R51x_I2C_R_SID 0x44 +#define R51x_I2C_DATA 0x45 +#define R51x_I2C_CLOCK 0x46 +#define R51x_I2C_TIMEOUT 0x47 + +/* I2C snapshot registers */ +#define R511_SI2C_SADDR_3 0x48 +#define R511_SI2C_DATA 0x49 + +/* System control registers */ +#define R51x_SYS_RESET 0x50 + /* Reset type definitions */ +#define OV511_RESET_UDC 0x01 +#define OV511_RESET_I2C 0x02 +#define OV511_RESET_FIFO 0x04 +#define OV511_RESET_OMNICE 0x08 +#define OV511_RESET_DRAM 0x10 +#define OV511_RESET_CAM_INT 0x20 +#define OV511_RESET_OV511 0x40 +#define OV511_RESET_NOREGS 0x3F /* All but OV511 & regs */ +#define OV511_RESET_ALL 0x7F + +#define R511_SYS_CLOCK_DIV 0x51 +#define R51x_SYS_SNAP 0x52 +#define R51x_SYS_INIT 0x53 +#define R511_SYS_PWR_CLK 0x54 /* OV511+/OV518(+) only */ +#define R511_SYS_LED_CTL 0x55 /* OV511+ only */ +#define R511_SYS_USER 0x5E +#define R511_SYS_CUST_ID 0x5F + +/* OmniCE (compression) registers */ +#define R511_COMP_PHY 0x70 +#define R511_COMP_PHUV 0x71 +#define R511_COMP_PVY 0x72 +#define R511_COMP_PVUV 0x73 +#define R511_COMP_QHY 0x74 +#define R511_COMP_QHUV 0x75 +#define R511_COMP_QVY 0x76 +#define R511_COMP_QVUV 0x77 +#define R511_COMP_EN 0x78 +#define R511_COMP_LUT_EN 0x79 +#define R511_COMP_LUT_BEGIN 0x80 + +/* --------------------------------- */ +/* ALTERNATE NUMBERS */ +/* --------------------------------- */ /* Alternate numbers for various max packet sizes (OV511 only) */ #define OV511_ALT_SIZE_992 0 @@ -159,6 +166,10 @@ #define OV518_ALT_SIZE_768 6 #define OV518_ALT_SIZE_896 7 +/* --------------------------------- */ +/* OV7610 REGISTER MNEMONICS */ +/* --------------------------------- */ + /* OV7610 registers */ #define OV7610_REG_GAIN 0x00 /* gain setting (5:0) */ #define OV7610_REG_BLUE 0x01 /* blue channel balance */ @@ -210,26 +221,27 @@ /* 36-37 reserved */ #define OV7610_REG_COM_K 0x38 /* misc registers */ +/* --------------------------------- */ +/* I2C ADDRESSES */ +/* --------------------------------- */ + +#define OV7xx0_SID 0x42 +#define OV6xx0_SID 0xC0 +#define OV8xx0_SID 0xA0 +#define KS0127_SID 0xD8 +#define SAA7111A_SID 0x48 + +/* --------------------------------- */ +/* MISCELLANEOUS DEFINES */ +/* --------------------------------- */ + +#define I2C_CLOCK_PRESCALER 0x03 + #define FRAMES_PER_DESC 10 /* FIXME - What should this be? */ -#define FRAME_SIZE_PER_DESC 993 /* FIXME - Deprecated */ #define MAX_FRAME_SIZE_PER_DESC 993 /* For statically allocated stuff */ #define PIXELS_PER_SEG 256 /* Pixels per segment */ -#define OV511_ENDPOINT_ADDRESS 1 /* Isoc endpoint number */ - -/* I2C addresses */ -#define OV7xx0_I2C_WRITE_ID 0x42 -#define OV7xx0_I2C_READ_ID 0x43 -#define OV6xx0_I2C_WRITE_ID 0xC0 -#define OV6xx0_I2C_READ_ID 0xC1 -#define OV8xx0_I2C_WRITE_ID 0xA0 -#define OV8xx0_I2C_READ_ID 0xA1 -#define KS0127_I2C_WRITE_ID 0xD8 -#define KS0127_I2C_READ_ID 0xD9 -#define SAA7111A_I2C_WRITE_ID 0x48 -#define SAA7111A_I2C_READ_ID 0x49 - -#define OV511_I2C_CLOCK_PRESCALER 0x03 +#define OV511_ENDPOINT_ADDRESS 1 /* Isoc endpoint number */ /* Bridge types */ enum { @@ -429,11 +441,14 @@ #define OV511_NUMFRAMES 2 #if OV511_NUMFRAMES > VIDEO_MAX_FRAME -#error "OV511_NUMFRAMES is too high" + #error "OV511_NUMFRAMES is too high" #endif #define OV511_NUMSBUF 2 +/* Control transfers use up to 4 bytes */ +#define OV511_CBUF_SIZE 4 + struct usb_ov511 { struct video_device vdev; @@ -535,6 +550,10 @@ /* I2C interface to kernel */ struct semaphore i2c_lock; /* Protect I2C controller regs */ unsigned char primary_i2c_slave; /* I2C write id of sensor */ + + /* Control transaction stuff */ + unsigned char *cbuf; /* Buffer for payload */ + struct semaphore cbuf_lock; }; struct cam_list { diff -Nru a/drivers/usb/pwc-if.c b/drivers/usb/pwc-if.c --- a/drivers/usb/pwc-if.c Tue Feb 26 11:58:00 2002 +++ b/drivers/usb/pwc-if.c Tue Feb 26 11:58:00 2002 @@ -179,28 +179,24 @@ /* Private functions */ /* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = page_address(vmalloc_to_page(va)); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ ret = __pa(kva); return ret; } -static void * rvmalloc(signed long size) +static void * rvmalloc(unsigned long size) { void * mem; - unsigned long adr, page; + unsigned long adr; - /* Round it off to PAGE_SIZE */ - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); - + size=PAGE_ALIGN(size); mem=vmalloc_32(size); if (mem) { @@ -208,8 +204,7 @@ adr=(unsigned long) mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -217,20 +212,16 @@ return mem; } -static void rvfree(void * mem, signed long size) +static void rvfree(void * mem, unsigned long size) { - unsigned long adr, page; - - /* Round it off to PAGE_SIZE */ - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); + unsigned long adr; + if (mem) { adr=(unsigned long) mem; - while (size > 0) + while ((long) size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } diff -Nru a/drivers/usb/se401.c b/drivers/usb/se401.c --- a/drivers/usb/se401.c Tue Feb 26 11:57:58 2002 +++ b/drivers/usb/se401.c Tue Feb 26 11:57:58 2002 @@ -84,15 +84,14 @@ **********************************************************************/ /* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = page_address(vmalloc_to_page(va)); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ ret = __pa(kva); return ret; } @@ -100,12 +99,9 @@ static void *rvmalloc(unsigned long size) { void *mem; - unsigned long adr, page; - - /* Round it off to PAGE_SIZE */ - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); + unsigned long adr; + size = PAGE_ALIGN(size); mem = vmalloc_32(size); if (!mem) return NULL; @@ -113,13 +109,9 @@ memset(mem, 0, size); /* Clear the ram out, no junk to the user */ adr = (unsigned long) mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } return mem; @@ -127,23 +119,16 @@ static void rvfree(void *mem, unsigned long size) { - unsigned long adr, page; + unsigned long adr; if (!mem) return; - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); - - adr=(unsigned long) mem; - while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + adr = (unsigned long) mem; + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } vfree(mem); } diff -Nru a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile --- a/drivers/usb/storage/Makefile Tue Feb 26 11:57:59 2002 +++ b/drivers/usb/storage/Makefile Tue Feb 26 11:57:59 2002 @@ -1,7 +1,7 @@ # # Makefile for the USB Mass Storage device drivers. # -# 15 Aug 2000, Christoph Hellwig +# 15 Aug 2000, Christoph Hellwig # Rewritten to use lists instead of if-statements. # diff -Nru a/drivers/usb/stv680.c b/drivers/usb/stv680.c --- a/drivers/usb/stv680.c Tue Feb 26 11:57:57 2002 +++ b/drivers/usb/stv680.c Tue Feb 26 11:57:57 2002 @@ -127,54 +127,25 @@ * And the STV0680 driver - Kevin ********************************************************************/ -/* Given PGD from the address space's page table, return the kernel - * virtual mapping of the physical memory mapped at ADR. - */ -static inline unsigned long uvirt_to_kva (pgd_t * pgd, unsigned long adr) -{ - unsigned long ret = 0UL; - pmd_t *pmd; - pte_t *ptep, pte; - - if (!pgd_none (*pgd)) { - pmd = pmd_offset (pgd, adr); - if (!pmd_none (*pmd)) { - preempt_disable(); - ptep = pte_offset_map (pmd, adr); - pte = *ptep; - pte_unmap(pte); - preempt_enable(); - if (pte_present (pte)) { - ret = (unsigned long) page_address (pte_page (pte)); - ret |= (adr & (PAGE_SIZE - 1)); - } - } - } - return ret; -} - -/* Here we want the physical address of the memory. This is used when - * initializing the contents of the area and marking the pages as reserved. +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa (unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR (adr); - kva = uvirt_to_kva (pgd_offset_k (va), va); - ret = __pa (kva); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ + ret = __pa(kva); return ret; } static void *rvmalloc (unsigned long size) { void *mem; - unsigned long adr, page; - - /* Round it off to PAGE_SIZE */ - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); + unsigned long adr; + size = PAGE_ALIGN(size); mem = vmalloc_32 (size); if (!mem) return NULL; @@ -182,36 +153,25 @@ memset (mem, 0, size); /* Clear the ram out, no junk to the user */ adr = (unsigned long) mem; while (size > 0) { - page = kvirt_to_pa (adr); - mem_map_reserve (virt_to_page (__va (page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } return mem; } static void rvfree (void *mem, unsigned long size) { - unsigned long adr, page; + unsigned long adr; if (!mem) return; - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); - adr = (unsigned long) mem; - while (size > 0) { - page = kvirt_to_pa (adr); - mem_map_unreserve (virt_to_page (__va (page))); + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } vfree (mem); } diff -Nru a/drivers/usb/uhci.c b/drivers/usb/uhci.c --- a/drivers/usb/uhci.c Tue Feb 26 11:57:58 2002 +++ b/drivers/usb/uhci.c Tue Feb 26 11:57:58 2002 @@ -4,7 +4,7 @@ * Maintainer: Johannes Erdfelt * * (C) Copyright 1999 Linus Torvalds - * (C) Copyright 1999-2001 Johannes Erdfelt, johannes@erdfelt.com + * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com * (C) Copyright 1999 Randy Dunlap * (C) Copyright 1999 Georg Acher, acher@in.tum.de * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de @@ -240,10 +240,10 @@ unsigned long flags; /* If it's not inserted, don't remove it */ + spin_lock_irqsave(&uhci->frame_list_lock, flags); if (td->frame == -1 && list_empty(&td->fl_list)) - return; + goto out; - spin_lock_irqsave(&uhci->frame_list_lock, flags); if (td->frame != -1 && uhci->fl->frame_cpu[td->frame] == td) { if (list_empty(&td->fl_list)) { uhci->fl->frame[td->frame] = td->link; @@ -268,6 +268,7 @@ list_del_init(&td->fl_list); td->frame = -1; +out: spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } @@ -358,6 +359,9 @@ pci_pool_free(uhci->qh_pool, qh, qh->dma_handle); } +/* + * MUST be called with uhci->frame_list_lock acquired + */ static void _uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct urb *urb) { struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; @@ -417,11 +421,10 @@ return; /* Only go through the hoops if it's actually linked in */ + spin_lock_irqsave(&uhci->frame_list_lock, flags); if (!list_empty(&qh->list)) { qh->urbp = NULL; - spin_lock_irqsave(&uhci->frame_list_lock, flags); - pqh = list_entry(qh->list.prev, struct uhci_qh, list); if (pqh->urbp) { @@ -444,9 +447,8 @@ qh->element = qh->link = UHCI_PTR_TERM; list_del_init(&qh->list); - - spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } + spin_unlock_irqrestore(&uhci->frame_list_lock, flags); spin_lock_irqsave(&uhci->qh_remove_list_lock, flags); @@ -658,6 +660,9 @@ return urbp; } +/* + * MUST be called with urb->lock acquired + */ static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td) { struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; @@ -667,6 +672,9 @@ list_add_tail(&td->list, &urbp->td_list); } +/* + * MUST be called with urb->lock acquired + */ static void uhci_remove_td_from_urb(struct uhci_td *td) { if (list_empty(&td->list)) @@ -677,22 +685,22 @@ td->urb = NULL; } +/* + * MUST be called with urb->lock acquired + */ static void uhci_destroy_urb_priv(struct urb *urb) { struct list_head *head, *tmp; struct urb_priv *urbp; struct uhci *uhci; - unsigned long flags; - - spin_lock_irqsave(&urb->lock, flags); urbp = (struct urb_priv *)urb->hcpriv; if (!urbp) - goto out; + return; if (!urbp->dev || !urbp->dev->bus || !urbp->dev->bus->hcpriv) { warn("uhci_destroy_urb_priv: urb %p belongs to disconnected device or bus?", urb); - goto out; + return; } if (!list_empty(&urb->urb_list)) @@ -715,20 +723,21 @@ uhci_free_td(uhci, td); } - if (urbp->setup_packet_dma_handle) + if (urbp->setup_packet_dma_handle) { pci_unmap_single(uhci->dev, urbp->setup_packet_dma_handle, sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE); + urbp->setup_packet_dma_handle = 0; + } - if (urbp->transfer_buffer_dma_handle) + if (urbp->transfer_buffer_dma_handle) { pci_unmap_single(uhci->dev, urbp->transfer_buffer_dma_handle, urb->transfer_buffer_length, usb_pipein(urb->pipe) ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); + urbp->transfer_buffer_dma_handle = 0; + } urb->hcpriv = NULL; kmem_cache_free(uhci_up_cachep, urbp); - -out: - spin_unlock_irqrestore(&urb->lock, flags); } static void uhci_inc_fsbr(struct uhci *uhci, struct urb *urb) @@ -872,7 +881,7 @@ * It's IN if the pipe is an output pipe or we're not expecting * data back. */ - destination &= ~TD_PID; + destination &= ~TD_TOKEN_PID_MASK; if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length) destination |= USB_PID_IN; else @@ -1312,9 +1321,7 @@ struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; struct list_head *tmp, *head; int ret = 0; - unsigned long flags; - spin_lock_irqsave(&uhci->urb_list_lock, flags); head = &uhci->urb_list; tmp = head->next; while (tmp != head) { @@ -1337,8 +1344,6 @@ } else ret = -1; /* no previous urb found */ - spin_unlock_irqrestore(&uhci->urb_list_lock, flags); - return ret; } @@ -1446,34 +1451,30 @@ return ret; } +/* + * MUST be called with uhci->urb_list_lock acquired + */ static struct urb *uhci_find_urb_ep(struct uhci *uhci, struct urb *urb) { struct list_head *tmp, *head; - unsigned long flags; - struct urb *u = NULL; /* We don't match Isoc transfers since they are special */ if (usb_pipeisoc(urb->pipe)) return NULL; - spin_lock_irqsave(&uhci->urb_list_lock, flags); head = &uhci->urb_list; tmp = head->next; while (tmp != head) { - u = list_entry(tmp, struct urb, urb_list); + struct urb *u = list_entry(tmp, struct urb, urb_list); tmp = tmp->next; if (u->dev == urb->dev && u->pipe == urb->pipe && u->status == -EINPROGRESS) - goto out; + return u; } - u = NULL; - -out: - spin_unlock_irqrestore(&uhci->urb_list_lock, flags); - return u; + return NULL; } static int uhci_submit_urb(struct urb *urb, int mem_flags) @@ -1492,19 +1493,25 @@ return -ENODEV; } + /* increment the reference count of the urb, as we now also control it */ + urb = usb_get_urb(urb); + uhci = (struct uhci *)urb->dev->bus->hcpriv; INIT_LIST_HEAD(&urb->urb_list); usb_inc_dev_use(urb->dev); - spin_lock_irqsave(&urb->lock, flags); + spin_lock_irqsave(&uhci->urb_list_lock, flags); + spin_lock(&urb->lock); if (urb->status == -EINPROGRESS || urb->status == -ECONNRESET || urb->status == -ECONNABORTED) { dbg("uhci_submit_urb: urb not available to submit (status = %d)", urb->status); /* Since we can have problems on the out path */ - spin_unlock_irqrestore(&urb->lock, flags); + spin_unlock(&urb->lock); + spin_unlock_irqrestore(&uhci->urb_list_lock, flags); usb_dec_dev_use(urb->dev); + usb_put_urb(urb); return ret; } @@ -1572,18 +1579,21 @@ out: urb->status = ret; - spin_unlock_irqrestore(&urb->lock, flags); - if (ret == -EINPROGRESS) { - spin_lock_irqsave(&uhci->urb_list_lock, flags); /* We use _tail to make find_urb_ep more efficient */ list_add_tail(&urb->urb_list, &uhci->urb_list); + + spin_unlock(&urb->lock); spin_unlock_irqrestore(&uhci->urb_list_lock, flags); return 0; } uhci_unlink_generic(uhci, urb); + + spin_unlock(&urb->lock); + spin_unlock_irqrestore(&uhci->urb_list_lock, flags); + uhci_call_completion(urb); return ret; @@ -1592,7 +1602,7 @@ /* * Return the result of a transfer * - * Must be called with urb_list_lock acquired + * MUST be called with urb_list_lock acquired */ static void uhci_transfer_result(struct uhci *uhci, struct urb *urb) { @@ -1631,10 +1641,10 @@ urbp->status = ret; - spin_unlock_irqrestore(&urb->lock, flags); - - if (ret == -EINPROGRESS) + if (ret == -EINPROGRESS) { + spin_unlock_irqrestore(&urb->lock, flags); return; + } switch (usb_pipetype(urb->pipe)) { case PIPE_CONTROL: @@ -1664,15 +1674,22 @@ usb_pipetype(urb->pipe), urb); } + /* Remove it from uhci->urb_list */ list_del_init(&urb->urb_list); uhci_add_complete(urb); + + spin_unlock_irqrestore(&urb->lock, flags); } +/* + * MUST be called with urb->lock acquired + */ static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb) { struct list_head *head, *tmp; struct urb_priv *urbp = urb->hcpriv; + int prevactive = 1; /* We can get called when urbp allocation fails, so check */ if (!urbp) @@ -1680,6 +1697,19 @@ uhci_dec_fsbr(uhci, urb); /* Safe since it checks */ + /* + * Now we need to find out what the last successful toggle was + * so we can update the local data toggle for the next transfer + * + * There's 3 way's the last successful completed TD is found: + * + * 1) The TD is NOT active and the actual length < expected length + * 2) The TD is NOT active and it's the last TD in the chain + * 3) The TD is active and the previous TD is NOT active + * + * Control and Isochronous ignore the toggle, so this is safe + * for all types + */ head = &urbp->td_list; tmp = head->next; while (tmp != head) { @@ -1687,15 +1717,18 @@ tmp = tmp->next; - /* Control and Isochronous ignore the toggle, so this */ - /* is safe for all types */ - if ((!(td->status & TD_CTRL_ACTIVE) && - (uhci_actual_length(td->status) < uhci_expected_length(td->info)) || - tmp == head)) { + if (!(td->status & TD_CTRL_ACTIVE) && + (uhci_actual_length(td->status) < uhci_expected_length(td->info) || + tmp == head)) usb_settoggle(urb->dev, uhci_endpoint(td->info), uhci_packetout(td->info), uhci_toggle(td->info) ^ 1); - } + else if ((td->status & TD_CTRL_ACTIVE) && !prevactive) + usb_settoggle(urb->dev, uhci_endpoint(td->info), + uhci_packetout(td->info), + uhci_toggle(td->info)); + + prevactive = td->status & TD_CTRL_ACTIVE; } uhci_delete_queued_urb(uhci, urb); @@ -1718,6 +1751,9 @@ uhci = (struct uhci *)urb->dev->bus->hcpriv; + spin_lock_irqsave(&uhci->urb_list_lock, flags); + spin_lock(&urb->lock); + /* Release bandwidth for Interrupt or Isoc. transfers */ /* Spinlock needed ? */ if (urb->bandwidth) { @@ -1733,35 +1769,41 @@ } } - if (urb->status != -EINPROGRESS) + if (urb->status != -EINPROGRESS) { + spin_unlock(&urb->lock); + spin_unlock_irqrestore(&uhci->urb_list_lock, flags); return 0; + } - spin_lock_irqsave(&uhci->urb_list_lock, flags); list_del_init(&urb->urb_list); - spin_unlock_irqrestore(&uhci->urb_list_lock, flags); uhci_unlink_generic(uhci, urb); /* Short circuit the virtual root hub */ if (urb->dev == uhci->rh.dev) { rh_unlink_urb(urb); + + spin_unlock(&urb->lock); + spin_unlock_irqrestore(&uhci->urb_list_lock, flags); + uhci_call_completion(urb); } else { if (urb->transfer_flags & USB_ASYNC_UNLINK) { - /* urb_list is available now since we called */ - /* uhci_unlink_generic already */ - urbp->status = urb->status = -ECONNABORTED; - spin_lock_irqsave(&uhci->urb_remove_list_lock, flags); + spin_lock(&uhci->urb_remove_list_lock); - /* Check to see if the remove list is empty */ + /* If we're the first, set the next interrupt bit */ if (list_empty(&uhci->urb_remove_list)) uhci_set_next_interrupt(uhci); list_add(&urb->urb_list, &uhci->urb_remove_list); - spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags); + spin_unlock(&uhci->urb_remove_list_lock); + + spin_unlock(&urb->lock); + spin_unlock_irqrestore(&uhci->urb_list_lock, flags); + } else { urb->status = -ENOENT; @@ -1774,6 +1816,9 @@ } else schedule_timeout(1+1*HZ/1000); + spin_unlock(&urb->lock); + spin_unlock_irqrestore(&uhci->urb_list_lock, flags); + uhci_call_completion(urb); } } @@ -1907,12 +1952,14 @@ /* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */ static int rh_send_irq(struct urb *urb) { - int i, len = 1; struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; + struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; unsigned int io_addr = uhci->io_addr; + unsigned long flags; + int i, len = 1; __u16 data = 0; - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; + spin_lock_irqsave(&urb->lock, flags); for (i = 0; i < uhci->rh.numports; i++) { data |= ((inw(io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i + 1)) : 0); len = (i + 1) / 8 + 1; @@ -1922,6 +1969,8 @@ urb->actual_length = len; urbp->status = 0; + spin_unlock_irqrestore(&urb->lock, flags); + if ((data > 0) && (uhci->rh.send != 0)) { dbg("root-hub INT complete: port1: %x port2: %x data: %x", inw(io_addr + USBPORTSC1), inw(io_addr + USBPORTSC2), data); @@ -1948,7 +1997,6 @@ spin_lock_irqsave(&uhci->urb_list_lock, flags); head = &uhci->urb_list; - tmp = head->next; while (tmp != head) { struct urb *u = list_entry(tmp, struct urb, urb_list); @@ -1956,6 +2004,8 @@ tmp = tmp->next; + spin_lock(&urb->lock); + /* Check if the FSBR timed out */ if (urbp->fsbr && !urbp->fsbr_timeout && time_after_eq(jiffies, urbp->fsbrtime + IDLE_TIMEOUT)) uhci_fsbr_timeout(uhci, u); @@ -1965,6 +2015,8 @@ list_del(&u->urb_list); list_add_tail(&u->urb_list, &list); } + + spin_unlock(&urb->lock); } spin_unlock_irqrestore(&uhci->urb_list_lock, flags); @@ -2198,6 +2250,9 @@ return stat; } +/* + * MUST be called with urb->lock acquired + */ static int rh_unlink_urb(struct urb *urb) { struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; @@ -2233,16 +2288,25 @@ static void uhci_call_completion(struct urb *urb) { - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; + struct urb_priv *urbp; struct usb_device *dev = urb->dev; struct uhci *uhci = (struct uhci *)dev->bus->hcpriv; int is_ring = 0, killed, resubmit_interrupt, status; struct urb *nurb; + unsigned long flags; + + spin_lock_irqsave(&urb->lock, flags); + + urbp = (struct urb_priv *)urb->hcpriv; + if (!urbp || !urb->dev) { + spin_unlock_irqrestore(&urb->lock, flags); + return; + } killed = (urb->status == -ENOENT || urb->status == -ECONNABORTED || urb->status == -ECONNRESET); resubmit_interrupt = (usb_pipetype(urb->pipe) == PIPE_INTERRUPT && - urb->interval && !killed); + urb->interval); nurb = urb->next; if (nurb && !killed) { @@ -2267,14 +2331,6 @@ is_ring = (nurb == urb); } - status = urbp->status; - if (!resubmit_interrupt) - /* We don't need urb_priv anymore */ - uhci_destroy_urb_priv(urb); - - if (!killed) - urb->status = status; - if (urbp->transfer_buffer_dma_handle) pci_dma_sync_single(uhci->dev, urbp->transfer_buffer_dma_handle, urb->transfer_buffer_length, usb_pipein(urb->pipe) ? @@ -2284,11 +2340,28 @@ pci_dma_sync_single(uhci->dev, urbp->setup_packet_dma_handle, sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE); + status = urbp->status; + if (!resubmit_interrupt || killed) + /* We don't need urb_priv anymore */ + uhci_destroy_urb_priv(urb); + + if (!killed) + urb->status = status; + urb->dev = NULL; - if (urb->complete) + spin_unlock_irqrestore(&urb->lock, flags); + + if (urb->complete) { urb->complete(urb); - if (resubmit_interrupt) { + /* Recheck the status. The completion handler may have */ + /* unlinked the resubmitting interrupt URB */ + killed = (urb->status == -ENOENT || + urb->status == -ECONNABORTED || + urb->status == -ECONNRESET); + } + + if (resubmit_interrupt && !killed) { urb->dev = dev; uhci_reset_interrupt(urb); } else { @@ -2299,6 +2372,7 @@ /* We decrement the usage count after we're done */ /* with everything */ usb_dec_dev_use(dev); + usb_put_urb(urb); } } } @@ -2315,11 +2389,14 @@ struct urb_priv *urbp = list_entry(tmp, struct urb_priv, complete_list); struct urb *urb = urbp->urb; - tmp = tmp->next; - list_del_init(&urbp->complete_list); + spin_unlock_irqrestore(&uhci->complete_list_lock, flags); uhci_call_completion(urb); + + spin_lock_irqsave(&uhci->complete_list_lock, flags); + head = &uhci->complete_list; + tmp = head->next; } spin_unlock_irqrestore(&uhci->complete_list_lock, flags); } @@ -2341,7 +2418,8 @@ list_del_init(&urb->urb_list); urbp->status = urb->status = -ECONNRESET; - uhci_call_completion(urb); + + uhci_add_complete(urb); } spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags); } @@ -2996,7 +3074,7 @@ id_table: uhci_pci_ids, probe: uhci_pci_probe, - remove: uhci_pci_remove, + remove: __devexit_p(uhci_pci_remove), #ifdef CONFIG_PM suspend: uhci_pci_suspend, @@ -3074,3 +3152,4 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); + diff -Nru a/drivers/usb/uhci.h b/drivers/usb/uhci.h --- a/drivers/usb/uhci.h Tue Feb 26 11:57:57 2002 +++ b/drivers/usb/uhci.h Tue Feb 26 11:57:57 2002 @@ -121,15 +121,16 @@ * for TD : (a.k.a. Token) */ #define TD_TOKEN_TOGGLE 19 -#define TD_PID 0xFF +#define TD_TOKEN_PID_MASK 0xFF +#define TD_TOKEN_EXPLEN_MASK 0x7FF /* expected length, encoded as n - 1 */ #define uhci_maxlen(token) ((token) >> 21) -#define uhci_expected_length(info) (((info >> 21) + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */ +#define uhci_expected_length(info) (((info >> 21) + 1) & TD_TOKEN_EXPLEN_MASK) /* 1-based */ #define uhci_toggle(token) (((token) >> TD_TOKEN_TOGGLE) & 1) #define uhci_endpoint(token) (((token) >> 15) & 0xf) #define uhci_devaddr(token) (((token) >> 8) & 0x7f) #define uhci_devep(token) (((token) >> 8) & 0x7ff) -#define uhci_packetid(token) ((token) & 0xff) +#define uhci_packetid(token) ((token) & TD_TOKEN_PID_MASK) #define uhci_packetout(token) (uhci_packetid(token) != USB_PID_IN) #define uhci_packetin(token) (uhci_packetid(token) == USB_PID_IN) @@ -163,7 +164,7 @@ struct list_head list; /* P: urb->lock */ int frame; - struct list_head fl_list; /* P: frame_list_lock */ + struct list_head fl_list; /* P: uhci->frame_list_lock */ } __attribute__((aligned(16))); /* @@ -306,21 +307,25 @@ struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */ spinlock_t frame_list_lock; - struct uhci_frame_list *fl; /* Frame list */ + struct uhci_frame_list *fl; /* P: uhci->frame_list_lock */ int fsbr; /* Full speed bandwidth reclamation */ int is_suspended; + /* Main list of URB's currently controlled by this HC */ + spinlock_t urb_list_lock; + struct list_head urb_list; /* P: uhci->urb_list_lock */ + + /* List of QH's that are done, but waiting to be unlinked (race) */ spinlock_t qh_remove_list_lock; - struct list_head qh_remove_list; + struct list_head qh_remove_list; /* P: uhci->qh_remove_list_lock */ + /* List of asynchronously unlinked URB's */ spinlock_t urb_remove_list_lock; - struct list_head urb_remove_list; - - spinlock_t urb_list_lock; - struct list_head urb_list; + struct list_head urb_remove_list; /* P: uhci->urb_remove_list_lock */ + /* List of URB's awaiting completion callback */ spinlock_t complete_list_lock; - struct list_head complete_list; + struct list_head complete_list; /* P: uhci->complete_list_lock */ struct virt_root_hub rh; /* private data of the virtual root hub */ }; @@ -333,7 +338,7 @@ dma_addr_t transfer_buffer_dma_handle; struct uhci_qh *qh; /* QH for this URB */ - struct list_head td_list; + struct list_head td_list; /* P: urb->lock */ int fsbr : 1; /* URB turned on FSBR */ int fsbr_timeout : 1; /* URB timed out on FSBR */ @@ -345,11 +350,36 @@ int status; /* Final status */ unsigned long inserttime; /* In jiffies */ - unsigned long fsbrtime; /* In jiffies */ + unsigned long fsbrtime; /* In jiffies */ - struct list_head queue_list; - struct list_head complete_list; + struct list_head queue_list; /* P: uhci->frame_list_lock */ + struct list_head complete_list; /* P: uhci->complete_list_lock */ }; + +/* + * Locking in uhci.c + * + * spinlocks are used extensively to protect the many lists and data + * structures we have. It's not that pretty, but it's necessary. We + * need to be done with all of the locks (except complete_list_lock) when + * we call urb->complete. I've tried to make it simple enough so I don't + * have to spend hours racking my brain trying to figure out if the + * locking is safe. + * + * Here's the safe locking order to prevent deadlocks: + * + * #1 uhci->urb_list_lock + * #2 urb->lock + * #3 uhci->urb_remove_list_lock, uhci->frame_list_lock, + * uhci->qh_remove_list_lock + * #4 uhci->complete_list_lock + * + * If you're going to grab 2 or more locks at once, ALWAYS grab the lock + * at the lowest level FIRST and NEVER grab locks at the same level at the + * same time. + * + * So, if you need uhci->urb_list_lock, grab it before you grab urb->lock + */ /* ------------------------------------------------------------------------- Virtual Root HUB diff -Nru a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c --- a/drivers/usb/usb-ohci.c Tue Feb 26 11:57:58 2002 +++ b/drivers/usb/usb-ohci.c Tue Feb 26 11:57:58 2002 @@ -205,6 +205,7 @@ urb_free_priv ((struct ohci *)urb->dev->bus->hcpriv, urb_priv); usb_dec_dev_use (urb->dev); urb->dev = NULL; + usb_put_urb (urb); } } @@ -553,6 +554,9 @@ // if(usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe))) // return -EPIPE; + /* increment the reference count of the urb, as we now also control it */ + urb = usb_get_urb (urb); + usb_inc_dev_use (urb->dev); ohci = (ohci_t *) urb->dev->bus->hcpriv; @@ -568,12 +572,14 @@ * such as powering down ports */ if (ohci->disabled) { usb_dec_dev_use (urb->dev); + usb_put_urb (urb); return -ESHUTDOWN; } /* every endpoint has a ed, locate and fill it */ if (!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1, mem_flags))) { usb_dec_dev_use (urb->dev); + usb_put_urb (urb); return -ENOMEM; } @@ -595,6 +601,7 @@ size = urb->number_of_packets; if (size <= 0) { usb_dec_dev_use (urb->dev); + usb_put_urb (urb); return -EINVAL; } for (i = 0; i < urb->number_of_packets; i++) { @@ -615,6 +622,7 @@ urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (td_t *), mem_flags); if (!urb_priv) { usb_dec_dev_use (urb->dev); + usb_put_urb (urb); return -ENOMEM; } memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (td_t *)); @@ -632,6 +640,7 @@ urb_free_priv (ohci, urb_priv); spin_unlock_irqrestore (&usb_ed_lock, flags); usb_dec_dev_use (urb->dev); + usb_put_urb (urb); return -ENOMEM; } } @@ -640,6 +649,7 @@ urb_free_priv (ohci, urb_priv); spin_unlock_irqrestore (&usb_ed_lock, flags); usb_dec_dev_use (urb->dev); + usb_put_urb (urb); return -EINVAL; } @@ -662,6 +672,7 @@ urb_free_priv (ohci, urb_priv); spin_unlock_irqrestore (&usb_ed_lock, flags); usb_dec_dev_use (urb->dev); + usb_put_urb (urb); return bustime; } usb_claim_bandwidth (urb->dev, urb, bustime, usb_pipeisoc (urb->pipe)); @@ -2100,6 +2111,7 @@ urb->dev = NULL; if (urb->complete) urb->complete (urb); + usb_put_urb (urb); return 0; } @@ -2123,6 +2135,7 @@ urb->complete (urb); } else urb->status = -ENOENT; + usb_put_urb (urb); } return 0; } @@ -2859,7 +2872,7 @@ id_table: &ohci_pci_ids [0], probe: ohci_pci_probe, - remove: ohci_pci_remove, + remove: __devexit_p(ohci_pci_remove), #ifdef CONFIG_PM suspend: ohci_pci_suspend, diff -Nru a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c --- a/drivers/usb/usb-uhci.c Tue Feb 26 11:57:59 2002 +++ b/drivers/usb/usb-uhci.c Tue Feb 26 11:57:59 2002 @@ -1217,6 +1217,7 @@ urb->complete ((struct urb *) urb); } usb_dec_dev_use (usb_dev); + usb_put_urb (urb); } else spin_unlock_irqrestore (&s->urb_list_lock, flags); @@ -1305,7 +1306,7 @@ #else kfree (urb_priv); #endif - + usb_put_urb (urb); } } } @@ -1650,6 +1651,9 @@ return -EINVAL; } + /* increment the reference count of the urb, as we now also control it */ + urb = usb_get_urb (urb); + usb_inc_dev_use (urb->dev); spin_lock_irqsave (&s->urb_list_lock, flags); @@ -1665,6 +1669,7 @@ (!(urb->transfer_flags & USB_QUEUE_BULK) || !(queued_urb->transfer_flags & USB_QUEUE_BULK)))) { spin_unlock_irqrestore (&s->urb_list_lock, flags); usb_dec_dev_use (urb->dev); + usb_put_urb (urb); err("ENXIO %08x, flags %x, urb %p, burb %p",urb->pipe,urb->transfer_flags,urb,queued_urb); return -ENXIO; // urb already queued } @@ -1678,6 +1683,7 @@ if (!urb_priv) { usb_dec_dev_use (urb->dev); spin_unlock_irqrestore (&s->urb_list_lock, flags); + usb_put_urb (urb); return -ENOMEM; } @@ -1766,6 +1772,7 @@ #else kfree (urb_priv); #endif + usb_put_urb (urb); return ret; } @@ -2730,6 +2737,7 @@ } usb_dec_dev_use (usb_dev); + usb_put_urb (urb); } } diff -Nru a/drivers/usb/usbvideo.c b/drivers/usb/usbvideo.c --- a/drivers/usb/usbvideo.c Tue Feb 26 11:57:59 2002 +++ b/drivers/usb/usbvideo.c Tue Feb 26 11:57:59 2002 @@ -59,33 +59,26 @@ /* Memory management functions */ /*******************************/ -#define MDEBUG(x) do { } while(0) /* Debug memory management */ - /* * Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ unsigned long usbvideo_kvirt_to_pa(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = page_address(vmalloc_to_page(va)); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ ret = __pa(kva); - MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); return ret; } void *usbvideo_rvmalloc(unsigned long size) { void *mem; - unsigned long adr, page; - - /* Round it off to PAGE_SIZE */ - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); + unsigned long adr; + size = PAGE_ALIGN(size); mem = vmalloc_32(size); if (!mem) return NULL; @@ -93,13 +86,9 @@ memset(mem, 0, size); /* Clear the ram out, no junk to the user */ adr = (unsigned long) mem; while (size > 0) { - page = usbvideo_kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } return mem; @@ -107,23 +96,16 @@ void usbvideo_rvfree(void *mem, unsigned long size) { - unsigned long adr, page; + unsigned long adr; if (!mem) return; - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); - - adr=(unsigned long) mem; - while (size > 0) { - page = usbvideo_kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + adr = (unsigned long) mem; + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } vfree(mem); } diff -Nru a/drivers/usb/vicam.c b/drivers/usb/vicam.c --- a/drivers/usb/vicam.c Tue Feb 26 11:57:58 2002 +++ b/drivers/usb/vicam.c Tue Feb 26 11:57:58 2002 @@ -40,6 +40,8 @@ #include #include #include +#include +#include #include #include #include @@ -91,83 +93,25 @@ * ******************************************************************************/ -/* [DaveM] I've recoded most of this so that: - * 1) It's easier to tell what is happening - * 2) It's more portable, especially for translating things - * out of vmalloc mapped areas in the kernel. - * 3) Less unnecessary translations happen. - * - * The code used to assume that the kernel vmalloc mappings - * existed in the page tables of every process, this is simply - * not guarenteed. We now use pgd_offset_k which is the - * defined way to get at the kernel page tables. - */ - -/* Given PGD from the address space's page table, return the kernel - * virtual mapping of the physical memory mapped at ADR. - */ -static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) -{ - unsigned long ret = 0UL; - pmd_t *pmd; - pte_t *ptep, pte; - - if (!pgd_none(*pgd)) { - pmd = pmd_offset(pgd, adr); - if (!pmd_none(*pmd)) { - preempt_disable(); - ptep = pte_offset_map(pmd, adr); - pte = *ptep; - pte_unmap(pte); - preempt_enable(); - if(pte_present(pte)) { - ret = (unsigned long) page_address(pte_page(pte)); - ret |= (adr & (PAGE_SIZE - 1)); - - } - } - } - return ret; -} - -static inline unsigned long uvirt_to_bus(unsigned long adr) -{ - unsigned long kva, ret; - - kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr); - ret = virt_to_bus((void *)kva); - return ret; -} - -static inline unsigned long kvirt_to_bus(unsigned long adr) -{ - unsigned long va, kva, ret; - - va = VMALLOC_VMADDR(adr); - kva = uvirt_to_kva(pgd_offset_k(va), va); - ret = virt_to_bus((void *)kva); - return ret; -} - /* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = uvirt_to_kva(pgd_offset_k(va), va); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ ret = __pa(kva); return ret; } -static void * rvmalloc(signed long size) +static void * rvmalloc(unsigned long size) { void * mem; - unsigned long adr, page; + unsigned long adr; + size=PAGE_ALIGN(size); mem=vmalloc_32(size); if (mem) { @@ -175,8 +119,7 @@ adr=(unsigned long) mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -184,17 +127,16 @@ return mem; } -static void rvfree(void * mem, signed long size) +static void rvfree(void * mem, unsigned long size) { - unsigned long adr, page; + unsigned long adr; if (mem) { adr=(unsigned long) mem; - while (size > 0) + while ((long) size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } diff -Nru a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c --- a/drivers/video/cyber2000fb.c Tue Feb 26 11:57:57 2002 +++ b/drivers/video/cyber2000fb.c Tue Feb 26 11:57:58 2002 @@ -1683,7 +1683,7 @@ static struct pci_driver cyberpro_driver = { name: "CyberPro", probe: cyberpro_probe, - remove: cyberpro_remove, + remove: __devexit_p(cyberpro_remove), suspend: cyberpro_suspend, resume: cyberpro_resume, id_table: cyberpro_pci_table diff -Nru a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c --- a/drivers/video/imsttfb.c Tue Feb 26 11:57:59 2002 +++ b/drivers/video/imsttfb.c Tue Feb 26 11:57:59 2002 @@ -1643,7 +1643,7 @@ name: "imsttfb", id_table: imsttfb_pci_tbl, probe: imsttfb_probe, - remove: imsttfb_remove, + remove: __devexit_p(imsttfb_remove), }; static struct fb_ops imsttfb_ops = { diff -Nru a/drivers/video/neofb.c b/drivers/video/neofb.c --- a/drivers/video/neofb.c Tue Feb 26 11:57:56 2002 +++ b/drivers/video/neofb.c Tue Feb 26 11:57:56 2002 @@ -2332,7 +2332,7 @@ name: "neofb", id_table: neofb_devices, probe: neofb_probe, - remove: neofb_remove + remove: __devexit_p(neofb_remove) }; /* **************************** init-time only **************************** */ diff -Nru a/drivers/video/radeonfb.c b/drivers/video/radeonfb.c --- a/drivers/video/radeonfb.c Tue Feb 26 11:58:00 2002 +++ b/drivers/video/radeonfb.c Tue Feb 26 11:58:00 2002 @@ -619,7 +619,7 @@ name: "radeonfb", id_table: radeonfb_pci_table, probe: radeonfb_pci_register, - remove: radeonfb_pci_unregister, + remove: __devexit_p(radeonfb_pci_unregister), }; diff -Nru a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c --- a/drivers/video/riva/fbdev.c Tue Feb 26 11:57:57 2002 +++ b/drivers/video/riva/fbdev.c Tue Feb 26 11:57:57 2002 @@ -1811,7 +1811,7 @@ info = &rinfo->info; strcpy(info->modename, rinfo->drvr_name); - info->node = -1; + info->node = NODEV; info->flags = FBINFO_FLAG_DEFAULT; info->fbops = &riva_fb_ops; @@ -2082,7 +2082,7 @@ name: "rivafb", id_table: rivafb_pci_tbl, probe: rivafb_init_one, - remove: rivafb_remove_one, + remove: __devexit_p(rivafb_remove_one), }; diff -Nru a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c --- a/drivers/video/tdfxfb.c Tue Feb 26 11:57:58 2002 +++ b/drivers/video/tdfxfb.c Tue Feb 26 11:57:58 2002 @@ -495,7 +495,7 @@ name: "tdfxfb", id_table: tdfxfb_id_table, probe: tdfxfb_probe, - remove: tdfxfb_remove, + remove: __devexit_p(tdfxfb_remove), }; MODULE_DEVICE_TABLE(pci, tdfxfb_id_table); diff -Nru a/fs/Makefile b/fs/Makefile --- a/fs/Makefile Tue Feb 26 11:57:56 2002 +++ b/fs/Makefile Tue Feb 26 11:57:56 2002 @@ -1,7 +1,7 @@ # # Makefile for the Linux filesystems. # -# 14 Sep 2000, Christoph Hellwig +# 14 Sep 2000, Christoph Hellwig # Rewritten to use lists instead of if-statements. # diff -Nru a/fs/bad_inode.c b/fs/bad_inode.c --- a/fs/bad_inode.c Tue Feb 26 11:57:57 2002 +++ b/fs/bad_inode.c Tue Feb 26 11:57:57 2002 @@ -17,9 +17,7 @@ */ static int bad_follow_link(struct dentry *dent, struct nameidata *nd) { - dput(nd->dentry); - nd->dentry = dget(dent); - return 0; + return vfs_follow_link(nd, ERR_PTR(-EIO)); } static int return_EIO(void) diff -Nru a/fs/dcache.c b/fs/dcache.c --- a/fs/dcache.c Tue Feb 26 11:57:57 2002 +++ b/fs/dcache.c Tue Feb 26 11:57:57 2002 @@ -30,6 +30,7 @@ /* #define DCACHE_DEBUG 1 */ spinlock_t dcache_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; +rwlock_t dparent_lock __cacheline_aligned_in_smp = RW_LOCK_UNLOCKED; /* Right now the dcache depends on the kernel lock */ #define check_lock() if (!kernel_locked()) BUG() @@ -916,7 +917,9 @@ /* Switch the parents and the names.. */ switch_names(dentry, target); + write_lock(&dparent_lock); do_switch(dentry->d_parent, target->d_parent); + write_unlock(&dparent_lock); do_switch(dentry->d_name.len, target->d_name.len); do_switch(dentry->d_name.hash, target->d_name.hash); diff -Nru a/fs/fat/inode.c b/fs/fat/inode.c --- a/fs/fat/inode.c Tue Feb 26 11:57:59 2002 +++ b/fs/fat/inode.c Tue Feb 26 11:57:59 2002 @@ -516,7 +516,9 @@ fh[1] = inode->i_generation; fh[2] = MSDOS_I(inode)->i_location; fh[3] = MSDOS_I(inode)->i_logstart; + read_lock(&dparent_lock); fh[4] = MSDOS_I(de->d_parent->d_inode)->i_logstart; + read_unlock(&dparent_lock); return 3; } @@ -625,6 +627,18 @@ } b = (struct fat_boot_sector *) bh->b_data; + if (!b->reserved) { + if (!silent) + printk("FAT: bogus number of reserved sectors\n"); + brelse(bh); + goto out_invalid; + } + if (!b->fats) { + if (!silent) + printk("FAT: bogus number of FAT structure\n"); + brelse(bh); + goto out_invalid; + } if (!b->secs_track) { if (!silent) printk("FAT: bogus sectors-per-track value\n"); diff -Nru a/fs/file.c b/fs/file.c --- a/fs/file.c Tue Feb 26 11:57:56 2002 +++ b/fs/file.c Tue Feb 26 11:57:56 2002 @@ -1,5 +1,5 @@ /* - * linux/fs/open.c + * linux/fs/file.c * * Copyright (C) 1998-1999, Stephen Tweedie and Bill Hawes * diff -Nru a/fs/inode.c b/fs/inode.c --- a/fs/inode.c Tue Feb 26 11:57:59 2002 +++ b/fs/inode.c Tue Feb 26 11:57:59 2002 @@ -144,6 +144,8 @@ INIT_LIST_HEAD(&inode->i_devices); sema_init(&inode->i_sem, 1); spin_lock_init(&inode->i_data.i_shared_lock); + INIT_LIST_HEAD(&inode->i_data.i_mmap); + INIT_LIST_HEAD(&inode->i_data.i_mmap_shared); } static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) diff -Nru a/fs/intermezzo/kml_reint.c b/fs/intermezzo/kml_reint.c --- a/fs/intermezzo/kml_reint.c Tue Feb 26 11:58:00 2002 +++ b/fs/intermezzo/kml_reint.c Tue Feb 26 11:58:00 2002 @@ -280,7 +280,7 @@ old_fs = get_fs(); set_fs (get_ds()); error = lento_mknod (mknod->path, mknod->mode, - MKDEV(mknod->major, mknod->minor), &info); + mk_kdev(mknod->major, mknod->minor), &info); set_fs (old_fs); kmlreint_post_secure (rec); EXIT; diff -Nru a/fs/intermezzo/psdev.c b/fs/intermezzo/psdev.c --- a/fs/intermezzo/psdev.c Tue Feb 26 11:57:58 2002 +++ b/fs/intermezzo/psdev.c Tue Feb 26 11:57:58 2002 @@ -789,7 +789,7 @@ } error = lento_mknod(input.name, input.mode, - MKDEV(input.major,input.minor),&input.info); + mk_kdev(input.major,input.minor),&input.info); EXIT; return error; } diff -Nru a/fs/locks.c b/fs/locks.c --- a/fs/locks.c Tue Feb 26 11:57:59 2002 +++ b/fs/locks.c Tue Feb 26 11:57:59 2002 @@ -1459,7 +1459,7 @@ (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) { struct address_space *mapping = inode->i_mapping; - if (mapping->i_mmap_shared != NULL) { + if (!list_empty(&mapping->i_mmap_shared)) { error = -EAGAIN; goto out_putf; } @@ -1615,7 +1615,7 @@ (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) { struct address_space *mapping = inode->i_mapping; - if (mapping->i_mmap_shared != NULL) { + if (!list_empty(&mapping->i_mmap_shared)) { error = -EAGAIN; goto out_putf; } diff -Nru a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c --- a/fs/ncpfs/dir.c Tue Feb 26 11:57:56 2002 +++ b/fs/ncpfs/dir.c Tue Feb 26 11:57:56 2002 @@ -257,12 +257,18 @@ __ncp_lookup_validate(struct dentry * dentry, int flags) { struct ncp_server *server; - struct inode *dir = dentry->d_parent->d_inode; + struct dentry *parent; + struct inode *dir; struct ncp_entry_info finfo; int res, val = 0, len = dentry->d_name.len + 1; __u8 __name[len]; - if (!dentry->d_inode || !dir) + read_lock(&dparent_lock); + parent = dget(dentry->d_parent); + read_unlock(&dparent_lock); + dir = parent->d_inode; + + if (!dentry->d_inode) goto finished; server = NCP_SERVER(dir); @@ -313,6 +319,7 @@ finished: DDPRINTK("ncp_lookup_validate: result=%d\n", val); + dput(parent); return val; } diff -Nru a/fs/nfs/dir.c b/fs/nfs/dir.c --- a/fs/nfs/dir.c Tue Feb 26 11:57:59 2002 +++ b/fs/nfs/dir.c Tue Feb 26 11:57:59 2002 @@ -467,12 +467,16 @@ { struct inode *dir; struct inode *inode; + struct dentry *parent; int error; struct nfs_fh fhandle; struct nfs_fattr fattr; + read_lock(&dparent_lock); + parent = dget(dentry->d_parent); + read_unlock(&dparent_lock); lock_kernel(); - dir = dentry->d_parent->d_inode; + dir = parent->d_inode; inode = dentry->d_inode; if (!inode) { @@ -508,6 +512,7 @@ nfs_renew_times(dentry); out_valid: unlock_kernel(); + dput(parent); return 1; out_bad: NFS_CACHEINV(dir); @@ -521,6 +526,7 @@ } d_drop(dentry); unlock_kernel(); + dput(parent); return 0; } diff -Nru a/fs/nfsd/export.c b/fs/nfsd/export.c --- a/fs/nfsd/export.c Tue Feb 26 11:57:59 2002 +++ b/fs/nfsd/export.c Tue Feb 26 11:57:59 2002 @@ -112,11 +112,15 @@ struct list_head *head = &clp->cl_export[EXPORT_HASH(sb->s_dev)]; struct list_head *p; + spin_lock(&dcache_lock); list_for_each(p, head) { svc_export *exp = list_entry(p, svc_export, ex_hash); - if (is_subdir(dentry, exp->ex_dentry)) + if (is_subdir(dentry, exp->ex_dentry)) { + spin_unlock(&dcache_lock); return exp; + } } + spin_unlock(&dcache_lock); return NULL; } @@ -132,12 +136,16 @@ struct list_head *p; struct dentry *ndentry; + spin_lock(&dcache_lock); list_for_each(p, head) { svc_export *exp = list_entry(p, svc_export, ex_hash); ndentry = exp->ex_dentry; - if (ndentry && is_subdir(ndentry->d_parent, dentry)) + if (ndentry && is_subdir(ndentry->d_parent, dentry)) { + spin_unlock(&dcache_lock); return exp; + } } + spin_unlock(&dcache_lock); return NULL; } diff -Nru a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c --- a/fs/nfsd/nfs3xdr.c Tue Feb 26 11:57:56 2002 +++ b/fs/nfsd/nfs3xdr.c Tue Feb 26 11:57:56 2002 @@ -699,10 +699,12 @@ fh_init(&fh, NFS3_FHSIZE); if (isdotent(name, namlen)) { - dchild = dparent; - if (namlen == 2) - dchild = dchild->d_parent; - dchild = dget(dchild); + if (namlen == 2) { + read_lock(&dparent_lock); + dchild = dget(dparent->d_parent); + read_unlock(&dparent_lock); + } else + dchild = dget(dparent); } else dchild = lookup_one_len(name, dparent,namlen); if (IS_ERR(dchild)) diff -Nru a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c --- a/fs/nfsd/nfsfh.c Tue Feb 26 11:57:58 2002 +++ b/fs/nfsd/nfsfh.c Tue Feb 26 11:57:58 2002 @@ -477,6 +477,11 @@ /* Something wrong. We need to drop the whole dentry->result path * whatever it was */ + /* + * FIXME: the loop below will do Bad Things(tm) if + * dentry (or one of its ancestors) become attached + * to the tree (e.g. due to VFAT-style alias handling) + */ struct dentry *d; for (d=result ; d ; d=(d->d_parent == d)?NULL:d->d_parent) d_drop(d); @@ -610,7 +615,7 @@ dentry = dget(exp->ex_dentry); break; default: - dentry = find_fh_dentry(exp->ex_dentry->d_inode->i_sb, + dentry = find_fh_dentry(exp->ex_dentry->d_sb, datap, data_left, fh->fh_fileid_type, !(exp->ex_flags & NFSEXP_NOSUBTREECHECK)); } @@ -619,7 +624,7 @@ tfh[0] = fh->ofh_ino; tfh[1] = fh->ofh_generation; tfh[2] = fh->ofh_dirino; - dentry = find_fh_dentry(exp->ex_dentry->d_inode->i_sb, + dentry = find_fh_dentry(exp->ex_dentry->d_sb, tfh, 3, fh->ofh_dirino?2:1, !(exp->ex_flags & NFSEXP_NOSUBTREECHECK)); } @@ -676,11 +681,15 @@ if (exp->ex_dentry != dentry) { struct dentry *tdentry = dentry; + spin_lock(&dcache_lock); do { tdentry = tdentry->d_parent; if (exp->ex_dentry == tdentry) break; /* executable only by root and we can't be root */ + /* + * FIXME: permissions check is not that simple + */ if (current->fsuid && (exp->ex_flags & NFSEXP_ROOTSQUASH) && !(tdentry->d_inode->i_uid @@ -700,8 +709,10 @@ printk("nfsd Security: %s/%s bad export.\n", dentry->d_parent->d_name.name, dentry->d_name.name); + spin_unlock(&dcache_lock); goto out; } + spin_unlock(&dcache_lock); } } @@ -729,7 +740,7 @@ inline int _fh_update(struct dentry *dentry, struct svc_export *exp, __u32 *datap, int *maxsize) { - struct super_block *sb = dentry->d_inode->i_sb; + struct super_block *sb = dentry->d_sb; if (dentry == exp->ex_dentry) { *maxsize = 0; @@ -806,7 +817,7 @@ if (ref_fh && ref_fh->fh_handle.fh_version == 0xca && - parent->d_inode->i_sb->s_op->dentry_to_fh == NULL) { + dentry->d_sb->s_op->dentry_to_fh == NULL) { /* old style filehandle please */ memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE); fhp->fh_handle.fh_size = NFS_FHSIZE; diff -Nru a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c --- a/fs/nfsd/vfs.c Tue Feb 26 11:57:59 2002 +++ b/fs/nfsd/vfs.c Tue Feb 26 11:57:59 2002 @@ -114,29 +114,33 @@ if (isdotent(name, len)) { if (len==1) dentry = dget(dparent); - else if (dparent != exp->ex_dentry) + else if (dparent != exp->ex_dentry) { + read_lock(&dparent_lock); dentry = dget(dparent->d_parent); - else if (!EX_CROSSMNT(exp)) + read_unlock(&dparent_lock); + } else if (!EX_CROSSMNT(exp)) dentry = dget(dparent); /* .. == . just like at / */ else { /* checking mountpoint crossing is very different when stepping up */ struct svc_export *exp2 = NULL; - struct dentry *dp; + struct dentry *dp, *old; struct vfsmount *mnt = mntget(exp->ex_mnt); dentry = dget(dparent); while(follow_up(&mnt, &dentry)) ; - dp = dget(dentry->d_parent); - dput(dentry); - dentry = dp; + old = dentry; + read_lock(&dparent_lock); + dp = dentry->d_parent; for ( ; !exp2 && dp->d_parent != dp; dp=dp->d_parent) exp2 = exp_get_by_name(exp->ex_client, mnt, dp); if (!exp2) { - dput(dentry); dentry = dget(dparent); } else { + dget(dentry->d_parent); exp = exp2; } + read_unlock(&dparent_lock); + dput(old); mntput(mnt); } } else { diff -Nru a/fs/pipe.c b/fs/pipe.c --- a/fs/pipe.c Tue Feb 26 11:57:56 2002 +++ b/fs/pipe.c Tue Feb 26 11:57:56 2002 @@ -116,7 +116,7 @@ * writers synchronously that there is more * room. */ - wake_up_interruptible_sync(PIPE_WAIT(*inode)); + wake_up_interruptible(PIPE_WAIT(*inode)); if (!PIPE_EMPTY(*inode)) BUG(); goto do_more_read; @@ -214,7 +214,7 @@ * is going to give up this CPU, so it doesnt have * to do idle reschedules. */ - wake_up_interruptible_sync(PIPE_WAIT(*inode)); + wake_up_interruptible(PIPE_WAIT(*inode)); PIPE_WAITING_WRITERS(*inode)++; pipe_wait(inode); PIPE_WAITING_WRITERS(*inode)--; diff -Nru a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c --- a/fs/reiserfs/inode.c Tue Feb 26 11:57:58 2002 +++ b/fs/reiserfs/inode.c Tue Feb 26 11:57:58 2002 @@ -1325,15 +1325,17 @@ if (maxlen < 5 || ! need_parent) return 3 ; + read_lock(&dparent_lock); inode = dentry->d_parent->d_inode ; data[3] = inode->i_ino ; data[4] = le32_to_cpu(INODE_PKEY (inode)->k_dir_id) ; *lenp = 5 ; - if (maxlen < 6) - return 5 ; - data[5] = inode->i_generation ; - *lenp = 6 ; - return 6 ; + if (maxlen >= 6) { + data[5] = inode->i_generation ; + *lenp = 6 ; + } + read_unlock(&dparent_lock); + return *lenp ; } diff -Nru a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c --- a/fs/reiserfs/namei.c Tue Feb 26 11:57:56 2002 +++ b/fs/reiserfs/namei.c Tue Feb 26 11:57:56 2002 @@ -344,8 +344,6 @@ struct reiserfs_dir_entry de; INITIALIZE_PATH (path_to_entry); - reiserfs_check_lock_depth("lookup") ; - if (dentry->d_name.len > REISERFS_MAX_NAME_LEN (dir->i_sb->s_blocksize)) return ERR_PTR(-ENAMETOOLONG); diff -Nru a/fs/smbfs/dir.c b/fs/smbfs/dir.c --- a/fs/smbfs/dir.c Tue Feb 26 11:57:59 2002 +++ b/fs/smbfs/dir.c Tue Feb 26 11:57:59 2002 @@ -378,12 +378,14 @@ void smb_renew_times(struct dentry * dentry) { + read_lock(&dparent_lock); for (;;) { dentry->d_time = jiffies; if (IS_ROOT(dentry)) break; dentry = dentry->d_parent; } + read_unlock(&dparent_lock); } static struct dentry * diff -Nru a/fs/smbfs/proc.c b/fs/smbfs/proc.c --- a/fs/smbfs/proc.c Tue Feb 26 11:57:57 2002 +++ b/fs/smbfs/proc.c Tue Feb 26 11:57:57 2002 @@ -245,15 +245,20 @@ * Build the path string walking the tree backward from end to ROOT * and store it in reversed order [see reverse_string()] */ + read_lock(&dparent_lock); while (!IS_ROOT(entry)) { - if (maxlen < 3) + if (maxlen < 3) { + read_unlock(&dparent_lock); return -ENAMETOOLONG; + } len = server->convert(path, maxlen-2, entry->d_name.name, entry->d_name.len, server->local_nls, server->remote_nls); - if (len < 0) + if (len < 0) { + read_unlock(&dparent_lock); return len; + } reverse_string(path, len); path += len; *path++ = '\\'; @@ -263,6 +268,7 @@ if (IS_ROOT(entry)) break; } + read_unlock(&dparent_lock); reverse_string(buf, path-buf); /* maxlen is at least 1 */ diff -Nru a/fs/super.c b/fs/super.c --- a/fs/super.c Tue Feb 26 11:57:59 2002 +++ b/fs/super.c Tue Feb 26 11:57:59 2002 @@ -355,6 +355,7 @@ } up_write(&s->s_umount); put_super(s); + yield(); return 0; } @@ -381,33 +382,86 @@ * remove_super - makes superblock unreachable * @s: superblock in question * - * Removes superblock from the lists, unlocks it, drop the reference - * and releases the hosting device. @s should have no active - * references by that time and after remove_super() it's essentially - * in rundown mode - all remaining references are temporary, no new - * reference of any sort are going to appear and all holders of - * temporary ones will eventually drop them. At that point superblock - * itself will be destroyed; all its contents is already gone. + * Removes superblock from the lists, unlocks it and drop the reference + * @s should have no active references by that time and after + * remove_super() it's essentially in rundown mode - all remaining + * references are temporary, no new reference of any sort are going + * to appear and all holders of temporary ones will eventually drop them. + * At that point superblock itself will be destroyed; all its contents + * is already gone. */ static void remove_super(struct super_block *s) { - kdev_t dev = s->s_dev; - struct block_device *bdev = s->s_bdev; - struct file_system_type *fs = s->s_type; - spin_lock(&sb_lock); list_del(&s->s_list); list_del(&s->s_instances); spin_unlock(&sb_lock); up_write(&s->s_umount); put_super(s); - put_filesystem(fs); +} + +static void generic_shutdown_super(struct super_block *sb) +{ + struct dentry *root = sb->s_root; + struct super_operations *sop = sb->s_op; + + if (root) { + sb->s_root = NULL; + shrink_dcache_parent(root); + dput(root); + fsync_super(sb); + lock_super(sb); + lock_kernel(); + sb->s_flags &= ~MS_ACTIVE; + /* bad name - it should be evict_inodes() */ + invalidate_inodes(sb); + if (sop) { + if (sop->write_super && sb->s_dirt) + sop->write_super(sb); + if (sop->put_super) + sop->put_super(sb); + } + + /* Forget any remaining inodes */ + if (invalidate_inodes(sb)) { + printk("VFS: Busy inodes after unmount. " + "Self-destruct in 5 seconds. Have a nice day...\n"); + } + + unlock_kernel(); + unlock_super(sb); + } + remove_super(sb); +} + +static void shutdown_super(struct super_block *sb) +{ + struct file_system_type *fs = sb->s_type; + kdev_t dev = sb->s_dev; + struct block_device *bdev = sb->s_bdev; + + /* Need to clean after the sucker */ + if (fs->fs_flags & FS_LITTER && sb->s_root) + d_genocide(sb->s_root); + generic_shutdown_super(sb); if (bdev) blkdev_put(bdev, BDEV_FS); else put_anon_dev(dev); } +void kill_super(struct super_block *sb) +{ + struct file_system_type *fs = sb->s_type; + + if (!deactivate_super(sb)) + return; + + down_write(&sb->s_umount); + shutdown_super(sb); + put_filesystem(fs); +} + struct vfsmount *alloc_vfsmnt(char *name); void free_vfsmnt(struct vfsmount *mnt); @@ -724,8 +778,8 @@ return s; failed: - deactivate_super(s); - remove_super(s); + up_write(&s->s_umount); + kill_super(s); goto out; out1: blkdev_put(bdev, BDEV_FS); @@ -748,8 +802,8 @@ error = fill_super(s, data, flags & MS_VERBOSE ? 1 : 0); if (error) { - deactivate_super(s); - remove_super(s); + up_write(&s->s_umount); + kill_super(s); return ERR_PTR(error); } s->s_flags |= MS_ACTIVE; @@ -774,8 +828,8 @@ s->s_flags = flags; error = fill_super(s, data, flags & MS_VERBOSE ? 1 : 0); if (error) { - deactivate_super(s); - remove_super(s); + up_write(&s->s_umount); + kill_super(s); return ERR_PTR(error); } s->s_flags |= MS_ACTIVE; @@ -814,45 +868,6 @@ out: put_filesystem(type); return (struct vfsmount *)sb; -} - -void kill_super(struct super_block *sb) -{ - struct dentry *root = sb->s_root; - struct file_system_type *fs = sb->s_type; - struct super_operations *sop = sb->s_op; - - if (!deactivate_super(sb)) - return; - - down_write(&sb->s_umount); - sb->s_root = NULL; - /* Need to clean after the sucker */ - if (fs->fs_flags & FS_LITTER) - d_genocide(root); - shrink_dcache_parent(root); - dput(root); - fsync_super(sb); - lock_super(sb); - lock_kernel(); - sb->s_flags &= ~MS_ACTIVE; - invalidate_inodes(sb); /* bad name - it should be evict_inodes() */ - if (sop) { - if (sop->write_super && sb->s_dirt) - sop->write_super(sb); - if (sop->put_super) - sop->put_super(sb); - } - - /* Forget any remaining inodes */ - if (invalidate_inodes(sb)) { - printk("VFS: Busy inodes after unmount. " - "Self-destruct in 5 seconds. Have a nice day...\n"); - } - - unlock_kernel(); - unlock_super(sb); - remove_super(sb); } struct vfsmount *kern_mount(struct file_system_type *type) diff -Nru a/fs/sysv/ChangeLog b/fs/sysv/ChangeLog --- a/fs/sysv/ChangeLog Tue Feb 26 11:57:56 2002 +++ b/fs/sysv/ChangeLog Tue Feb 26 11:57:56 2002 @@ -81,7 +81,7 @@ * super.c (sysv_read_super): Likewise. (v7_read_super): Likewise. -Sat Dec 15 2001 Christoph Hellwig +Sat Dec 15 2001 Christoph Hellwig * inode.c (sysv_read_inode): Mark inode as bad in case of failure. * super.c (complete_read_super): Check for bad root inode. @@ -90,13 +90,13 @@ * file.c (sysv_sync_file): Call fsync_inode_data_buffers. -Fri Oct 26 2001 Christoph Hellwig +Fri Oct 26 2001 Christoph Hellwig * dir.c, ialloc.c, namei.c, include/linux/sysv_fs_i.h: Implement per-Inode lookup offset cache. Modelled after Ted's ext2 patch. -Fri Oct 26 2001 Christoph Hellwig +Fri Oct 26 2001 Christoph Hellwig * inode.c, super.c, include/linux/sysv_fs.h, include/linux/sysv_fs_sb.h: diff -Nru a/fs/sysv/symlink.c b/fs/sysv/symlink.c --- a/fs/sysv/symlink.c Tue Feb 26 11:58:00 2002 +++ b/fs/sysv/symlink.c Tue Feb 26 11:58:00 2002 @@ -2,7 +2,7 @@ * linux/fs/sysv/symlink.c * * Handling of System V filesystem fast symlinks extensions. - * Aug 2001, Christoph Hellwig (hch@caldera.de) + * Aug 2001, Christoph Hellwig (hch@infradead.org) */ #include diff -Nru a/fs/udf/dir.c b/fs/udf/dir.c --- a/fs/udf/dir.c Tue Feb 26 11:57:58 2002 +++ b/fs/udf/dir.c Tue Feb 26 11:57:58 2002 @@ -224,7 +224,7 @@ if ( cfi.fileCharacteristics & FILE_PARENT ) { - iblock = udf_get_lb_pblock(dir->i_sb, UDF_I_LOCATION(filp->f_dentry->d_parent->d_inode), 0); + iblock = parent_ino(filp->f_dentry); flen = 2; memcpy(fname, "..", flen); dt_type = DT_DIR; diff -Nru a/fs/ufs/swab.h b/fs/ufs/swab.h --- a/fs/ufs/swab.h Tue Feb 26 11:58:00 2002 +++ b/fs/ufs/swab.h Tue Feb 26 11:58:00 2002 @@ -3,7 +3,7 @@ * * Copyright (C) 1997, 1998 Francois-Rene Rideau * Copyright (C) 1998 Jakub Jelinek - * Copyright (C) 2001 Christoph Hellwig + * Copyright (C) 2001 Christoph Hellwig */ #ifndef _UFS_SWAB_H diff -Nru a/include/asm-alpha/bitops.h b/include/asm-alpha/bitops.h --- a/include/asm-alpha/bitops.h Tue Feb 26 11:57:59 2002 +++ b/include/asm-alpha/bitops.h Tue Feb 26 11:57:59 2002 @@ -460,6 +460,27 @@ #ifdef __KERNEL__ +/* + * Every architecture must define this function. It's the fastest + * way of searching a 140-bit bitmap where the first 100 bits are + * unlikely to be set. It's guaranteed that at least one of the 140 + * bits is set. + */ +static inline unsigned long +sched_find_first_bit(unsigned long b[3]) +{ + unsigned long b0 = b[0], b1 = b[1], b2 = b[2]; + unsigned long ofs; + + ofs = (b1 ? 64 : 128); + b1 = (b1 ? b1 : b2); + ofs = (b0 ? 0 : ofs); + b0 = (b0 ? b0 : b1); + + return __ffs(b0) + ofs; +} + + #define ext2_set_bit __test_and_set_bit #define ext2_clear_bit __test_and_clear_bit #define ext2_test_bit test_bit diff -Nru a/include/asm-alpha/mmu_context.h b/include/asm-alpha/mmu_context.h --- a/include/asm-alpha/mmu_context.h Tue Feb 26 11:57:59 2002 +++ b/include/asm-alpha/mmu_context.h Tue Feb 26 11:57:59 2002 @@ -21,31 +21,6 @@ #include #endif -/* ??? This does not belong here. */ -/* - * Every architecture must define this function. It's the fastest - * way of searching a 168-bit bitmap where the first 128 bits are - * unlikely to be set. It's guaranteed that at least one of the 168 - * bits is set. - */ -#if MAX_RT_PRIO != 128 || MAX_PRIO > 192 -# error update this function. -#endif - -static inline int -sched_find_first_bit(unsigned long *b) -{ - unsigned long b0 = b[0], b1 = b[1], b2 = b[2]; - unsigned long offset = 128; - - if (unlikely(b0 | b1)) { - b2 = (b0 ? b0 : b1); - offset = (b0 ? 0 : 64); - } - - return __ffs(b2) + offset; -} - extern inline unsigned long __reload_thread(struct pcb_struct *pcb) diff -Nru a/include/asm-alpha/spinlock.h b/include/asm-alpha/spinlock.h --- a/include/asm-alpha/spinlock.h Tue Feb 26 11:57:59 2002 +++ b/include/asm-alpha/spinlock.h Tue Feb 26 11:57:59 2002 @@ -121,8 +121,8 @@ " bne %1,6b\n" " br 1b\n" ".previous" - : "=m" (*(volatile int *)lock), "=&r" (regx) - : "0" (*(volatile int *)lock) : "memory"); + : "=m" (*lock), "=&r" (regx) + : "0" (*lock) : "memory"); } static inline void _raw_read_lock(rwlock_t * lock) @@ -141,8 +141,8 @@ " blbs %1,6b\n" " br 1b\n" ".previous" - : "=m" (*(volatile int *)lock), "=&r" (regx) - : "m" (*(volatile int *)lock) : "memory"); + : "=m" (*lock), "=&r" (regx) + : "m" (*lock) : "memory"); } #endif /* CONFIG_DEBUG_RWLOCK */ @@ -164,8 +164,8 @@ ".subsection 2\n" "6: br 1b\n" ".previous" - : "=m" (*(volatile int *)lock), "=&r" (regx) - : "m" (*(volatile int *)lock) : "memory"); + : "=m" (*lock), "=&r" (regx) + : "m" (*lock) : "memory"); } #endif /* _ALPHA_SPINLOCK_H */ diff -Nru a/include/asm-alpha/system.h b/include/asm-alpha/system.h --- a/include/asm-alpha/system.h Tue Feb 26 11:57:56 2002 +++ b/include/asm-alpha/system.h Tue Feb 26 11:57:56 2002 @@ -131,15 +131,13 @@ #define __halt() __asm__ __volatile__ ("call_pal %0 #halt" : : "i" (PAL_halt)) #define prepare_to_switch() do { } while(0) -#define switch_to(prev,next,last) \ -do { \ - unsigned long pcbb; \ - pcbb = virt_to_phys(&(next)->thread_info->pcb); \ - (last) = alpha_switch_to(pcbb, (prev)); \ - check_mmu_context(); \ +#define switch_to(prev,next) \ +do { \ + alpha_switch_to(virt_to_phys(&(next)->thread_info->pcb), (prev)); \ + check_mmu_context(); \ } while (0) -extern struct task_struct* alpha_switch_to(unsigned long, struct task_struct*); +extern void alpha_switch_to(unsigned long, struct task_struct*); #define mb() \ __asm__ __volatile__("mb": : :"memory") @@ -368,7 +366,59 @@ * it must clobber "memory" (also for interrupts in UP). */ -extern __inline__ unsigned long +static inline unsigned long +__xchg_u8(volatile char *m, unsigned long val) +{ + unsigned long ret, tmp, addr64; + + __asm__ __volatile__( + " andnot %4,7,%3\n" + " insbl %1,%4,%1\n" + "1: ldq_l %2,0(%3)\n" + " extbl %2,%4,%0\n" + " mskbl %2,%4,%2\n" + " or %1,%2,%2\n" + " stq_c %2,0(%3)\n" + " beq %2,2f\n" +#ifdef CONFIG_SMP + " mb\n" +#endif + ".subsection 2\n" + "2: br 1b\n" + ".previous" + : "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64) + : "r" ((long)m), "1" (val) : "memory"); + + return ret; +} + +static inline unsigned long +__xchg_u16(volatile short *m, unsigned long val) +{ + unsigned long ret, tmp, addr64; + + __asm__ __volatile__( + " andnot %4,7,%3\n" + " inswl %1,%4,%1\n" + "1: ldq_l %2,0(%3)\n" + " extwl %2,%4,%0\n" + " mskwl %2,%4,%2\n" + " or %1,%2,%2\n" + " stq_c %2,0(%3)\n" + " beq %2,2f\n" +#ifdef CONFIG_SMP + " mb\n" +#endif + ".subsection 2\n" + "2: br 1b\n" + ".previous" + : "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64) + : "r" ((long)m), "1" (val) : "memory"); + + return ret; +} + +static inline unsigned long __xchg_u32(volatile int *m, unsigned long val) { unsigned long dummy; @@ -390,7 +440,7 @@ return val; } -extern __inline__ unsigned long +static inline unsigned long __xchg_u64(volatile long *m, unsigned long val) { unsigned long dummy; @@ -416,10 +466,14 @@ if something tries to do an invalid xchg(). */ extern void __xchg_called_with_bad_pointer(void); -static __inline__ unsigned long +static inline unsigned long __xchg(volatile void *ptr, unsigned long x, int size) { switch (size) { + case 1: + return __xchg_u8(ptr, x); + case 2: + return __xchg_u16(ptr, x); case 4: return __xchg_u32(ptr, x); case 8: @@ -451,7 +505,65 @@ #define __HAVE_ARCH_CMPXCHG 1 -extern __inline__ unsigned long +static inline unsigned long +__cmpxchg_u8(volatile char *m, long old, long new) +{ + unsigned long prev, tmp, cmp, addr64; + + __asm__ __volatile__( + " andnot %5,7,%4\n" + " insbl %1,%5,%1\n" + "1: ldq_l %2,0(%4)\n" + " extbl %2,%5,%0\n" + " cmpeq %0,%6,%3\n" + " beq %3,2f\n" + " mskbl %2,%5,%2\n" + " or %1,%2,%2\n" + " stq_c %2,0(%4)\n" + " beq %2,3f\n" +#ifdef CONFIG_SMP + " mb\n" +#endif + "2:\n" + ".subsection 2\n" + "3: br 1b\n" + ".previous" + : "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64) + : "r" ((long)m), "Ir" (old), "1" (new) : "memory"); + + return prev; +} + +static inline unsigned long +__cmpxchg_u16(volatile short *m, long old, long new) +{ + unsigned long prev, tmp, cmp, addr64; + + __asm__ __volatile__( + " andnot %5,7,%4\n" + " inswl %1,%5,%1\n" + "1: ldq_l %2,0(%4)\n" + " extwl %2,%5,%0\n" + " cmpeq %0,%6,%3\n" + " beq %3,2f\n" + " mskwl %2,%5,%2\n" + " or %1,%2,%2\n" + " stq_c %2,0(%4)\n" + " beq %2,3f\n" +#ifdef CONFIG_SMP + " mb\n" +#endif + "2:\n" + ".subsection 2\n" + "3: br 1b\n" + ".previous" + : "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64) + : "r" ((long)m), "Ir" (old), "1" (new) : "memory"); + + return prev; +} + +static inline unsigned long __cmpxchg_u32(volatile int *m, int old, int new) { unsigned long prev, cmp; @@ -476,7 +588,7 @@ return prev; } -extern __inline__ unsigned long +static inline unsigned long __cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new) { unsigned long prev, cmp; @@ -505,10 +617,14 @@ if something tries to do an invalid cmpxchg(). */ extern void __cmpxchg_called_with_bad_pointer(void); -static __inline__ unsigned long +static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) { switch (size) { + case 1: + return __cmpxchg_u8(ptr, old, new); + case 2: + return __cmpxchg_u16(ptr, old, new); case 4: return __cmpxchg_u32(ptr, old, new); case 8: diff -Nru a/include/asm-arm/arch-adifcc/serial.h b/include/asm-arm/arch-adifcc/serial.h --- a/include/asm-arm/arch-adifcc/serial.h Tue Feb 26 11:57:59 2002 +++ b/include/asm-arm/arch-adifcc/serial.h Tue Feb 26 11:57:59 2002 @@ -5,7 +5,7 @@ * * Copyright (c) 2001 MontaVista Software, Inc. */ - +#include /* * This assumes you have a 1.8432 MHz clock for your UART. diff -Nru a/include/asm-arm/arch-anakin/ide.h b/include/asm-arm/arch-anakin/ide.h --- a/include/asm-arm/arch-anakin/ide.h Tue Feb 26 11:57:56 2002 +++ b/include/asm-arm/arch-anakin/ide.h Tue Feb 26 11:57:56 2002 @@ -7,7 +7,6 @@ * (jonm@bluemug.com). */ -#include #include #include diff -Nru a/include/asm-arm/arch-anakin/uncompress.h b/include/asm-arm/arch-anakin/uncompress.h --- a/include/asm-arm/arch-anakin/uncompress.h Tue Feb 26 11:58:00 2002 +++ b/include/asm-arm/arch-anakin/uncompress.h Tue Feb 26 11:58:00 2002 @@ -14,6 +14,7 @@ #ifndef __ASM_ARCH_UNCOMPRESS_H #define __ASM_ARCH_UNCOMPRESS_H +#include #include #include diff -Nru a/include/asm-arm/arch-clps711x/memory.h b/include/asm-arm/arch-clps711x/memory.h --- a/include/asm-arm/arch-clps711x/memory.h Tue Feb 26 11:57:56 2002 +++ b/include/asm-arm/arch-clps711x/memory.h Tue Feb 26 11:57:56 2002 @@ -20,6 +20,8 @@ #ifndef __ASM_ARCH_MMU_H #define __ASM_ARCH_MMU_H +#include + /* * Task size: 3GB */ diff -Nru a/include/asm-arm/arch-ebsa285/keyboard.h b/include/asm-arm/arch-ebsa285/keyboard.h --- a/include/asm-arm/arch-ebsa285/keyboard.h Tue Feb 26 11:57:58 2002 +++ b/include/asm-arm/arch-ebsa285/keyboard.h Tue Feb 26 11:57:58 2002 @@ -6,6 +6,7 @@ * Copyright (C) 1998-2001 Russell King * (C) 1998 Phil Blundell */ +#include #include #include #include diff -Nru a/include/asm-arm/arch-epxa10db/time.h b/include/asm-arm/arch-epxa10db/time.h --- a/include/asm-arm/arch-epxa10db/time.h Tue Feb 26 11:57:59 2002 +++ b/include/asm-arm/arch-epxa10db/time.h Tue Feb 26 11:57:59 2002 @@ -17,7 +17,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include diff -Nru a/include/asm-arm/arch-iop310/irqs.h b/include/asm-arm/arch-iop310/irqs.h --- a/include/asm-arm/arch-iop310/irqs.h Tue Feb 26 11:57:58 2002 +++ b/include/asm-arm/arch-iop310/irqs.h Tue Feb 26 11:57:58 2002 @@ -11,7 +11,7 @@ * 06/13/01: Added 80310 on-chip interrupt sources * */ - +#include /* * XS80200 specific IRQs diff -Nru a/include/asm-arm/arch-iop310/memory.h b/include/asm-arm/arch-iop310/memory.h --- a/include/asm-arm/arch-iop310/memory.h Tue Feb 26 11:57:58 2002 +++ b/include/asm-arm/arch-iop310/memory.h Tue Feb 26 11:57:58 2002 @@ -5,6 +5,7 @@ #ifndef __ASM_ARCH_MEMORY_H #define __ASM_ARCH_MEMORY_H +#include /* * Task size: 3GB diff -Nru a/include/asm-arm/arch-iop310/serial.h b/include/asm-arm/arch-iop310/serial.h --- a/include/asm-arm/arch-iop310/serial.h Tue Feb 26 11:58:00 2002 +++ b/include/asm-arm/arch-iop310/serial.h Tue Feb 26 11:58:00 2002 @@ -1,7 +1,7 @@ /* * include/asm-arm/arch-iop310/serial.h */ - +#include /* * This assumes you have a 1.8432 MHz clock for your UART. diff -Nru a/include/asm-arm/arch-iop310/timex.h b/include/asm-arm/arch-iop310/timex.h --- a/include/asm-arm/arch-iop310/timex.h Tue Feb 26 11:57:56 2002 +++ b/include/asm-arm/arch-iop310/timex.h Tue Feb 26 11:57:56 2002 @@ -3,7 +3,7 @@ * * IOP310 architecture timex specifications */ - +#include #ifdef CONFIG_ARCH_IQ80310 diff -Nru a/include/asm-arm/arch-iop310/uncompress.h b/include/asm-arm/arch-iop310/uncompress.h --- a/include/asm-arm/arch-iop310/uncompress.h Tue Feb 26 11:57:59 2002 +++ b/include/asm-arm/arch-iop310/uncompress.h Tue Feb 26 11:57:59 2002 @@ -1,6 +1,7 @@ /* * linux/include/asm-arm/arch-iop80310/uncompress.h */ +#include #ifdef CONFIG_ARCH_IQ80310 #define UART1_BASE ((volatile unsigned char *)0xfe800000) diff -Nru a/include/asm-arm/arch-sa1100/assabet.h b/include/asm-arm/arch-sa1100/assabet.h --- a/include/asm-arm/arch-sa1100/assabet.h Tue Feb 26 11:57:56 2002 +++ b/include/asm-arm/arch-sa1100/assabet.h Tue Feb 26 11:57:56 2002 @@ -12,6 +12,8 @@ #ifndef __ASM_ARCH_ASSABET_H #define __ASM_ARCH_ASSABET_H +#include + /* System Configuration Register flags */ #define ASSABET_SCR_SDRAM_LOW (1<<2) /* SDRAM size (low bit) */ diff -Nru a/include/asm-arm/arch-sa1100/cerf.h b/include/asm-arm/arch-sa1100/cerf.h --- a/include/asm-arm/arch-sa1100/cerf.h Tue Feb 26 11:57:59 2002 +++ b/include/asm-arm/arch-sa1100/cerf.h Tue Feb 26 11:57:59 2002 @@ -1,6 +1,8 @@ #ifndef _INCLUDE_CERF_H_ #define _INCLUDE_CERF_H_ +#include + #ifdef CONFIG_SA1100_CERF_CPLD diff -Nru a/include/asm-arm/arch-sa1100/pangolin.h b/include/asm-arm/arch-sa1100/pangolin.h --- a/include/asm-arm/arch-sa1100/pangolin.h Tue Feb 26 11:57:59 2002 +++ b/include/asm-arm/arch-sa1100/pangolin.h Tue Feb 26 11:57:59 2002 @@ -6,10 +6,11 @@ * This file contains the hardware specific definitions for Pangolin * */ - #ifndef __ASM_ARCH_HARDWARE_H #error "include instead" #endif + +#include #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE diff -Nru a/include/asm-arm/arch-shark/keyboard.h b/include/asm-arm/arch-shark/keyboard.h --- a/include/asm-arm/arch-shark/keyboard.h Tue Feb 26 11:57:57 2002 +++ b/include/asm-arm/arch-shark/keyboard.h Tue Feb 26 11:57:57 2002 @@ -6,6 +6,7 @@ * (C) 1998 Russell King * (C) 1998 Phil Blundell */ +#include #include #include #include diff -Nru a/include/asm-arm/bitops.h b/include/asm-arm/bitops.h --- a/include/asm-arm/bitops.h Tue Feb 26 11:57:56 2002 +++ b/include/asm-arm/bitops.h Tue Feb 26 11:57:56 2002 @@ -302,6 +302,23 @@ } /* + * ffz = Find First Zero in word. Undefined if no zero exists, + * so code should check against ~0UL first.. + */ +static inline unsigned long __ffs(unsigned long word) +{ + int k; + + k = 31; + if (word & 0x0000ffff) { k -= 16; word <<= 16; } + if (word & 0x00ff0000) { k -= 8; word <<= 8; } + if (word & 0x0f000000) { k -= 4; word <<= 4; } + if (word & 0x30000000) { k -= 2; word <<= 2; } + if (word & 0x40000000) { k -= 1; } + return k; +} + +/* * ffs: find first bit set. This is defined the same way as * the libc and compiler builtin ffs routines, therefore * differs in spirit from the above ffz (man ffs). diff -Nru a/include/asm-arm/current.h b/include/asm-arm/current.h --- a/include/asm-arm/current.h Tue Feb 26 11:57:56 2002 +++ b/include/asm-arm/current.h Tue Feb 26 11:57:56 2002 @@ -1,12 +1,13 @@ #ifndef _ASMARM_CURRENT_H #define _ASMARM_CURRENT_H +#include + static inline struct task_struct *get_current(void) __attribute__ (( __const__ )); static inline struct task_struct *get_current(void) { - register unsigned long sp asm ("sp"); - return (struct task_struct *)(sp & ~0x1fff); + return current_thread_info()->task; } #define current (get_current()) diff -Nru a/include/asm-arm/fpstate.h b/include/asm-arm/fpstate.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/fpstate.h Tue Feb 26 11:58:00 2002 @@ -0,0 +1,29 @@ +/* + * linux/include/asm-arm/fpstate.h + * + * Copyright (C) 1995 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __ASM_ARM_FPSTATE_H +#define __ASM_ARM_FPSTATE_H + +#define FP_SIZE 35 + +struct fp_hard_struct { + unsigned int save[FP_SIZE]; /* as yet undefined */ +}; + +struct fp_soft_struct { + unsigned int save[FP_SIZE]; /* undefined information */ +}; + +union fp_state { + struct fp_hard_struct hard; + struct fp_soft_struct soft; +}; + +#endif diff -Nru a/include/asm-arm/hardirq.h b/include/asm-arm/hardirq.h --- a/include/asm-arm/hardirq.h Tue Feb 26 11:57:56 2002 +++ b/include/asm-arm/hardirq.h Tue Feb 26 11:57:56 2002 @@ -34,6 +34,7 @@ #define irq_exit(cpu,irq) (local_irq_count(cpu)--) #define synchronize_irq() do { } while (0) +#define release_irqlock(cpu) do { } while (0) #else #error SMP not supported diff -Nru a/include/asm-arm/mmu_context.h b/include/asm-arm/mmu_context.h --- a/include/asm-arm/mmu_context.h Tue Feb 26 11:57:59 2002 +++ b/include/asm-arm/mmu_context.h Tue Feb 26 11:57:59 2002 @@ -42,14 +42,34 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned int cpu) { - if (prev != next) { + if (prev != next) cpu_switch_mm(next->pgd, tsk); - clear_bit(cpu, &prev->cpu_vm_mask); - } - set_bit(cpu, &next->cpu_vm_mask); } #define activate_mm(prev, next) \ switch_mm((prev),(next),NULL,smp_processor_id()) + +/* + * Find first bit set in a 168-bit bitmap, where the first + * 128 bits are unlikely to be set. + */ +static inline int sched_find_first_bit(unsigned long *b) +{ +#if MAX_RT_PRIO != 128 || MAX_PRIO != 168 +#error update this function +#endif + + if (unlikely(b[0])) + return __ffs(b[0]); + if (unlikely(b[1])) + return __ffs(b[1]) + 32; + if (unlikely(b[2])) + return __ffs(b[2]) + 64; + if (unlikely(b[3])) + return __ffs(b[3]) + 96; + if (b[4]) + return __ffs(b[4]) + MAX_RT_PRIO; + return __ffs(b[5]) + 32 + MAX_RT_PRIO; +} #endif diff -Nru a/include/asm-arm/pgalloc.h b/include/asm-arm/pgalloc.h --- a/include/asm-arm/pgalloc.h Tue Feb 26 11:58:00 2002 +++ b/include/asm-arm/pgalloc.h Tue Feb 26 11:58:00 2002 @@ -57,40 +57,48 @@ { unsigned long *ret; + preempt_disable(); if ((ret = pgd_quicklist) != NULL) { pgd_quicklist = (unsigned long *)__pgd_next(ret); ret[1] = ret[2]; clean_dcache_entry(ret + 1); pgtable_cache_size--; } + preempt_enable(); return (pgd_t *)ret; } static inline void free_pgd_fast(pgd_t *pgd) { + preempt_disable(); __pgd_next(pgd) = (unsigned long) pgd_quicklist; pgd_quicklist = (unsigned long *) pgd; pgtable_cache_size++; + preempt_enable(); } static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) { unsigned long *ret; + preempt_disable(); if((ret = pte_quicklist) != NULL) { pte_quicklist = (unsigned long *)__pte_next(ret); ret[0] = 0; clean_dcache_entry(ret); pgtable_cache_size--; } + preempt_enable(); return (pte_t *)ret; } static inline void free_pte_fast(pte_t *pte) { + preempt_disable(); __pte_next(pte) = (unsigned long) pte_quicklist; pte_quicklist = (unsigned long *) pte; pgtable_cache_size++; + preempt_enable(); } #else /* CONFIG_NO_PGT_CACHE */ diff -Nru a/include/asm-arm/proc-armo/processor.h b/include/asm-arm/proc-armo/processor.h --- a/include/asm-arm/proc-armo/processor.h Tue Feb 26 11:57:58 2002 +++ b/include/asm-arm/proc-armo/processor.h Tue Feb 26 11:57:58 2002 @@ -23,7 +23,7 @@ #define KERNEL_STACK_SIZE 4096 -struct context_save_struct { +struct cpu_context_save { unsigned long r4; unsigned long r5; unsigned long r6; @@ -35,7 +35,7 @@ unsigned long pc; }; -#define INIT_CSS (struct context_save_struct){ 0, 0, 0, 0, 0, 0, 0, 0, SVC26_MODE } +#define INIT_CSS (struct cpu_context_save){ 0, 0, 0, 0, 0, 0, 0, 0, SVC26_MODE } typedef struct { void (*put_byte)(void); /* Special calling convention */ @@ -73,15 +73,5 @@ #define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1022]) #define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1020]) - -/* Allocation and freeing of basic task resources. */ -/* - * NOTE! The task struct and the stack go together - */ -extern unsigned long get_page_8k(int priority); -extern void free_page_8k(unsigned long page); - -#define ll_alloc_task_struct() ((struct task_struct *)get_page_8k(GFP_KERNEL)) -#define ll_free_task_struct(p) free_page_8k((unsigned long)(p)) #endif diff -Nru a/include/asm-arm/proc-armv/processor.h b/include/asm-arm/proc-armv/processor.h --- a/include/asm-arm/proc-armv/processor.h Tue Feb 26 11:57:59 2002 +++ b/include/asm-arm/proc-armv/processor.h Tue Feb 26 11:57:59 2002 @@ -22,7 +22,7 @@ #define KERNEL_STACK_SIZE PAGE_SIZE -struct context_save_struct { +struct cpu_context_save { unsigned long cpsr; unsigned long r4; unsigned long r5; @@ -35,15 +35,12 @@ unsigned long pc; }; -#define INIT_CSS (struct context_save_struct){ SVC_MODE, 0, 0, 0, 0, 0, 0, 0, 0, 0 } +#define INIT_CSS (struct cpu_context_save){ SVC_MODE, 0, 0, 0, 0, 0, 0, 0, 0, 0 } -#define EXTRA_THREAD_STRUCT \ - unsigned int domain; - -#define EXTRA_THREAD_STRUCT_INIT \ - domain: domain_val(DOMAIN_USER, DOMAIN_CLIENT) | \ - domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \ - domain_val(DOMAIN_IO, DOMAIN_CLIENT) +#define INIT_EXTRA_THREAD_INFO \ + cpu_domain: domain_val(DOMAIN_USER, DOMAIN_CLIENT) | \ + domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \ + domain_val(DOMAIN_IO, DOMAIN_CLIENT) #define start_thread(regs,pc,sp) \ ({ \ @@ -63,12 +60,5 @@ #define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1021]) #define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1019]) - -/* Allocation and freeing of basic task resources. */ -/* - * NOTE! The task struct and the stack go together - */ -#define ll_alloc_task_struct() ((struct task_struct *) __get_free_pages(GFP_KERNEL,1)) -#define ll_free_task_struct(p) free_pages((unsigned long)(p),1) #endif diff -Nru a/include/asm-arm/proc-armv/uaccess.h b/include/asm-arm/proc-armv/uaccess.h --- a/include/asm-arm/proc-armv/uaccess.h Tue Feb 26 11:57:56 2002 +++ b/include/asm-arm/proc-armv/uaccess.h Tue Feb 26 11:57:56 2002 @@ -16,8 +16,7 @@ static inline void set_fs (mm_segment_t fs) { - current->addr_limit = fs; - + current_thread_info()->addr_limit = fs; modify_domain(DOMAIN_KERNEL, fs ? DOMAIN_CLIENT : DOMAIN_MANAGER); } @@ -26,7 +25,7 @@ unsigned long flag, sum; \ __asm__("adds %1, %2, %3; sbcccs %1, %1, %0; movcc %0, #0" \ : "=&r" (flag), "=&r" (sum) \ - : "r" (addr), "Ir" (size), "0" (current->addr_limit) \ + : "r" (addr), "Ir" (size), "0" (current_thread_info()->addr_limit) \ : "cc"); \ flag; }) @@ -34,7 +33,7 @@ unsigned long flag; \ __asm__("cmp %2, %0; movlo %0, #0" \ : "=&r" (flag) \ - : "0" (current->addr_limit), "r" (addr) \ + : "0" (current_thread_info()->addr_limit), "r" (addr) \ : "cc"); \ (flag == 0); }) diff -Nru a/include/asm-arm/processor.h b/include/asm-arm/processor.h --- a/include/asm-arm/processor.h Tue Feb 26 11:57:59 2002 +++ b/include/asm-arm/processor.h Tue Feb 26 11:57:59 2002 @@ -17,23 +17,6 @@ */ #define current_text_addr() ({ __label__ _l; _l: &&_l;}) -#define FP_SIZE 35 - -struct fp_hard_struct { - unsigned int save[FP_SIZE]; /* as yet undefined */ -}; - -struct fp_soft_struct { - unsigned int save[FP_SIZE]; /* undefined information */ -}; - -union fp_state { - struct fp_hard_struct hard; - struct fp_soft_struct soft; -}; - -typedef unsigned long mm_segment_t; /* domain register */ - #ifdef __KERNEL__ #define EISA_bus 0 @@ -54,37 +37,15 @@ }; struct thread_struct { - atomic_t refcount; /* fault info */ unsigned long address; unsigned long trap_no; unsigned long error_code; - /* floating point */ - union fp_state fpstate; /* debugging */ struct debug_info debug; - /* context info */ - struct context_save_struct *save; - EXTRA_THREAD_STRUCT }; -#define INIT_THREAD { \ - refcount: ATOMIC_INIT(1), \ - EXTRA_THREAD_STRUCT_INIT \ -} - -/* - * Return saved PC of a blocked thread. - */ -static inline unsigned long thread_saved_pc(struct thread_struct *t) -{ - return t->save ? pc_pointer(t->save->pc) : 0; -} - -static inline unsigned long get_css_fp(struct thread_struct *t) -{ - return t->save ? t->save->fp : 0; -} +#define INIT_THREAD { } /* Forward declaration, a strange C thing */ struct task_struct; @@ -98,21 +59,7 @@ unsigned long get_wchan(struct task_struct *p); -#define THREAD_SIZE (8192) - -extern struct task_struct *alloc_task_struct(void); -extern void __free_task_struct(struct task_struct *); -#define get_task_struct(p) atomic_inc(&(p)->thread.refcount) -#define free_task_struct(p) \ - do { \ - if (atomic_dec_and_test(&(p)->thread.refcount)) \ - __free_task_struct((p)); \ - } while (0) - -#define init_task (init_task_union.task) -#define init_stack (init_task_union.stack) - -#define cpu_relax() do { } while (0) +#define cpu_relax() do { } while (0) /* * Create a new kernel thread diff -Nru a/include/asm-arm/smplock.h b/include/asm-arm/smplock.h --- a/include/asm-arm/smplock.h Tue Feb 26 11:57:56 2002 +++ b/include/asm-arm/smplock.h Tue Feb 26 11:57:56 2002 @@ -3,31 +3,34 @@ * * Default SMP lock implementation */ +#include #include #include extern spinlock_t kernel_flag; +#ifdef CONFIG_PREEMPT +#define kernel_locked() preempt_get_count() +#else #define kernel_locked() spin_is_locked(&kernel_flag) +#endif /* * Release global kernel lock and global interrupt lock */ -#define release_kernel_lock(task, cpu) \ -do { \ - if (task->lock_depth >= 0) \ - spin_unlock(&kernel_flag); \ - release_irqlock(cpu); \ - __sti(); \ +#define release_kernel_lock(task, cpu) \ +do { \ + if (unlikely(task->lock_depth >= 0)) \ + spin_unlock(&kernel_flag); \ } while (0) /* * Re-acquire the kernel lock */ -#define reacquire_kernel_lock(task) \ -do { \ - if (task->lock_depth >= 0) \ - spin_lock(&kernel_flag); \ +#define reacquire_kernel_lock(task) \ +do { \ + if (unlikely(task->lock_depth >= 0)) \ + spin_lock(&kernel_flag); \ } while (0) @@ -40,8 +43,14 @@ */ static inline void lock_kernel(void) { +#ifdef CONFIG_PREEMPT + if (current->lock_depth == -1) + spin_lock(&kernel_flag); + ++current->lock_depth; +#else if (!++current->lock_depth) spin_lock(&kernel_flag); +#endif } static inline void unlock_kernel(void) diff -Nru a/include/asm-arm/softirq.h b/include/asm-arm/softirq.h --- a/include/asm-arm/softirq.h Tue Feb 26 11:57:59 2002 +++ b/include/asm-arm/softirq.h Tue Feb 26 11:57:59 2002 @@ -5,20 +5,22 @@ #include #define __cpu_bh_enable(cpu) \ - do { barrier(); local_bh_count(cpu)--; } while (0) + do { barrier(); local_bh_count(cpu)--; preempt_enable(); } while (0) #define cpu_bh_disable(cpu) \ - do { local_bh_count(cpu)++; barrier(); } while (0) + do { preempt_disable(); local_bh_count(cpu)++; barrier(); } while (0) #define local_bh_disable() cpu_bh_disable(smp_processor_id()) #define __local_bh_enable() __cpu_bh_enable(smp_processor_id()) #define in_softirq() (local_bh_count(smp_processor_id()) != 0) -#define local_bh_enable() \ +#define _local_bh_enable() \ do { \ unsigned int *ptr = &local_bh_count(smp_processor_id()); \ if (!--*ptr && ptr[-2]) \ __asm__("bl%? __do_softirq": : : "lr");/* out of line */\ } while (0) + +#define local_bh_enable() do { _local_bh_enable(); preempt_enable(); } while (0) #endif /* __ASM_SOFTIRQ_H */ diff -Nru a/include/asm-arm/stat.h b/include/asm-arm/stat.h --- a/include/asm-arm/stat.h Tue Feb 26 11:57:57 2002 +++ b/include/asm-arm/stat.h Tue Feb 26 11:57:57 2002 @@ -42,8 +42,14 @@ * insane amounts of padding around dev_t's. */ struct stat64 { - unsigned short st_dev; - unsigned char __pad0[10]; +#if defined(__ARMEB__) + unsigned char __pad0b[6]; + unsigned short st_dev; +#else + unsigned short st_dev; + unsigned char __pad0b[6]; +#endif + unsigned char __pad0[4]; #define STAT64_HAS_BROKEN_ST_INO 1 unsigned long __st_ino; @@ -53,14 +59,25 @@ unsigned long st_uid; unsigned long st_gid; - unsigned short st_rdev; - unsigned char __pad3[10]; +#if defined(__ARMEB__) + unsigned char __pad3b[6]; + unsigned short st_rdev; +#else /* Must be little */ + unsigned short st_rdev; + unsigned char __pad3b[6]; +#endif + unsigned char __pad3[4]; long long st_size; unsigned long st_blksize; - unsigned long st_blocks; /* Number 512-byte blocks allocated. */ - unsigned long __pad4; /* future possible st_blocks high bits */ +#if defined(__ARMEB__) + unsigned long __pad4; /* Future possible st_blocks hi bits */ + unsigned long st_blocks; /* Number 512-byte blocks allocated. */ +#else /* Must be little */ + unsigned long st_blocks; /* Number 512-byte blocks allocated. */ + unsigned long __pad4; /* Future possible st_blocks hi bits */ +#endif unsigned long st_atime; unsigned long __pad5; diff -Nru a/include/asm-arm/system.h b/include/asm-arm/system.h --- a/include/asm-arm/system.h Tue Feb 26 11:57:57 2002 +++ b/include/asm-arm/system.h Tue Feb 26 11:57:57 2002 @@ -6,6 +6,8 @@ #include #include +struct thread_info; + /* information about the system we're running on */ extern unsigned int system_rev; extern unsigned int system_serial_low; @@ -48,12 +50,13 @@ * `prev' will never be the same as `next'. * The `mb' is to tell GCC not to cache `current' across this call. */ -extern struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *next); +struct thread_info; +extern struct task_struct *__switch_to(struct thread_info *, struct thread_info *); -#define switch_to(prev,next,last) \ - do { \ - last = __switch_to(prev,next); \ - mb(); \ +#define switch_to(prev,next,last) \ + do { \ + last = __switch_to(prev->thread_info,next->thread_info); \ + mb(); \ } while (0) /* For spinlocks etc */ diff -Nru a/include/asm-arm/thread_info.h b/include/asm-arm/thread_info.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/thread_info.h Tue Feb 26 11:58:00 2002 @@ -0,0 +1,134 @@ +/* + * linux/include/asm-arm/thread_info.h + * + * Copyright (C) 2002 Russell King. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_ARM_THREAD_INFO_H +#define __ASM_ARM_THREAD_INFO_H + +#ifdef __KERNEL__ + +#ifndef __ASSEMBLY__ + +struct task_struct; +struct exec_domain; + +#include +#include +#include +#include + +typedef unsigned long mm_segment_t; /* domain register */ + +/* + * low level task data that entry.S needs immediate access to. + */ +struct thread_info { + __u32 flags; /* low level flags */ + __s32 preempt_count; /* 0 => preemptable, <0 => bug */ + mm_segment_t addr_limit; /* address limit */ + __u32 cpu; /* cpu */ + struct cpu_context_save *cpu_context; /* cpu context */ + __u32 cpu_domain; /* cpu domain */ + struct task_struct *task; /* main task structure */ + struct exec_domain *exec_domain; /* execution domain */ + union fp_state fpstate; +}; + +#define INIT_THREAD_INFO(tsk) \ +{ \ + task: &tsk, \ + exec_domain: &default_exec_domain, \ + flags: 0, \ + preempt_count: 0, \ + addr_limit: KERNEL_DS, \ + INIT_EXTRA_THREAD_INFO, \ +} + +#define init_thread_info (init_thread_union.thread_info) +#define init_stack (init_thread_union.stack) + +/* + * how to get the thread information struct from C + */ +static inline struct thread_info *current_thread_info(void) __attribute__ (( __const__ )); + +static inline struct thread_info *current_thread_info(void) +{ + register unsigned long sp asm ("sp"); + return (struct thread_info *)(sp & ~0x1fff); +} + +#define THREAD_SIZE (8192) + +extern struct thread_info *alloc_thread_info(void); +extern void free_thread_info(struct thread_info *); + +#define get_thread_info(ti) get_task_struct((ti)->task) +#define put_thread_info(ti) put_task_struct((ti)->task) + +static inline unsigned long __thread_saved_pc(struct thread_info *thread) +{ + struct cpu_context_save *context = thread->cpu_context; + + return context ? pc_pointer(context->pc) : 0; +} + +static inline unsigned long __thread_saved_fp(struct thread_info *thread) +{ + struct cpu_context_save *context = thread->cpu_context; + + return context ? context->fp : 0; +} + +#define thread_saved_pc(tsk) __thread_saved_pc((tsk)->thread_info) +#define thread_saved_fp(tsk) __thread_saved_fp((tsk)->thread_info) + +#else /* !__ASSEMBLY__ */ + +#define TI_FLAGS 0 +#define TI_PREEMPT 4 +#define TI_ADDR_LIMIT 8 +#define TI_CPU 12 +#define TI_CPU_SAVE 16 +#define TI_CPU_DOMAIN 20 +#define TI_TASK 24 +#define TI_EXEC_DOMAIN 28 +#define TI_FPSTATE 32 + +#endif + +/* + * thread information flags: + * TIF_SYSCALL_TRACE - syscall trace active + * TIF_NOTIFY_RESUME - resumption notification requested + * TIF_SIGPENDING - signal pending + * TIF_NEED_RESCHED - rescheduling necessary + * TIF_USEDFPU - FPU was used by this task this quantum (SMP) + * TIF_POLLING_NRFLAG - true if poll_idle() is polling TIF_NEED_RESCHED + */ +#define TIF_NOTIFY_RESUME 0 +#define TIF_SIGPENDING 1 +#define TIF_NEED_RESCHED 2 +#define TIF_SYSCALL_TRACE 8 +#define TIF_USED_FPU 16 +#define TIF_POLLING_NRFLAG 17 + +#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) +#define _TIF_SIGPENDING (1 << TIF_SIGPENDING) +#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) +#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) +#define _TIF_USED_FPU (1 << TIF_USED_FPU) +#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) + +/* + * Change these and you break ASM code in entry-common.S + */ +#define _TIF_WORK_MASK 0x000000ff + +#endif /* __KERNEL__ */ +#endif /* __ASM_ARM_THREAD_INFO_H */ diff -Nru a/include/asm-arm/uaccess.h b/include/asm-arm/uaccess.h --- a/include/asm-arm/uaccess.h Tue Feb 26 11:57:56 2002 +++ b/include/asm-arm/uaccess.h Tue Feb 26 11:57:56 2002 @@ -32,7 +32,7 @@ extern unsigned long search_exception_table(unsigned long); #define get_ds() (KERNEL_DS) -#define get_fs() (current->addr_limit) +#define get_fs() (current_thread_info()->addr_limit) #define segment_eq(a,b) ((a) == (b)) #include diff -Nru a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h --- a/include/asm-arm/unistd.h Tue Feb 26 11:57:59 2002 +++ b/include/asm-arm/unistd.h Tue Feb 26 11:57:59 2002 @@ -244,6 +244,19 @@ #define __NR_security (__NR_SYSCALL_BASE+223) #define __NR_gettid (__NR_SYSCALL_BASE+224) #define __NR_readahead (__NR_SYSCALL_BASE+225) +#define __NR_setxattr (__NR_SYSCALL_BASE+226) +#define __NR_lsetxattr (__NR_SYSCALL_BASE+227) +#define __NR_fsetxattr (__NR_SYSCALL_BASE+228) +#define __NR_getxattr (__NR_SYSCALL_BASE+229) +#define __NR_lgetxattr (__NR_SYSCALL_BASE+230) +#define __NR_fgetxattr (__NR_SYSCALL_BASE+231) +#define __NR_listxattr (__NR_SYSCALL_BASE+232) +#define __NR_llistxattr (__NR_SYSCALL_BASE+233) +#define __NR_flistxattr (__NR_SYSCALL_BASE+234) +#define __NR_removexattr (__NR_SYSCALL_BASE+235) +#define __NR_lremovexattr (__NR_SYSCALL_BASE+236) +#define __NR_fremovexattr (__NR_SYSCALL_BASE+237) +#define __NR_tkill (__NR_SYSCALL_BASE+238) /* * The following SWIs are ARM private. diff -Nru a/include/asm-i386/fixmap.h b/include/asm-i386/fixmap.h --- a/include/asm-i386/fixmap.h Tue Feb 26 11:57:56 2002 +++ b/include/asm-i386/fixmap.h Tue Feb 26 11:57:56 2002 @@ -65,6 +65,11 @@ FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, #endif + __end_of_permanent_fixed_addresses, + /* temporary boot-time mappings, used before ioremap() is functional */ +#define NR_FIX_BTMAPS 16 + FIX_BTMAP_END = __end_of_permanent_fixed_addresses, + FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS - 1, __end_of_fixed_addresses }; @@ -86,8 +91,8 @@ * at the top of mem.. */ #define FIXADDR_TOP (0xffffe000UL) -#define FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT) -#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE) +#define __FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT) +#define FIXADDR_START (FIXADDR_TOP - __FIXADDR_SIZE) #define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT)) diff -Nru a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h --- a/include/asm-i386/hw_irq.h Tue Feb 26 11:57:59 2002 +++ b/include/asm-i386/hw_irq.h Tue Feb 26 11:57:59 2002 @@ -35,14 +35,13 @@ * into a single vector (CALL_FUNCTION_VECTOR) to save vector space. * TLB, reschedule and local APIC vectors are performance-critical. * - * Vectors 0xf0-0xf9 are free (reserved for future Linux use). + * Vectors 0xf0-0xfa are free (reserved for future Linux use). */ #define SPURIOUS_APIC_VECTOR 0xff #define ERROR_APIC_VECTOR 0xfe #define INVALIDATE_TLB_VECTOR 0xfd #define RESCHEDULE_VECTOR 0xfc -#define TASK_MIGRATION_VECTOR 0xfb -#define CALL_FUNCTION_VECTOR 0xfa +#define CALL_FUNCTION_VECTOR 0xfb /* * Local APIC timer IRQ vector is on a different priority level, diff -Nru a/include/asm-i386/io.h b/include/asm-i386/io.h --- a/include/asm-i386/io.h Tue Feb 26 11:57:59 2002 +++ b/include/asm-i386/io.h Tue Feb 26 11:57:59 2002 @@ -95,6 +95,14 @@ extern void iounmap(void *addr); /* + * bt_ioremap() and bt_iounmap() are for temporary early boot-time + * mappings, before the real ioremap() is functional. + * A boot-time mapping is currently limited to at most 16 pages. + */ +extern void *bt_ioremap(unsigned long offset, unsigned long size); +extern void bt_iounmap(void *addr, unsigned long size); + +/* * ISA I/O bus memory addresses are 1:1 with the physical address. */ #define isa_virt_to_bus virt_to_phys diff -Nru a/include/linux/dcache.h b/include/linux/dcache.h --- a/include/linux/dcache.h Tue Feb 26 11:57:59 2002 +++ b/include/linux/dcache.h Tue Feb 26 11:57:59 2002 @@ -126,6 +126,7 @@ #define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */ extern spinlock_t dcache_lock; +extern rwlock_t dparent_lock; /** * d_drop - drop a dentry diff -Nru a/include/linux/dnotify.h b/include/linux/dnotify.h --- a/include/linux/dnotify.h Tue Feb 26 11:57:56 2002 +++ b/include/linux/dnotify.h Tue Feb 26 11:57:56 2002 @@ -33,13 +33,13 @@ static inline void dnotify_parent(struct dentry *dentry, unsigned long event) { struct dentry *parent; - spin_lock(&dcache_lock); + read_lock(&dparent_lock); parent = dentry->d_parent; if (parent->d_inode->i_dnotify_mask & event) { dget(parent); - spin_unlock(&dcache_lock); + read_unlock(&dparent_lock); __inode_dir_notify(parent->d_inode, event); dput(parent); } else - spin_unlock(&dcache_lock); + read_unlock(&dparent_lock); } diff -Nru a/include/linux/fs.h b/include/linux/fs.h --- a/include/linux/fs.h Tue Feb 26 11:57:58 2002 +++ b/include/linux/fs.h Tue Feb 26 11:57:58 2002 @@ -377,8 +377,8 @@ unsigned long nrpages; /* number of total pages */ struct address_space_operations *a_ops; /* methods */ struct inode *host; /* owner: inode, block_device */ - struct vm_area_struct *i_mmap; /* list of private mappings */ - struct vm_area_struct *i_mmap_shared; /* list of shared mappings */ + list_t i_mmap; /* list of private mappings */ + list_t i_mmap_shared; /* list of private mappings */ spinlock_t i_shared_lock; /* and spinlock protecting it */ int gfp_mask; /* how to allocate the pages */ }; @@ -1511,9 +1511,9 @@ static inline ino_t parent_ino(struct dentry *dentry) { ino_t res; - spin_lock(&dcache_lock); + read_lock(&dparent_lock); res = dentry->d_parent->d_inode->i_ino; - spin_unlock(&dcache_lock); + read_unlock(&dparent_lock); return res; } diff -Nru a/include/linux/lvm.h b/include/linux/lvm.h --- a/include/linux/lvm.h Tue Feb 26 11:57:56 2002 +++ b/include/linux/lvm.h Tue Feb 26 11:57:56 2002 @@ -477,8 +477,16 @@ * Structure Logical Volume (LV) Version 3 */ -/* core */ -typedef struct lv_v5 { +struct kern_lv_v5; +struct user_lv_v5; +typedef struct user_lv_v5 userlv_t; +#ifdef __KERNEL__ +typedef struct kern_lv_v5 lv_t; +#else +typedef struct user_lv_v5 lv_t; +#endif + +struct user_lv_v5 { char lv_name[NAME_LEN]; char vg_name[NAME_LEN]; uint lv_access; @@ -501,15 +509,18 @@ uint lv_read_ahead; /* delta to version 1 starts here */ - struct lv_v5 *lv_snapshot_org; - struct lv_v5 *lv_snapshot_prev; - struct lv_v5 *lv_snapshot_next; + lv_t *lv_snapshot_org; + lv_t *lv_snapshot_prev; + lv_t *lv_snapshot_next; lv_block_exception_t *lv_block_exception; uint lv_remap_ptr; uint lv_remap_end; uint lv_chunk_size; uint lv_snapshot_minor; -#ifdef __KERNEL__ +}; + +struct kern_lv_v5{ + struct user_lv_v5 u; struct kiobuf *lv_iobuf; sector_t blocks[LVM_MAX_SECTORS]; struct kiobuf *lv_COW_table_iobuf; @@ -520,12 +531,8 @@ wait_queue_head_t lv_snapshot_wait; int lv_snapshot_use_rate; struct vg_v3 *vg; - uint lv_allocated_snapshot_le; -#else - char dummy[200]; -#endif -} lv_t; +}; /* disk */ typedef struct lv_disk_v3 { @@ -679,13 +686,13 @@ } static int inline LVM_GET_COW_TABLE_CHUNKS_PER_PE(vg_t *vg, lv_t *lv) { - return vg->pe_size / lv->lv_chunk_size; + return vg->pe_size / lv->u.lv_chunk_size; } static int inline LVM_GET_COW_TABLE_ENTRIES_PER_PE(vg_t *vg, lv_t *lv) { - ulong chunks = vg->pe_size / lv->lv_chunk_size; + ulong chunks = vg->pe_size / lv->u.lv_chunk_size; ulong entry_size = sizeof(lv_COW_table_disk_t); - ulong chunk_size = lv->lv_chunk_size * SECTOR_SIZE; + ulong chunk_size = lv->u.lv_chunk_size * SECTOR_SIZE; ulong entries = (vg->pe_size * SECTOR_SIZE) / (entry_size + chunk_size); diff -Nru a/include/linux/mm.h b/include/linux/mm.h --- a/include/linux/mm.h Tue Feb 26 11:57:56 2002 +++ b/include/linux/mm.h Tue Feb 26 11:57:56 2002 @@ -61,8 +61,7 @@ * one of the address_space->i_mmap{,shared} lists, * for shm areas, the list of attaches, otherwise unused. */ - struct vm_area_struct *vm_next_share; - struct vm_area_struct **vm_pprev_share; + list_t shared; /* Function pointers to deal with this struct. */ struct vm_operations_struct * vm_ops; @@ -585,7 +584,7 @@ extern struct vm_area_struct *find_extend_vma(struct mm_struct *mm, unsigned long addr); -extern struct page * vmalloc_to_page(unsigned long adr); +extern struct page * vmalloc_to_page(void *addr); #endif /* __KERNEL__ */ diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h --- a/include/linux/pci_ids.h Tue Feb 26 11:57:59 2002 +++ b/include/linux/pci_ids.h Tue Feb 26 11:57:59 2002 @@ -772,6 +772,7 @@ #define PCI_VENDOR_ID_3COM 0x10b7 #define PCI_DEVICE_ID_3COM_3C985 0x0001 #define PCI_DEVICE_ID_3COM_3C339 0x3390 +#define PCI_DEVICE_ID_3COM_3C359 0x3590 #define PCI_DEVICE_ID_3COM_3C590 0x5900 #define PCI_DEVICE_ID_3COM_3C595TX 0x5950 #define PCI_DEVICE_ID_3COM_3C595T4 0x5951 @@ -1461,9 +1462,9 @@ #define PCI_VENDOR_ID_OXSEMI 0x1415 #define PCI_DEVICE_ID_OXSEMI_12PCI840 0x8403 #define PCI_DEVICE_ID_OXSEMI_16PCI954 0x9501 -#define PCI_DEVICE_ID_OXSEMI_16PCI952 0x950A #define PCI_DEVICE_ID_OXSEMI_16PCI95N 0x9511 #define PCI_DEVICE_ID_OXSEMI_16PCI954PP 0x9513 +#define PCI_DEVICE_ID_OXSEMI_16PCI952 0x9521 #define PCI_VENDOR_ID_AIRONET 0x14b9 #define PCI_DEVICE_ID_AIRONET_4800_1 0x0001 diff -Nru a/include/linux/rtc.h b/include/linux/rtc.h --- a/include/linux/rtc.h Tue Feb 26 11:57:56 2002 +++ b/include/linux/rtc.h Tue Feb 26 11:57:56 2002 @@ -66,4 +66,17 @@ #define RTC_WKALM_SET _IOW('p', 0x0f, struct rtc_wkalrm)/* Set wakeup alarm*/ #define RTC_WKALM_RD _IOR('p', 0x10, struct rtc_wkalrm)/* Get wakeup alarm*/ +#ifdef __KERNEL__ + +typedef struct rtc_task { + void (*func)(void *private_data); + void *private_data; +} rtc_task_t; + +int rtc_register(rtc_task_t *task); +int rtc_unregister(rtc_task_t *task); +int rtc_control(rtc_task_t *t, unsigned int cmd, unsigned long arg); + +#endif /* __KERNEL__ */ + #endif /* _LINUX_RTC_H_ */ diff -Nru a/include/linux/sched.h b/include/linux/sched.h --- a/include/linux/sched.h Tue Feb 26 11:57:57 2002 +++ b/include/linux/sched.h Tue Feb 26 11:57:57 2002 @@ -150,8 +150,7 @@ extern void update_one_process(struct task_struct *p, unsigned long user, unsigned long system, int cpu); extern void scheduler_tick(int user_tick, int system); -extern void sched_task_migrated(struct task_struct *p); -extern void smp_migrate_task(int cpu, task_t *task); +extern void migration_init(void); extern unsigned long cache_decay_ticks; @@ -286,6 +285,7 @@ wait_queue_head_t wait_chldexit; /* for wait4() */ struct completion *vfork_done; /* for vfork() */ + unsigned long rt_priority; unsigned long it_real_value, it_prof_value, it_virt_value; unsigned long it_real_incr, it_prof_incr, it_virt_incr; @@ -382,7 +382,12 @@ */ #define _STK_LIM (8*1024*1024) +#if CONFIG_SMP extern void set_cpus_allowed(task_t *p, unsigned long new_mask); +#else +# define set_cpus_allowed(p, new_mask) do { } while (0) +#endif + extern void set_user_nice(task_t *p, long nice); extern int task_prio(task_t *p); extern int task_nice(task_t *p); @@ -460,7 +465,6 @@ extern unsigned long prof_shift; extern void FASTCALL(__wake_up(wait_queue_head_t *q, unsigned int mode, int nr)); -extern void FASTCALL(__wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr)); extern void FASTCALL(sleep_on(wait_queue_head_t *q)); extern long FASTCALL(sleep_on_timeout(wait_queue_head_t *q, signed long timeout)); @@ -474,13 +478,9 @@ #define wake_up(x) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1) #define wake_up_nr(x, nr) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, nr) #define wake_up_all(x) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 0) -#define wake_up_sync(x) __wake_up_sync((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1) -#define wake_up_sync_nr(x, nr) __wake_up_sync((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, nr) #define wake_up_interruptible(x) __wake_up((x),TASK_INTERRUPTIBLE, 1) #define wake_up_interruptible_nr(x, nr) __wake_up((x),TASK_INTERRUPTIBLE, nr) #define wake_up_interruptible_all(x) __wake_up((x),TASK_INTERRUPTIBLE, 0) -#define wake_up_interruptible_sync(x) __wake_up_sync((x),TASK_INTERRUPTIBLE, 1) -#define wake_up_interruptible_sync_nr(x) __wake_up_sync((x),TASK_INTERRUPTIBLE, nr) asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru); extern int in_group_p(gid_t); diff -Nru a/include/math-emu/op-4.h b/include/math-emu/op-4.h --- a/include/math-emu/op-4.h Tue Feb 26 11:57:58 2002 +++ b/include/math-emu/op-4.h Tue Feb 26 11:57:58 2002 @@ -645,7 +645,7 @@ X##_f[1] = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE); \ X##_f[2] = (rsize <= 2*_FP_W_TYPE_SIZE ? 0 : r >> 2*_FP_W_TYPE_SIZE); \ X##_f[3] = (rsize <= 3*_FP_W_TYPE_SIZE ? 0 : r >> 3*_FP_W_TYPE_SIZE); \ - } while (0); + } while (0) #define _FP_FRAC_CONV_4_1(dfs, sfs, D, S) \ do { \ diff -Nru a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h --- a/include/sound/ac97_codec.h Tue Feb 26 11:57:56 2002 +++ b/include/sound/ac97_codec.h Tue Feb 26 11:57:56 2002 @@ -135,6 +135,7 @@ struct _snd_ac97 { void (*write) (ac97_t *ac97, unsigned short reg, unsigned short val); unsigned short (*read) (ac97_t *ac97, unsigned short reg); + void (*wait) (ac97_t *ac97); void (*init) (ac97_t *ac97); snd_info_entry_t *proc_entry; snd_info_entry_t *proc_regs_entry; diff -Nru a/include/sound/asound.h b/include/sound/asound.h --- a/include/sound/asound.h Tue Feb 26 11:57:59 2002 +++ b/include/sound/asound.h Tue Feb 26 11:57:59 2002 @@ -127,7 +127,7 @@ * * *****************************************************************************/ -#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 0) +#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 1) typedef unsigned long sndrv_pcm_uframes_t; typedef long sndrv_pcm_sframes_t; @@ -411,6 +411,7 @@ SNDRV_PCM_IOCTL_PAUSE = _IOW('A', 0x45, int), SNDRV_PCM_IOCTL_REWIND = _IOW('A', 0x46, sndrv_pcm_uframes_t), SNDRV_PCM_IOCTL_RESUME = _IO('A', 0x47), + SNDRV_PCM_IOCTL_XRUN = _IO('A', 0x48), SNDRV_PCM_IOCTL_WRITEI_FRAMES = _IOW('A', 0x50, struct sndrv_xferi), SNDRV_PCM_IOCTL_READI_FRAMES = _IOR('A', 0x51, struct sndrv_xferi), SNDRV_PCM_IOCTL_WRITEN_FRAMES = _IOW('A', 0x52, struct sndrv_xfern), @@ -578,7 +579,7 @@ * * ****************************************************************************/ -#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 0) +#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 0) struct sndrv_ctl_card_info { int card; /* card number */ diff -Nru a/include/sound/core.h b/include/sound/core.h --- a/include/sound/core.h Tue Feb 26 11:57:59 2002 +++ b/include/sound/core.h Tue Feb 26 11:57:59 2002 @@ -292,13 +292,21 @@ /* misc.c */ int snd_task_name(struct task_struct *task, char *name, size_t size); +#ifdef CONFIG_SND_VERBOSE_PRINTK +int snd_verbose_printk(const char *file, int line, const char *format); +#endif /* --- */ +#ifdef CONFIG_SND_VERBOSE_PRINTK +#define snd_printk(format, args...) do { \ + printk(snd_verbose_printk(__FILE__, __LINE__, format) ? format + 3 : format, ##args); \ +} while (0) +#else #define snd_printk(format, args...) do { \ - printk("ALSA %s:%d: ", __FILE__, __LINE__); \ printk(format, ##args); \ } while (0) +#endif #ifdef CONFIG_SND_DEBUG diff -Nru a/include/sound/emu10k1.h b/include/sound/emu10k1.h --- a/include/sound/emu10k1.h Tue Feb 26 11:57:58 2002 +++ b/include/sound/emu10k1.h Tue Feb 26 11:57:58 2002 @@ -588,7 +588,7 @@ #define REG53 0x53 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */ #define A_DBG 0x53 -#define A_DBG_SINGLE_STEP_ADDR 0x00020000 /* Set to zero to start dsp */ +#define A_DBG_SINGLE_STEP 0x00020000 /* Set to zero to start dsp */ #define A_DBG_ZC 0x40000000 /* zero tram counter */ #define A_DBG_STEP_ADDR 0x000003ff #define A_DBG_SATURATION_OCCURED 0x20000000 @@ -657,6 +657,11 @@ #define SRCS_RATELOCKED 0x01000000 /* Sample rate locked */ #define SRCS_ESTSAMPLERATE 0x0007ffff /* Do not modify this field. */ +/* Note that these values can vary +/- by a small amount */ +#define SRCS_SPDIFRATE_44 0x0003acd9 +#define SRCS_SPDIFRATE_48 0x00040000 +#define SRCS_SPDIFRATE_96 0x00080000 + #define MICIDX 0x63 /* Microphone recording buffer index register */ #define MICIDX_MASK 0x0000ffff /* 16-bit value */ #define MICIDX_IDX 0x10000063 @@ -683,15 +688,15 @@ #define A_MUSTAT2 A_MUCMD2 #define A_SPDIF_SAMPLERATE 0x76 /* Set the sample rate of SPDIF output */ -#define A_SPDIF_48000 0x00000000 -#define A_SPDIF_44100 0x00000040 -#define A_SPDIF_96000 0x00000080 +#define A_SPDIF_48000 0x00000080 +#define A_SPDIF_44100 0x00000000 +#define A_SPDIF_96000 0x00000040 #define A_FXRT2 0x7c -#define A_FXRT_CHANNELE 0x0000003f /* Effects send bus number for channel's effects send A */ -#define A_FXRT_CHANNELF 0x00003f00 /* Effects send bus number for channel's effects send B */ -#define A_FXRT_CHANNELG 0x003f0000 /* Effects send bus number for channel's effects send C */ -#define A_FXRT_CHANNELH 0x3f000000 /* Effects send bus number for channel's effects send D */ +#define A_FXRT_CHANNELE 0x0000003f /* Effects send bus number for channel's effects send E */ +#define A_FXRT_CHANNELF 0x00003f00 /* Effects send bus number for channel's effects send F */ +#define A_FXRT_CHANNELG 0x003f0000 /* Effects send bus number for channel's effects send G */ +#define A_FXRT_CHANNELH 0x3f000000 /* Effects send bus number for channel's effects send H */ #define A_SENDAMOUNTS 0x7d #define A_FXSENDAMOUNT_E_MASK 0xFF000000 @@ -797,8 +802,8 @@ }; typedef struct { - unsigned long send_routing[3]; - unsigned char send_volume[3][4]; + unsigned char send_routing[3][8]; + unsigned char send_volume[3][8]; unsigned short attn[3]; snd_kcontrol_t *ctl_send_routing; snd_kcontrol_t *ctl_send_volume; @@ -806,6 +811,15 @@ emu10k1_pcm_t *epcm; } emu10k1_pcm_mixer_t; +#define snd_emu10k1_compose_send_routing(route) \ +((route[0] | (route[1] << 4) | (route[2] << 8) | (route[3] << 12)) << 16) + +#define snd_emu10k1_compose_audigy_fxrt1(route) \ +(((unsigned int)route[0] | ((unsigned int)route[1] << 8) | ((unsigned int)route[2] << 16) | ((unsigned int)route[3] << 12)) << 24) + +#define snd_emu10k1_compose_audigy_fxrt2(route) \ +(((unsigned int)route[4] | ((unsigned int)route[5] << 8) | ((unsigned int)route[6] << 16) | ((unsigned int)route[7] << 12)) << 24) + typedef struct snd_emu10k1_memblk { snd_util_memblk_t mem; /* private part */ @@ -1102,11 +1116,11 @@ #define GPR_NOISE1 0x59 /* noise source */ #define GPR_IRQ 0x5a /* IRQ register */ #define GPR_DBAC 0x5b /* TRAM Delay Base Address Counter */ -#define GPR(x) (FXGPREGBASE + (x)) /* free GPRs: x = 0x00 - 0xff */ -#define ITRAM_DATA(x) (TANKMEMDATAREGBASE + (x)) /* x = 0x00 - 0x7f */ -#define ETRAM_DATA(x) (TANKMEMDATAREGBASE + 80 + (x)) /* x = 0x00 - 0x1f */ -#define ITRAM_ADDR(x) (TANKMEMADDRREGBASE + (x)) /* x = 0x00 - 0x7f */ -#define ETRAM_ADDR(x) (TANKMEMADDRREGBASE + 80 + (x)) /* x = 0x00 - 0x1f */ +#define GPR(x) (FXGPREGBASE + (x)) /* free GPRs: x = 0x00 - 0xff */ +#define ITRAM_DATA(x) (TANKMEMDATAREGBASE + 0x00 + (x)) /* x = 0x00 - 0x7f */ +#define ETRAM_DATA(x) (TANKMEMDATAREGBASE + 0x80 + (x)) /* x = 0x00 - 0x1f */ +#define ITRAM_ADDR(x) (TANKMEMADDRREGBASE + 0x00 + (x)) /* x = 0x00 - 0x7f */ +#define ETRAM_ADDR(x) (TANKMEMADDRREGBASE + 0x80 + (x)) /* x = 0x00 - 0x1f */ #define A_FXBUS(x) (0x00 + (x)) /* x = 0x00 - 0x3f? */ #define A_EXTIN(x) (0x40 + (x)) /* x = 0x00 - 0x1f? */ @@ -1171,6 +1185,10 @@ #define A_EXTIN_AC97_R 0x01 /* AC'97 capture channel - right */ #define A_EXTIN_SPDIF_CD_L 0x02 /* digital CD left */ #define A_EXTIN_SPDIF_CD_R 0x03 /* digital CD left */ +#define A_EXTIN_LINE2_L 0x08 /* audigy drive line2/mic2 - left */ +#define A_EXTIN_LINE2_R 0x09 /* right */ +#define A_EXTIN_AUX2_L 0x0c /* audigy drive aux2 - left */ +#define A_EXTIN_AUX2_R 0x0d /* - right */ /* Audigiy Outputs */ #define A_EXTOUT_FRONT_L 0x00 /* digital front left */ @@ -1189,9 +1207,38 @@ /* 0x0d ?? */ #define A_EXTOUT_AREAR_L 0x0e /* analog rear left */ #define A_EXTOUT_AREAR_R 0x0f /* right */ -/* 0x10-0x15 ?? */ -#define A_EXTOUT_ADC_CAP_L 0x16 /* ADC capture buffer left */ -#define A_EXTOUT_ADC_CAP_R 0x17 /* right */ +#define A_EXTOUT_AC97_L 0x10 /* AC97 left (front) */ +#define A_EXTOUT_AC97_R 0x11 /* right */ +#define A_EXTOUT_ADC_CAP_L 0x12 /* ADC capture buffer left */ +#define A_EXTOUT_ADC_CAP_R 0x13 /* right */ + +/* Audigy constants */ +#define A_C_00000000 0xc0 +#define A_C_00000001 0xc1 +#define A_C_00000002 0xc2 +#define A_C_00000003 0xc3 +#define A_C_00000004 0xc4 +#define A_C_00000008 0xc5 +#define A_C_00000010 0xc6 +#define A_C_00000020 0xc7 +#define A_C_00000100 0xc8 +#define A_C_00010000 0xc9 +#define A_C_00000800 0xca +#define A_C_10000000 0xcb +#define A_C_20000000 0xcc +#define A_C_40000000 0xcd +#define A_C_80000000 0xce +#define A_C_7fffffff 0xcf +#define A_C_ffffffff 0xd0 +#define A_C_fffffffe 0xd1 +#define A_C_c0000000 0xd2 +#define A_C_4f1bbcdc 0xd3 +#define A_C_5a7ef9db 0xd4 +#define A_C_00100000 0xd5 +/* 0xd6 = 0x7fffffff (?) ACCUM? */ +/* 0xd7 = 0x0000000 CCR */ +/* 0xd8 = noise1 */ +/* 0xd9 = noise2 */ /* definitions for debug register */ #define EMU10K1_DBG_ZC 0x80000000 /* zero tram counter */ diff -Nru a/include/sound/version.h b/include/sound/version.h --- a/include/sound/version.h Tue Feb 26 11:57:58 2002 +++ b/include/sound/version.h Tue Feb 26 11:57:58 2002 @@ -1,3 +1,3 @@ /* include/version.h. Generated automatically by configure. */ -#define CONFIG_SND_VERSION "0.9.0beta11" -#define CONFIG_SND_DATE " (Tue Feb 19 08:14:59 2002 UTC)" +#define CONFIG_SND_VERSION "0.9.0beta12" +#define CONFIG_SND_DATE " (Tue Feb 26 09:34:24 2002 UTC)" diff -Nru a/init/main.c b/init/main.c --- a/init/main.c Tue Feb 26 11:57:57 2002 +++ b/init/main.c Tue Feb 26 11:57:57 2002 @@ -413,7 +413,12 @@ */ static void __init do_basic_setup(void) { - + /* + * Let the per-CPU migration threads start up: + */ +#if CONFIG_SMP + migration_init(); +#endif /* * Tell the world that we're going to be the grim * reaper of innocent orphaned children. diff -Nru a/kernel/exec_domain.c b/kernel/exec_domain.c --- a/kernel/exec_domain.c Tue Feb 26 11:57:59 2002 +++ b/kernel/exec_domain.c Tue Feb 26 11:57:59 2002 @@ -4,7 +4,7 @@ * We group personalities into execution domains which have their * own handlers for kernel entry points, signal mapping, etc... * - * 2001-05-06 Complete rewrite, Christoph Hellwig (hch@caldera.de) + * 2001-05-06 Complete rewrite, Christoph Hellwig (hch@infradead.org) */ #include diff -Nru a/kernel/fork.c b/kernel/fork.c --- a/kernel/fork.c Tue Feb 26 11:57:57 2002 +++ b/kernel/fork.c Tue Feb 26 11:57:57 2002 @@ -219,11 +219,7 @@ /* insert tmp into the share list, just after mpnt */ spin_lock(&inode->i_mapping->i_shared_lock); - if((tmp->vm_next_share = mpnt->vm_next_share) != NULL) - mpnt->vm_next_share->vm_pprev_share = - &tmp->vm_next_share; - mpnt->vm_next_share = tmp; - tmp->vm_pprev_share = &mpnt->vm_next_share; + list_add_tail(&tmp->shared, &mpnt->shared); spin_unlock(&inode->i_mapping->i_shared_lock); } diff -Nru a/kernel/kmod.c b/kernel/kmod.c --- a/kernel/kmod.c Tue Feb 26 11:57:58 2002 +++ b/kernel/kmod.c Tue Feb 26 11:57:58 2002 @@ -159,7 +159,7 @@ ret = exec_usermodehelper(modprobe_path, argv, envp); if (ret) { - printk(KERN_ERR + printk(KERN_DEBUG "kmod: failed to exec %s -s -k %s, errno = %d\n", modprobe_path, (char*) module_name, errno); } diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c --- a/kernel/ksyms.c Tue Feb 26 11:57:56 2002 +++ b/kernel/ksyms.c Tue Feb 26 11:57:56 2002 @@ -107,6 +107,7 @@ EXPORT_SYMBOL(kfree); EXPORT_SYMBOL(vfree); EXPORT_SYMBOL(__vmalloc); +EXPORT_SYMBOL_GPL(vmalloc_to_page); EXPORT_SYMBOL(mem_map); EXPORT_SYMBOL(remap_page_range); EXPORT_SYMBOL(max_mapnr); @@ -442,7 +443,6 @@ /* process management */ EXPORT_SYMBOL(complete_and_exit); EXPORT_SYMBOL(__wake_up); -EXPORT_SYMBOL(__wake_up_sync); EXPORT_SYMBOL(wake_up_process); EXPORT_SYMBOL(sleep_on); EXPORT_SYMBOL(sleep_on_timeout); @@ -457,6 +457,9 @@ EXPORT_SYMBOL(set_user_nice); EXPORT_SYMBOL(task_nice); EXPORT_SYMBOL_GPL(idle_cpu); +#if CONFIG_SMP +EXPORT_SYMBOL_GPL(set_cpus_allowed); +#endif EXPORT_SYMBOL(jiffies); EXPORT_SYMBOL(xtime); EXPORT_SYMBOL(do_gettimeofday); diff -Nru a/kernel/sched.c b/kernel/sched.c --- a/kernel/sched.c Tue Feb 26 11:57:58 2002 +++ b/kernel/sched.c Tue Feb 26 11:57:58 2002 @@ -16,12 +16,12 @@ #include #include #include +#include #include +#include #include #include -#include #include -#include /* * Priority of a process goes from 0 to 139. The 0-99 @@ -127,8 +127,6 @@ struct prio_array { int nr_active; - spinlock_t *lock; - runqueue_t *rq; unsigned long bitmap[BITMAP_SIZE]; list_t queue[MAX_PRIO]; }; @@ -146,6 +144,8 @@ task_t *curr, *idle; prio_array_t *active, *expired, arrays[2]; int prev_nr_running[NR_CPUS]; + task_t *migration_thread; + list_t migration_queue; } ____cacheline_aligned; static struct runqueue runqueues[NR_CPUS] __cacheline_aligned; @@ -156,23 +156,23 @@ #define cpu_curr(cpu) (cpu_rq(cpu)->curr) #define rt_task(p) ((p)->prio < MAX_RT_PRIO) -static inline runqueue_t *lock_task_rq(task_t *p, unsigned long *flags) +static inline runqueue_t *task_rq_lock(task_t *p, unsigned long *flags) { - struct runqueue *__rq; + struct runqueue *rq; repeat_lock_task: preempt_disable(); - __rq = task_rq(p); - spin_lock_irqsave(&__rq->lock, *flags); - if (unlikely(__rq != task_rq(p))) { - spin_unlock_irqrestore(&__rq->lock, *flags); + rq = task_rq(p); + spin_lock_irqsave(&rq->lock, *flags); + if (unlikely(rq != task_rq(p))) { + spin_unlock_irqrestore(&rq->lock, *flags); preempt_enable(); goto repeat_lock_task; } - return __rq; + return rq; } -static inline void unlock_task_rq(runqueue_t *rq, unsigned long *flags) +static inline void task_rq_unlock(runqueue_t *rq, unsigned long *flags) { spin_unlock_irqrestore(&rq->lock, *flags); preempt_enable(); @@ -184,7 +184,7 @@ static inline void dequeue_task(struct task_struct *p, prio_array_t *array) { array->nr_active--; - list_del_init(&p->run_list); + list_del(&p->run_list); if (list_empty(array->queue + p->prio)) __clear_bit(p->prio, array->bitmap); } @@ -289,31 +289,17 @@ cpu_relax(); barrier(); } - rq = lock_task_rq(p, &flags); + rq = task_rq_lock(p, &flags); if (unlikely(rq->curr == p)) { - unlock_task_rq(rq, &flags); + task_rq_unlock(rq, &flags); preempt_enable(); goto repeat; } - unlock_task_rq(rq, &flags); + task_rq_unlock(rq, &flags); preempt_enable(); } /* - * The SMP message passing code calls this function whenever - * the new task has arrived at the target CPU. We move the - * new task into the local runqueue. - * - * This function must be called with interrupts disabled. - */ -void sched_task_migrated(task_t *new_task) -{ - wait_task_inactive(new_task); - new_task->thread_info->cpu = smp_processor_id(); - wake_up_process(new_task); -} - -/* * Kick the remote CPU if the task is running currently, * this code is used by the signal code to signal tasks * which are in user-mode as quickly as possible. @@ -337,27 +323,27 @@ * "current->state = TASK_RUNNING" to mark yourself runnable * without the overhead of this. */ -static int try_to_wake_up(task_t * p, int synchronous) +static int try_to_wake_up(task_t * p) { unsigned long flags; int success = 0; runqueue_t *rq; - rq = lock_task_rq(p, &flags); + rq = task_rq_lock(p, &flags); p->state = TASK_RUNNING; if (!p->array) { activate_task(p, rq); - if ((rq->curr == rq->idle) || (p->prio < rq->curr->prio)) + if (p->prio < rq->curr->prio) resched_task(rq->curr); success = 1; } - unlock_task_rq(rq, &flags); + task_rq_unlock(rq, &flags); return success; } int wake_up_process(task_t * p) { - return try_to_wake_up(p, 0); + return try_to_wake_up(p); } void wake_up_forked_process(task_t * p) @@ -366,6 +352,7 @@ preempt_disable(); rq = this_rq(); + spin_lock_irq(&rq->lock); p->state = TASK_RUNNING; if (!rt_task(p)) { @@ -378,9 +365,9 @@ p->sleep_avg = p->sleep_avg * CHILD_PENALTY / 100; p->prio = effective_prio(p); } - spin_lock_irq(&rq->lock); p->thread_info->cpu = smp_processor_id(); activate_task(p, rq); + spin_unlock_irq(&rq->lock); preempt_enable(); } @@ -861,44 +848,33 @@ * started to run but is not in state TASK_RUNNING. try_to_wake_up() returns * zero in this (rare) case, and we handle it by continuing to scan the queue. */ -static inline void __wake_up_common (wait_queue_head_t *q, unsigned int mode, - int nr_exclusive, const int sync) +static inline void __wake_up_common(wait_queue_head_t *q, unsigned int mode, int nr_exclusive) { struct list_head *tmp; + unsigned int state; + wait_queue_t *curr; task_t *p; - list_for_each(tmp,&q->task_list) { - unsigned int state; - wait_queue_t *curr = list_entry(tmp, wait_queue_t, task_list); - + list_for_each(tmp, &q->task_list) { + curr = list_entry(tmp, wait_queue_t, task_list); p = curr->task; state = p->state; - if ((state & mode) && - try_to_wake_up(p, sync) && - ((curr->flags & WQ_FLAG_EXCLUSIVE) && - !--nr_exclusive)) - break; + if ((state & mode) && try_to_wake_up(p) && + ((curr->flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)) + break; } } -void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr) +void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr_exclusive) { - if (q) { - unsigned long flags; - wq_read_lock_irqsave(&q->lock, flags); - __wake_up_common(q, mode, nr, 0); - wq_read_unlock_irqrestore(&q->lock, flags); - } -} + unsigned long flags; -void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr) -{ - if (q) { - unsigned long flags; - wq_read_lock_irqsave(&q->lock, flags); - __wake_up_common(q, mode, nr, 1); - wq_read_unlock_irqrestore(&q->lock, flags); - } + if (unlikely(!q)) + return; + + wq_read_lock_irqsave(&q->lock, flags); + __wake_up_common(q, mode, nr_exclusive); + wq_read_unlock_irqrestore(&q->lock, flags); } void complete(struct completion *x) @@ -907,7 +883,7 @@ spin_lock_irqsave(&x->wait.lock, flags); x->done++; - __wake_up_common(&x->wait, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1, 0); + __wake_up_common(&x->wait, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1); spin_unlock_irqrestore(&x->wait.lock, flags); } @@ -994,34 +970,6 @@ return timeout; } -/* - * Change the current task's CPU affinity. Migrate the process to a - * proper CPU and schedule away if the current CPU is removed from - * the allowed bitmask. - */ -void set_cpus_allowed(task_t *p, unsigned long new_mask) -{ - new_mask &= cpu_online_map; - if (!new_mask) - BUG(); - if (p != current) - BUG(); - - p->cpus_allowed = new_mask; - /* - * Can the task run on the current CPU? If not then - * migrate the process off to a proper CPU. - */ - if (new_mask & (1UL << smp_processor_id())) - return; -#if CONFIG_SMP - current->state = TASK_UNINTERRUPTIBLE; - smp_migrate_task(__ffs(new_mask), current); - - schedule(); -#endif -} - void scheduling_functions_end_here(void) { } void set_user_nice(task_t *p, long nice) @@ -1036,7 +984,7 @@ * We have to be careful, if called from sys_setpriority(), * the task might be in the middle of scheduling on another CPU. */ - rq = lock_task_rq(p, &flags); + rq = task_rq_lock(p, &flags); if (rt_task(p)) { p->static_prio = NICE_TO_PRIO(nice); goto out_unlock; @@ -1056,7 +1004,7 @@ resched_task(rq->curr); } out_unlock: - unlock_task_rq(rq, &flags); + task_rq_unlock(rq, &flags); } #ifndef __alpha__ @@ -1154,7 +1102,7 @@ * To be able to change p->policy safely, the apropriate * runqueue lock must be held. */ - rq = lock_task_rq(p, &flags); + rq = task_rq_lock(p, &flags); if (policy < 0) policy = p->policy; @@ -1189,7 +1137,7 @@ retval = 0; p->policy = policy; p->rt_priority = lp.sched_priority; - if (rt_task(p)) + if (policy != SCHED_OTHER) p->prio = 99 - p->rt_priority; else p->prio = p->static_prio; @@ -1197,7 +1145,7 @@ activate_task(p, task_rq(p)); out_unlock: - unlock_task_rq(rq, &flags); + task_rq_unlock(rq, &flags); out_unlock_tasklist: read_unlock_irq(&tasklist_lock); @@ -1477,7 +1425,7 @@ void __init init_idle(task_t *idle, int cpu) { - runqueue_t *idle_rq = cpu_rq(cpu), *rq = idle->array->rq; + runqueue_t *idle_rq = cpu_rq(cpu), *rq = cpu_rq(idle->thread_info->cpu); unsigned long flags; __save_flags(flags); @@ -1509,14 +1457,13 @@ runqueue_t *rq = cpu_rq(i); prio_array_t *array; - rq->active = rq->arrays + 0; + rq->active = rq->arrays; rq->expired = rq->arrays + 1; spin_lock_init(&rq->lock); + INIT_LIST_HEAD(&rq->migration_queue); for (j = 0; j < 2; j++) { array = rq->arrays + j; - array->rq = rq; - array->lock = &rq->lock; for (k = 0; k < MAX_PRIO; k++) { INIT_LIST_HEAD(array->queue + k); __clear_bit(k, array->bitmap); @@ -1545,3 +1492,173 @@ atomic_inc(&init_mm.mm_count); enter_lazy_tlb(&init_mm, current, smp_processor_id()); } + +#if CONFIG_SMP + +/* + * This is how migration works: + * + * 1) we queue a migration_req_t structure in the source CPU's + * runqueue and wake up that CPU's migration thread. + * 2) we down() the locked semaphore => thread blocks. + * 3) migration thread wakes up (implicitly it forces the migrated + * thread off the CPU) + * 4) it gets the migration request and checks whether the migrated + * task is still in the wrong runqueue. + * 5) if it's in the wrong runqueue then the migration thread removes + * it and puts it into the right queue. + * 6) migration thread up()s the semaphore. + * 7) we wake up and the migration is done. + */ + +typedef struct { + list_t list; + task_t *task; + struct semaphore sem; +} migration_req_t; + +/* + * Change a given task's CPU affinity. Migrate the process to a + * proper CPU and schedule it away if the CPU it's executing on + * is removed from the allowed bitmask. + * + * NOTE: the caller must have a valid reference to the task, the + * task must not exit() & deallocate itself prematurely. + */ +void set_cpus_allowed(task_t *p, unsigned long new_mask) +{ + unsigned long flags; + migration_req_t req; + runqueue_t *rq; + + new_mask &= cpu_online_map; + if (!new_mask) + BUG(); + + rq = task_rq_lock(p, &flags); + p->cpus_allowed = new_mask; + /* + * Can the task run on the task's current CPU? If not then + * migrate the process off to a proper CPU. + */ + if (new_mask & (1UL << p->thread_info->cpu)) { + task_rq_unlock(rq, &flags); + return; + } + + init_MUTEX_LOCKED(&req.sem); + req.task = p; + list_add(&req.list, &rq->migration_queue); + task_rq_unlock(rq, &flags); + wake_up_process(rq->migration_thread); + + down(&req.sem); +} + +static volatile unsigned long migration_mask; + +static int migration_thread(void * unused) +{ + struct sched_param param = { sched_priority: 99 }; + runqueue_t *rq; + int ret; + + daemonize(); + sigfillset(¤t->blocked); + set_fs(KERNEL_DS); + ret = setscheduler(0, SCHED_FIFO, ¶m); + + /* + * We have to migrate manually - there is no migration thread + * to do this for us yet :-) + * + * We use the following property of the Linux scheduler. At + * this point no other task is running, so by keeping all + * migration threads running, the load-balancer will distribute + * them between all CPUs equally. At that point every migration + * task binds itself to the current CPU. + */ + + /* wait for all migration threads to start up. */ + while (!migration_mask) + yield(); + + for (;;) { + preempt_disable(); + if (test_and_clear_bit(smp_processor_id(), &migration_mask)) + current->cpus_allowed = 1 << smp_processor_id(); + if (test_thread_flag(TIF_NEED_RESCHED)) + schedule(); + if (!migration_mask) + break; + preempt_enable(); + } + rq = this_rq(); + rq->migration_thread = current; + preempt_enable(); + + sprintf(current->comm, "migration_CPU%d", smp_processor_id()); + + for (;;) { + runqueue_t *rq_src, *rq_dest; + struct list_head *head; + int cpu_src, cpu_dest; + migration_req_t *req; + unsigned long flags; + task_t *p; + + spin_lock_irqsave(&rq->lock, flags); + head = &rq->migration_queue; + current->state = TASK_INTERRUPTIBLE; + if (list_empty(head)) { + spin_unlock_irqrestore(&rq->lock, flags); + schedule(); + continue; + } + req = list_entry(head->next, migration_req_t, list); + list_del_init(head->next); + spin_unlock_irqrestore(&rq->lock, flags); + + p = req->task; + cpu_dest = __ffs(p->cpus_allowed); + rq_dest = cpu_rq(cpu_dest); +repeat: + cpu_src = p->thread_info->cpu; + rq_src = cpu_rq(cpu_src); + + double_rq_lock(rq_src, rq_dest); + if (p->thread_info->cpu != cpu_src) { + double_rq_unlock(rq_src, rq_dest); + goto repeat; + } + if (rq_src == rq) { + p->thread_info->cpu = cpu_dest; + if (p->array) { + deactivate_task(p, rq_src); + activate_task(p, rq_dest); + } + } + double_rq_unlock(rq_src, rq_dest); + + up(&req->sem); + } +} + +void __init migration_init(void) +{ + int cpu; + + for (cpu = 0; cpu < smp_num_cpus; cpu++) + if (kernel_thread(migration_thread, NULL, + CLONE_FS | CLONE_FILES | CLONE_SIGNAL) < 0) + BUG(); + + migration_mask = (1 << smp_num_cpus) - 1; + + for (cpu = 0; cpu < smp_num_cpus; cpu++) + while (!cpu_rq(cpu)->migration_thread) + schedule_timeout(2); + if (migration_mask) + BUG(); +} +#endif diff -Nru a/mm/filemap.c b/mm/filemap.c --- a/mm/filemap.c Tue Feb 26 11:57:58 2002 +++ b/mm/filemap.c Tue Feb 26 11:57:58 2002 @@ -1399,7 +1399,7 @@ * virtual addresses, take care about potential aliasing * before reading the page on the kernel side. */ - if (mapping->i_mmap_shared != NULL) + if (!list_empty(&mapping->i_mmap_shared)) flush_dcache_page(page); /* diff -Nru a/mm/memory.c b/mm/memory.c --- a/mm/memory.c Tue Feb 26 11:57:59 2002 +++ b/mm/memory.c Tue Feb 26 11:57:59 2002 @@ -1032,31 +1032,35 @@ return -1; } -static void vmtruncate_list(struct vm_area_struct *mpnt, unsigned long pgoff) +static void vmtruncate_list(list_t *head, unsigned long pgoff) { - do { - unsigned long start = mpnt->vm_start; - unsigned long end = mpnt->vm_end; - unsigned long len = end - start; - unsigned long diff; + unsigned long start, end, len, diff; + struct vm_area_struct *vma; + list_t *curr; + + list_for_each(curr, head) { + vma = list_entry(curr, struct vm_area_struct, shared); + start = vma->vm_start; + end = vma->vm_end; + len = end - start; /* mapping wholly truncated? */ - if (mpnt->vm_pgoff >= pgoff) { - zap_page_range(mpnt, start, len); + if (vma->vm_pgoff >= pgoff) { + zap_page_range(vma, start, len); continue; } /* mapping wholly unaffected? */ len = len >> PAGE_SHIFT; - diff = pgoff - mpnt->vm_pgoff; + diff = pgoff - vma->vm_pgoff; if (diff >= len) continue; /* Ok, partially affected.. */ start += diff << PAGE_SHIFT; len = (len - diff) << PAGE_SHIFT; - zap_page_range(mpnt, start, len); - } while ((mpnt = mpnt->vm_next_share) != NULL); + zap_page_range(vma, start, len); + } } /* @@ -1077,14 +1081,14 @@ goto do_expand; inode->i_size = offset; spin_lock(&mapping->i_shared_lock); - if (!mapping->i_mmap && !mapping->i_mmap_shared) + if (list_empty(&mapping->i_mmap) && list_empty(&mapping->i_mmap_shared)) goto out_unlock; pgoff = (offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; - if (mapping->i_mmap != NULL) - vmtruncate_list(mapping->i_mmap, pgoff); - if (mapping->i_mmap_shared != NULL) - vmtruncate_list(mapping->i_mmap_shared, pgoff); + if (!list_empty(&mapping->i_mmap)) + vmtruncate_list(&mapping->i_mmap, pgoff); + if (!list_empty(&mapping->i_mmap_shared)) + vmtruncate_list(&mapping->i_mmap_shared, pgoff); out_unlock: spin_unlock(&mapping->i_shared_lock); @@ -1480,8 +1484,9 @@ /* * Map a vmalloc()-space virtual address to the physical page. */ -struct page * vmalloc_to_page(unsigned long addr) +struct page * vmalloc_to_page(void * vmalloc_addr) { + unsigned long addr = (unsigned long) vmalloc_addr; struct page *page = NULL; pgd_t *pgd = pgd_offset_k(addr); pmd_t *pmd; diff -Nru a/mm/mmap.c b/mm/mmap.c --- a/mm/mmap.c Tue Feb 26 11:57:56 2002 +++ b/mm/mmap.c Tue Feb 26 11:57:56 2002 @@ -101,9 +101,7 @@ struct inode *inode = file->f_dentry->d_inode; if (vma->vm_flags & VM_DENYWRITE) atomic_inc(&inode->i_writecount); - if(vma->vm_next_share) - vma->vm_next_share->vm_pprev_share = vma->vm_pprev_share; - *vma->vm_pprev_share = vma->vm_next_share; + list_del_init(&vma->shared); } } @@ -308,20 +306,14 @@ if (file) { struct inode * inode = file->f_dentry->d_inode; struct address_space *mapping = inode->i_mapping; - struct vm_area_struct **head; if (vma->vm_flags & VM_DENYWRITE) atomic_dec(&inode->i_writecount); - head = &mapping->i_mmap; if (vma->vm_flags & VM_SHARED) - head = &mapping->i_mmap_shared; - - /* insert vma into inode's share list */ - if((vma->vm_next_share = *head) != NULL) - (*head)->vm_pprev_share = &vma->vm_next_share; - *head = vma; - vma->vm_pprev_share = head; + list_add_tail(&vma->shared, &mapping->i_mmap_shared); + else + list_add_tail(&vma->shared, &mapping->i_mmap); } } diff -Nru a/mm/shmem.c b/mm/shmem.c --- a/mm/shmem.c Tue Feb 26 11:57:59 2002 +++ b/mm/shmem.c Tue Feb 26 11:57:59 2002 @@ -904,7 +904,7 @@ if ((desc->error = shmem_getpage(inode, index, &page))) break; - if (mapping->i_mmap_shared != NULL) + if (!list_empty(&mapping->i_mmap_shared)) flush_dcache_page(page); /* diff -Nru a/mm/vmalloc.c b/mm/vmalloc.c --- a/mm/vmalloc.c Tue Feb 26 11:57:56 2002 +++ b/mm/vmalloc.c Tue Feb 26 11:57:56 2002 @@ -6,6 +6,7 @@ * SMP-safe vmalloc/vfree/ioremap, Tigran Aivazian , May 2000 */ +#include #include #include #include @@ -163,6 +164,7 @@ ret = 0; } while (address && (address < end)); spin_unlock(&init_mm.page_table_lock); + flush_cache_all(); return ret; } @@ -273,6 +275,43 @@ if (count == 0) goto finished; *buf = *addr; + buf++; + addr++; + count--; + } while (--n > 0); + } +finished: + read_unlock(&vmlist_lock); + return buf - buf_start; +} + +long vwrite(char *buf, char *addr, unsigned long count) +{ + struct vm_struct *tmp; + char *vaddr, *buf_start = buf; + unsigned long n; + + /* Don't allow overflow */ + if ((unsigned long) addr + count < count) + count = -(unsigned long) addr; + + read_lock(&vmlist_lock); + for (tmp = vmlist; tmp; tmp = tmp->next) { + vaddr = (char *) tmp->addr; + if (addr >= vaddr + tmp->size - PAGE_SIZE) + continue; + while (addr < vaddr) { + if (count == 0) + goto finished; + buf++; + addr++; + count--; + } + n = vaddr + tmp->size - PAGE_SIZE - addr; + do { + if (count == 0) + goto finished; + *addr = *buf; buf++; addr++; count--; diff -Nru a/net/Makefile b/net/Makefile --- a/net/Makefile Tue Feb 26 11:57:59 2002 +++ b/net/Makefile Tue Feb 26 11:57:59 2002 @@ -1,7 +1,7 @@ # # Makefile for the linux networking. # -# 2 Sep 2000, Christoph Hellwig +# 2 Sep 2000, Christoph Hellwig # Rewritten to use lists instead of if-statements. # diff -Nru a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c --- a/net/wanrouter/wanmain.c Tue Feb 26 11:57:57 2002 +++ b/net/wanrouter/wanmain.c Tue Feb 26 11:57:57 2002 @@ -9,7 +9,7 @@ * o Logical connection management (switched virtual circuits) * o Protocol encapsulation/decapsulation * -* Author: Gideon Hack +* Author: Gideon Hack * * Copyright: (c) 1995-1999 Sangoma Technologies Inc. * @@ -18,11 +18,11 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ -* Nov 24, 2000 Nenad Corbic Updated for 2.4.X kernels +* Nov 24, 2000 Nenad Corbic Updated for 2.4.X kernels * Nov 07, 2000 Nenad Corbic Fixed the Mulit-Port PPP for kernels 2.2.16 and * greater. * Aug 2, 2000 Nenad Corbic Block the Multi-Port PPP from running on -* kernels 2.2.16 or greater. The SyncPPP +* kernels 2.2.16 or greater. The SyncPPP * has changed. * Jul 13, 2000 Nenad Corbic Added SyncPPP support * Added extra debugging in device_setup(). @@ -39,7 +39,7 @@ * Dec 22, 1998 Arnaldo Melo vmalloc/vfree used in device_setup to allocate * kernel memory and copy configuration data to * kernel space (for big firmwares) -* Jun 02, 1999 Gideon Hack Updates for Linux 2.0.X and 2.2.X kernels. +* Jun 02, 1999 Gideon Hack Updates for Linux 2.0.X and 2.2.X kernels. *****************************************************************************/ #include @@ -55,28 +55,10 @@ #include /* htons(), etc. */ #include /* WAN router API definitions */ - -#if defined(LINUX_2_4) - #include /* vmalloc, vfree */ - #include /* copy_to/from_user */ - #include /* __initfunc et al. */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3) - #include -#else - #include <../drivers/net/wan/syncppp.h> -#endif - -#elif defined(LINUX_2_1) - #define LINUX_2_1 - #include /* vmalloc, vfree */ - #include /* copy_to/from_user */ - #include /* __initfunc et al. */ - #include <../drivers/net/syncppp.h> - -#else - #include /* kernel <-> user copy */ -#endif +#include /* vmalloc, vfree */ +#include /* copy_to/from_user */ +#include /* __initfunc et al. */ +#include #define KMEM_SAFETYZONE 8 @@ -84,7 +66,7 @@ static void * dbg_kmalloc(unsigned int size, int prio, int line) { int i = 0; void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio); - char * c1 = v; + char * c1 = v; c1 += sizeof(unsigned int); *((unsigned int *)v) = size; @@ -137,12 +119,11 @@ #define kfree(x) dbg_kfree(x,__LINE__) *****************************************************************************/ - /* - * Function Prototypes + * Function Prototypes */ -/* +/* * Kernel loadable module interface. */ #ifdef MODULE @@ -150,8 +131,8 @@ void cleanup_module (void); #endif -/* - * WAN device IOCTL handlers +/* + * WAN device IOCTL handlers */ static int device_setup(wan_device_t *wandev, wandev_conf_t *u_conf); @@ -159,9 +140,9 @@ static int device_shutdown(wan_device_t *wandev); static int device_new_if(wan_device_t *wandev, wanif_conf_t *u_conf); static int device_del_if(wan_device_t *wandev, char *u_name); - -/* - * Miscellaneous + +/* + * Miscellaneous */ static wan_device_t *find_device (char *name); @@ -181,8 +162,8 @@ wan_device_t* router_devlist = NULL; /* list of registered devices */ static int devcnt = 0; -/* - * Organize Unique Identifiers for encapsulation/decapsulation +/* + * Organize Unique Identifiers for encapsulation/decapsulation */ static unsigned char oui_ether[] = { 0x00, 0x00, 0x00 }; @@ -213,18 +194,15 @@ #ifdef CONFIG_VENDOR_SANGOMA sdladrv_init(); wanpipe_init(); -#endif - +#endif + return err; } - -#ifdef LINUX_2_4 static void __exit wanrouter_cleanup (void) { wanrouter_proc_cleanup(); } -#endif #else @@ -249,10 +227,10 @@ printk(KERN_INFO "%s v%u.%u %s\n", fullname, ROUTER_VERSION, ROUTER_RELEASE, copyright); - + err = wanrouter_proc_init(); - - if (err){ + + if (err){ printk(KERN_INFO "%s: can't create entry in proc filesystem!\n", modname); } @@ -299,21 +277,21 @@ if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC) || (wandev->name == NULL)) return -EINVAL; - + namelen = strlen(wandev->name); if (!namelen || (namelen > WAN_DRVNAME_SZ)) return -EINVAL; - + if (find_device(wandev->name) != NULL) return -EEXIST; -#ifdef WANDEBUG +#ifdef WANDEBUG printk(KERN_INFO "%s: registering WAN device %s\n", modname, wandev->name); #endif /* - * Register /proc directory entry + * Register /proc directory entry */ err = wanrouter_proc_add(wandev); if (err) { @@ -327,7 +305,7 @@ * Initialize fields of the wan_device structure maintained by the * router and update local data. */ - + wandev->ndev = 0; wandev->dev = NULL; wandev->next = router_devlist; @@ -364,20 +342,18 @@ if (wandev == NULL) return -ENODEV; -#ifdef WANDEBUG +#ifdef WANDEBUG printk(KERN_INFO "%s: unregistering WAN device %s\n", modname, name); #endif - if (wandev->state != WAN_UNCONFIGURED) { + if (wandev->state != WAN_UNCONFIGURED) device_shutdown(wandev); - } - - if (prev){ + + if (prev) prev->next = wandev->next; - }else{ + else router_devlist = wandev->next; - } - + --devcnt; wanrouter_proc_delete(wandev); MOD_DEC_USE_COUNT; @@ -457,7 +433,7 @@ skb->data[cnt+1], skb->data[cnt+2], skb->data[cnt+3], dev->name); return 0; - } + } ethertype = *((unsigned short*)&skb->data[cnt+4]); cnt += 6; break; @@ -491,23 +467,20 @@ struct proc_dir_entry *dent; wan_device_t *wandev; - #if defined (LINUX_2_1) || defined (LINUX_2_4) - if (!capable(CAP_NET_ADMIN)){ + if (!capable(CAP_NET_ADMIN)) return -EPERM; - } - #endif - + if ((cmd >> 8) != ROUTER_IOCTL) return -EINVAL; - + dent = PDE(inode); if ((dent == NULL) || (dent->data == NULL)) return -EINVAL; - + wandev = dent->data; if (wandev->magic != ROUTER_MAGIC) return -EINVAL; - + switch (cmd) { case ROUTER_SETUP: err = device_setup(wandev, (void*)arg); @@ -560,103 +533,62 @@ wandev_conf_t *conf; int err = -EINVAL; - if (wandev->setup == NULL){ /* Nothing to do ? */ + if (wandev->setup == NULL) { /* Nothing to do ? */ printk(KERN_INFO "%s: ERROR, No setup script: wandev->setup()\n", wandev->name); return 0; } - #ifdef LINUX_2_0 - err = verify_area (VERIFY_READ, u_conf, sizeof(wandev_conf_t)); - if(err){ - return err; - } - #endif - conf = kmalloc(sizeof(wandev_conf_t), GFP_KERNEL); if (conf == NULL){ printk(KERN_INFO "%s: ERROR, Failed to allocate kernel memory !\n", wandev->name); return -ENOBUFS; } - - #if defined (LINUX_2_1) || defined (LINUX_2_4) - if(copy_from_user(conf, u_conf, sizeof(wandev_conf_t))) { + + if (copy_from_user(conf, u_conf, sizeof(wandev_conf_t))) { printk(KERN_INFO "%s: Failed to copy user config data to kernel space!\n", wandev->name); kfree(conf); return -EFAULT; } - #else - memcpy_fromfs ((void *)conf, (void *)u_conf, sizeof(wandev_conf_t)); - #endif - - if (conf->magic != ROUTER_MAGIC){ + + if (conf->magic != ROUTER_MAGIC) { kfree(conf); printk(KERN_INFO "%s: ERROR, Invalid MAGIC Number\n", wandev->name); - return -EINVAL; + return -EINVAL; } - if (conf->data_size && conf->data){ - if(conf->data_size > 128000 || conf->data_size < 0) { - printk(KERN_INFO + if (conf->data_size && conf->data) { + if (conf->data_size > 128000 || conf->data_size < 0) { + printk(KERN_INFO "%s: ERROR, Invalid firmware data size %i !\n", wandev->name, conf->data_size); kfree(conf); - return -EINVAL;; + return -EINVAL; } -#if defined (LINUX_2_1) || defined (LINUX_2_4) data = vmalloc(conf->data_size); - if (data) { - if(!copy_from_user(data, conf->data, conf->data_size)){ - conf->data=data; - err = wandev->setup(wandev,conf); - }else{ - printk(KERN_INFO - "%s: ERROR, Faild to copy from user data !\n", - wandev->name); - err = -EFAULT; - } - }else{ - printk(KERN_INFO + if (!data) { + printk(KERN_INFO "%s: ERROR, Faild allocate kernel memory !\n", wandev->name); - err = -ENOBUFS; - } - - if (data){ - vfree(data); - } -#else - err = verify_area(VERIFY_READ, conf->data, conf->data_size); - if (!err) { - data = kmalloc(conf->data_size, GFP_KERNEL); - if (data) { - memcpy_fromfs(data, (void*)conf->data, - conf->data_size); - conf->data = data; - }else{ - printk(KERN_INFO - "%s: ERROR, Faild allocate kernel memory !\n",wandev->name); - err = -ENOMEM; - } - }else{ - printk(KERN_INFO - "%s: ERROR, Faild to copy from user data !\n",wandev->name); + kfree(conf); + return -ENOBUFS; } - - if (!err){ + if (!copy_from_user(data, conf->data, conf->data_size)) { + conf->data = data; err = wandev->setup(wandev, conf); + } else { + printk(KERN_INFO + "%s: ERROR, Faild to copy from user data !\n", + wandev->name); + err = -EFAULT; } - - if (data){ - kfree(data); - } -#endif - }else{ - printk(KERN_INFO + vfree(data); + } else { + printk(KERN_INFO "%s: ERROR, No firmware found ! Firmware size = %i !\n", wandev->name, conf->data_size); } @@ -670,37 +602,33 @@ * o delete all not opened logical channels for this device * o call driver's shutdown() entry point */ - + static int device_shutdown (wan_device_t *wandev) { netdevice_t *dev; int err=0; - - if (wandev->state == WAN_UNCONFIGURED){ + + if (wandev->state == WAN_UNCONFIGURED) return 0; - } printk(KERN_INFO "\n%s: Shutting Down!\n",wandev->name); - + for (dev = wandev->dev; dev;) { - if ((err=delete_interface(wandev, dev->name)) != 0){ + if ((err=delete_interface(wandev, dev->name)) != 0) return err; - } - /* The above function deallocates the current dev * structure. Therefore, we cannot use dev->priv * as the next element: wandev->dev points to the * next element */ dev = wandev->dev; } - - if (wandev->ndev){ + + if (wandev->ndev) return -EBUSY; /* there are opened interfaces */ - } - + if (wandev->shutdown) err=wandev->shutdown(wandev); - + return err; } @@ -712,13 +640,6 @@ { wandev_stat_t stat; - #ifdef LINUX_2_0 - int err; - err = verify_area(VERIFY_WRITE, u_stat, sizeof(wandev_stat_t)); - if (err) - return err; - #endif - memset(&stat, 0, sizeof(stat)); /* Ask device driver to update device statistics */ @@ -729,12 +650,8 @@ stat.ndev = wandev->ndev; stat.state = wandev->state; - #if defined (LINUX_2_1) || defined (LINUX_2_4) - if(copy_to_user(u_stat, &stat, sizeof(stat))) + if (copy_to_user(u_stat, &stat, sizeof(stat))) return -EFAULT; - #else - memcpy_tofs((void*)u_stat, (void*)&stat, sizeof(stat)); - #endif return 0; } @@ -760,103 +677,67 @@ if ((wandev->state == WAN_UNCONFIGURED) || (wandev->new_if == NULL)) return -ENODEV; - -#if defined (LINUX_2_1) || defined (LINUX_2_4) - if(copy_from_user(&conf, u_conf, sizeof(wanif_conf_t))) + + if (copy_from_user(&conf, u_conf, sizeof(wanif_conf_t))) return -EFAULT; -#else - err = verify_area(VERIFY_READ, u_conf, sizeof(wanif_conf_t)); - if (err) - return err; - memcpy_fromfs((void*)&conf, (void*)u_conf, sizeof(wanif_conf_t)); -#endif - + if (conf.magic != ROUTER_MAGIC) return -EINVAL; - err = -EPROTONOSUPPORT; - - + if (conf.config_id == WANCONFIG_MPPP) { #ifdef CONFIG_WANPIPE_MULTPPP - if (conf.config_id == WANCONFIG_MPPP){ - pppdev = kmalloc(sizeof(struct ppp_device), GFP_KERNEL); - if (pppdev == NULL){ + if (pppdev == NULL) return -ENOBUFS; - } memset(pppdev, 0, sizeof(struct ppp_device)); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,16) pppdev->dev = kmalloc(sizeof(netdevice_t), GFP_KERNEL); - if (pppdev->dev == NULL){ + if (pppdev->dev == NULL) { kfree(pppdev); return -ENOBUFS; } memset(pppdev->dev, 0, sizeof(netdevice_t)); -#endif - err = wandev->new_if(wandev, (netdevice_t *)pppdev, &conf); - - #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,16) - dev = pppdev->dev; - #else - dev = &pppdev->dev; - #endif - - }else{ - - dev = kmalloc(sizeof(netdevice_t), GFP_KERNEL); - if (dev == NULL){ - return -ENOBUFS; - } - memset(dev, 0, sizeof(netdevice_t)); - err = wandev->new_if(wandev, dev, &conf); - } - + dev = pppdev->dev; #else - /* Sync PPP is disabled */ - if (conf.config_id != WANCONFIG_MPPP){ - + printk(KERN_INFO "%s: Wanpipe Mulit-Port PPP support has not been compiled in!\n", + wandev->name); + return -EPROTONOSUPPORT; +#endif + } else { dev = kmalloc(sizeof(netdevice_t), GFP_KERNEL); - if (dev == NULL){ + if (dev == NULL) return -ENOBUFS; - } - memset(dev, 0, sizeof(netdevice_t)); + memset(dev, 0, sizeof(netdevice_t)); err = wandev->new_if(wandev, dev, &conf); - }else{ - printk(KERN_INFO "%s: Wanpipe Mulit-Port PPP support has not been compiled in!\n", - wandev->name); - return err; } -#endif - + if (!err) { /* Register network interface. This will invoke init() * function supplied by the driver. If device registered * successfully, add it to the interface list. */ - if (dev->name == NULL){ + if (dev->name == NULL) { err = -EINVAL; - }else if (dev_get(dev->name)){ + } else if (dev_get(dev->name)) { err = -EEXIST; /* name already exists */ - }else{ - - #ifdef WANDEBUG + } else { + + #ifdef WANDEBUG printk(KERN_INFO "%s: registering interface %s...\n", modname, dev->name); - #endif - + #endif + err = register_netdev(dev); if (!err) { netdevice_t *slave=NULL; unsigned long smp_flags=0; - + lock_adapter_irq(&wandev->lock, &smp_flags); - - if (wandev->dev == NULL){ + + if (wandev->dev == NULL) { wandev->dev = dev; - }else{ + } else { for (slave=wandev->dev; *((netdevice_t**)slave->priv); slave=*((netdevice_t**)slave->priv)); @@ -864,7 +745,7 @@ *((netdevice_t**)slave->priv) = dev; } ++wandev->ndev; - + unlock_adapter_irq(&wandev->lock, &smp_flags); return 0; /* done !!! */ } @@ -874,25 +755,23 @@ } /* This code has moved from del_if() function */ - if (dev->priv){ + if (dev->priv) { kfree(dev->priv); - dev->priv=NULL; + dev->priv = NULL; } - - #ifdef CONFIG_WANPIPE_MULTPPP - if (conf.config_id == WANCONFIG_MPPP){ + +#ifdef CONFIG_WANPIPE_MULTPPP + if (conf.config_id == WANCONFIG_MPPP) kfree(pppdev); - }else{ + else kfree(dev); - } - #else +#else /* Sync PPP is disabled */ - if (conf.config_id != WANCONFIG_MPPP){ + if (conf.config_id != WANCONFIG_MPPP) kfree(dev); - } - #endif - +#endif + return err; } @@ -910,42 +789,31 @@ if (wandev->state == WAN_UNCONFIGURED) return -ENODEV; - - #ifdef LINUX_2_0 - err = verify_area(VERIFY_READ, u_name, WAN_IFNAME_SZ); - if (err) - return err; - #endif memset(name, 0, sizeof(name)); - #if defined (LINUX_2_1) || defined (LINUX_2_4) - if(copy_from_user(name, u_name, WAN_IFNAME_SZ)) + if (copy_from_user(name, u_name, WAN_IFNAME_SZ)) return -EFAULT; - #else - memcpy_fromfs((void*)name, (void*)u_name, WAN_IFNAME_SZ); - #endif err = delete_interface(wandev, name); if (err) - return(err); + return err; /* If last interface being deleted, shutdown card * This helps with administration at leaf nodes - * (You can tell if the person at the other end of the phone + * (You can tell if the person at the other end of the phone * has an interface configured) and avoids DoS vulnerabilities * in binary driver files - this fixes a problem with the current * Sangoma driver going into strange states when all the network * interfaces are deleted and the link irrecoverably disconnected. - */ + */ - if (!wandev->ndev && wandev->shutdown){ + if (!wandev->ndev && wandev->shutdown) err = wandev->shutdown(wandev); - } + return err; } - /* * Miscellaneous Functions */ @@ -995,18 +863,12 @@ dev = *slave; } unlock_adapter_irq(&wandev->lock, &smp_flags); - - if (dev == NULL){ + + if (dev == NULL) return -ENODEV; /* interface not found */ - } - - #ifdef LINUX_2_4 - if (netif_running(dev)){ - #else - if (dev->start) { - #endif + + if (netif_running(dev)) return -EBUSY; /* interface in use */ - } if (wandev->del_if) wandev->del_if(wandev, dev); @@ -1023,9 +885,9 @@ } --wandev->ndev; unlock_adapter_irq(&wandev->lock, &smp_flags); - - printk(KERN_INFO "%s: unregistering '%s'\n", wandev->name, dev->name); - + + printk(KERN_INFO "%s: unregistering '%s'\n", wandev->name, dev->name); + /* Due to new interface linking method using dev->priv, * this code has moved from del_if() function.*/ if (dev->priv){ @@ -1035,48 +897,28 @@ unregister_netdev(dev); - #ifdef LINUX_2_4 - kfree(dev); - #else - if (dev->name){ - kfree(dev->name); - } kfree(dev); - #endif return 0; } void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags) { - #ifdef LINUX_2_0 - save_flags(*smp_flags); - cli(); - #else spin_lock_irqsave(lock, *smp_flags); - #endif } void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags) { - #ifdef LINUX_2_0 - restore_flags(*smp_flags); - #else spin_unlock_irqrestore(lock, *smp_flags); - #endif } - - -#if defined (LINUX_2_1) || defined (LINUX_2_4) EXPORT_SYMBOL(register_wan_device); EXPORT_SYMBOL(unregister_wan_device); EXPORT_SYMBOL(wanrouter_encapsulate); EXPORT_SYMBOL(wanrouter_type_trans); EXPORT_SYMBOL(lock_adapter_irq); EXPORT_SYMBOL(unlock_adapter_irq); -#endif /* * End diff -Nru a/net/wanrouter/wanproc.c b/net/wanrouter/wanproc.c --- a/net/wanrouter/wanproc.c Tue Feb 26 11:57:59 2002 +++ b/net/wanrouter/wanproc.c Tue Feb 26 11:57:59 2002 @@ -31,23 +31,15 @@ #include /* htons(), etc. */ #include #include /* WAN router API definitions */ +#include +#include +#include /* __initfunc et al. */ +#include /* copy_to_user */ - - -#if defined(LINUX_2_1) || defined(LINUX_2_4) - #include /* __initfunc et al. */ - #include /* copy_to_user */ - #define PROC_STATS_FORMAT "%30s: %12lu\n" -#else - #define PROC_STATS_FORMAT "%30s: %12u\n" - #include /* kernel <-> user copy */ -#endif - +#define PROC_STATS_FORMAT "%30s: %12lu\n" /****** Defines and Macros **************************************************/ -#define PROC_BUFSZ 4000 /* buffer size for printing proc info */ - #define PROT_DECODE(prot) ((prot == WANCONFIG_FR) ? " FR" :\ (prot == WANCONFIG_X25) ? " X25" : \ (prot == WANCONFIG_PPP) ? " PPP" : \ @@ -69,962 +61,346 @@ #ifdef CONFIG_PROC_FS +/* Proc filesystem interface */ +static int router_proc_perms(struct inode *, int); -#ifdef LINUX_2_4 /* Start of LINUX 2.4.X code */ +/* Miscellaneous */ +/* + * Structures for interfacing with the /proc filesystem. + * Router creates its own directory /proc/net/router with the folowing + * entries: + * config device configuration + * status global device statistics + * entry for each WAN device + */ - /* Proc filesystem interface */ - static int router_proc_perms(struct inode *, int); - static ssize_t router_proc_read(struct file* file, char* buf, size_t count, loff_t *ppos); - - /* Methods for preparing data for reading proc entries */ - - static int config_get_info(char* buf, char** start, off_t offs, int len); - static int status_get_info(char* buf, char** start, off_t offs, int len); - static int wandev_get_info(char* buf, char** start, off_t offs, int len); - - /* Miscellaneous */ - - /* - * Structures for interfacing with the /proc filesystem. - * Router creates its own directory /proc/net/router with the folowing - * entries: - * config device configuration - * status global device statistics - * entry for each WAN device - */ - - /* - * Generic /proc/net/router/ file and inode operations - */ - static struct file_operations router_fops = - { - read: router_proc_read, - }; - - static struct inode_operations router_inode = - { - permission: router_proc_perms, - }; - - /* - * /proc/net/router/ file operations - */ - - static struct file_operations wandev_fops = - { - read: router_proc_read, - ioctl: wanrouter_ioctl, - }; - - /* - * /proc/net/router - */ - - static struct proc_dir_entry *proc_router; - - /* Strings */ - static char conf_hdr[] = - "Device name | port |IRQ|DMA| mem.addr |mem.size|" - "option1|option2|option3|option4\n"; - - static char stat_hdr[] = - "Device name |protocol|station|interface|clocking|baud rate" - "| MTU |ndev|link state\n"; - - - /* - * Interface functions - */ - - /* - * Initialize router proc interface. - */ - - int __init wanrouter_proc_init (void) - { - struct proc_dir_entry *p; - proc_router = proc_mkdir(ROUTER_NAME, proc_net); - if (!proc_router) - goto fail; - - p = create_proc_entry("config",0,proc_router); - if (!p) - goto fail_config; - p->proc_fops = &router_fops; - p->proc_iops = &router_inode; - p->get_info = config_get_info; - p = create_proc_entry("status",0,proc_router); - if (!p) - goto fail_stat; - p->proc_fops = &router_fops; - p->proc_iops = &router_inode; - p->get_info = status_get_info; - return 0; - fail_stat: - remove_proc_entry("config", proc_router); - fail_config: - remove_proc_entry(ROUTER_NAME, proc_net); - fail: - return -ENOMEM; - } +/* + * Generic /proc/net/router/ file and inode operations + */ - /* - * Clean up router proc interface. - */ - - void wanrouter_proc_cleanup (void) - { - remove_proc_entry("config", proc_router); - remove_proc_entry("status", proc_router); - remove_proc_entry(ROUTER_NAME,proc_net); - } +static struct inode_operations router_inode = +{ + permission: router_proc_perms, +}; - /* - * Add directory entry for WAN device. - */ - - int wanrouter_proc_add (wan_device_t* wandev) - { - if (wandev->magic != ROUTER_MAGIC) - return -EINVAL; - - wandev->dent = create_proc_entry(wandev->name, 0, proc_router); - if (!wandev->dent) - return -ENOMEM; - wandev->dent->proc_fops = &wandev_fops; - wandev->dent->proc_iops = &router_inode; - wandev->dent->get_info = wandev_get_info; - wandev->dent->data = wandev; - return 0; - } +/* + * /proc/net/router + */ - /* - * Delete directory entry for WAN device. - */ - - int wanrouter_proc_delete(wan_device_t* wandev) - { - if (wandev->magic != ROUTER_MAGIC) - return -EINVAL; - remove_proc_entry(wandev->name, proc_router); - return 0; - } +static struct proc_dir_entry *proc_router; - /****** Proc filesystem entry points ****************************************/ +/* Strings */ - /* - * Verify access rights. - */ +/* + * Interface functions + */ - static int router_proc_perms (struct inode* inode, int op) - { - return 0; - } +/****** Proc filesystem entry points ****************************************/ - /* - * Read router proc directory entry. - * This is universal routine for reading all entries in /proc/net/wanrouter - * directory. Each directory entry contains a pointer to the 'method' for - * preparing data for that entry. - * o verify arguments - * o allocate kernel buffer - * o call get_info() to prepare data - * o copy data to user space - * o release kernel buffer - * - * Return: number of bytes copied to user space (0, if no data) - * <0 error - */ - - static ssize_t router_proc_read(struct file* file, char* buf, size_t count, - loff_t *ppos) - { - struct inode *inode = file->f_dentry->d_inode; - struct proc_dir_entry* dent; - char* page; - int pos, offs, len; +/* + * Verify access rights. + */ - if (count <= 0) - return 0; - - dent = PDE(inode); - if ((dent == NULL) || (dent->get_info == NULL)) - return 0; - - page = kmalloc(PROC_BUFSZ, GFP_KERNEL); - if (page == NULL) - return -ENOBUFS; - - pos = dent->get_info(page, dent->data, 0, 0); - offs = file->f_pos; - if (offs < pos) { - len = min_t(unsigned int, pos - offs, count); - if (copy_to_user(buf, (page + offs), len)) { - kfree(page); - return -EFAULT; - } - file->f_pos += len; - } - else - len = 0; - kfree(page); - return len; - } +static int router_proc_perms (struct inode* inode, int op) +{ + return 0; +} - /* - * Prepare data for reading 'Config' entry. - * Return length of data. - */ - - static int config_get_info(char* buf, char** start, off_t offs, int len) - { - int cnt = sizeof(conf_hdr) - 1; - wan_device_t* wandev; - strcpy(buf, conf_hdr); - for (wandev = router_devlist; - wandev && (cnt < (PROC_BUFSZ - 120)); - wandev = wandev->next) { - if (wandev->state) cnt += sprintf(&buf[cnt], - "%-15s|0x%-4X|%3u|%3u| 0x%-8lX |0x%-6X|%7u|%7u|%7u|%7u\n", - wandev->name, - wandev->ioport, - wandev->irq, - wandev->dma, - wandev->maddr, - wandev->msize, - wandev->hw_opt[0], - wandev->hw_opt[1], - wandev->hw_opt[2], - wandev->hw_opt[3]); - } +/* + * Iterator + */ +static void *r_start(struct seq_file *m, loff_t *pos) +{ + wan_device_t *wandev; + loff_t l = *pos; - return cnt; - } + lock_kernel(); + if (!l--) + return (void *)1; + for (wandev = router_devlist; l-- && wandev; wandev = wandev->next) + ; + return wandev; +} +static void *r_next(struct seq_file *m, void *v, loff_t *pos) +{ + wan_device_t *wandev = v; + (*pos)++; + return (v == (void *)1) ? router_devlist : wandev->next; +} +static void r_stop(struct seq_file *m, void *v) +{ + unlock_kernel(); +} - /* - * Prepare data for reading 'Status' entry. - * Return length of data. - */ - - static int status_get_info(char* buf, char** start, off_t offs, int len) - { - int cnt = 0; - wan_device_t* wandev; - - //cnt += sprintf(&buf[cnt], "\nSTATUS:\n\n"); - strcpy(&buf[cnt], stat_hdr); - cnt += sizeof(stat_hdr) - 1; - - for (wandev = router_devlist; - wandev && (cnt < (PROC_BUFSZ - 80)); - wandev = wandev->next) { - if (!wandev->state) continue; - cnt += sprintf(&buf[cnt], - "%-15s|%-8s|%-7s|%-9s|%-8s|%9u|%5u|%3u |", - wandev->name, - PROT_DECODE(wandev->config_id), - wandev->config_id == WANCONFIG_FR ? - (wandev->station ? " Node" : " CPE") : - (wandev->config_id == WANCONFIG_X25 ? - (wandev->station ? " DCE" : " DTE") : - (" N/A")), - wandev->interface ? " V.35" : " RS-232", - wandev->clocking ? "internal" : "external", - wandev->bps, - wandev->mtu, - wandev->ndev); - - switch (wandev->state) { - - case WAN_UNCONFIGURED: - cnt += sprintf(&buf[cnt], "%-12s\n", "unconfigured"); - break; - - case WAN_DISCONNECTED: - cnt += sprintf(&buf[cnt], "%-12s\n", "disconnected"); - break; - - case WAN_CONNECTING: - cnt += sprintf(&buf[cnt], "%-12s\n", "connecting"); - break; - - case WAN_CONNECTED: - cnt += sprintf(&buf[cnt], "%-12s\n", "connected"); - break; - - default: - cnt += sprintf(&buf[cnt], "%-12s\n", "invalid"); - break; - } - } - return cnt; +static int config_show(struct seq_file *m, void *v) +{ + wan_device_t *p = v; + if (v == (void *)1) { + seq_puts(m, "Device name | port |IRQ|DMA| mem.addr |"); + seq_puts(m, "mem.size|option1|option2|option3|option4\n"); + return 0; } + if (!p->state) + return 0; + seq_printf(m, "%-15s|0x%-4X|%3u|%3u| 0x%-8lX |0x%-6X|%7u|%7u|%7u|%7u\n", + p->name, p->ioport, p->irq, p->dma, p->maddr, p->msize, + p->hw_opt[0], p->hw_opt[1], p->hw_opt[2], p->hw_opt[3]); + return 0; +} - /* - * Prepare data for reading entry. - * Return length of data. - * - * On entry, the 'start' argument will contain a pointer to WAN device - * data space. - */ - - static int wandev_get_info(char* buf, char** start, off_t offs, int len) - { - wan_device_t* wandev = (void*)start; - int cnt = 0; - int rslt = 0; - - if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC)) - return 0; - if (!wandev->state) - return sprintf(&buf[cnt], "device is not configured!\n"); - - /* Update device statistics */ - if (wandev->update) { - - rslt = wandev->update(wandev); - if(rslt) { - switch (rslt) { - case -EAGAIN: - return sprintf(&buf[cnt], "Device is busy!\n"); - - default: - return sprintf(&buf[cnt], - "Device is not configured!\n"); - } - } - } - - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "total packets received", wandev->stats.rx_packets); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "total packets transmitted", wandev->stats.tx_packets); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "total bytes received", wandev->stats.rx_bytes); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "total bytes transmitted", wandev->stats.tx_bytes); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "bad packets received", wandev->stats.rx_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "packet transmit problems", wandev->stats.tx_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "received frames dropped", wandev->stats.rx_dropped); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "transmit frames dropped", wandev->stats.tx_dropped); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "multicast packets received", wandev->stats.multicast); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "transmit collisions", wandev->stats.collisions); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "receive length errors", wandev->stats.rx_length_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "receiver overrun errors", wandev->stats.rx_over_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "CRC errors", wandev->stats.rx_crc_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "frame format errors (aborts)", wandev->stats.rx_frame_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "receiver fifo overrun", wandev->stats.rx_fifo_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "receiver missed packet", wandev->stats.rx_missed_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "aborted frames transmitted", wandev->stats.tx_aborted_errors); - return cnt; +static int status_show(struct seq_file *m, void *v) +{ + wan_device_t *p = v; + if (v == (void *)1) { + seq_puts(m, "Device name |protocol|station|interface|"); + seq_puts(m, "clocking|baud rate| MTU |ndev|link state\n"); + return 0; } + if (!p->state) + return 0; + seq_printf(m, "%-15s|%-8s|%-7s|%-9s|%-8s|%9u|%5u|%3u |", + p->name, + PROT_DECODE(p->config_id), + p->config_id == WANCONFIG_FR ? + (p->station ? " Node" : " CPE") : + (p->config_id == WANCONFIG_X25 ? + (p->station ? " DCE" : " DTE") : + (" N/A")), + p->interface ? " V.35" : " RS-232", + p->clocking ? "internal" : "external", + p->bps, + p->mtu, + p->ndev); + + switch (p->state) { + case WAN_UNCONFIGURED: + seq_printf(m, "%-12s\n", "unconfigured"); + break; + case WAN_DISCONNECTED: + seq_printf(m, "%-12s\n", "disconnected"); + break; + case WAN_CONNECTING: + seq_printf(m, "%-12s\n", "connecting"); + break; + case WAN_CONNECTED: + seq_printf(m, "%-12s\n", "connected"); + break; + default: + seq_printf(m, "%-12s\n", "invalid"); + break; + } + return 0; +} +static struct seq_operations config_op = { + start: r_start, + next: r_next, + stop: r_stop, + show: config_show +}; + +static struct seq_operations status_op = { + start: r_start, + next: r_next, + stop: r_stop, + show: status_show +}; -#else /* ------------------- END OF LINUX 2.4.X VERSION -------------*/ - - - - /* Proc filesystem interface */ - static int router_proc_perms(struct inode *, int); -#ifdef LINUX_2_1 - static ssize_t router_proc_read(struct file *file, char *buf, size_t count, loff_t *ppos); -#else - static int router_proc_read( - struct inode* inode, struct file* file, char* buf, int count); - static int device_write( - struct inode* inode, struct file* file, const char* buf, int count); -#endif - - /* Methods for preparing data for reading proc entries */ - static int config_get_info(char* buf, char** start, off_t offs, int len, - int dummy); - static int status_get_info(char* buf, char** start, off_t offs, int len, - int dummy); - static int wandev_get_info(char* buf, char** start, off_t offs, int len, - int dummy); - - /* Miscellaneous */ - - /* - * Global Data - */ - - /* - * Names of the proc directory entries - */ - - static char name_root[] = ROUTER_NAME; - static char name_conf[] = "config"; - static char name_stat[] = "status"; - - /* - * Structures for interfacing with the /proc filesystem. - * Router creates its own directory /proc/net/router with the folowing - * entries: - * config device configuration - * status global device statistics - * entry for each WAN device - */ - - /* - * Generic /proc/net/router/ file and inode operations - */ -#ifdef LINUX_2_1 - static struct file_operations router_fops = - { - NULL, /* lseek */ - router_proc_read, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* select */ - NULL, /* ioctl */ - NULL, /* mmap */ - NULL, /* no special open code */ - NULL, /* flush */ - NULL, /* no special release code */ - NULL /* can't fsync */ - }; -#else - static struct file_operations router_fops = - { - NULL, /* lseek */ - router_proc_read, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* select */ - NULL, /* ioctl */ - NULL, /* mmap */ - NULL, /* no special open code */ - NULL, /* no special release code */ - NULL /* can't fsync */ - }; -#endif +static int config_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &config_op); +} - static struct inode_operations router_inode = - { - &router_fops, - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - NULL, /* follow link */ - NULL, /* readlink */ - NULL, /* readpage */ - NULL, /* writepage */ - NULL, /* bmap */ - NULL, /* truncate */ - router_proc_perms - }; - - /* - * /proc/net/router/ file and inode operations - */ - -#ifdef LINUX_2_1 - static struct file_operations wandev_fops = - { - NULL, /* lseek */ - router_proc_read, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* select */ - wanrouter_ioctl, /* ioctl */ - NULL, /* mmap */ - NULL, /* no special open code */ - NULL, /* flush */ - NULL, /* no special release code */ - NULL /* can't fsync */ - }; -#else - static struct file_operations wandev_fops = - { - NULL, /* lseek */ - router_proc_read, /* read */ - device_write, /* write */ - NULL, /* readdir */ - NULL, /* select */ - wanrouter_ioctl, /* ioctl */ - NULL, /* mmap */ - NULL, /* no special open code */ - NULL, /* no special release code */ - NULL /* can't fsync */ - }; -#endif +static int status_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &status_op); +} - static struct inode_operations wandev_inode = - { - &wandev_fops, - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - NULL, /* readlink */ - NULL, /* follow_link */ - NULL, /* readpage */ - NULL, /* writepage */ - NULL, /* bmap */ - NULL, /* truncate */ - router_proc_perms - }; - - /* - * Proc filesystem derectory entries. - */ - - /* - * /proc/net/router - */ - - static struct proc_dir_entry proc_router = - { - 0, /* .low_ino */ - sizeof(name_root) - 1, /* .namelen */ - name_root, /* .name */ - 0555 | S_IFDIR, /* .mode */ - 2, /* .nlink */ - 0, /* .uid */ - 0, /* .gid */ - 0, /* .size */ - &proc_dir_inode_operations, /* .ops */ - NULL, /* .get_info */ - NULL, /* .fill_node */ - NULL, /* .next */ - NULL, /* .parent */ - NULL, /* .subdir */ - NULL, /* .data */ - }; - - /* - * /proc/net/router/config - */ - - static struct proc_dir_entry proc_router_conf = - { - 0, /* .low_ino */ - sizeof(name_conf) - 1, /* .namelen */ - name_conf, /* .name */ - 0444 | S_IFREG, /* .mode */ - 1, /* .nlink */ - 0, /* .uid */ - 0, /* .gid */ - 0, /* .size */ - &router_inode, /* .ops */ - &config_get_info, /* .get_info */ - NULL, /* .fill_node */ - NULL, /* .next */ - NULL, /* .parent */ - NULL, /* .subdir */ - NULL, /* .data */ - }; - - /* - * /proc/net/router/status - */ - - static struct proc_dir_entry proc_router_stat = - { - 0, /* .low_ino */ - sizeof(name_stat) - 1, /* .namelen */ - name_stat, /* .name */ - 0444 | S_IFREG, /* .mode */ - 1, /* .nlink */ - 0, /* .uid */ - 0, /* .gid */ - 0, /* .size */ - &router_inode, /* .ops */ - status_get_info, /* .get_info */ - NULL, /* .fill_node */ - NULL, /* .next */ - NULL, /* .parent */ - NULL, /* .subdir */ - NULL, /* .data */ - }; - - /* Strings */ - static char conf_hdr[] = - "Device name | port |IRQ|DMA| mem.addr |mem.size|" - "option1|option2|option3|option4\n"; - - static char stat_hdr[] = - "Device name |protocol|station|interface|clocking|baud rate| MTU |ndev" - "|link state\n"; - - - /* - * Interface functions - */ - - /* - * Initialize router proc interface. - */ - -#ifdef LINUX_2_1 - __initfunc(int wanrouter_proc_init (void)) - { - int err = proc_register(proc_net, &proc_router); - - if (!err) { - proc_register(&proc_router, &proc_router_conf); - proc_register(&proc_router, &proc_router_stat); - } - return err; - } -#else - int wanrouter_proc_init (void) - { - int err = proc_register_dynamic(&proc_net, &proc_router); - - if (!err) { - proc_register_dynamic(&proc_router, &proc_router_conf); - proc_register_dynamic(&proc_router, &proc_router_stat); - } - return err; - } -#endif +static struct file_operations config_fops = +{ + open: config_open, + read: seq_read, + llseek: seq_lseek, + release: seq_release, +}; - /* - * Clean up router proc interface. - */ - - void wanrouter_proc_cleanup (void) - { - proc_unregister(&proc_router, proc_router_conf.low_ino); - proc_unregister(&proc_router, proc_router_stat.low_ino); -#ifdef LINUX_2_1 - proc_unregister(proc_net, proc_router.low_ino); -#else - proc_unregister(&proc_net, proc_router.low_ino); -#endif - } +static struct file_operations status_fops = +{ + open: status_open, + read: seq_read, + llseek: seq_lseek, + release: seq_release, +}; - /* - * Add directory entry for WAN device. - */ - - int wanrouter_proc_add (wan_device_t* wandev) - { - if (wandev->magic != ROUTER_MAGIC) - return -EINVAL; - - memset(&wandev->dent, 0, sizeof(wandev->dent)); - wandev->dent.namelen = strlen(wandev->name); - wandev->dent.name = wandev->name; - wandev->dent.mode = 0444 | S_IFREG; - wandev->dent.nlink = 1; - wandev->dent.ops = &wandev_inode; - wandev->dent.get_info = &wandev_get_info; - wandev->dent.data = wandev; -#ifdef LINUX_2_1 - return proc_register(&proc_router, &wandev->dent); -#else - return proc_register_dynamic(&proc_router, &wandev->dent); -#endif - } +static void *single_start(struct seq_file *p, loff_t *pos) +{ + return *pos == 0 ? p->private : NULL; +} +static void *single_next(struct seq_file *p, void *v, loff_t *pos) +{ + ++*pos; + return NULL; +} +static void single_stop(struct seq_file *p, void *v) +{ +} +static int wandev_show(struct seq_file *m, void *v) +{ + wan_device_t *wandev = v; - /* - * Delete directory entry for WAN device. - */ - - int wanrouter_proc_delete(wan_device_t* wandev) - { - if (wandev->magic != ROUTER_MAGIC) - return -EINVAL; - proc_unregister(&proc_router, wandev->dent.low_ino); + if (wandev->magic != ROUTER_MAGIC) return 0; - } - - /****** Proc filesystem entry points ****************************************/ - - /* - * Verify access rights. - */ - static int router_proc_perms (struct inode* inode, int op) - { + if (!wandev->state) { + seq_puts(m, "device is not configured!\n"); return 0; } - /* - * Read router proc directory entry. - * This is universal routine for reading all entries in /proc/net/wanrouter - * directory. Each directory entry contains a pointer to the 'method' for - * preparing data for that entry. - * o verify arguments - * o allocate kernel buffer - * o call get_info() to prepare data - * o copy data to user space - * o release kernel buffer - * - * Return: number of bytes copied to user space (0, if no data) - * <0 error - */ -#ifdef LINUX_2_1 - static ssize_t router_proc_read(struct file* file, char* buf, size_t count, - loff_t *ppos) - { - struct inode *inode = file->f_dentry->d_inode; - struct proc_dir_entry* dent; - char* page; - int pos, offs, len; - - if (count <= 0) - return 0; - - dent = PDE(inode); - if ((dent == NULL) || (dent->get_info == NULL)) + /* Update device statistics */ + if (wandev->update) { + int err = wandev->update(wandev); + if (err == -EAGAIN) { + seq_printf(m, "Device is busy!\n"); return 0; - - page = kmalloc(PROC_BUFSZ, GFP_KERNEL); - if (page == NULL) - return -ENOBUFS; - - pos = dent->get_info(page, dent->data, 0, 0, 0); - offs = file->f_pos; - if (offs < pos) { - len = min_t(unsigned int, pos - offs, count); - if (copy_to_user(buf, (page + offs), len)) { - kfree(page); - return -EFAULT; - } - file->f_pos += len; } - else - len = 0; - kfree(page); - return len; - } - -#else - static int router_proc_read( - struct inode* inode, struct file* file, char* buf, int count) - { - struct proc_dir_entry* dent; - char* page; - int err, pos, offs, len; - - if (count <= 0) + if (err) { + seq_printf(m, "Device is not configured!\n"); return 0; - dent = PDE(inode); - if ((dent == NULL) || (dent->get_info == NULL)) - return -ENODATA; - err = verify_area(VERIFY_WRITE, buf, count); - if (err) return err; - - page = kmalloc(PROC_BUFSZ, GFP_KERNEL); - if (page == NULL) - return -ENOMEM; - - pos = dent->get_info(page, dent->data, 0, 0, 0); - offs = file->f_pos; - if (offs < pos) { - len = min_t(unsigned int, pos - offs, count); - memcpy_tofs((void*)buf, (void*)(page + offs), len); - file->f_pos += len; - } - else len = 0; - kfree(page); - return len; - } -#endif - - - /* - * Prepare data for reading 'Config' entry. - * Return length of data. - */ - - static int config_get_info(char* buf, char** start, off_t offs, int len, - int dummy) - { - int cnt = sizeof(conf_hdr) - 1; - wan_device_t* wandev; - strcpy(buf, conf_hdr); - for (wandev = router_devlist; - wandev && (cnt < (PROC_BUFSZ - 120)); - wandev = wandev->next) { - if (wandev->state) cnt += sprintf(&buf[cnt], - "%-15s|0x%-4X|%3u|%3u| 0x%-8lX |0x%-6X|%7u|%7u|%7u|%7u\n", - wandev->name, - wandev->ioport, - wandev->irq, - wandev->dma, - wandev->maddr, - wandev->msize, - wandev->hw_opt[0], - wandev->hw_opt[1], - wandev->hw_opt[2], - wandev->hw_opt[3]); } - - return cnt; } - /* - * Prepare data for reading 'Status' entry. - * Return length of data. - */ - - static int status_get_info(char* buf, char** start, off_t offs, int len, - int dummy) - { - int cnt = 0; - wan_device_t* wandev; - - //cnt += sprintf(&buf[cnt], "\nSTATUS:\n\n"); - strcpy(&buf[cnt], stat_hdr); - cnt += sizeof(stat_hdr) - 1; - - for (wandev = router_devlist; - wandev && (cnt < (PROC_BUFSZ - 80)); - wandev = wandev->next) { - if (!wandev->state) continue; - cnt += sprintf(&buf[cnt], - "%-15s|%-8s|%-7s|%-9s|%-8s|%9u|%5u|%3u |", - wandev->name, - PROT_DECODE(wandev->config_id), - wandev->config_id == WANCONFIG_FR ? - (wandev->station ? " Node" : " CPE") : - (wandev->config_id == WANCONFIG_X25 ? - (wandev->station ? " DCE" : " DTE") : - (" N/A")), - wandev->interface ? " V.35" : " RS-232", - wandev->clocking ? "internal" : "external", - wandev->bps, - wandev->mtu, - wandev->ndev); - - switch (wandev->state) { - - case WAN_UNCONFIGURED: - cnt += sprintf(&buf[cnt], "%-12s\n", "unconfigured"); - break; - - case WAN_DISCONNECTED: - cnt += sprintf(&buf[cnt], "%-12s\n", "disconnected"); - break; - - case WAN_CONNECTING: - cnt += sprintf(&buf[cnt], "%-12s\n", "connecting"); - break; - - case WAN_CONNECTED: - cnt += sprintf(&buf[cnt], "%-12s\n", "connected"); - break; - - case WAN_FT1_READY: - cnt += sprintf(&buf[cnt], "%-12s\n", "ft1 ready"); - break; - - default: - cnt += sprintf(&buf[cnt], "%-12s\n", "invalid"); - break; - } - } - return cnt; + seq_printf(m, PROC_STATS_FORMAT, + "total packets received", wandev->stats.rx_packets); + seq_printf(m, PROC_STATS_FORMAT, + "total packets transmitted", wandev->stats.tx_packets); + seq_printf(m, PROC_STATS_FORMAT, + "total bytes received", wandev->stats.rx_bytes); + seq_printf(m, PROC_STATS_FORMAT, + "total bytes transmitted", wandev->stats.tx_bytes); + seq_printf(m, PROC_STATS_FORMAT, + "bad packets received", wandev->stats.rx_errors); + seq_printf(m, PROC_STATS_FORMAT, + "packet transmit problems", wandev->stats.tx_errors); + seq_printf(m, PROC_STATS_FORMAT, + "received frames dropped", wandev->stats.rx_dropped); + seq_printf(m, PROC_STATS_FORMAT, + "transmit frames dropped", wandev->stats.tx_dropped); + seq_printf(m, PROC_STATS_FORMAT, + "multicast packets received", wandev->stats.multicast); + seq_printf(m, PROC_STATS_FORMAT, + "transmit collisions", wandev->stats.collisions); + seq_printf(m, PROC_STATS_FORMAT, + "receive length errors", wandev->stats.rx_length_errors); + seq_printf(m, PROC_STATS_FORMAT, + "receiver overrun errors", wandev->stats.rx_over_errors); + seq_printf(m, PROC_STATS_FORMAT, + "CRC errors", wandev->stats.rx_crc_errors); + seq_printf(m, PROC_STATS_FORMAT, + "frame format errors (aborts)", wandev->stats.rx_frame_errors); + seq_printf(m, PROC_STATS_FORMAT, + "receiver fifo overrun", wandev->stats.rx_fifo_errors); + seq_printf(m, PROC_STATS_FORMAT, + "receiver missed packet", wandev->stats.rx_missed_errors); + seq_printf(m, PROC_STATS_FORMAT, + "aborted frames transmitted", wandev->stats.tx_aborted_errors); + return 0; +} +static struct seq_operations wandev_op = { + start: single_start, + next: single_next, + stop: single_stop, + show: wandev_show, +}; +static int wandev_open(struct inode *inode, struct file *file) +{ + int ret = seq_open(file, &wandev_op); + if (!ret) { + struct seq_file *m = file->private_data; + m->private = PDE(inode)->data; } + return ret; +} - /* - * Prepare data for reading entry. - * Return length of data. - * - * On entry, the 'start' argument will contain a pointer to WAN device - * data space. - */ - - static int wandev_get_info(char* buf, char** start, off_t offs, int len, - int dummy) - { - wan_device_t* wandev = (void*)start; - int cnt = 0; - int rslt = 0; +static struct file_operations wandev_fops = +{ + open: wandev_open, + read: seq_read, + llseek: seq_lseek, + release: seq_release, + ioctl: wanrouter_ioctl, +}; - if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC)) - return 0; - if (!wandev->state) - return sprintf(&buf[cnt], "Device is not configured!\n"); +/* + * Initialize router proc interface. + */ - /* Update device statistics */ - if (wandev->update) { +int __init wanrouter_proc_init (void) +{ + struct proc_dir_entry *p; + proc_router = proc_mkdir(ROUTER_NAME, proc_net); + if (!proc_router) + goto fail; + + p = create_proc_entry("config",0,proc_router); + if (!p) + goto fail_config; + p->proc_fops = &config_fops; + p->proc_iops = &router_inode; + p = create_proc_entry("status",0,proc_router); + if (!p) + goto fail_stat; + p->proc_fops = &status_fops; + p->proc_iops = &router_inode; + return 0; +fail_stat: + remove_proc_entry("config", proc_router); +fail_config: + remove_proc_entry(ROUTER_NAME, proc_net); +fail: + return -ENOMEM; +} - rslt = wandev->update(wandev); - if(rslt) { - switch (rslt) { - case -EAGAIN: - return sprintf(&buf[cnt], "Device is busy!\n"); - - default: - return sprintf(&buf[cnt], - "Device is not configured!\n"); - } - } - } +/* + * Clean up router proc interface. + */ - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "total packets received", wandev->stats.rx_packets); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "total packets transmitted", wandev->stats.tx_packets); -#ifdef LINUX_2_1 - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "total bytes received", wandev->stats.rx_bytes); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "total bytes transmitted", wandev->stats.tx_bytes); -#endif - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "bad packets received", wandev->stats.rx_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "packet transmit problems", wandev->stats.tx_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "received frames dropped", wandev->stats.rx_dropped); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "transmit frames dropped", wandev->stats.tx_dropped); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "multicast packets received", wandev->stats.multicast); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "transmit collisions", wandev->stats.collisions); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "receive length errors", wandev->stats.rx_length_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "receiver overrun errors", wandev->stats.rx_over_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "CRC errors", wandev->stats.rx_crc_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "frame format errors (aborts)", wandev->stats.rx_frame_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "receiver fifo overrun", wandev->stats.rx_fifo_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "receiver missed packet", wandev->stats.rx_missed_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "aborted frames transmitted", wandev->stats.tx_aborted_errors); +void wanrouter_proc_cleanup (void) +{ + remove_proc_entry("config", proc_router); + remove_proc_entry("status", proc_router); + remove_proc_entry(ROUTER_NAME,proc_net); +} - return cnt; - } +/* + * Add directory entry for WAN device. + */ -#endif /* End of ifdef LINUX_2_4 */ +int wanrouter_proc_add (wan_device_t* wandev) +{ + if (wandev->magic != ROUTER_MAGIC) + return -EINVAL; + + wandev->dent = create_proc_entry(wandev->name, 0, proc_router); + if (!wandev->dent) + return -ENOMEM; + wandev->dent->proc_fops = &wandev_fops; + wandev->dent->proc_iops = &router_inode; + wandev->dent->data = wandev; + return 0; +} +/* + * Delete directory entry for WAN device. + */ + +int wanrouter_proc_delete(wan_device_t* wandev) +{ + if (wandev->magic != ROUTER_MAGIC) + return -EINVAL; + remove_proc_entry(wandev->name, proc_router); + return 0; +} #else @@ -1039,7 +415,6 @@ void wanrouter_proc_cleanup(void) { - return; } int wanrouter_proc_add(wan_device_t *wandev) @@ -1054,34 +429,7 @@ #endif -/*============================================================================ - * Write WAN device ???. - * o Find WAN device associated with this node - */ -#ifdef LINUX_2_0 -static int device_write( - struct inode* inode, struct file* file, const char* buf, int count) -{ - int err = verify_area(VERIFY_READ, buf, count); - struct proc_dir_entry* dent; - wan_device_t* wandev; - - if (err) return err; - - dent = PDE(inode); - if ((dent == NULL) || (dent->data == NULL)) - return -ENODATA; - - wandev = dent->data; - - printk(KERN_ERR "%s: writing %d bytes to %s...\n", - name_root, count, dent->name); - - return 0; -} -#endif - /* * End */ - + diff -Nru a/sound/Makefile b/sound/Makefile --- a/sound/Makefile Tue Feb 26 11:57:58 2002 +++ b/sound/Makefile Tue Feb 26 11:57:58 2002 @@ -10,6 +10,7 @@ subdir-$(CONFIG_SOUND_PRIME) += oss ifeq ($(CONFIG_SOUND_PRIME),y) + subdir-m += oss obj-y += oss/sounddrivers.o endif diff -Nru a/sound/core/Config.in b/sound/core/Config.in --- a/sound/core/Config.in Tue Feb 26 11:57:58 2002 +++ b/sound/core/Config.in Tue Feb 26 11:57:58 2002 @@ -1,6 +1,5 @@ # ALSA soundcard-configuration -dep_tristate ' RTC Timer support' CONFIG_SND_RTCTIMER $CONFIG_SND dep_tristate ' Sequencer support' CONFIG_SND_SEQUENCER $CONFIG_SND if [ "$CONFIG_SND_SEQUENCER" != "n" ]; then dep_tristate ' Sequencer dummy client' CONFIG_SND_SEQ_DUMMY $CONFIG_SND_SEQUENCER @@ -13,9 +12,10 @@ dep_tristate ' OSS Sequencer API' CONFIG_SND_SEQUENCER_OSS $CONFIG_SND_SEQUENCER fi fi +dep_tristate ' RTC Timer support' CONFIG_SND_RTCTIMER $CONFIG_SND +bool ' Verbose printk' CONFIG_SND_VERBOSE_PRINTK bool ' Debug' CONFIG_SND_DEBUG if [ "$CONFIG_SND_DEBUG" = "y" ]; then bool ' Debug memory' CONFIG_SND_DEBUG_MEMORY - bool ' Debug full' CONFIG_SND_DEBUG_FULL bool ' Debug detection' CONFIG_SND_DEBUG_DETECT fi diff -Nru a/sound/core/Makefile b/sound/core/Makefile --- a/sound/core/Makefile Tue Feb 26 11:57:57 2002 +++ b/sound/core/Makefile Tue Feb 26 11:57:57 2002 @@ -33,16 +33,18 @@ subdir-$(CONFIG_SND_MIXER_OSS) += oss subdir-$(CONFIG_SND_PCM_OSS) += oss ifeq ($(filter $(subdir-y),oss),oss) + subdir-m += oss obj-y += oss/oss.o endif subdir-$(CONFIG_SND_SEQUENCER) += seq ifeq ($(CONFIG_SND_SEQUENCER),y) - ifeq ($(CONFIG_SND),y) - obj-y += seq/sq.o - endif + subdir-m += seq + obj-y += seq/sq.o endif +obj-$(CONFIG_SND_SEQUENCER) += snd-timer.o + # Toplevel Module Dependency obj-$(CONFIG_SND_DUMMY) += snd-pcm.o snd-timer.o snd.o obj-$(CONFIG_SND_VIRMIDI) += snd-rawmidi.o snd.o snd-timer.o @@ -69,7 +71,7 @@ obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o obj-$(CONFIG_SND_OPTI93X) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_SB) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o +obj-$(CONFIG_SND_SB8) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o obj-$(CONFIG_SND_SB16) += snd-pcm.o snd-timer.o snd.o snd-hwdep.o snd-rawmidi.o obj-$(CONFIG_SND_SBAWE) += snd-pcm.o snd-timer.o snd.o snd-hwdep.o snd-rawmidi.o obj-$(CONFIG_SND_ES968) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o @@ -79,7 +81,7 @@ obj-$(CONFIG_SND_CS4281) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o obj-$(CONFIG_SND_ENS1370) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o obj-$(CONFIG_SND_ENS1371) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o -obj-$(CONFIG_SND_ES1938) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o +obj-$(CONFIG_SND_ES1938) += snd-pcm.o snd-timer.o snd.o snd-hwdep.o snd-rawmidi.o obj-$(CONFIG_SND_ES1968) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o obj-$(CONFIG_SND_FM801) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o obj-$(CONFIG_SND_ICE1712) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o diff -Nru a/sound/core/control.c b/sound/core/control.c --- a/sound/core/control.c Tue Feb 26 11:57:57 2002 +++ b/sound/core/control.c Tue Feb 26 11:57:57 2002 @@ -166,7 +166,7 @@ ev->mask = mask; list_add_tail(&ev->list, &ctl->events); } else { - snd_printk("No memory available to allocate event\n"); + snd_printk(KERN_ERR "No memory available to allocate event\n"); } _found: wake_up(&ctl->change_sleep); diff -Nru a/sound/core/device.c b/sound/core/device.c --- a/sound/core/device.c Tue Feb 26 11:57:56 2002 +++ b/sound/core/device.c Tue Feb 26 11:57:56 2002 @@ -58,11 +58,11 @@ list_del(&dev->list); if (dev->state == SNDRV_DEV_REGISTERED && dev->ops->dev_unregister) { if (dev->ops->dev_unregister(dev)) - snd_printk("device unregister failure\n"); + snd_printk(KERN_ERR "device unregister failure\n"); } else { if (dev->ops->dev_free) { if (dev->ops->dev_free(dev)) - snd_printk("device free failure\n"); + snd_printk(KERN_ERR "device free failure\n"); } } snd_magic_kfree(dev); diff -Nru a/sound/core/hwdep.c b/sound/core/hwdep.c --- a/sound/core/hwdep.c Tue Feb 26 11:57:56 2002 +++ b/sound/core/hwdep.c Tue Feb 26 11:57:56 2002 @@ -321,7 +321,7 @@ if ((err = snd_register_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device, &snd_hwdep_reg, name)) < 0) { - snd_printk("unable to register hardware dependant device %i:%i\n", + snd_printk(KERN_ERR "unable to register hardware dependant device %i:%i\n", hwdep->card->number, hwdep->device); snd_hwdep_devices[idx] = NULL; up(®ister_mutex); @@ -331,12 +331,12 @@ hwdep->ossreg = 0; if (hwdep->oss_type >= 0) { if ((hwdep->oss_type == SNDRV_OSS_DEVICE_TYPE_DMFM) && (hwdep->device != 0)) { - snd_printk ("only hwdep device 0 can be registered as OSS direct FM device!\n"); + snd_printk (KERN_WARNING "only hwdep device 0 can be registered as OSS direct FM device!\n"); } else { if (snd_register_oss_device(hwdep->oss_type, hwdep->card, hwdep->device, &snd_hwdep_reg, hwdep->oss_dev) < 0) { - snd_printk("unable to register OSS compatibility device %i:%i\n", + snd_printk(KERN_ERR "unable to register OSS compatibility device %i:%i\n", hwdep->card->number, hwdep->device); } else { snd_oss_info_register(SNDRV_OSS_INFO_DEV_SYNTH, hwdep->card->number, hwdep->name); diff -Nru a/sound/core/info.c b/sound/core/info.c --- a/sound/core/info.c Tue Feb 26 11:57:59 2002 +++ b/sound/core/info.c Tue Feb 26 11:57:59 2002 @@ -29,6 +29,7 @@ #include #include #include +#include #ifdef CONFIG_DEVFS_FS #include #endif @@ -162,31 +163,40 @@ { snd_info_private_data_t *data; struct snd_info_entry *entry; + int ret = -EINVAL; data = snd_magic_cast(snd_info_private_data_t, file->private_data, return -ENXIO); entry = data->entry; + lock_kernel(); switch (entry->content) { case SNDRV_INFO_CONTENT_TEXT: switch (orig) { case 0: /* SEEK_SET */ file->f_pos = offset; - return file->f_pos; + ret = file->f_pos; + goto out; case 1: /* SEEK_CUR */ file->f_pos += offset; - return file->f_pos; + ret = file->f_pos; + goto out; case 2: /* SEEK_END */ default: - return -EINVAL; + goto out; } break; case SNDRV_INFO_CONTENT_DATA: - if (entry->c.ops->llseek) - return entry->c.ops->llseek(entry, + if (entry->c.ops->llseek) { + ret = entry->c.ops->llseek(entry, data->file_private_data, file, offset, orig); + goto out; + } break; } - return -ENXIO; + ret = -ENXIO; +out: + unlock_kernel(); + return ret; } static ssize_t snd_info_entry_read(struct file *file, char *buffer, @@ -420,7 +430,7 @@ if (entry->c.text.write) { entry->c.text.write(entry, data->wbuffer); if (data->wbuffer->error) { - snd_printk("data write error to %s (%i)\n", + snd_printk(KERN_WARNING "data write error to %s (%i)\n", entry->name, data->wbuffer->error); } diff -Nru a/sound/core/init.c b/sound/core/init.c --- a/sound/core/init.c Tue Feb 26 11:57:57 2002 +++ b/sound/core/init.c Tue Feb 26 11:57:57 2002 @@ -74,7 +74,7 @@ if (idx < 0 || idx >= snd_ecards_limit) { write_unlock(&snd_card_rwlock); if (idx >= snd_ecards_limit) - snd_printk("card %i is out of range (0-%i)\n", idx, snd_ecards_limit-1); + snd_printk(KERN_ERR "card %i is out of range (0-%i)\n", idx, snd_ecards_limit-1); goto __error; } snd_cards_lock |= 1 << idx; /* lock it */ @@ -140,26 +140,26 @@ snd_mixer_oss_notify_callback(card, 1); #endif if (snd_device_free_all(card, SNDRV_DEV_CMD_PRE) < 0) { - snd_printk("unable to free all devices (pre)\n"); + snd_printk(KERN_ERR "unable to free all devices (pre)\n"); /* Fatal, but this situation should never occur */ } if (snd_device_free_all(card, SNDRV_DEV_CMD_NORMAL) < 0) { - snd_printk("unable to free all devices (normal)\n"); + snd_printk(KERN_ERR "unable to free all devices (normal)\n"); /* Fatal, but this situation should never occur */ } if (snd_ctl_unregister(card) < 0) { - snd_printk("unable to unregister control minors\n"); + snd_printk(KERN_ERR "unable to unregister control minors\n"); /* Not fatal error */ } if (snd_device_free_all(card, SNDRV_DEV_CMD_POST) < 0) { - snd_printk("unable to free all devices (post)\n"); + snd_printk(KERN_ERR "unable to free all devices (post)\n"); /* Fatal, but this situation should never occur */ } if (card->private_free) card->private_free(card); snd_info_free_entry(card->proc_id); if (snd_info_card_unregister(card) < 0) { - snd_printk("unable to unregister card info\n"); + snd_printk(KERN_WARNING "unable to unregister card info\n"); /* Not fatal error */ } write_lock(&snd_card_rwlock); diff -Nru a/sound/core/memory.c b/sound/core/memory.c --- a/sound/core/memory.c Tue Feb 26 11:57:56 2002 +++ b/sound/core/memory.c Tue Feb 26 11:57:56 2002 @@ -68,28 +68,28 @@ struct list_head *head; struct snd_alloc_track *t; if (snd_alloc_pages > 0) - snd_printk("Not freed snd_alloc_pages = %li\n", snd_alloc_pages); + snd_printk(KERN_ERR "Not freed snd_alloc_pages = %li\n", snd_alloc_pages); if (snd_alloc_kmalloc > 0) - snd_printk("Not freed snd_alloc_kmalloc = %li\n", snd_alloc_kmalloc); + snd_printk(KERN_ERR "Not freed snd_alloc_kmalloc = %li\n", snd_alloc_kmalloc); if (snd_alloc_vmalloc > 0) - snd_printk("Not freed snd_alloc_vmalloc = %li\n", snd_alloc_vmalloc); + snd_printk(KERN_ERR "Not freed snd_alloc_vmalloc = %li\n", snd_alloc_vmalloc); for (head = snd_alloc_kmalloc_list.prev; head != &snd_alloc_kmalloc_list; head = head->prev) { t = list_entry(head, struct snd_alloc_track, list); if (t->magic != KMALLOC_MAGIC) { - snd_printk("Corrupted kmalloc\n"); + snd_printk(KERN_ERR "Corrupted kmalloc\n"); break; } - snd_printk("kmalloc(%ld) from %p not freed\n", (long) t->size, t->caller); + snd_printk(KERN_ERR "kmalloc(%ld) from %p not freed\n", (long) t->size, t->caller); } for (head = snd_alloc_vmalloc_list.prev; head != &snd_alloc_vmalloc_list; head = head->prev) { t = list_entry(head, struct snd_alloc_track, list); if (t->magic != VMALLOC_MAGIC) { - snd_printk("Corrupted vmalloc\n"); + snd_printk(KERN_ERR "Corrupted vmalloc\n"); break; } - snd_printk("vmalloc(%ld) from %p not freed\n", (long) t->size, t->caller); + snd_printk(KERN_ERR "vmalloc(%ld) from %p not freed\n", (long) t->size, t->caller); } } @@ -125,12 +125,12 @@ unsigned long flags; struct snd_alloc_track *t; if (obj == NULL) { - snd_printk("null kfree (called from %p)\n", __builtin_return_address(0)); + snd_printk(KERN_WARNING "null kfree (called from %p)\n", __builtin_return_address(0)); return; } t = snd_alloc_track_entry(obj); if (t->magic != KMALLOC_MAGIC) { - snd_printk("bad kfree (called from %p)\n", __builtin_return_address(0)); + snd_printk(KERN_WARNING "bad kfree (called from %p)\n", __builtin_return_address(0)); return; } spin_lock_irqsave(&snd_alloc_kmalloc_lock, flags); @@ -166,7 +166,7 @@ { unsigned long *ptr = _ptr; if (ptr == NULL) { - snd_printk("null snd_magic_kfree (called from %p)\n", __builtin_return_address(0)); + snd_printk(KERN_WARNING "null snd_magic_kfree (called from %p)\n", __builtin_return_address(0)); return; } *--ptr = 0; @@ -174,7 +174,7 @@ struct snd_alloc_track *t; t = snd_alloc_track_entry(ptr); if (t->magic != KMALLOC_MAGIC) { - snd_printk("bad snd_magic_kfree (called from %p)\n", __builtin_return_address(0)); + snd_printk(KERN_ERR "bad snd_magic_kfree (called from %p)\n", __builtin_return_address(0)); return; } } @@ -204,12 +204,12 @@ { struct snd_alloc_track *t; if (obj == NULL) { - snd_printk("null vfree (called from %p)\n", __builtin_return_address(0)); + snd_printk(KERN_WARNING "null vfree (called from %p)\n", __builtin_return_address(0)); return; } t = snd_alloc_track_entry(obj); if (t->magic != VMALLOC_MAGIC) { - snd_printk("bad vfree (called from %p)\n", __builtin_return_address(0)); + snd_printk(KERN_ERR "bad vfree (called from %p)\n", __builtin_return_address(0)); return; } spin_lock(&snd_alloc_vmalloc_lock); @@ -516,29 +516,36 @@ /* * A dirty hack... when the kernel code is fixed this should be removed. * - * since pci_alloc_consistent always tries GFP_ATOMIC when the requested + * since pci_alloc_consistent always tries GFP_DMA when the requested * pci memory region is below 32bit, it happens quite often that even * 2 order or pages cannot be allocated. * - * so in the following, GFP_ATOMIC is used only when the first allocation + * so in the following, GFP_DMA is used only when the first allocation * doesn't match the requested region. */ +#ifdef __i386__ +#define get_phys_addr(x) virt_to_phys(x) +#else /* ppc */ +#define get_phys_addr(x) virt_to_bus(x) +#endif void *snd_pci_hack_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) { void *ret; int gfp = GFP_ATOMIC; + if (hwdev == NULL) + gfp |= GFP_DMA; ret = (void *)__get_free_pages(gfp, get_order(size)); if (ret) { - if (hwdev && ((virt_to_phys(ret) + size - 1) & ~hwdev->dma_mask)) { + if (hwdev && ((get_phys_addr(ret) + size - 1) & ~hwdev->dma_mask)) { free_pages((unsigned long)ret, get_order(size)); ret = (void *)__get_free_pages(gfp | GFP_DMA, get_order(size)); } } if (ret) { memset(ret, 0, size); - *dma_handle = virt_to_phys(ret); + *dma_handle = get_phys_addr(ret); } return ret; } diff -Nru a/sound/core/misc.c b/sound/core/misc.c --- a/sound/core/misc.c Tue Feb 26 11:57:58 2002 +++ b/sound/core/misc.c Tue Feb 26 11:57:58 2002 @@ -36,3 +36,18 @@ name[idx] = '\0'; return 0; } + +#ifdef CONFIG_SND_VERBOSE_PRINTK +int snd_verbose_printk(const char *file, int line, const char *format) +{ + if (format[0] == '<' && format[1] >= '0' && format[1] <= '9' && format[2] == '>') { + char tmp[] = "<0>ALSA %s:%d: "; + tmp[1] = format[1]; + printk("%sALSA %s:%d: ", tmp, file, line); + return 1; + } else { + printk("ALSA %s:%d: ", file, line); + return 0; + } +} +#endif diff -Nru a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c --- a/sound/core/pcm_lib.c Tue Feb 26 11:57:59 2002 +++ b/sound/core/pcm_lib.c Tue Feb 26 11:57:59 2002 @@ -104,7 +104,7 @@ snd_timestamp_now((snd_timestamp_t*)&runtime->status->tstamp); #ifdef CONFIG_SND_DEBUG if (pos > runtime->buffer_size) { - snd_printk("BUG: stream = %i, pos = 0x%lx, buffer size = 0x%lx, period size = 0x%lx\n", substream->stream, pos, runtime->buffer_size, runtime->period_size); + snd_printk(KERN_ERR "BUG: stream = %i, pos = 0x%lx, buffer size = 0x%lx, period size = 0x%lx\n", substream->stream, pos, runtime->buffer_size, runtime->period_size); } else #endif snd_runtime_check(pos <= runtime->buffer_size, return 0); @@ -170,7 +170,7 @@ snd_timestamp_now((snd_timestamp_t*)&runtime->status->tstamp); #ifdef CONFIG_SND_DEBUG if (pos > runtime->buffer_size) { - snd_printk("BUG: stream = %i, pos = 0x%lx, buffer size = 0x%lx, period size = 0x%lx\n", substream->stream, pos, runtime->buffer_size, runtime->period_size); + snd_printk(KERN_ERR "BUG: stream = %i, pos = 0x%lx, buffer size = 0x%lx, period size = 0x%lx\n", substream->stream, pos, runtime->buffer_size, runtime->period_size); } else #endif snd_runtime_check(pos <= runtime->buffer_size, return 0); diff -Nru a/sound/core/pcm_native.c b/sound/core/pcm_native.c --- a/sound/core/pcm_native.c Tue Feb 26 11:57:58 2002 +++ b/sound/core/pcm_native.c Tue Feb 26 11:57:58 2002 @@ -837,6 +837,42 @@ #endif /* CONFIG_PM */ +static int snd_pcm_xrun(snd_pcm_substream_t *substream) +{ + snd_card_t *card = substream->pcm->card; + snd_pcm_runtime_t *runtime = substream->runtime; + int result; + + snd_power_lock(card); + spin_lock_irq(&runtime->lock); + _xrun_recovery: + switch (runtime->status->state) { + case SNDRV_PCM_STATE_XRUN: + result = 0; /* already there */ + break; + case SNDRV_PCM_STATE_RUNNING: + result = snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); + break; + case SNDRV_PCM_STATE_SUSPENDED: + while (snd_power_get_state(card) != SNDRV_CTL_POWER_D0) { + if (substream->ffile->f_flags & O_NONBLOCK) { + result = -EAGAIN; + goto _end; + } + spin_unlock_irq(&runtime->lock); + snd_power_wait(card); + spin_lock_irq(&runtime->lock); + } + goto _xrun_recovery; + default: + result = -EBADFD; + } + _end: + spin_unlock_irq(&runtime->lock); + snd_power_unlock(card); + return result; +} + static inline int snd_pcm_pre_reset(snd_pcm_substream_t * substream, int state) { snd_pcm_runtime_t *runtime = substream->runtime; @@ -1999,6 +2035,10 @@ return snd_pcm_link(substream, (long) arg); case SNDRV_PCM_IOCTL_UNLINK: return snd_pcm_unlink(substream); + case SNDRV_PCM_IOCTL_RESUME: + return snd_pcm_resume(substream); + case SNDRV_PCM_IOCTL_XRUN: + return snd_pcm_xrun(substream); } snd_printd("unknown ioctl = 0x%x\n", cmd); return -ENOTTY; @@ -2071,8 +2111,6 @@ return snd_pcm_playback_drop(substream); case SNDRV_PCM_IOCTL_DELAY: return snd_pcm_playback_delay(substream, (snd_pcm_sframes_t*) arg); - case SNDRV_PCM_IOCTL_RESUME: - return snd_pcm_resume(substream); } return snd_pcm_common_ioctl1(substream, cmd, arg); } @@ -2136,8 +2174,6 @@ return snd_pcm_capture_drop(substream); case SNDRV_PCM_IOCTL_DELAY: return snd_pcm_capture_delay(substream, (snd_pcm_sframes_t*) arg); - case SNDRV_PCM_IOCTL_RESUME: - return snd_pcm_resume(substream); } return snd_pcm_common_ioctl1(substream, cmd, arg); } diff -Nru a/sound/core/rawmidi.c b/sound/core/rawmidi.c --- a/sound/core/rawmidi.c Tue Feb 26 11:57:57 2002 +++ b/sound/core/rawmidi.c Tue Feb 26 11:57:57 2002 @@ -769,7 +769,7 @@ } #ifdef CONFIG_SND_DEBUG default: - snd_printk("rawmidi: unknown command = 0x%x\n", cmd); + snd_printk(KERN_WARNING "rawmidi: unknown command = 0x%x\n", cmd); #endif } return -ENOTTY; @@ -1408,7 +1408,7 @@ if ((err = snd_register_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device, &snd_rawmidi_reg, name)) < 0) { - snd_printk("unable to register rawmidi device %i:%i\n", rmidi->card->number, rmidi->device); + snd_printk(KERN_ERR "unable to register rawmidi device %i:%i\n", rmidi->card->number, rmidi->device); snd_rawmidi_devices[idx] = NULL; up(®ister_mutex); return err; @@ -1425,7 +1425,7 @@ if (rmidi->device == snd_midi_map[rmidi->card->number]) { if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI, rmidi->card, 0, &snd_rawmidi_reg, name) < 0) { - snd_printk("unable to register OSS rawmidi device %i:%i\n", rmidi->card->number, 0); + snd_printk(KERN_ERR "unable to register OSS rawmidi device %i:%i\n", rmidi->card->number, 0); } else { rmidi->ossreg++; snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIDI, rmidi->card->number, rmidi->name); @@ -1434,7 +1434,7 @@ if (rmidi->device == snd_amidi_map[rmidi->card->number]) { if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI, rmidi->card, 1, &snd_rawmidi_reg, name) < 0) { - snd_printk("unable to register OSS rawmidi device %i:%i\n", rmidi->card->number, 1); + snd_printk(KERN_ERR "unable to register OSS rawmidi device %i:%i\n", rmidi->card->number, 1); } else { rmidi->ossreg++; } @@ -1532,11 +1532,11 @@ /* check device map table */ for (i = 0; i < SNDRV_CARDS; i++) { if (snd_midi_map[i] < 0 || snd_midi_map[i] >= SNDRV_RAWMIDI_DEVICES) { - snd_printk("invalid midi_map[%d] = %d\n", i, snd_midi_map[i]); + snd_printk(KERN_ERR "invalid midi_map[%d] = %d\n", i, snd_midi_map[i]); snd_midi_map[i] = 0; } if (snd_amidi_map[i] < 0 || snd_amidi_map[i] >= SNDRV_RAWMIDI_DEVICES) { - snd_printk("invalid amidi_map[%d] = %d\n", i, snd_amidi_map[i]); + snd_printk(KERN_ERR "invalid amidi_map[%d] = %d\n", i, snd_amidi_map[i]); snd_amidi_map[i] = 1; } } diff -Nru a/sound/core/rtctimer.c b/sound/core/rtctimer.c --- a/sound/core/rtctimer.c Tue Feb 26 11:57:58 2002 +++ b/sound/core/rtctimer.c Tue Feb 26 11:57:58 2002 @@ -156,13 +156,13 @@ snd_timer_t *timer; if (rtctimer_freq < 2 || rtctimer_freq > 8192) { - snd_printk("rtctimer: invalid frequency %d\n", rtctimer_freq); + snd_printk(KERN_ERR "rtctimer: invalid frequency %d\n", rtctimer_freq); return -EINVAL; } for (order = 1; rtctimer_freq > order; order <<= 1) ; if (rtctimer_freq != order) { - snd_printk("rtctimer: invalid frequency %d\n", rtctimer_freq); + snd_printk(KERN_ERR "rtctimer: invalid frequency %d\n", rtctimer_freq); return -EINVAL; } diff -Nru a/sound/core/seq/Makefile b/sound/core/seq/Makefile --- a/sound/core/seq/Makefile Tue Feb 26 11:58:00 2002 +++ b/sound/core/seq/Makefile Tue Feb 26 11:58:00 2002 @@ -32,6 +32,8 @@ snd-seq-dummy-objs := seq_dummy.o snd-seq-virmidi-objs := seq_virmidi.o +obj-$(CONFIG_SND_SEQUENCER) += snd-seq.o snd-seq-device.o +obj-$(CONFIG_SND_SEQUENCER_OSS) += snd-seq-midi-event.o obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o # Toplevel Module Dependency @@ -56,7 +58,7 @@ obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o obj-$(CONFIG_SND_OPTI93X) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o -obj-$(CONFIG_SND_SB) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o +obj-$(CONFIG_SND_SB8) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o obj-$(CONFIG_SND_SB16) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o obj-$(CONFIG_SND_SBAWE) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o snd-seq-virmidi.o obj-$(CONFIG_SND_ES968) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o @@ -66,7 +68,7 @@ obj-$(CONFIG_SND_CS4281) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o obj-$(CONFIG_SND_ENS1370) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o obj-$(CONFIG_SND_ENS1371) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o -obj-$(CONFIG_SND_ES1938) += snd-seq-device.o snd-seq-midi-emul.o snd-seq.o snd-seq-instr.o +obj-$(CONFIG_SND_ES1938) += snd-seq-device.o snd-seq-midi-emul.o snd-seq.o snd-seq-instr.o snd-seq-midi.o snd-seq-midi-event.o obj-$(CONFIG_SND_ES1968) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o obj-$(CONFIG_SND_FM801) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o obj-$(CONFIG_SND_ICE1712) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o @@ -76,7 +78,7 @@ obj-$(CONFIG_SND_CS46XX) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o obj-$(CONFIG_SND_EMU10K1) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-virmidi.o obj-$(CONFIG_SND_TRIDENT) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o -obj-$(CONFIG_SND_YMFPCI) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o +obj-$(CONFIG_SND_YMFPCI) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o include $(TOPDIR)/Rules.make diff -Nru a/sound/core/seq/instr/Makefile b/sound/core/seq/instr/Makefile --- a/sound/core/seq/instr/Makefile Tue Feb 26 11:57:58 2002 +++ b/sound/core/seq/instr/Makefile Tue Feb 26 11:57:58 2002 @@ -33,7 +33,7 @@ obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-ainstr-fm.o obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-ainstr-fm.o obj-$(CONFIG_SND_OPTI93X) += snd-ainstr-fm.o -obj-$(CONFIG_SND_SB) += snd-ainstr-fm.o +obj-$(CONFIG_SND_SB8) += snd-ainstr-fm.o obj-$(CONFIG_SND_SB16) += snd-ainstr-fm.o obj-$(CONFIG_SND_SBAWE) += snd-ainstr-fm.o obj-$(CONFIG_SND_WAVEFRONT) += snd-ainstr-fm.o @@ -44,6 +44,7 @@ obj-$(CONFIG_SND_FM801) += snd-ainstr-fm.o obj-$(CONFIG_SND_SONICVIBES) += snd-ainstr-fm.o obj-$(CONFIG_SND_TRIDENT) += snd-ainstr-simple.o +obj-$(CONFIG_SND_YMFPCI) += snd-ainstr-fm.o include $(TOPDIR)/Rules.make diff -Nru a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c --- a/sound/core/seq/oss/seq_oss.c Tue Feb 26 11:57:58 2002 +++ b/sound/core/seq/oss/seq_oss.c Tue Feb 26 11:57:58 2002 @@ -222,7 +222,7 @@ NULL, 0, &seq_oss_reg, SNDRV_SEQ_OSS_DEVNAME)) < 0) { - snd_printk("can't register device seq\n"); + snd_printk(KERN_ERR "can't register device seq\n"); up(®ister_mutex); return rc; } @@ -230,7 +230,7 @@ NULL, 0, &seq_oss_reg, SNDRV_SEQ_OSS_DEVNAME)) < 0) { - snd_printk("can't register device music\n"); + snd_printk(KERN_ERR "can't register device music\n"); snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0); up(®ister_mutex); return rc; @@ -245,11 +245,10 @@ { down(®ister_mutex); debug_printk(("device unregistered\n")); - if (snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC, NULL, 0) < 0) - - snd_printk("error unregister device music\n"); + if (snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC, NULL, 0) < 0) + snd_printk(KERN_ERR "error unregister device music\n"); if (snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0) < 0) - snd_printk("error unregister device seq\n"); + snd_printk(KERN_ERR "error unregister device seq\n"); up(®ister_mutex); } diff -Nru a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c --- a/sound/core/seq/oss/seq_oss_init.c Tue Feb 26 11:57:56 2002 +++ b/sound/core/seq/oss/seq_oss_init.c Tue Feb 26 11:57:56 2002 @@ -184,7 +184,7 @@ seq_oss_devinfo_t *dp; if ((dp = snd_kcalloc(sizeof(*dp), GFP_KERNEL)) == NULL) { - snd_printk("can't malloc device info\n"); + snd_printk(KERN_ERR "can't malloc device info\n"); return -ENOMEM; } @@ -193,7 +193,7 @@ break; } if (i >= SNDRV_SEQ_OSS_MAX_CLIENTS) { - snd_printk("too many applications\n"); + snd_printk(KERN_ERR "too many applications\n"); return -ENOMEM; } @@ -209,14 +209,14 @@ snd_seq_oss_midi_setup(dp); if (dp->synth_opened == 0 && dp->max_mididev == 0) { - snd_printk("no device found\n"); + snd_printk(KERN_ERR "no device found\n"); kfree(dp); return -ENODEV; } /* create port */ if ((rc = create_port(dp)) < 0) { - snd_printk("can't create port\n"); + snd_printk(KERN_ERR "can't create port\n"); free_devinfo(dp); return rc; } @@ -259,7 +259,7 @@ /* initialize timer */ if ((dp->timer = snd_seq_oss_timer_new(dp)) == NULL) { - snd_printk("can't alloc timer\n"); + snd_printk(KERN_ERR "can't alloc timer\n"); delete_seq_queue(dp); delete_port(dp); return -ENOMEM; diff -Nru a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c --- a/sound/core/seq/oss/seq_oss_midi.c Tue Feb 26 11:57:56 2002 +++ b/sound/core/seq/oss/seq_oss_midi.c Tue Feb 26 11:57:56 2002 @@ -173,7 +173,7 @@ * allocate midi info record */ if ((mdev = snd_kcalloc(sizeof(*mdev), GFP_KERNEL)) == NULL) { - snd_printk("can't malloc midi info\n"); + snd_printk(KERN_ERR "can't malloc midi info\n"); return -ENOMEM; } @@ -190,7 +190,7 @@ /* create MIDI coder */ if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &mdev->coder) < 0) { - snd_printk("can't malloc midi coder\n"); + snd_printk(KERN_ERR "can't malloc midi coder\n"); kfree(mdev); return -ENOMEM; } diff -Nru a/sound/core/seq/oss/seq_oss_readq.c b/sound/core/seq/oss/seq_oss_readq.c --- a/sound/core/seq/oss/seq_oss_readq.c Tue Feb 26 11:57:58 2002 +++ b/sound/core/seq/oss/seq_oss_readq.c Tue Feb 26 11:57:58 2002 @@ -47,12 +47,12 @@ seq_oss_readq_t *q; if ((q = snd_kcalloc(sizeof(*q), GFP_KERNEL)) == NULL) { - snd_printk("can't malloc read queue\n"); + snd_printk(KERN_ERR "can't malloc read queue\n"); return NULL; } if ((q->q = snd_kcalloc(sizeof(evrec_t) * maxlen, GFP_KERNEL)) == NULL) { - snd_printk("can't malloc read queue buffer\n"); + snd_printk(KERN_ERR "can't malloc read queue buffer\n"); kfree(q); return NULL; } diff -Nru a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c --- a/sound/core/seq/oss/seq_oss_synth.c Tue Feb 26 11:57:56 2002 +++ b/sound/core/seq/oss/seq_oss_synth.c Tue Feb 26 11:57:56 2002 @@ -111,7 +111,7 @@ unsigned long flags; if ((rec = snd_kcalloc(sizeof(*rec), GFP_KERNEL)) == NULL) { - snd_printk("can't malloc synth info\n"); + snd_printk(KERN_ERR "can't malloc synth info\n"); return -ENOMEM; } rec->seq_device = -1; @@ -136,7 +136,7 @@ if (i >= max_synth_devs) { if (max_synth_devs >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS) { spin_unlock_irqrestore(®ister_lock, flags); - snd_printk("no more synth slot\n"); + snd_printk(KERN_ERR "no more synth slot\n"); kfree(rec); return -ENOMEM; } @@ -165,7 +165,7 @@ } if (index >= max_synth_devs) { spin_unlock_irqrestore(®ister_lock, flags); - snd_printk("can't unregister synth\n"); + snd_printk(KERN_ERR "can't unregister synth\n"); return -EINVAL; } synth_devs[index] = NULL; diff -Nru a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c --- a/sound/core/seq/seq_clientmgr.c Tue Feb 26 11:57:57 2002 +++ b/sound/core/seq/seq_clientmgr.c Tue Feb 26 11:57:57 2002 @@ -265,7 +265,7 @@ down(®ister_mutex); switch (client->type) { case NO_CLIENT: - snd_printk("Seq: Trying to free unused client %d\n", client->number); + snd_printk(KERN_WARNING "Seq: Trying to free unused client %d\n", client->number); break; case USER_CLIENT: case KERNEL_CLIENT: @@ -274,7 +274,7 @@ break; default: - snd_printk("Seq: Trying to free client %d with undefined type = %d\n", client->number, client->type); + snd_printk(KERN_ERR "Seq: Trying to free client %d with undefined type = %d\n", client->number, client->type); } up(®ister_mutex); diff -Nru a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c --- a/sound/core/seq/seq_device.c Tue Feb 26 11:57:57 2002 +++ b/sound/core/seq/seq_device.c Tue Feb 26 11:57:57 2002 @@ -295,7 +295,7 @@ if (ops == NULL) return -ENOMEM; if (ops->driver & DRIVER_LOADED) { - snd_printk("driver_register: driver '%s' already exists\n", id); + snd_printk(KERN_WARNING "driver_register: driver '%s' already exists\n", id); unlock_driver(ops); return -EBUSY; } @@ -363,7 +363,7 @@ return -ENXIO; if (! (ops->driver & DRIVER_LOADED) || (ops->driver & DRIVER_LOCKED)) { - snd_printk("driver_unregister: cannot unload driver '%s': status=%x\n", id, ops->driver); + snd_printk(KERN_ERR "driver_unregister: cannot unload driver '%s': status=%x\n", id, ops->driver); unlock_driver(ops); return -EBUSY; } @@ -378,7 +378,7 @@ ops->driver = 0; if (ops->num_init_devices > 0) - snd_printk("free_driver: init_devices > 0!! (%d)\n", ops->num_init_devices); + snd_printk(KERN_ERR "free_driver: init_devices > 0!! (%d)\n", ops->num_init_devices); up(&ops->reg_mutex); unlock_driver(ops); @@ -423,15 +423,14 @@ if (dev->status != SNDRV_SEQ_DEVICE_FREE) return 0; /* already initialized */ if (ops->argsize != dev->argsize) { - snd_printk("incompatible device '%s' for plug-in '%s'\n", dev->name, ops->id); -printk(" %d %d\n", ops->argsize, dev->argsize); + snd_printk(KERN_ERR "incompatible device '%s' for plug-in '%s' (%d %d)\n", dev->name, ops->id, ops->argsize, dev->argsize); return -EINVAL; } if (ops->ops.init_device(dev) >= 0) { dev->status = SNDRV_SEQ_DEVICE_REGISTERED; ops->num_init_devices++; } else { - snd_printk("init_device failed: %s: %s\n", dev->name, dev->id); + snd_printk(KERN_ERR "init_device failed: %s: %s\n", dev->name, dev->id); } return 0; @@ -449,7 +448,7 @@ if (dev->status != SNDRV_SEQ_DEVICE_REGISTERED) return 0; /* not registered */ if (ops->argsize != dev->argsize) { - snd_printk("incompatible device '%s' for plug-in '%s'\n", dev->name, ops->id); + snd_printk(KERN_ERR "incompatible device '%s' for plug-in '%s' (%d %d)\n", dev->name, ops->id, ops->argsize, dev->argsize); return -EINVAL; } if ((result = ops->ops.free_device(dev)) >= 0 || result == -ENXIO) { @@ -457,7 +456,7 @@ dev->driver_data = NULL; ops->num_init_devices--; } else { - snd_printk("free_device failed: %s: %s\n", dev->name, dev->id); + snd_printk(KERN_ERR "free_device failed: %s: %s\n", dev->name, dev->id); } return 0; @@ -517,7 +516,7 @@ remove_drivers(); snd_info_unregister(info_entry); if (num_ops) - snd_printk("drivers not released (%d)\n", num_ops); + snd_printk(KERN_ERR "drivers not released (%d)\n", num_ops); } module_init(alsa_seq_device_init) diff -Nru a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c --- a/sound/core/seq/seq_dummy.c Tue Feb 26 11:57:59 2002 +++ b/sound/core/seq/seq_dummy.c Tue Feb 26 11:57:59 2002 @@ -206,7 +206,7 @@ int i; if (ports < 1) { - snd_printk("invalid number of ports %d\n", ports); + snd_printk(KERN_ERR "invalid number of ports %d\n", ports); return -EINVAL; } diff -Nru a/sound/core/seq/seq_instr.c b/sound/core/seq/seq_instr.c --- a/sound/core/seq/seq_instr.c Tue Feb 26 11:57:59 2002 +++ b/sound/core/seq/seq_instr.c Tue Feb 26 11:57:59 2002 @@ -132,7 +132,7 @@ } spin_unlock_irqrestore(&list->lock, flags); if (snd_seq_instr_free(instr, 0)<0) - snd_printk("instrument free problem\n"); + snd_printk(KERN_WARNING "instrument free problem\n"); } while ((cluster = list->chash[idx]) != NULL) { list->chash[idx] = cluster->next; @@ -221,7 +221,7 @@ schedule_timeout(1); } if (snd_seq_instr_free(instr, atomic)<0) - snd_printk("instrument free problem\n"); + snd_printk(KERN_WARNING "instrument free problem\n"); instr = next; } } @@ -324,7 +324,7 @@ return; spin_lock_irqsave(&list->lock, flags); if (instr->use <= 0) { - snd_printk("free_use: fatal!!! use = %i, name = '%s'\n", instr->use, instr->name); + snd_printk(KERN_ERR "free_use: fatal!!! use = %i, name = '%s'\n", instr->use, instr->name); } else { instr->use--; } diff -Nru a/sound/core/seq/seq_lock.c b/sound/core/seq/seq_lock.c --- a/sound/core/seq/seq_lock.c Tue Feb 26 11:57:59 2002 +++ b/sound/core/seq/seq_lock.c Tue Feb 26 11:57:59 2002 @@ -68,12 +68,12 @@ int max_count = 5 * HZ; if (atomic_read(lockp) < 0) { - printk("seq_lock: lock trouble [counter = %d] in %s:%d\n", atomic_read(lockp), file, line); + printk(KERN_WARNING "seq_lock: lock trouble [counter = %d] in %s:%d\n", atomic_read(lockp), file, line); return; } while (atomic_read(lockp) > 0) { if (max_count == 0) { - snd_printk("seq_lock: timeout [%d left] in %s:%d\n", atomic_read(lockp), file, line); + snd_printk(KERN_WARNING "seq_lock: timeout [%d left] in %s:%d\n", atomic_read(lockp), file, line); break; } set_current_state(TASK_UNINTERRUPTIBLE); diff -Nru a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c --- a/sound/core/seq/seq_memory.c Tue Feb 26 11:57:57 2002 +++ b/sound/core/seq/seq_memory.c Tue Feb 26 11:57:57 2002 @@ -423,7 +423,7 @@ while (atomic_read(&pool->counter) > 0) { if (max_count == 0) { - snd_printk("snd_seq_pool_done timeout: %d cells remain\n", atomic_read(&pool->counter)); + snd_printk(KERN_WARNING "snd_seq_pool_done timeout: %d cells remain\n", atomic_read(&pool->counter)); break; } set_current_state(TASK_UNINTERRUPTIBLE); diff -Nru a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c --- a/sound/core/seq/seq_ports.c Tue Feb 26 11:58:00 2002 +++ b/sound/core/seq/seq_ports.c Tue Feb 26 11:58:00 2002 @@ -143,7 +143,7 @@ snd_assert(client, return NULL); if (client->num_ports >= SNDRV_SEQ_MAX_PORTS - 1) { - snd_printk("too many ports for client %d\n", client->number); + snd_printk(KERN_WARNING "too many ports for client %d\n", client->number); return NULL; } diff -Nru a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c --- a/sound/core/seq/seq_timer.c Tue Feb 26 11:58:00 2002 +++ b/sound/core/seq/seq_timer.c Tue Feb 26 11:58:00 2002 @@ -285,7 +285,7 @@ t = snd_timer_open(str, &tid, q->queue); } if (t == NULL) { - snd_printk("fatal error: cannot create timer\n"); + snd_printk(KERN_ERR "fatal error: cannot create timer\n"); return -ENODEV; } } diff -Nru a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c --- a/sound/core/seq/seq_virmidi.c Tue Feb 26 11:57:56 2002 +++ b/sound/core/seq/seq_virmidi.c Tue Feb 26 11:57:56 2002 @@ -431,7 +431,7 @@ /* should check presence of port more strictly.. */ break; default: - snd_printk("seq_mode is not set: %d\n", rdev->seq_mode); + snd_printk(KERN_ERR "seq_mode is not set: %d\n", rdev->seq_mode); return -EINVAL; } return 0; diff -Nru a/sound/core/sound.c b/sound/core/sound.c --- a/sound/core/sound.c Tue Feb 26 11:57:57 2002 +++ b/sound/core/sound.c Tue Feb 26 11:57:57 2002 @@ -319,7 +319,7 @@ #else if (register_chrdev(snd_major, "alsa", &snd_fops)) { #endif - snd_printk("unable to register native major device number %d\n", snd_major); + snd_printk(KERN_ERR "unable to register native major device number %d\n", snd_major); #ifdef CONFIG_SND_OSSEMUL snd_oss_cleanup_module(); #endif @@ -349,7 +349,7 @@ } #endif #ifndef MODULE - printk("Advanced Linux Sound Architecture Driver Version " CONFIG_SND_VERSION CONFIG_SND_DATE ".\n"); + printk(KERN_INFO "Advanced Linux Sound Architecture Driver Version " CONFIG_SND_VERSION CONFIG_SND_DATE ".\n"); #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) && defined(CONFIG_APM) pm_init(); @@ -391,7 +391,7 @@ #else if (unregister_chrdev(snd_major, "alsa") != 0) #endif - snd_printk("unable to unregister major device number %d\n", snd_major); + snd_printk(KERN_ERR "unable to unregister major device number %d\n", snd_major); #ifdef CONFIG_DEVFS_FS devfs_unregister(devfs_handle); #endif @@ -455,7 +455,7 @@ EXPORT_SYMBOL(snd_device_register); EXPORT_SYMBOL(snd_device_free); EXPORT_SYMBOL(snd_device_free_all); - /* misc.c */ + /* isadma.c */ #ifdef CONFIG_ISA EXPORT_SYMBOL(snd_dma_program); EXPORT_SYMBOL(snd_dma_disable); @@ -494,38 +494,10 @@ EXPORT_SYMBOL(snd_ctl_unregister_ioctl); /* misc.c */ EXPORT_SYMBOL(snd_task_name); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) -EXPORT_SYMBOL(try_inc_mod_count); -EXPORT_SYMBOL(snd_compat_mem_region); -EXPORT_SYMBOL(snd_compat_request_region); -EXPORT_SYMBOL(snd_compat_release_resource); -#endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) && defined(CONFIG_PCI) -EXPORT_SYMBOL(snd_pci_compat_match_device); -EXPORT_SYMBOL(snd_pci_compat_register_driver); -EXPORT_SYMBOL(snd_pci_compat_unregister_driver); -EXPORT_SYMBOL(snd_pci_compat_get_size); -EXPORT_SYMBOL(snd_pci_compat_get_flags); -EXPORT_SYMBOL(snd_pci_compat_set_power_state); -EXPORT_SYMBOL(snd_pci_compat_enable_device); -EXPORT_SYMBOL(snd_pci_compat_find_capability); -EXPORT_SYMBOL(snd_pci_compat_alloc_consistent); -EXPORT_SYMBOL(snd_pci_compat_free_consistent); -EXPORT_SYMBOL(snd_pci_compat_dma_supported); -EXPORT_SYMBOL(snd_pci_compat_get_dma_mask); -EXPORT_SYMBOL(snd_pci_compat_set_dma_mask); -EXPORT_SYMBOL(snd_pci_compat_get_driver_data); -EXPORT_SYMBOL(snd_pci_compat_set_driver_data); -#endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) && defined(CONFIG_PM) -EXPORT_SYMBOL(pm_register); -EXPORT_SYMBOL(pm_unregister); -EXPORT_SYMBOL(pm_send); +#ifdef CONFIG_SND_VERBOSE_PRINTK +EXPORT_SYMBOL(snd_verbose_printk); #endif /* wrappers */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) -EXPORT_SYMBOL(snd_wrapper_kill_fasync); -#endif #ifdef CONFIG_SND_DEBUG_MEMORY EXPORT_SYMBOL(snd_wrapper_kmalloc); EXPORT_SYMBOL(snd_wrapper_kfree); diff -Nru a/sound/core/timer.c b/sound/core/timer.c --- a/sound/core/timer.c Tue Feb 26 11:57:56 2002 +++ b/sound/core/timer.c Tue Feb 26 11:57:56 2002 @@ -681,7 +681,7 @@ snd_assert(timer != NULL, return -ENXIO); down(®ister_mutex); if (! list_empty(&timer->open_list_head)) { - snd_printk("timer 0x%lx is busy?\n", (long)timer); + snd_printk(KERN_WARNING "timer 0x%lx is busy?\n", (long)timer); list_for_each_safe(p, n, &timer->open_list_head) { list_del_init(p); ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, open_list); @@ -1318,10 +1318,10 @@ } snd_timer_proc_entry = entry; if ((err = snd_timer_register_system()) < 0) - snd_printk("unable to register system timer (%i)\n", err); + snd_printk(KERN_ERR "unable to register system timer (%i)\n", err); if ((err = snd_register_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0, &snd_timer_reg, "timer"))<0) - snd_printk("unable to register timer device (%i)\n", err); + snd_printk(KERN_ERR "unable to register timer device (%i)\n", err); return 0; } diff -Nru a/sound/drivers/dummy.c b/sound/drivers/dummy.c --- a/sound/drivers/dummy.c Tue Feb 26 11:57:58 2002 +++ b/sound/drivers/dummy.c Tue Feb 26 11:57:58 2002 @@ -562,7 +562,7 @@ for (dev = cards = 0; dev < SNDRV_CARDS && snd_enable[dev]; dev++) { if (snd_card_dummy_probe(dev) < 0) { #ifdef MODULE - snd_printk("Dummy soundcard #%i not found or device busy\n", dev + 1); + printk(KERN_ERR "Dummy soundcard #%i not found or device busy\n", dev + 1); #endif break; } @@ -570,7 +570,7 @@ } if (!cards) { #ifdef MODULE - snd_printk("Dummy soundcard not found or device busy\n"); + printk(KERN_ERR "Dummy soundcard not found or device busy\n"); #endif return -ENODEV; } diff -Nru a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c --- a/sound/drivers/mpu401/mpu401.c Tue Feb 26 11:58:00 2002 +++ b/sound/drivers/mpu401/mpu401.c Tue Feb 26 11:58:00 2002 @@ -81,7 +81,7 @@ if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, snd_port[dev], 0, snd_irq[dev], snd_irq[dev] >= 0 ? SA_INTERRUPT : 0, NULL) < 0) { - snd_printk("MPU401 not detected at 0x%lx\n", snd_port[dev]); + printk(KERN_ERR "MPU401 not detected at 0x%lx\n", snd_port[dev]); snd_card_free(card); return -ENODEV; } @@ -113,7 +113,7 @@ } if (!cards) { #ifdef MODULE - snd_printk("MPU-401 device not found or device busy\n"); + printk(KERN_ERR "MPU-401 device not found or device busy\n"); #endif return -ENODEV; } diff -Nru a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c --- a/sound/drivers/mtpav.c Tue Feb 26 11:57:58 2002 +++ b/sound/drivers/mtpav.c Tue Feb 26 11:57:58 2002 @@ -761,7 +761,7 @@ snd_mtpav_portscan(mtp_card); - snd_printk("Motu MidiTimePiece on parallel port irq: %d ioport: 0x%lx\n", snd_irq, snd_port); + printk(KERN_INFO "Motu MidiTimePiece on parallel port irq: %d ioport: 0x%lx\n", snd_irq, snd_port); return 0; diff -Nru a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c --- a/sound/drivers/serial-u16550.c Tue Feb 26 11:57:57 2002 +++ b/sound/drivers/serial-u16550.c Tue Feb 26 11:57:57 2002 @@ -891,7 +891,7 @@ if ((err = snd_uart16550_detect(snd_port[dev])) <= 0) { snd_card_free(card); - snd_printk("no UART detected at 0x%lx\n", (long)snd_port[dev]); + printk(KERN_ERR "no UART detected at 0x%lx\n", (long)snd_port[dev]); return err; } @@ -940,7 +940,7 @@ if (cards == 0) { #ifdef MODULE - snd_printk("serial midi soundcard not found or device busy\n"); + printk(KERN_ERR "serial midi soundcard not found or device busy\n"); #endif return -ENODEV; } diff -Nru a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c --- a/sound/drivers/virmidi.c Tue Feb 26 11:57:58 2002 +++ b/sound/drivers/virmidi.c Tue Feb 26 11:57:58 2002 @@ -136,7 +136,7 @@ for (dev = cards = 0; dev < SNDRV_CARDS && snd_enable[dev]; dev++) { if (snd_card_virmidi_probe(dev) < 0) { #ifdef MODULE - snd_printk("Card-VirMIDI #%i not found or device busy\n", dev + 1); + printk(KERN_ERR "Card-VirMIDI #%i not found or device busy\n", dev + 1); #endif break; } @@ -144,7 +144,7 @@ } if (!cards) { #ifdef MODULE - snd_printk("Card-VirMIDI soundcard not found or device busy\n"); + printk(KERN_ERR "Card-VirMIDI soundcard not found or device busy\n"); #endif return -ENODEV; } diff -Nru a/sound/isa/Config.in b/sound/isa/Config.in --- a/sound/isa/Config.in Tue Feb 26 11:57:57 2002 +++ b/sound/isa/Config.in Tue Feb 26 11:57:57 2002 @@ -3,13 +3,13 @@ mainmenu_option next_comment comment 'ISA devices' -dep_tristate 'Analog Devices SoundPort AD1816A' CONFIG_SND_AD1816A $CONFIG_SND +dep_tristate 'Analog Devices SoundPort AD1816A' CONFIG_SND_AD1816A $CONFIG_SND $CONFIG_ISAPNP dep_tristate 'Generic AD1848/CS4248 driver' CONFIG_SND_AD1848 $CONFIG_SND dep_tristate 'Generic Cirrus Logic CS4231 driver' CONFIG_SND_CS4231 $CONFIG_SND dep_tristate 'Generic Cirrus Logic CS4232 driver' CONFIG_SND_CS4232 $CONFIG_SND dep_tristate 'Generic Cirrus Logic CS4236+ driver' CONFIG_SND_CS4236 $CONFIG_SND -dep_tristate 'Generic ESS ES968 driver' CONFIG_SND_ES968 $CONFIG_SND -dep_tristate 'Generic ESS ES1688 driver' CONFIG_SND_ES1688 $CONFIG_SND +dep_tristate 'Generic ESS ES968 driver' CONFIG_SND_ES968 $CONFIG_SND $CONFIG_ISAPNP +dep_tristate 'Generic ESS ES688/ES1688 driver' CONFIG_SND_ES1688 $CONFIG_SND dep_tristate 'Generic ESS ES18xx driver' CONFIG_SND_ES18XX $CONFIG_SND dep_tristate 'Gravis UltraSound Classic' CONFIG_SND_GUSCLASSIC $CONFIG_SND dep_tristate 'Gravis UltraSound Extreme' CONFIG_SND_GUSEXTREME $CONFIG_SND @@ -26,10 +26,10 @@ bool ' Sound Blaster 16/AWE CSP support' CONFIG_SND_SB16_CSP fi dep_tristate 'Turtle Beach Maui,Tropez,Tropez+ (Wavefront)' CONFIG_SND_WAVEFRONT $CONFIG_SND -dep_tristate 'Avance Logic ALS100/ALS120' CONFIG_SND_ALS100 $CONFIG_SND -dep_tristate 'Aztech Systems AZT2320' CONFIG_SND_AZT2320 $CONFIG_SND +dep_tristate 'Avance Logic ALS100/ALS120' CONFIG_SND_ALS100 $CONFIG_SND $CONFIG_ISAPNP +dep_tristate 'Aztech Systems AZT2320' CONFIG_SND_AZT2320 $CONFIG_SND $CONFIG_ISAPNP dep_tristate 'C-Media CMI8330' CONFIG_SND_CMI8330 $CONFIG_SND -dep_tristate 'Diamond Technologies DT-0197H' CONFIG_SND_DT0197H $CONFIG_SND +dep_tristate 'Diamond Technologies DT-0197H' CONFIG_SND_DT0197H $CONFIG_SND $CONFIG_ISAPNP dep_tristate 'Yamaha OPL3-SA2/SA3' CONFIG_SND_OPL3SA2 $CONFIG_SND dep_tristate 'Aztech Sound Galaxy' CONFIG_SND_SGALAXY $CONFIG_SND diff -Nru a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c --- a/sound/isa/ad1816a/ad1816a.c Tue Feb 26 11:57:58 2002 +++ b/sound/isa/ad1816a/ad1816a.c Tue Feb 26 11:57:58 2002 @@ -36,6 +36,8 @@ #define chip_t ad1816a_t +#define PFX "ad1816a: " + EXPORT_NO_SYMBOLS; MODULE_AUTHOR("Massimo Piccioni "); MODULE_DESCRIPTION("AD1816A, AD1815"); @@ -176,7 +178,7 @@ isapnp_resource_change(&pdev->irq_resource[0], snd_irq[dev], 1); if (pdev->activate(pdev) < 0) { - snd_printk("AUDIO isapnp configure failure\n"); + printk(KERN_ERR PFX "AUDIO isapnp configure failure\n"); return -EBUSY; } @@ -202,7 +204,7 @@ if (pdev->activate(pdev) < 0) { /* not fatal error */ - snd_printk("MPU-401 isapnp configure failure\n"); + printk(KERN_ERR PFX "MPU-401 isapnp configure failure\n"); snd_mpu_port[dev] = -1; acard->devmpu = NULL; } else { @@ -257,7 +259,7 @@ return error; } #else - snd_printk("you have to enable ISA PnP support.\n"); + printk(KERN_ERR PFX "you have to enable ISA PnP support.\n"); return -ENOSYS; #endif /* __ISAPNP__ */ @@ -284,14 +286,14 @@ if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, snd_mpu_port[dev], 0, snd_mpu_irq[dev], SA_INTERRUPT, NULL) < 0) - snd_printk("no MPU-401 device at 0x%lx.\n", snd_mpu_port[dev]); + printk(KERN_ERR PFX "no MPU-401 device at 0x%lx.\n", snd_mpu_port[dev]); } if (snd_fm_port[dev] > 0) { if (snd_opl3_create(card, snd_fm_port[dev], snd_fm_port[dev] + 2, OPL3_HW_AUTO, 0, &opl3) < 0) { - snd_printk("no OPL device at 0x%lx-0x%lx.\n", snd_fm_port[dev], snd_fm_port[dev] + 2); + printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx.\n", snd_fm_port[dev], snd_fm_port[dev] + 2); } else { if ((error = snd_opl3_timer_new(opl3, 1, 2)) < 0) { snd_card_free(card); @@ -346,11 +348,11 @@ #ifdef __ISAPNP__ cards += isapnp_probe_cards(snd_ad1816a_pnpids, snd_ad1816a_isapnp_detect); #else - snd_printk("you have to enable ISA PnP support.\n"); + printk(KERN_ERR PFX "you have to enable ISA PnP support.\n"); #endif #ifdef MODULE if (!cards) - snd_printk("no AD1816A based soundcards found.\n"); + printk(KERN_ERR "no AD1816A based soundcards found.\n"); #endif /* MODULE */ return cards ? 0 : -ENODEV; } diff -Nru a/sound/isa/ad1848/ad1848.c b/sound/isa/ad1848/ad1848.c --- a/sound/isa/ad1848/ad1848.c Tue Feb 26 11:57:56 2002 +++ b/sound/isa/ad1848/ad1848.c Tue Feb 26 11:57:56 2002 @@ -135,7 +135,7 @@ if (!cards) { #ifdef MODULE - snd_printk("AD1848 soundcard not found or device busy\n"); + printk(KERN_ERR "AD1848 soundcard not found or device busy\n"); #endif return -ENODEV; } diff -Nru a/sound/isa/als100.c b/sound/isa/als100.c --- a/sound/isa/als100.c Tue Feb 26 11:57:57 2002 +++ b/sound/isa/als100.c Tue Feb 26 11:57:57 2002 @@ -39,6 +39,8 @@ #define chip_t sb_t +#define PFX "als100: " + EXPORT_NO_SYMBOLS; MODULE_AUTHOR("Massimo Piccioni "); @@ -178,7 +180,7 @@ isapnp_resource_change(&pdev->irq_resource[0], snd_irq[dev], 1); if (pdev->activate(pdev)<0) { - snd_printk("AUDIO isapnp configure failure\n"); + printk(KERN_ERR PFX "AUDIO isapnp configure failure\n"); return -EBUSY; } @@ -201,7 +203,7 @@ 1); if (pdev->activate(pdev)<0) { - snd_printk("MPU-401 isapnp configure failure\n"); + printk(KERN_ERR PFX "MPU-401 isapnp configure failure\n"); snd_mpu_port[dev] = -1; acard->devmpu = NULL; } else { @@ -219,7 +221,7 @@ isapnp_resource_change(&pdev->resource[0], snd_fm_port[dev], 4); if (pdev->activate(pdev)<0) { - snd_printk("OPL isapnp configure failure\n"); + printk(KERN_ERR PFX "OPL isapnp configure failure\n"); snd_fm_port[dev] = -1; acard->devopl = NULL; } else { @@ -277,7 +279,7 @@ return error; } #else - snd_printk("you have to enable PnP support ...\n"); + printk(KERN_ERR PFX "you have to enable PnP support ...\n"); snd_card_free(card); return -ENOSYS; #endif /* __ISAPNP__ */ @@ -307,14 +309,14 @@ snd_mpu_port[dev], 0, snd_mpu_irq[dev], SA_INTERRUPT, NULL) < 0) - snd_printk("no MPU-401 device at 0x%lx\n", snd_mpu_port[dev]); + printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", snd_mpu_port[dev]); } if (snd_fm_port[dev] > 0) { if (snd_opl3_create(card, snd_fm_port[dev], snd_fm_port[dev] + 2, OPL3_HW_AUTO, 0, &opl3) < 0) { - snd_printk("no OPL device at 0x%lx-0x%lx\n", + printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx\n", snd_fm_port[dev], snd_fm_port[dev] + 2); } else { if ((error = snd_opl3_timer_new(opl3, 0, 1)) < 0) { @@ -370,11 +372,11 @@ #ifdef __ISAPNP__ cards += isapnp_probe_cards(snd_als100_pnpids, snd_als100_isapnp_detect); #else - snd_printk("you have to enable ISA PnP support.\n"); + printk(KERN_ERR PFX "you have to enable ISA PnP support.\n"); #endif #ifdef MODULE if (!cards) - snd_printk("no ALS100 based soundcards found\n"); + printk(KERN_ERR "no ALS100 based soundcards found\n"); #endif return cards ? 0 : -ENODEV; } diff -Nru a/sound/isa/azt2320.c b/sound/isa/azt2320.c --- a/sound/isa/azt2320.c Tue Feb 26 11:58:00 2002 +++ b/sound/isa/azt2320.c Tue Feb 26 11:58:00 2002 @@ -50,6 +50,8 @@ #define chip_t cs4231_t +#define PFX "azt2320: " + EXPORT_NO_SYMBOLS; MODULE_AUTHOR("Massimo Piccioni "); @@ -191,7 +193,7 @@ isapnp_resource_change(&pdev->irq_resource[0], snd_irq[dev], 1); if (pdev->activate(pdev) < 0) { - snd_printk("AUDIO isapnp configure failure\n"); + printk(KERN_ERR PFX "AUDIO isapnp configure failure\n"); return -EBUSY; } @@ -217,7 +219,7 @@ if (pdev->activate(pdev) < 0) { /* not fatal error */ - snd_printk("MPU-401 isapnp configure failure\n"); + printk(KERN_ERR PFX "MPU-401 isapnp configure failure\n"); snd_mpu_port[dev] = -1; acard->devmpu = NULL; } else { @@ -329,7 +331,7 @@ snd_mpu_port[dev], 0, snd_mpu_irq[dev], SA_INTERRUPT, NULL) < 0) - snd_printk("no MPU-401 device at 0x%lx\n", + printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", snd_mpu_port[dev]); } @@ -337,7 +339,7 @@ if (snd_opl3_create(card, snd_fm_port[dev], snd_fm_port[dev] + 2, OPL3_HW_AUTO, 0, &opl3) < 0) { - snd_printk("no OPL device at 0x%lx-0x%lx\n", + printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx\n", snd_fm_port[dev], snd_fm_port[dev] + 2); } else { if ((error = snd_opl3_timer_new(opl3, 1, 2)) < 0) { @@ -393,11 +395,11 @@ #ifdef __ISAPNP__ cards += isapnp_probe_cards(snd_azt2320_pnpids, snd_azt2320_isapnp_detect); #else - snd_printk("you have to enable ISA PnP support.\n"); + printk(KERN_ERR PFX "you have to enable ISA PnP support.\n"); #endif #ifdef MODULE if (!cards) - snd_printk("no AZT2320 based soundcards found\n"); + printk(KERN_ERR "no AZT2320 based soundcards found\n"); #endif return cards ? 0 : -ENODEV; } diff -Nru a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c --- a/sound/isa/cmi8330.c Tue Feb 26 11:57:57 2002 +++ b/sound/isa/cmi8330.c Tue Feb 26 11:57:57 2002 @@ -488,7 +488,7 @@ if (!cards) { #ifdef MODULE - snd_printk("CMI8330 not found or device busy\n"); + printk(KERN_ERR "CMI8330 not found or device busy\n"); #endif return -ENODEV; } diff -Nru a/sound/isa/cs423x/cs4231.c b/sound/isa/cs423x/cs4231.c --- a/sound/isa/cs423x/cs4231.c Tue Feb 26 11:57:56 2002 +++ b/sound/isa/cs423x/cs4231.c Tue Feb 26 11:57:56 2002 @@ -135,7 +135,7 @@ snd_mpu_port[dev], 0, snd_mpu_irq[dev], SA_INTERRUPT, NULL) < 0) - snd_printk("MPU401 not detected\n"); + printk(KERN_ERR "cs4231: MPU401 not detected\n"); } strcpy(card->driver, "CS4231"); strcpy(card->shortname, pcm->name); @@ -161,7 +161,7 @@ } if (!cards) { #ifdef MODULE - snd_printk("CS4231 soundcard not found or device busy\n"); + printk(KERN_ERR "CS4231 soundcard not found or device busy\n"); #endif return -ENODEV; } diff -Nru a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c --- a/sound/isa/cs423x/cs4231_lib.c Tue Feb 26 11:57:57 2002 +++ b/sound/isa/cs423x/cs4231_lib.c Tue Feb 26 11:57:57 2002 @@ -1335,7 +1335,7 @@ } if (chip->res_cport) { release_resource(chip->res_cport); - kfree_nocheck(chip->res_port); + kfree_nocheck(chip->res_cport); } if (chip->irq >= 0) { disable_irq(chip->irq); diff -Nru a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c --- a/sound/isa/cs423x/cs4236.c Tue Feb 26 11:57:57 2002 +++ b/sound/isa/cs423x/cs4236.c Tue Feb 26 11:57:57 2002 @@ -309,7 +309,7 @@ if (snd_dma2[dev] != SNDRV_AUTO_DMA) isapnp_resource_change(&pdev->dma_resource[1], snd_dma2[dev] < 0 ? 4 : snd_dma2[dev], 1); if (pdev->activate(pdev)<0) { - snd_printk(IDENT " isapnp configure failed for WSS (out of resources?)\n"); + printk(KERN_ERR IDENT " isapnp configure failed for WSS (out of resources?)\n"); return -EBUSY; } snd_port[dev] = pdev->resource[0].start; @@ -331,7 +331,7 @@ if (snd_cport[dev] != SNDRV_AUTO_PORT) isapnp_resource_change(&pdev->resource[0], snd_cport[dev], 8); if (pdev->activate(pdev)<0) { - snd_printk(IDENT " isapnp configure failed for control (out of resources?)\n"); + printk(KERN_ERR IDENT " isapnp configure failed for control (out of resources?)\n"); acard->wss->deactivate(acard->wss); return -EBUSY; } @@ -352,7 +352,7 @@ if (pdev->activate(pdev)<0) { snd_mpu_port[dev] = SNDRV_AUTO_PORT; snd_mpu_irq[dev] = SNDRV_AUTO_IRQ; - snd_printk(IDENT " isapnp configure failed for MPU (out of resources?)\n"); + printk(KERN_ERR IDENT " isapnp configure failed for MPU (out of resources?)\n"); } else { snd_mpu_port[dev] = pdev->resource[0].start; if (pdev->irq_resource[0].flags & IORESOURCE_IRQ) { @@ -429,7 +429,7 @@ card->private_free = snd_card_cs4236_free; #ifdef __ISAPNP__ if (snd_isapnp[dev] && (err = snd_card_cs4236_isapnp(dev, acard))<0) { - snd_printk("isapnp detection failed and probing for " IDENT " is not supported\n"); + printk(KERN_ERR "isapnp detection failed and probing for " IDENT " is not supported\n"); snd_card_free(card); return -ENXIO; } @@ -442,7 +442,7 @@ snd_sb_port[dev] = SNDRV_AUTO_PORT; if (snd_sb_port[dev] != SNDRV_AUTO_PORT) if ((acard->res_sb_port = request_region(snd_sb_port[dev], 16, IDENT " SB")) == NULL) { - snd_printk("unable to register SB port at 0x%lx\n", snd_sb_port[dev]); + printk(KERN_ERR IDENT ": unable to register SB port at 0x%lx\n", snd_sb_port[dev]); snd_card_free(card); return -ENOMEM; } @@ -501,7 +501,7 @@ if (snd_opl3_create(card, snd_fm_port[dev], snd_fm_port[dev] + 2, OPL3_HW_OPL3_CS, 0, &opl3) < 0) { - snd_printk(IDENT ": OPL3 not detected\n"); + printk(KERN_ERR IDENT ": OPL3 not detected\n"); } else { if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { snd_card_free(card); @@ -515,7 +515,7 @@ snd_mpu_port[dev], 0, snd_mpu_irq[dev], snd_mpu_irq[dev] >= 0 ? SA_INTERRUPT : 0, NULL) < 0) - snd_printk(IDENT ": MPU401 not detected\n"); + printk(KERN_ERR IDENT ": MPU401 not detected\n"); } strcpy(card->driver, pcm->name); strcpy(card->shortname, pcm->name); @@ -575,7 +575,7 @@ #endif if (!cards) { #ifdef MODULE - snd_printk(IDENT " soundcard not found or device busy\n"); + printk(KERN_ERR IDENT " soundcard not found or device busy\n"); #endif return -ENODEV; } diff -Nru a/sound/isa/dt0197h.c b/sound/isa/dt0197h.c --- a/sound/isa/dt0197h.c Tue Feb 26 11:57:59 2002 +++ b/sound/isa/dt0197h.c Tue Feb 26 11:57:59 2002 @@ -36,6 +36,8 @@ #define chip_t sb_t +#define PFX "dt0197h: " + EXPORT_NO_SYMBOLS; MODULE_AUTHOR("Massimo Piccioni "); @@ -150,7 +152,7 @@ isapnp_resource_change(&pdev->irq_resource[0], snd_irq[dev], 1); if (pdev->activate(pdev)<0) { - snd_printk("AUDIO isapnp configure failure\n"); + printk(KERN_ERR PFX "AUDIO isapnp configure failure\n"); return -EBUSY; } @@ -170,7 +172,7 @@ 1); if (pdev->activate(pdev)<0) { - snd_printk("MPU-401 isapnp configure failure\n"); + printk(KERN_ERR PFX "MPU-401 isapnp configure failure\n"); snd_mpu_port[dev] = -1; acard->devmpu = NULL; } else { @@ -186,7 +188,7 @@ isapnp_resource_change(&pdev->resource[0], snd_fm_port[dev], 4); if (pdev->activate(pdev)<0) { - snd_printk("OPL isapnp configure failure\n"); + printk(KERN_ERR PFX "OPL isapnp configure failure\n"); snd_fm_port[dev] = -1; acard->devopl = NULL; } else { @@ -244,7 +246,7 @@ return error; } #else - snd_printk("you have to enable PnP support ...\n"); + printk(KERN_ERR PFX "you have to enable PnP support ...\n"); snd_card_free(card); return -ENOSYS; #endif /* __ISAPNP__ */ @@ -276,7 +278,7 @@ snd_mpu_irq[dev], SA_INTERRUPT, NULL) < 0) - snd_printk("no MPU-401 device at 0x%lx ?\n", + printk(KERN_ERR PFX "no MPU-401 device at 0x%lx ?\n", snd_mpu_port[dev]); } @@ -285,7 +287,7 @@ snd_fm_port[dev], snd_fm_port[dev] + 2, OPL3_HW_AUTO, 0, &opl3) < 0) { - snd_printk("no OPL device at 0x%lx-0x%lx ?\n", + printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx ?\n", snd_fm_port[dev], snd_fm_port[dev] + 2); } else { if ((error = snd_opl3_timer_new(opl3, 0, 1)) < 0) { @@ -341,11 +343,11 @@ #ifdef __ISAPNP__ cards += isapnp_probe_cards(snd_dt0197h_pnpids, snd_dt0197h_isapnp_detect); #else - snd_printk("you have to enable ISA PnP support.\n"); + printk(KERN_ERR PFX "you have to enable ISA PnP support.\n"); #endif #ifdef MODULE if (!cards) - snd_printk("no DT-0197H based soundcards found\n"); + printk(KERN_ERR "no DT-0197H based soundcards found\n"); #endif return cards ? 0 : -ENODEV; } diff -Nru a/sound/isa/es1688/es1688.c b/sound/isa/es1688/es1688.c --- a/sound/isa/es1688/es1688.c Tue Feb 26 11:57:58 2002 +++ b/sound/isa/es1688/es1688.c Tue Feb 26 11:57:58 2002 @@ -133,7 +133,7 @@ } if ((snd_opl3_create(card, chip->port, chip->port + 2, OPL3_HW_OPL3, 0, &opl3)) < 0) { - snd_printk("opl3 not detected at 0x%lx\n", chip->port); + printk(KERN_ERR "es1688: opl3 not detected at 0x%lx\n", chip->port); } else { if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { snd_card_free(card); @@ -194,7 +194,7 @@ cards += snd_legacy_auto_probe(possible_ports, snd_audiodrive_legacy_auto_probe); if (!cards) { #ifdef MODULE - snd_printk("ESS AudioDrive ES1688 soundcard not found or device busy\n"); + printk(KERN_ERR "ESS AudioDrive ES1688 soundcard not found or device busy\n"); #endif return -ENODEV; } diff -Nru a/sound/isa/es18xx.c b/sound/isa/es18xx.c --- a/sound/isa/es18xx.c Tue Feb 26 11:57:59 2002 +++ b/sound/isa/es18xx.c Tue Feb 26 11:57:59 2002 @@ -86,6 +86,8 @@ #define SNDRV_GET_ID #include +#define PFX "es18xx: " + struct _snd_es18xx { unsigned long port; /* port of ESS chip */ unsigned long mpu_port; /* MPU-401 port of ESS chip */ @@ -1510,7 +1512,7 @@ static int __init snd_es18xx_probe(es18xx_t *chip) { if (snd_es18xx_identify(chip) < 0) { - snd_printk("[0x%lx] ESS chip not found\n", chip->port); + printk(KERN_ERR PFX "[0x%lx] ESS chip not found\n", chip->port); return -ENODEV; } @@ -1752,27 +1754,27 @@ if ((chip->res_port = request_region(port, 16, "ES18xx")) == NULL) { snd_es18xx_free(chip); - snd_printk("unable to grap ports 0x%lx-0x%lx\n", port, port + 16 - 1); + printk(KERN_ERR PFX "unable to grap ports 0x%lx-0x%lx\n", port, port + 16 - 1); return -EBUSY; } if (request_irq(irq, snd_es18xx_interrupt, SA_INTERRUPT, "ES18xx", (void *) chip)) { snd_es18xx_free(chip); - snd_printk("unable to grap IRQ %d\n", irq); + printk(KERN_ERR PFX "unable to grap IRQ %d\n", irq); return -EBUSY; } chip->irq = irq; if (request_dma(dma1, "ES18xx DMA 1")) { snd_es18xx_free(chip); - snd_printk("unable to grap DMA1 %d\n", dma1); + printk(KERN_ERR PFX "unable to grap DMA1 %d\n", dma1); return -EBUSY; } chip->dma1 = dma1; if (request_dma(dma2, "ES18xx DMA 2")) { snd_es18xx_free(chip); - snd_printk("unable to grap DMA2 %d\n", dma2); + printk(KERN_ERR PFX "unable to grap DMA2 %d\n", dma2); return -EBUSY; } chip->dma2 = dma2; @@ -2008,7 +2010,7 @@ if (acard->devc->prepare(acard->devc)<0) return -EAGAIN; if (acard->devc->activate(acard->devc)<0) { - snd_printk("isapnp control configure failure (out of resources?)\n"); + printk(KERN_ERR PFX "isapnp control configure failure (out of resources?)\n"); return -EAGAIN; } snd_printdd("isapnp: port=0x%lx\n", acard->devc->resource[0].start); @@ -2031,7 +2033,7 @@ if (snd_irq[dev] != SNDRV_AUTO_IRQ) isapnp_resource_change(&pdev->irq_resource[0], snd_irq[dev], 1); if (pdev->activate(pdev)<0) { - snd_printk("isapnp configure failure (out of resources?)\n"); + printk(KERN_ERR PFX "isapnp configure failure (out of resources?)\n"); acard->devc->deactivate(acard->devc); return -EBUSY; } @@ -2147,7 +2149,7 @@ } if (snd_opl3_create(card, chip->fm_port, chip->fm_port + 2, OPL3_HW_OPL3, 0, &opl3) < 0) { - snd_printk("opl3 not detected at 0x%lx\n", chip->port); + printk(KERN_ERR PFX "opl3 not detected at 0x%lx\n", chip->port); } else { if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { snd_card_free(card); @@ -2259,7 +2261,7 @@ #endif if(!cards) { #ifdef MODULE - snd_printk("ESS AudioDrive ES18xx soundcard not found or device busy\n"); + printk(KERN_ERR "ESS AudioDrive ES18xx soundcard not found or device busy\n"); #endif return -ENODEV; } diff -Nru a/sound/isa/gus/gusclassic.c b/sound/isa/gus/gusclassic.c --- a/sound/isa/gus/gusclassic.c Tue Feb 26 11:57:59 2002 +++ b/sound/isa/gus/gusclassic.c Tue Feb 26 11:57:59 2002 @@ -251,7 +251,7 @@ cards += snd_legacy_auto_probe(possible_ports, snd_gusclassic_legacy_auto_probe); if (!cards) { #ifdef MODULE - snd_printk("GUS Classic soundcard not found or device busy\n"); + printk(KERN_ERR "GUS Classic soundcard not found or device busy\n"); #endif return -ENODEV; } diff -Nru a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c --- a/sound/isa/gus/gusextreme.c Tue Feb 26 11:57:59 2002 +++ b/sound/isa/gus/gusextreme.c Tue Feb 26 11:57:59 2002 @@ -316,7 +316,7 @@ if (snd_opl3_create(card, es1688->port, es1688->port + 2, OPL3_HW_OPL3, 0, &opl3) < 0) { - snd_printk("opl3 not detected at 0x%lx\n", es1688->port); + printk(KERN_ERR "gusextreme: opl3 not detected at 0x%lx\n", es1688->port); } else { if ((err = snd_opl3_hwdep_new(opl3, 0, 2, NULL)) < 0) { snd_card_free(card); @@ -376,7 +376,7 @@ cards += snd_legacy_auto_probe(possible_ports, snd_gusextreme_legacy_auto_probe); if (!cards) { #ifdef MODULE - snd_printk("GUS Extreme soundcard not found or device busy\n"); + printk(KERN_ERR "GUS Extreme soundcard not found or device busy\n"); #endif return -ENODEV; } diff -Nru a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c --- a/sound/isa/gus/gusmax.c Tue Feb 26 11:57:56 2002 +++ b/sound/isa/gus/gusmax.c Tue Feb 26 11:57:56 2002 @@ -292,13 +292,13 @@ } if (!gus->max_flag) { snd_card_free(card); - snd_printk("GUS MAX soundcard was not detected at 0x%lx\n", gus->gf1.port); + printk(KERN_ERR "GUS MAX soundcard was not detected at 0x%lx\n", gus->gf1.port); return -ENODEV; } if (request_irq(irq, snd_gusmax_interrupt, SA_INTERRUPT, "GUS MAX", (void *)maxcard)) { snd_card_free(card); - snd_printk("unable to grab IRQ %d\n", irq); + printk(KERN_ERR "gusmax: unable to grab IRQ %d\n", irq); return -EBUSY; } maxcard->irq = irq; @@ -387,7 +387,7 @@ cards += snd_legacy_auto_probe(possible_ports, snd_gusmax_legacy_auto_probe); if (!cards) { #ifdef MODULE - snd_printk("GUS MAX soundcard not found or device busy\n"); + printk(KERN_ERR "GUS MAX soundcard not found or device busy\n"); #endif return -ENODEV; } diff -Nru a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c --- a/sound/isa/gus/interwave.c Tue Feb 26 11:57:56 2002 +++ b/sound/isa/gus/interwave.c Tue Feb 26 11:57:56 2002 @@ -948,7 +948,7 @@ continue; } #ifdef MODULE - snd_printk("InterWave soundcard #%i not found at 0x%lx or device busy\n", dev, snd_port[dev]); + printk(KERN_ERR "InterWave soundcard #%i not found at 0x%lx or device busy\n", dev, snd_port[dev]); #endif } /* legacy auto configured cards */ @@ -960,7 +960,7 @@ if (!cards) { #ifdef MODULE - snd_printk("InterWave soundcard not found or device busy\n"); + printk(KERN_ERR "InterWave soundcard not found or device busy\n"); #endif return -ENODEV; } diff -Nru a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c --- a/sound/isa/opl3sa2.c Tue Feb 26 11:57:59 2002 +++ b/sound/isa/opl3sa2.c Tue Feb 26 11:57:59 2002 @@ -893,7 +893,7 @@ #endif if (!cards) { #ifdef MODULE - snd_printk("Yamaha OPL3-SA soundcard not found or device busy\n"); + printk(KERN_ERR "Yamaha OPL3-SA soundcard not found or device busy\n"); #endif return -ENODEV; } diff -Nru a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c --- a/sound/isa/opti9xx/opti92x-ad1848.c Tue Feb 26 11:57:57 2002 +++ b/sound/isa/opti9xx/opti92x-ad1848.c Tue Feb 26 11:57:57 2002 @@ -2154,9 +2154,9 @@ if ((error = snd_card_opti9xx_probe())) { #ifdef MODULE #ifdef OPTi93X - snd_printk("no OPTi 82C93x soundcard found\n"); + printk(KERN_ERR "no OPTi 82C93x soundcard found\n"); #else - snd_printk("no OPTi 82C92x soundcard found\n"); + printk(KERN_ERR "no OPTi 82C92x soundcard found\n"); #endif /* OPTi93X */ #endif return error; diff -Nru a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c --- a/sound/isa/sb/sb16.c Tue Feb 26 11:57:58 2002 +++ b/sound/isa/sb/sb16.c Tue Feb 26 11:57:58 2002 @@ -43,6 +43,12 @@ #define chip_t sb_t +#ifdef SNDRV_SBAWE +#define PFX "sbawe: " +#else +#define PFX "sb16: " +#endif + #ifndef SNDRV_SBAWE EXPORT_NO_SYMBOLS; #endif @@ -296,7 +302,7 @@ if (snd_irq[dev] != SNDRV_AUTO_IRQ) isapnp_resource_change(&pdev->irq_resource[0], snd_irq[dev], 1); if (pdev->activate(pdev) < 0) { - snd_printk("isapnp configure failure (out of resources?)\n"); + printk(KERN_ERR PFX "isapnp configure failure (out of resources?)\n"); return -EBUSY; } snd_port[dev] = pdev->resource[0].start; @@ -322,7 +328,7 @@ isapnp_resource_change(&pdev->resource[2], snd_awe_port[dev] + 0x800, 4); } if (pdev->activate(pdev)<0) { - snd_printk("WaveTable isapnp configure failure (out of resources?)\n"); + printk(KERN_ERR PFX "WaveTable isapnp configure failure (out of resources?)\n"); acard->dev->deactivate(acard->dev); return -EBUSY; } @@ -402,21 +408,21 @@ if (irq == SNDRV_AUTO_IRQ) { if ((irq = snd_legacy_find_free_irq(possible_irqs)) < 0) { snd_card_free(card); - snd_printk("unable to find a free IRQ\n"); + printk(KERN_ERR PFX "unable to find a free IRQ\n"); return -EBUSY; } } if (dma8 == SNDRV_AUTO_DMA) { if ((dma8 = snd_legacy_find_free_dma(possible_dmas8)) < 0) { snd_card_free(card); - snd_printk("unable to find a free 8-bit DMA\n"); + printk(KERN_ERR PFX "unable to find a free 8-bit DMA\n"); return -EBUSY; } } if (dma16 == SNDRV_AUTO_DMA) { if ((dma16 = snd_legacy_find_free_dma(possible_dmas16)) < 0) { snd_card_free(card); - snd_printk("unable to find a free 16-bit DMA\n"); + printk(KERN_ERR PFX "unable to find a free 16-bit DMA\n"); return -EBUSY; } } @@ -475,7 +481,7 @@ if (snd_opl3_create(card, snd_fm_port[dev], snd_fm_port[dev] + 2, OPL3_HW_OPL3, snd_fm_port[dev] == snd_port[dev], &opl3) < 0) { - snd_printk("no OPL device at 0x%lx-0x%lx\n", + printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx\n", snd_fm_port[dev], snd_fm_port[dev] + 2); } else { #ifdef SNDRV_SBAWE_EMU8000 @@ -503,7 +509,7 @@ chip->csp = csp->private_data; chip->hardware = SB_HW_16CSP; } else { - snd_printk("warning - CSP chip not detected on soundcard #%i\n", dev + 1); + printk(KERN_INFO PFX "warning - CSP chip not detected on soundcard #%i\n", dev + 1); } } #endif @@ -511,7 +517,7 @@ if (snd_awe_port[dev] > 0) { if (snd_emu8000_new(card, 1, snd_awe_port[dev], snd_seq_ports[dev], NULL) < 0) { - snd_printk("fatal error - EMU-8000 synthesizer not detected at 0x%lx\n", snd_awe_port[dev]); + printk(KERN_ERR PFX "fatal error - EMU-8000 synthesizer not detected at 0x%lx\n", snd_awe_port[dev]); snd_card_free(card); return -ENXIO; } @@ -612,7 +618,7 @@ continue; } #ifdef MODULE - snd_printk("Sound Blaster 16+ soundcard #%i not found at 0x%lx or device busy\n", dev, snd_port[dev]); + printk(KERN_ERR "Sound Blaster 16+ soundcard #%i not found at 0x%lx or device busy\n", dev, snd_port[dev]); #endif } /* legacy auto configured cards */ @@ -624,11 +630,11 @@ if (!cards) { #ifdef MODULE - snd_printk("Sound Blaster 16 soundcard not found or device busy\n"); + printk(KERN_ERR "Sound Blaster 16 soundcard not found or device busy\n"); #ifdef SNDRV_SBAWE_EMU8000 - snd_printk("In case, if you have non-AWE card, try snd-card-sb16 module\n"); + printk(KERN_ERR "In case, if you have non-AWE card, try snd-card-sb16 module\n"); #else - snd_printk("In case, if you have AWE card, try snd-card-sbawe module\n"); + printk(KERN_ERR "In case, if you have AWE card, try snd-card-sbawe module\n"); #endif #endif return -ENODEV; diff -Nru a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c --- a/sound/isa/sb/sb8.c Tue Feb 26 11:57:59 2002 +++ b/sound/isa/sb/sb8.c Tue Feb 26 11:57:59 2002 @@ -144,13 +144,13 @@ if ((err = snd_opl3_create(card, chip->port + 8, 0, OPL3_HW_AUTO, 1, &opl3)) < 0) { - snd_printk("no OPL device at 0x%lx\n", chip->port + 8); + printk(KERN_ERR "sb8: no OPL device at 0x%lx\n", chip->port + 8); } } else { if ((err = snd_opl3_create(card, chip->port, chip->port + 2, OPL3_HW_AUTO, 1, &opl3)) < 0) { - snd_printk("no OPL device at 0x%lx-0x%lx\n", + printk(KERN_ERR "sb8: no OPL device at 0x%lx-0x%lx\n", chip->port, chip->port + 2); } } @@ -211,7 +211,7 @@ cards += snd_legacy_auto_probe(possible_ports, snd_card_sb8_legacy_auto_probe); if (!cards) { #ifdef MODULE - snd_printk("Sound Blaster soundcard not found or device busy\n"); + printk(KERN_ERR "Sound Blaster soundcard not found or device busy\n"); #endif return -ENODEV; } diff -Nru a/sound/isa/sgalaxy.c b/sound/isa/sgalaxy.c --- a/sound/isa/sgalaxy.c Tue Feb 26 11:57:59 2002 +++ b/sound/isa/sgalaxy.c Tue Feb 26 11:57:59 2002 @@ -305,7 +305,7 @@ } if (!cards) { #ifdef MODULE - snd_printk("Sound Galaxy soundcard not found or device busy\n"); + printk(KERN_ERR "Sound Galaxy soundcard not found or device busy\n"); #endif return -ENODEV; } diff -Nru a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c --- a/sound/isa/wavefront/wavefront.c Tue Feb 26 11:57:57 2002 +++ b/sound/isa/wavefront/wavefront.c Tue Feb 26 11:57:57 2002 @@ -740,7 +740,7 @@ #endif if (!cards) { #ifdef MODULE - snd_printk ("No cards found or devices busy\n"); + printk (KERN_ERR "No WaveFront cards found or devices busy\n"); #endif return -ENODEV; } diff -Nru a/sound/last.c b/sound/last.c --- a/sound/last.c Tue Feb 26 11:57:56 2002 +++ b/sound/last.c Tue Feb 26 11:57:56 2002 @@ -27,14 +27,14 @@ { int idx, ok = 0; - printk("ALSA device list:\n"); + printk(KERN_INFO "ALSA device list:\n"); for (idx = 0; idx < SNDRV_CARDS; idx++) if (snd_cards[idx] != NULL) { - printk(" #%i: %s\n", idx, snd_cards[idx]->longname); + printk(KERN_INFO " #%i: %s\n", idx, snd_cards[idx]->longname); ok++; } if (ok == 0) - printk(" No soundcards found.\n"); + printk(KERN_INFO " No soundcards found.\n"); return 0; } diff -Nru a/sound/oss/btaudio.c b/sound/oss/btaudio.c --- a/sound/oss/btaudio.c Tue Feb 26 11:57:58 2002 +++ b/sound/oss/btaudio.c Tue Feb 26 11:57:58 2002 @@ -1030,7 +1030,7 @@ name: "btaudio", id_table: btaudio_pci_tbl, probe: btaudio_probe, - remove: btaudio_remove, + remove: __devexit_p(btaudio_remove), }; int btaudio_init_module(void) diff -Nru a/sound/oss/cs4232.c b/sound/oss/cs4232.c --- a/sound/oss/cs4232.c Tue Feb 26 11:57:56 2002 +++ b/sound/oss/cs4232.c Tue Feb 26 11:57:56 2002 @@ -277,7 +277,7 @@ } } -void __exit unload_cs4232(struct address_info *hw_config) +static void __exit unload_cs4232(struct address_info *hw_config) { int base = hw_config->io_base, irq = hw_config->irq; int dma1 = hw_config->dma, dma2 = hw_config->dma2; @@ -460,10 +460,12 @@ return 0; } -int cs4232_isapnp_remove(struct pci_dev *dev, const struct isapnp_device_id *id) +static int __exit cs4232_isapnp_remove(struct pci_dev *dev, + const struct isapnp_device_id *id) { struct address_info *cfg = (struct address_info*)pci_get_drvdata(dev); - if (cfg) unload_cs4232(cfg); + if (cfg) + unload_cs4232(cfg); pci_set_drvdata(dev,NULL); dev->deactivate(dev); return 0; diff -Nru a/sound/oss/emu10k1/main.c b/sound/oss/emu10k1/main.c --- a/sound/oss/emu10k1/main.c Tue Feb 26 11:57:59 2002 +++ b/sound/oss/emu10k1/main.c Tue Feb 26 11:57:59 2002 @@ -1127,7 +1127,7 @@ name: "emu10k1", id_table: emu10k1_pci_tbl, probe: emu10k1_probe, - remove: emu10k1_remove, + remove: __devexit_p(emu10k1_remove), }; static int __init emu10k1_init_module(void) diff -Nru a/sound/oss/i810_audio.c b/sound/oss/i810_audio.c --- a/sound/oss/i810_audio.c Tue Feb 26 11:57:58 2002 +++ b/sound/oss/i810_audio.c Tue Feb 26 11:57:58 2002 @@ -2958,7 +2958,7 @@ return -ENODEV; } -static void __exit i810_remove(struct pci_dev *pci_dev) +static void __devexit i810_remove(struct pci_dev *pci_dev) { int i; struct i810_card *card = pci_get_drvdata(pci_dev); @@ -3118,7 +3118,7 @@ name: I810_MODULE_NAME, id_table: i810_pci_tbl, probe: i810_probe, - remove: i810_remove, + remove: __devexit_p(i810_remove), #ifdef CONFIG_PM suspend: i810_pm_suspend, resume: i810_pm_resume, diff -Nru a/sound/oss/mpu401.c b/sound/oss/mpu401.c --- a/sound/oss/mpu401.c Tue Feb 26 11:58:00 2002 +++ b/sound/oss/mpu401.c Tue Feb 26 11:58:00 2002 @@ -1227,7 +1227,7 @@ return ok; } -void __exit unload_mpu401(struct address_info *hw_config) +void unload_mpu401(struct address_info *hw_config) { void *p; int n=hw_config->slots[1]; diff -Nru a/sound/oss/rme96xx.c b/sound/oss/rme96xx.c --- a/sound/oss/rme96xx.c Tue Feb 26 11:57:59 2002 +++ b/sound/oss/rme96xx.c Tue Feb 26 11:57:59 2002 @@ -1162,7 +1162,7 @@ static int rme96xx_open(struct inode *in, struct file *f) { - int minor = MINOR(in->i_rdev); + int minor = minor(in->i_rdev); struct list_head *list; int devnum = ((minor-3)/16) % devices; /* default = 0 */ rme96xx_info *s; @@ -1490,7 +1490,7 @@ static int rme96xx_mixer_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); struct list_head *list; rme96xx_info *s; diff -Nru a/sound/oss/sonicvibes.c b/sound/oss/sonicvibes.c --- a/sound/oss/sonicvibes.c Tue Feb 26 11:57:59 2002 +++ b/sound/oss/sonicvibes.c Tue Feb 26 11:57:59 2002 @@ -1235,7 +1235,7 @@ static int sv_open_mixdev(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); struct list_head *list; struct sv_state *s; @@ -1893,7 +1893,7 @@ static int sv_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); unsigned char fmtm = ~0, fmts = 0; struct list_head *list; @@ -2142,7 +2142,7 @@ static int sv_midi_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); unsigned long flags; struct list_head *list; @@ -2364,7 +2364,7 @@ static int sv_dmfm_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); struct list_head *list; struct sv_state *s; diff -Nru a/sound/oss/trident.c b/sound/oss/trident.c --- a/sound/oss/trident.c Tue Feb 26 11:57:58 2002 +++ b/sound/oss/trident.c Tue Feb 26 11:57:58 2002 @@ -4149,7 +4149,7 @@ goto out; } -static void __exit trident_remove(struct pci_dev *pci_dev) +static void __devexit trident_remove(struct pci_dev *pci_dev) { int i; struct trident_card *card = pci_get_drvdata(pci_dev); @@ -4202,7 +4202,7 @@ name: TRIDENT_MODULE_NAME, id_table: trident_pci_tbl, probe: trident_probe, - remove: trident_remove, + remove: __devexit_p(trident_remove), suspend: trident_suspend, resume: trident_resume }; diff -Nru a/sound/oss/via82cxxx_audio.c b/sound/oss/via82cxxx_audio.c --- a/sound/oss/via82cxxx_audio.c Tue Feb 26 11:57:58 2002 +++ b/sound/oss/via82cxxx_audio.c Tue Feb 26 11:57:58 2002 @@ -311,7 +311,7 @@ */ static int via_init_one (struct pci_dev *dev, const struct pci_device_id *id); -static void via_remove_one (struct pci_dev *pdev); +static void __devexit via_remove_one (struct pci_dev *pdev); static ssize_t via_dsp_read(struct file *file, char *buffer, size_t count, loff_t *ppos); static ssize_t via_dsp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos); @@ -365,7 +365,7 @@ name: VIA_MODULE_NAME, id_table: via_pci_tbl, probe: via_init_one, - remove: via_remove_one, + remove: __devexit_p(via_remove_one), }; @@ -3271,7 +3271,7 @@ } -static void __exit via_remove_one (struct pci_dev *pdev) +static void __devexit via_remove_one (struct pci_dev *pdev) { struct via_info *card; diff -Nru a/sound/oss/ymfpci.c b/sound/oss/ymfpci.c --- a/sound/oss/ymfpci.c Tue Feb 26 11:57:56 2002 +++ b/sound/oss/ymfpci.c Tue Feb 26 11:57:56 2002 @@ -2652,7 +2652,7 @@ name: "ymfpci", id_table: ymf_id_tbl, probe: ymf_probe_one, - remove: ymf_remove_one, + remove: __devexit_p(ymf_remove_one), suspend: ymf_suspend, resume: ymf_resume }; diff -Nru a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c --- a/sound/pci/ac97/ac97_codec.c Tue Feb 26 11:57:58 2002 +++ b/sound/pci/ac97/ac97_codec.c Tue Feb 26 11:57:59 2002 @@ -115,7 +115,7 @@ { 0x43525960, 0xfffffff8, "CS4291", NULL }, { 0x48525300, 0xffffff00, "HMP9701", NULL }, { 0x49434501, 0xffffffff, "ICE1230", NULL }, -{ 0x49434511, 0xffffffff, "ICE1232", NULL }, // only guess --jk +{ 0x49434511, 0xffffffff, "ICE1232", NULL }, // alias VIA VT1611A? { 0x4e534300, 0xffffffff, "LM4540/43/45/46/48", NULL }, // only guess --jk { 0x4e534331, 0xffffffff, "LM4549", NULL }, { 0x53494c22, 0xffffffff, "Si3036", NULL }, @@ -1393,28 +1393,31 @@ ac97->card = card; spin_lock_init(&ac97->reg_lock); snd_ac97_write(ac97, AC97_RESET, 0); /* reset to defaults */ - udelay(50); - - /* it's necessary to wait awhile until registers are accessible after RESET */ - /* because the PCM or MASTER volume registers can be modified, */ - /* the REC_GAIN register is used for tests */ - end_time = jiffies + (HZ / 2); - do { - /* use preliminary reads to settle the communication */ - snd_ac97_read(ac97, AC97_RESET); - snd_ac97_read(ac97, AC97_VENDOR_ID1); - snd_ac97_read(ac97, AC97_VENDOR_ID2); - /* test if we can write to the PCM volume register */ - snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x8a05); - if ((err = snd_ac97_read(ac97, AC97_REC_GAIN)) == 0x8a05) - goto __access_ok; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/100); - } while (end_time - (signed long)jiffies >= 0); - snd_printd("AC'97 %d:%d does not respond - RESET [REC_GAIN = 0x%x]\n", ac97->num, ac97->addr, err); - snd_ac97_free(ac97); - return -ENXIO; - + if (ac97->wait) + ac97->wait(ac97); + else { + udelay(50); + + /* it's necessary to wait awhile until registers are accessible after RESET */ + /* because the PCM or MASTER volume registers can be modified, */ + /* the REC_GAIN register is used for tests */ + end_time = jiffies + HZ; + do { + /* use preliminary reads to settle the communication */ + snd_ac97_read(ac97, AC97_RESET); + snd_ac97_read(ac97, AC97_VENDOR_ID1); + snd_ac97_read(ac97, AC97_VENDOR_ID2); + /* test if we can write to the PCM volume register */ + snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x8a05); + if ((err = snd_ac97_read(ac97, AC97_REC_GAIN)) == 0x8a05) + goto __access_ok; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/100); + } while (end_time - (signed long)jiffies >= 0); + snd_printd("AC'97 %d:%d does not respond - RESET [REC_GAIN = 0x%x]\n", ac97->num, ac97->addr, err); + snd_ac97_free(ac97); + return -ENXIO; + } __access_ok: ac97->caps = snd_ac97_read(ac97, AC97_RESET); ac97->id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16; diff -Nru a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c --- a/sound/pci/ali5451/ali5451.c Tue Feb 26 11:57:59 2002 +++ b/sound/pci/ali5451/ali5451.c Tue Feb 26 11:57:59 2002 @@ -2253,7 +2253,7 @@ if ((err = pci_module_init(&driver)) < 0) { #ifdef MODULE - snd_printk("ALi pci audio not found or device busy.\n"); + printk(KERN_ERR "ALi pci audio not found or device busy.\n"); #endif return err; } diff -Nru a/sound/pci/als4000.c b/sound/pci/als4000.c --- a/sound/pci/als4000.c Tue Feb 26 11:57:59 2002 +++ b/sound/pci/als4000.c Tue Feb 26 11:57:59 2002 @@ -635,7 +635,7 @@ gcr+0x30, 1, pci->irq, 0, &chip->rmidi)) < 0) { snd_card_free(card); - snd_printk("no MPU-401device at 0x%lx ?\n", gcr+0x30); + printk(KERN_ERR "als4000: no MPU-401device at 0x%lx ?\n", gcr+0x30); return err; } @@ -650,7 +650,7 @@ if (snd_opl3_create(card, gcr+0x10, gcr+0x12, OPL3_HW_AUTO, 1, &opl3) < 0) { - snd_printk("no OPL device at 0x%lx-0x%lx ?\n", + printk(KERN_ERR "als4000: no OPL device at 0x%lx-0x%lx ?\n", gcr+0x10, gcr+0x12 ); } else { if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { @@ -692,7 +692,7 @@ if ((err = pci_module_init(&driver)) < 0) { #ifdef MODULE - snd_printk("no ALS4000 based soundcards found or device busy\n"); + printk(KERN_ERR "no ALS4000 based soundcards found or device busy\n"); #endif return err; } diff -Nru a/sound/pci/cmipci.c b/sound/pci/cmipci.c --- a/sound/pci/cmipci.c Tue Feb 26 11:57:57 2002 +++ b/sound/pci/cmipci.c Tue Feb 26 11:57:57 2002 @@ -113,6 +113,7 @@ #define CM_AC3EN1 0x00100000 /* enable AC3: model 037 */ #define CM_SPD24SEL 0x00020000 /* 24bit spdif: model 037 */ +#define CM_SPDIF_INVERSE 0x00010000 #define CM_ADCBITLEN_MASK 0x0000C000 #define CM_ADCBITLEN_16 0x00000000 @@ -131,6 +132,8 @@ #define CM_CH0_SRATE_176K 0x00000200 #define CM_CH0_SRATE_88K 0x00000100 +#define CM_SPDIF_INVERSE2 0x00000080 /* model 055? */ + #define CM_CH1FMT_MASK 0x0000000C #define CM_CH1FMT_SHIFT 2 #define CM_CH0FMT_MASK 0x00000003 @@ -201,6 +204,7 @@ #define CM_VIDWPPRT 0x00002000 #define CM_SFILENB 0x00001000 #define CM_MMODE_MASK 0x00000E00 +#define CM_SPDIF_SELECT 0x00000100 /* for model > 039 ? */ #define CM_ENCENTER 0x00000080 /* shared with FLINKON? */ #define CM_FLINKON 0x00000080 #define CM_FLINKOFF 0x00000040 @@ -347,7 +351,7 @@ unsigned int offset; /* physical address of the buffer */ unsigned int fmt; /* format bits */ int ch; /* channel (0/1) */ - int is_dac; /* is dac? */ + unsigned int is_dac; /* is dac? */ int bytes_per_frame; int shift; int ac3_shift; /* extra shift: 1 on soft ac3 mode */ @@ -388,6 +392,9 @@ unsigned int can_ac3_sw: 1; unsigned int can_ac3_hw: 1; unsigned int can_multi_ch: 1; + + unsigned int spdif_playback_avail: 1; /* spdif ready? */ + unsigned int spdif_playback_enabled: 1; /* spdif switch enabled? */ int spdif_counter; /* for software AC3 */ unsigned int dig_status; @@ -1133,11 +1140,13 @@ save_mixer_state(cm); spin_lock_irqsave(&cm->reg_lock, flags); + cm->spdif_playback_avail = up; if (up) { /* they are controlled via "IEC958 Output Switch" */ /* snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_ENSPDOUT); */ /* snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_SPDO2DAC); */ - snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_PLAYBACK_SPDF); + if (cm->spdif_playback_enabled) + snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_PLAYBACK_SPDF); setup_ac3(cm, do_ac3, rate); if (rate == 48000) @@ -2020,7 +2029,7 @@ CMIPCI_DOUBLE("Mic Capture Switch", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0, 1, 0, 0), CMIPCI_SB_VOL_MONO("PC Speaker Playback Volume", SB_DSP4_SPEAKER_DEV, 6, 3), CMIPCI_MIXER_VOL_STEREO("Aux Playback Volume", CM_REG_AUX_VOL, 4, 0, 15), - CMIPCI_MIXER_SW_STEREO("Aux Playback Switch", CM_REG_MIXER2, CM_VAUXLM_SHIFT, CM_VAUXRM_SHIFT, 0), + CMIPCI_MIXER_SW_STEREO("Aux Playback Switch", CM_REG_MIXER2, CM_VAUXLM_SHIFT, CM_VAUXRM_SHIFT, 1), CMIPCI_MIXER_SW_STEREO("Aux Capture Switch", CM_REG_MIXER2, CM_RAUXLEN_SHIFT, CM_RAUXREN_SHIFT, 0), CMIPCI_MIXER_SW_MONO("Mic Boost", CM_REG_MIXER2, CM_MICGAINZ_SHIFT, 1), CMIPCI_MIXER_VOL_MONO("Mic Capture Volume", CM_REG_MIXER2, CM_VADMIC_SHIFT, 7), @@ -2132,6 +2141,7 @@ DEFINE_BIT_SWITCH_ARG(spdif_0, CM_REG_FUNCTRL1, CM_SPDF_0, 0); DEFINE_BIT_SWITCH_ARG(spdo_48k, CM_REG_MISC_CTRL, CM_SPDF_AC97|CM_SPDIF48K, 0); #endif +DEFINE_BIT_SWITCH_ARG(spdif_in_1_2, CM_REG_MISC_CTRL, CM_SPDIF_SELECT, 0, 0); DEFINE_BIT_SWITCH_ARG(spdif_enable, CM_REG_LEGACY_CTRL, CM_ENSPDOUT, 0, 0); DEFINE_BIT_SWITCH_ARG(spdo2dac, CM_REG_FUNCTRL1, CM_SPDO2DAC, 0, 1); DEFINE_BIT_SWITCH_ARG(spdi_valid, CM_REG_MISC, CM_SPDVALID, 1, 0); @@ -2140,7 +2150,8 @@ DEFINE_SWITCH_ARG(spdo_5v, CM_REG_MISC_CTRL, CM_SPDO5V, 0, 0, 0); /* inverse: 0 = 5V */ DEFINE_BIT_SWITCH_ARG(spdif_loop, CM_REG_FUNCTRL1, CM_SPDFLOOP, 0, 1); DEFINE_BIT_SWITCH_ARG(spdi_monitor, CM_REG_MIXER1, CM_CDPLAY, 1, 0); -DEFINE_BIT_SWITCH_ARG(spdi_phase, CM_REG_MISC, 0x04, 0, 0); +DEFINE_BIT_SWITCH_ARG(spdi_phase, CM_REG_CHFORMAT, CM_SPDIF_INVERSE, 0, 0); +DEFINE_BIT_SWITCH_ARG(spdi_phase2, CM_REG_CHFORMAT, CM_SPDIF_INVERSE2, 0, 0); #if CM_CH_PLAY == 1 DEFINE_SWITCH_ARG(exchange_dac, CM_REG_MISC_CTRL, CM_XCHGDAC, 0, 0, 0); /* reversed */ #else @@ -2179,9 +2190,20 @@ static int snd_cmipci_spdout_enable_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { + cmipci_t *chip = snd_kcontrol_chip(kcontrol); int changed; changed = _snd_cmipci_uswitch_put(kcontrol, ucontrol, &cmipci_switch_arg_spdif_enable); changed |= _snd_cmipci_uswitch_put(kcontrol, ucontrol, &cmipci_switch_arg_spdo2dac); + if (changed) { + if (ucontrol->value.integer.value[0]) { + if (chip->spdif_playback_avail) + snd_cmipci_set_bit(chip, CM_REG_FUNCTRL1, CM_PLAYBACK_SPDF); + } else { + if (chip->spdif_playback_avail) + snd_cmipci_clear_bit(chip, CM_REG_FUNCTRL1, CM_PLAYBACK_SPDF); + } + } + chip->spdif_playback_enabled = ucontrol->value.integer.value[0]; return changed; } @@ -2213,17 +2235,19 @@ DEFINE_MIXER_SWITCH("IEC958 5V", spdo_5v), DEFINE_MIXER_SWITCH("IEC958 Loop", spdif_loop), DEFINE_MIXER_SWITCH("IEC958 In Monitor", spdi_monitor), - DEFINE_MIXER_SWITCH("IEC958 In Phase Inverse", spdi_phase), }; /* only for model 033/037 */ static snd_kcontrol_new_t snd_cmipci_old_mixer_switches[] __devinitdata = { DEFINE_MIXER_SWITCH("IEC958 Mix Analog", spdif_dac_out), + DEFINE_MIXER_SWITCH("IEC958 In Phase Inverse", spdi_phase), }; -/* only for model 039 */ +/* only for model 039 or later */ static snd_kcontrol_new_t snd_cmipci_extra_mixer_switches[] __devinitdata = { DEFINE_MIXER_SWITCH("Line-In As Bass", line_bass), + DEFINE_MIXER_SWITCH("IEC958 In Select", spdif_in_1_2), + DEFINE_MIXER_SWITCH("IEC958 In Phase Inverse", spdi_phase2), }; /* card control switches */ @@ -2283,7 +2307,7 @@ cm->spdif_pcm_ctl = kctl; if (cm->chip_version <= 37) { sw = snd_cmipci_old_mixer_switches; - for (idx = 0; idx < num_controls(snd_cmipci_extra_mixer_switches); idx++, sw++) { + for (idx = 0; idx < num_controls(snd_cmipci_old_mixer_switches); idx++, sw++) { err = snd_ctl_add(cm->card, snd_ctl_new1(sw, cm)); if (err < 0) return err; @@ -2573,10 +2597,10 @@ if (snd_opl3_create(card, iosynth, iosynth + 2, OPL3_HW_OPL3, 0, &cm->opl3) < 0) { - snd_printk("no OPL device at 0x%lx\n", iosynth); + printk(KERN_ERR "cmipci: no OPL device at 0x%lx\n", iosynth); } else { if ((err = snd_opl3_hwdep_new(cm->opl3, 0, 1, &cm->opl3hwdep)) < 0) - snd_printk("cannot create OPL3 hwdep\n"); + printk(KERN_ERR "cmipci: cannot create OPL3 hwdep\n"); } } @@ -2609,7 +2633,7 @@ if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_CMIPCI, iomidi, 0, cm->irq, 0, &cm->rmidi)) < 0) { - snd_printk("cmipci: no UART401 device at 0x%lx\n", iomidi); + printk(KERN_ERR "cmipci: no UART401 device at 0x%lx\n", iomidi); } } @@ -2711,7 +2735,7 @@ if ((err = pci_module_init(&driver)) < 0) { #ifdef MODULE - snd_printk("C-Media PCI soundcard not found or device busy\n"); + printk(KERN_ERR "C-Media PCI soundcard not found or device busy\n"); #endif return err; } diff -Nru a/sound/pci/cs4281.c b/sound/pci/cs4281.c --- a/sound/pci/cs4281.c Tue Feb 26 11:57:59 2002 +++ b/sound/pci/cs4281.c Tue Feb 26 11:57:59 2002 @@ -268,7 +268,7 @@ #define BA0_SERC1_SO1EN (1<<0) /* Primary Output Port Enable */ #define BA0_SERC2 0x042c /* Serial Port Configuration 2 */ -#define BA0_SERC2_SI1F(x) (((x)&7)>>1) */ Primary Input Port Format */ +#define BA0_SERC2_SI1F(x) (((x)&7)>>1) /* Primary Input Port Format */ #define BA0_SERC2_AC97 (1<<1) #define BA0_SERC2_SI1EN (1<<0) /* Primary Input Port Enable */ @@ -1910,7 +1910,7 @@ if ((err = pci_module_init(&driver)) < 0) { #ifdef MODULE - snd_printk("CS4281 soundcard not found or device busy\n"); + printk(KERN_ERR "CS4281 soundcard not found or device busy\n"); #endif return err; } diff -Nru a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c --- a/sound/pci/cs46xx/cs46xx.c Tue Feb 26 11:57:59 2002 +++ b/sound/pci/cs46xx/cs46xx.c Tue Feb 26 11:57:59 2002 @@ -183,7 +183,7 @@ if ((err = pci_module_init(&driver)) < 0) { #ifdef MODULE - snd_printk("Sound Fusion CS46xx soundcard not found or device busy\n"); + printk(KERN_ERR "Sound Fusion CS46xx soundcard not found or device busy\n"); #endif return err; } diff -Nru a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c --- a/sound/pci/emu10k1/emu10k1.c Tue Feb 26 11:57:56 2002 +++ b/sound/pci/emu10k1/emu10k1.c Tue Feb 26 11:57:56 2002 @@ -210,7 +210,7 @@ if ((err = pci_module_init(&driver)) < 0) { #ifdef MODULE - snd_printk("EMU10K1/Audigy soundcard not found or device busy\n"); + printk(KERN_ERR "EMU10K1/Audigy soundcard not found or device busy\n"); #endif return err; } diff -Nru a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c --- a/sound/pci/emu10k1/emu10k1_main.c Tue Feb 26 11:57:59 2002 +++ b/sound/pci/emu10k1/emu10k1_main.c Tue Feb 26 11:57:59 2002 @@ -218,6 +218,10 @@ */ outl(inl(emu->port + HCFG) | HCFG_AUDIOENABLE, emu->port + HCFG); + /* Enable analog/digital outs on audigy */ + if (emu->audigy) + outl(inl(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG); + #if 0 { unsigned int tmp; @@ -274,7 +278,7 @@ snd_emu10k1_ptr_write(emu, TCBS, 0, TCBS_BUFFSIZE_16K); snd_emu10k1_ptr_write(emu, TCB, 0, 0); if (emu->audigy) - snd_emu10k1_ptr_write(emu, A_DBG, 0, A_DBG_SINGLE_STEP_ADDR); + snd_emu10k1_ptr_write(emu, A_DBG, 0, A_DBG_SINGLE_STEP); else snd_emu10k1_ptr_write(emu, DBG, 0, 0x8000); @@ -625,18 +629,10 @@ } emu->fx8010.fxbus_mask = 0x303f; - if (extin_mask == 0) { - if (emu->audigy) - extin_mask = 0x000f; - else - extin_mask = 0x1fcf; - } - if (extout_mask == 0) { - if (emu->audigy) - extout_mask = 0x3fff; - else - extout_mask = 0x3fff; - } + if (extin_mask == 0) + extin_mask = 0x1fcf; + if (extout_mask == 0) + extout_mask = 0x3fff; emu->fx8010.extin_mask = extin_mask; emu->fx8010.extout_mask = extout_mask; diff -Nru a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c --- a/sound/pci/emu10k1/emufx.c Tue Feb 26 11:57:56 2002 +++ b/sound/pci/emu10k1/emufx.c Tue Feb 26 11:57:56 2002 @@ -95,12 +95,12 @@ /* 0x05 */ NULL, /* 0x06 */ NULL, /* 0x07 */ NULL, - /* 0x08 */ NULL, - /* 0x09 */ NULL, + /* 0x08 */ "Line/Mic 2 Left", + /* 0x09 */ "Line/Mic 2 Right", /* 0x0a */ NULL, /* 0x0b */ NULL, - /* 0x0c */ NULL, - /* 0x0d */ NULL, + /* 0x0c */ "Aux2 Left", + /* 0x0d */ "Aux2 Right", /* 0x0e */ NULL, /* 0x0f */ NULL }; @@ -141,14 +141,14 @@ }; static char *audigy_outs[32] = { - /* 0x00 */ NULL, - /* 0x01 */ NULL, - /* 0x02 */ NULL, - /* 0x03 */ NULL, + /* 0x00 */ "Digital Front Left", + /* 0x01 */ "Digital Front Right", + /* 0x02 */ "Digital Center", + /* 0x03 */ "Digital LEF", /* 0x04 */ "Headphone Left", /* 0x05 */ "Headphone Right", - /* 0x06 */ NULL, - /* 0x07 */ NULL, + /* 0x06 */ "Digital Rear Left", + /* 0x07 */ "Digital Rear Right", /* 0x08 */ "Front Left", /* 0x09 */ "Front Right", /* 0x0a */ "Center", @@ -157,14 +157,14 @@ /* 0x0d */ NULL, /* 0x0e */ "Rear Left", /* 0x0f */ "Rear Right", - /* 0x10 */ NULL, - /* 0x11 */ NULL, - /* 0x12 */ NULL, - /* 0x13 */ NULL, + /* 0x10 */ "AC97 Front Left", + /* 0x11 */ "AC97 Front Right", + /* 0x12 */ "ADC Caputre Left", + /* 0x13 */ "ADC Capture Right", /* 0x14 */ NULL, /* 0x15 */ NULL, - /* 0x16 */ "ADC Capture Left", - /* 0x17 */ "ADC Capture Right", + /* 0x16 */ NULL, + /* 0x17 */ NULL, /* 0x18 */ NULL, /* 0x19 */ NULL, /* 0x1a */ NULL, @@ -1034,7 +1034,7 @@ /* stop FX processor - this may be dangerous, but it's better to miss some samples than generate wrong ones - [jk] */ if (emu->audigy) - snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP_ADDR); + snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP); else snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP); /* ok, do the main job */ @@ -1220,36 +1220,34 @@ ptr = 0; nctl = 0; playback = 10; - capture = playback + 6; /* 5+1 channels */ - gpr = capture + 2; /* so far only a stereo capture */ + capture = playback + 10; /* we reserve 10 voices */ + gpr = capture + 10; tmp = 0x80; /* stop FX processor */ - snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP_ADDR); - -#define A_C_ZERO 0x0c0 + snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP); /* Wave Playback */ - A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_ZERO, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_ZERO, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT)); snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr, 100); gpr += 2; /* Wave Surround Playback */ - A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_C_ZERO, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_C_ZERO, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT)); snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Surround Playback Volume", gpr, 0); gpr += 2; /* Wave Center Playback */ /* Center = sub = Left/2 + Right/2 */ A_OP(icode, &ptr, iINTERP, A_GPR(tmp), A_FXBUS(FXBUS_PCM_LEFT), 0xcd, A_FXBUS(FXBUS_PCM_RIGHT)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_C_ZERO, A_GPR(gpr), A_GPR(tmp)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_C_00000000, A_GPR(gpr), A_GPR(tmp)); snd_emu10k1_init_mono_control(&controls[nctl++], "Wave Center Playback Volume", gpr, 0); gpr++; /* Wave LFE Playback */ - A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_C_ZERO, A_GPR(gpr), A_GPR(tmp)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_C_00000000, A_GPR(gpr), A_GPR(tmp)); snd_emu10k1_init_mono_control(&controls[nctl++], "Wave LFE Playback Volume", gpr, 0); gpr++; @@ -1260,8 +1258,8 @@ gpr += 2; /* Wave Capture */ - A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_C_ZERO, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT)); - A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_C_ZERO, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT)); + A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT)); + A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT)); snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Capture Volume", gpr, 0); gpr += 2; @@ -1271,14 +1269,20 @@ snd_emu10k1_init_stereo_control(&controls[nctl++], "Music Capture Volume", gpr, 0); gpr += 2; + /* Surround Playback */ + A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR)); + snd_emu10k1_init_stereo_control(&controls[nctl++], "Surround Playback Volume", gpr, 80); + gpr += 2; + /* Center Playback */ A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_GPR(playback+4), A_GPR(gpr), A_FXBUS(FXBUS_PCM_CENTER)); - snd_emu10k1_init_mono_control(&controls[nctl++], "Center Playback Volume", gpr, 0); + snd_emu10k1_init_mono_control(&controls[nctl++], "Center Playback Volume", gpr, 80); gpr++; /* LFE Playback */ A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_GPR(playback+5), A_GPR(gpr), A_FXBUS(FXBUS_PCM_LFE)); - snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 0); + snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 80); gpr++; /* @@ -1286,54 +1290,70 @@ */ #define A_ADD_VOLUME_IN(var,vol,input) \ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) - if (emu->fx8010.extin_mask & ((1<fx8010.extin_mask & ((1<fx8010.extout_mask & (1<<(out))) A_PUT_OUTPUT(out,src) +#define A_PUT_OUTPUT(out,src) A_OP(icode, &ptr, iACC3, A_EXTOUT(out), A_C_00000000, A_C_00000000, A_GPR(src)) #define A_PUT_STEREO_OUTPUT(out1,out2,src) \ - if (emu->fx8010.extout_mask & ((1<<(out1))|(1<<(out2)))) {\ - A_PUT_OUTPUT(out1,src);\ - A_PUT_OUTPUT(out2,src+1);} + {A_PUT_OUTPUT(out1,src); A_PUT_OUTPUT(out2,src+1);} /* digital outputs */ A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback); A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2); - A_PUT_MONO_OUTPUT(A_EXTOUT_CENTER, playback+4); - A_PUT_MONO_OUTPUT(A_EXTOUT_LFE, playback+5); + A_PUT_OUTPUT(A_EXTOUT_CENTER, playback+4); + A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5); /* analog speakers */ - A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback); + //A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback); + A_PUT_STEREO_OUTPUT(A_EXTOUT_AC97_L, A_EXTOUT_AC97_R, playback); A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2); - A_PUT_MONO_OUTPUT(A_EXTOUT_ACENTER, playback+4); - A_PUT_MONO_OUTPUT(A_EXTOUT_ALFE, playback+5); + A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4); + A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5); /* headphone */ A_PUT_STEREO_OUTPUT(A_EXTOUT_HEADPHONE_L, A_EXTOUT_HEADPHONE_R, playback); @@ -1946,7 +1966,7 @@ { /* stop processor */ if (emu->audigy) - snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg = A_DBG_SINGLE_STEP_ADDR); + snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg = A_DBG_SINGLE_STEP); else snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = EMU10K1_DBG_SINGLE_STEP); } @@ -2127,7 +2147,7 @@ if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (emu->audigy) - snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP_ADDR); + snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP); else snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP); return 0; @@ -2160,12 +2180,12 @@ if (addr > 0x1ff) return -EINVAL; if (emu->audigy) - snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP_ADDR | addr); + snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP | addr); else snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP | addr); udelay(10); if (emu->audigy) - snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP_ADDR | A_DBG_STEP_ADDR | addr); + snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP | A_DBG_STEP_ADDR | addr); else snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP | EMU10K1_DBG_STEP | addr); return 0; diff -Nru a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c --- a/sound/pci/emu10k1/emumixer.c Tue Feb 26 11:57:58 2002 +++ b/sound/pci/emu10k1/emumixer.c Tue Feb 26 11:57:58 2002 @@ -107,12 +107,40 @@ put: snd_emu10k1_spdif_put }; -/* FIXME: audigy has more routing/effects */ + +static void update_emu10k1_fxrt(emu10k1_t *emu, int voice, unsigned char *route) +{ + if (emu->audigy) { + snd_emu10k1_ptr_write(emu, A_FXRT1, voice, + snd_emu10k1_compose_audigy_fxrt1(route)); + snd_emu10k1_ptr_write(emu, A_FXRT2, voice, + snd_emu10k1_compose_audigy_fxrt2(route)); + } else { + snd_emu10k1_ptr_write(emu, FXRT, voice, + snd_emu10k1_compose_send_routing(route)); + } +} + +static void update_emu10k1_send_volume(emu10k1_t *emu, int voice, unsigned char *volume) +{ + snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]); + snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]); + snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]); + snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]); + if (emu->audigy) { + unsigned int val = ((unsigned int)volume[4] << 24) | + ((unsigned int)volume[5] << 16) | + ((unsigned int)volume[6] << 8) | + (unsigned int)volume[7]; + snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, val); + } +} + static int snd_emu10k1_send_routing_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { emu10k1_t *emu = snd_kcontrol_chip(kcontrol); uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 3*4; + uinfo->count = emu->audigy ? 3*8 : 3*4; uinfo->value.integer.min = 0; uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f; return 0; @@ -125,13 +153,14 @@ emu10k1_pcm_mixer_t *mix = (emu10k1_pcm_mixer_t *)kcontrol->private_value; emu10k1_t *emu = snd_kcontrol_chip(kcontrol); int voice, idx; + int num_efx = emu->audigy ? 8 : 4; + int mask = emu->audigy ? 0x3f : 0x0f; spin_lock_irqsave(&emu->reg_lock, flags); for (voice = 0; voice < 3; voice++) - for (idx = 0; idx < 4; idx++) - ucontrol->value.integer.value[(voice * 4) + idx] = emu->audigy ? - ((mix->send_routing[voice] >> (idx * 8)) & 0x3f) : - ((mix->send_routing[voice] >> (idx * 4)) & 0x0f); + for (idx = 0; idx < num_efx; idx++) + ucontrol->value.integer.value[(voice * num_efx) + idx] = + mix->send_routing[voice][idx] & mask; spin_unlock_irqrestore(&emu->reg_lock, flags); return 0; } @@ -143,44 +172,27 @@ emu10k1_pcm_mixer_t *mix = (emu10k1_pcm_mixer_t *)kcontrol->private_value; emu10k1_t *emu = snd_kcontrol_chip(kcontrol); int change = 0, voice, idx, val; + int num_efx = emu->audigy ? 8 : 4; + int mask = emu->audigy ? 0x3f : 0x0f; spin_lock_irqsave(&emu->reg_lock, flags); for (voice = 0; voice < 3; voice++) - for (idx = 0; idx < 4; idx++) { - val = ucontrol->value.integer.value[(voice * 4) + idx]; - if (emu->audigy) { - int shift = idx * 8; - val &= 0x3f; - if (((mix->send_routing[voice] >> shift) & 0x3f) != val) { - mix->send_routing[voice] &= ~(0x3f << shift); - mix->send_routing[voice] |= val << shift; - change = 1; - } - } else { - int shift = idx * 4; - val = ucontrol->value.integer.value[(voice * 4) + idx] & 15; - if (((mix->send_routing[voice] >> shift) & 15) != val) { - mix->send_routing[voice] &= ~(15 << shift); - mix->send_routing[voice] |= val << shift; - change = 1; - } + for (idx = 0; idx < num_efx; idx++) { + val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask; + if (mix->send_routing[voice][idx] != val) { + mix->send_routing[voice][idx] = val; + change = 1; } } if (change && mix->epcm) { if (mix->epcm->voices[0] && mix->epcm->voices[1]) { - if (emu->audigy) { - snd_emu10k1_ptr_write(emu, A_FXRT1, mix->epcm->voices[0]->number, mix->send_routing[1]); - snd_emu10k1_ptr_write(emu, A_FXRT1, mix->epcm->voices[1]->number, mix->send_routing[2]); - } else { - snd_emu10k1_ptr_write(emu, FXRT, mix->epcm->voices[0]->number, mix->send_routing[1] << 16); - snd_emu10k1_ptr_write(emu, FXRT, mix->epcm->voices[1]->number, mix->send_routing[2] << 16); - } + update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, + &mix->send_routing[1][0]); + update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number, + &mix->send_routing[2][0]); } else if (mix->epcm->voices[0]) { - if (emu->audigy) { - snd_emu10k1_ptr_write(emu, A_FXRT1, mix->epcm->voices[0]->number, mix->send_routing[0]); - } else { - snd_emu10k1_ptr_write(emu, FXRT, mix->epcm->voices[0]->number, mix->send_routing[0] << 16); - } + update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, + &mix->send_routing[0][0]); } } spin_unlock_irqrestore(&emu->reg_lock, flags); @@ -199,8 +211,9 @@ static int snd_emu10k1_send_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { + emu10k1_t *emu = snd_kcontrol_chip(kcontrol); uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 3*4; + uinfo->count = emu->audigy ? 3*8 : 3*4; uinfo->value.integer.min = 0; uinfo->value.integer.max = 255; return 0; @@ -213,10 +226,11 @@ emu10k1_pcm_mixer_t *mix = (emu10k1_pcm_mixer_t *)kcontrol->private_value; emu10k1_t *emu = snd_kcontrol_chip(kcontrol); int idx; + int num_efx = emu->audigy ? 8 : 4; spin_lock_irqsave(&emu->reg_lock, flags); - for (idx = 0; idx < 3*4; idx++) - ucontrol->value.integer.value[idx] = mix->send_volume[idx/4][idx%4]; + for (idx = 0; idx < 3*num_efx; idx++) + ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx]; spin_unlock_irqrestore(&emu->reg_lock, flags); return 0; } @@ -228,34 +242,25 @@ emu10k1_pcm_mixer_t *mix = (emu10k1_pcm_mixer_t *)kcontrol->private_value; emu10k1_t *emu = snd_kcontrol_chip(kcontrol); int change = 0, idx, val; + int num_efx = emu->audigy ? 8 : 4; spin_lock_irqsave(&emu->reg_lock, flags); - for (idx = 0; idx < 3*4; idx++) { + for (idx = 0; idx < 3*num_efx; idx++) { val = ucontrol->value.integer.value[idx] & 255; - if (mix->send_volume[idx/4][idx%4] != val) { - mix->send_volume[idx/4][idx%4] = val; + if (mix->send_volume[idx/num_efx][idx%num_efx] != val) { + mix->send_volume[idx/num_efx][idx%num_efx] = val; change = 1; } } if (change && mix->epcm) { - u32 voice; if (mix->epcm->voices[0] && mix->epcm->voices[1]) { - voice = mix->epcm->voices[0]->number; - snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, mix->send_volume[1][0]); - snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, mix->send_volume[1][1]); - snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, mix->send_volume[1][2]); - snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, mix->send_volume[1][3]); - voice = mix->epcm->voices[1]->number; - snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, mix->send_volume[2][0]); - snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, mix->send_volume[2][1]); - snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, mix->send_volume[2][2]); - snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, mix->send_volume[2][3]); + update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, + &mix->send_volume[1][0]); + update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number, + &mix->send_volume[2][0]); } else if (mix->epcm->voices[0]) { - voice = mix->epcm->voices[0]->number; - snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, mix->send_volume[0][0]); - snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, mix->send_volume[0][1]); - snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, mix->send_volume[0][2]); - snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, mix->send_volume[0][3]); + update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, + &mix->send_volume[0][0]); } } spin_unlock_irqrestore(&emu->reg_lock, flags); @@ -380,6 +385,71 @@ put: snd_emu10k1_shared_spdif_put }; +#if 0 // XXX: not working yet.. +/* + * Audigy analog / digital switches + */ +static int audigy_output_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int audigy_output_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + emu10k1_t *emu = snd_kcontrol_chip(kcontrol); + unsigned int mask = (unsigned int)kcontrol->private_value; + + ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & mask ? 0 : 1; + return 0; +} + +static int audigy_output_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + unsigned long flags; + emu10k1_t *emu = snd_kcontrol_chip(kcontrol); + unsigned int mask = (unsigned int)kcontrol->private_value; + unsigned int reg, oreg; + int change; + + spin_lock_irqsave(&emu->reg_lock, flags); + reg = oreg = inl(emu->port + A_IOCFG); + reg &= ~mask; + reg |= ucontrol->value.integer.value[0] & 1 ? 0 : mask; + change = (reg != oreg); + if (change) + outl(reg, emu->port + A_IOCFG); + spin_unlock_irqrestore(&emu->reg_lock, flags); + return change; +} + +static snd_kcontrol_new_t audigy_output_analog = +{ + iface: SNDRV_CTL_ELEM_IFACE_MIXER, + name: "Audigy Analog Output Switch", + info: audigy_output_info, + get: audigy_output_get, + put: audigy_output_put, + private_value: 0x40, +}; + +static snd_kcontrol_new_t audigy_output_digital = +{ + iface: SNDRV_CTL_ELEM_IFACE_MIXER, + name: "Audigy Digital Output Switch", + info: audigy_output_info, + get: audigy_output_get, + put: audigy_output_put, + private_value: 0x04, +}; +#endif // XXX + + +/* + */ static void snd_emu10k1_mixer_free_ac97(ac97_t *ac97) { emu10k1_t *emu = snd_magic_cast(emu10k1_t, ac97->private_data, return); @@ -407,6 +477,7 @@ for (pcm = 0; pcm < 32; pcm++) { emu10k1_pcm_mixer_t *mix; + int v; mix = &emu->pcm_mixer[pcm]; mix->epcm = NULL; @@ -417,11 +488,10 @@ kctl->id.index = pcm; if ((err = snd_ctl_add(card, kctl))) return err; - if (emu->audigy) { - mix->send_routing[0] = mix->send_routing[1] = mix->send_routing[2] = 0x3210; - } else { - mix->send_routing[0] = mix->send_routing[1] = mix->send_routing[2] = 0x03020100; - } + for (v = 0; v < 4; v++) + mix->send_routing[0][v] = + mix->send_routing[1][v] = + mix->send_routing[2][v] = v; if ((kctl = mix->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu)) == NULL) return -ENOMEM; @@ -457,10 +527,23 @@ return err; } - if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL) - return -ENOMEM; - if ((err = snd_ctl_add(card, kctl))) - return err; + if (emu->audigy) { +#if 0 // XXX + if ((kctl = snd_ctl_new1(&audigy_output_analog, emu)) == NULL) + return -ENOMEM; + if ((err = snd_ctl_add(card, kctl))) + return err; + if ((kctl = snd_ctl_new1(&audigy_output_digital, emu)) == NULL) + return -ENOMEM; + if ((err = snd_ctl_add(card, kctl))) + return err; +#endif // XXX + } else { + if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL) + return -ENOMEM; + if ((err = snd_ctl_add(card, kctl))) + return err; + } return 0; } diff -Nru a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c --- a/sound/pci/emu10k1/emupcm.c Tue Feb 26 11:57:56 2002 +++ b/sound/pci/emu10k1/emupcm.c Tue Feb 26 11:57:56 2002 @@ -237,8 +237,8 @@ emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[substream->number]; unsigned int silent_page, tmp; int voice, stereo, w_16; - unsigned char attn, send_a, send_b, send_c, send_d; - unsigned short send_routing; + unsigned char attn, send_amount[8]; + unsigned char send_routing[8]; unsigned long flags; unsigned int pitch_target; @@ -260,15 +260,16 @@ /* volume parameters */ if (extra) { attn = 0; - send_routing = emu->audigy ? 0x03020100 : 0x3210; - send_a = send_b = send_c = send_d = 0x00; + memset(send_routing, 0, sizeof(send_routing)); + send_routing[0] = 0; + send_routing[1] = 1; + send_routing[2] = 2; + send_routing[3] = 3; + memset(send_amount, 0, sizeof(send_amount)); } else { tmp = stereo ? (master ? 1 : 2) : 0; - send_a = mix->send_volume[tmp][0]; - send_b = mix->send_volume[tmp][1]; - send_c = mix->send_volume[tmp][2]; - send_d = mix->send_volume[tmp][3]; - send_routing = mix->send_routing[tmp]; + memcpy(send_routing, &mix->send_routing[tmp][0], 8); + memcpy(send_amount, &mix->send_volume[tmp][0], 8); } if (master) { @@ -290,16 +291,29 @@ // setup routing if (emu->audigy) { - snd_emu10k1_ptr_write(emu, A_FXRT1, voice, send_routing); - snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, 0); /* no effects */ - snd_emu10k1_ptr_write(emu, A_FXRT2, voice, 0); /* channels EFGH */ + snd_emu10k1_ptr_write(emu, A_FXRT1, voice, + ((unsigned int)send_routing[3] << 24) | + ((unsigned int)send_routing[2] << 16) | + ((unsigned int)send_routing[1] << 8) | + (unsigned int)send_routing[0]); + snd_emu10k1_ptr_write(emu, A_FXRT2, voice, + ((unsigned int)send_routing[7] << 24) | + ((unsigned int)send_routing[6] << 16) | + ((unsigned int)send_routing[5] << 8) | + (unsigned int)send_routing[4]); + snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, + ((unsigned int)send_amount[4] << 24) | + ((unsigned int)send_amount[5] << 16) | + ((unsigned int)send_amount[6] << 8) | + (unsigned int)send_amount[7]); } else - snd_emu10k1_ptr_write(emu, FXRT, voice, send_routing << 16); + snd_emu10k1_ptr_write(emu, FXRT, voice, + snd_emu10k1_compose_send_routing(send_routing)); // Stop CA // Assumption that PT is already 0 so no harm overwriting - snd_emu10k1_ptr_write(emu, PTRX, voice, (send_a << 8) | send_b); - snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_d << 24)); - snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_c << 24)); + snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]); + snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24)); + snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24)); pitch_target = emu10k1_calc_pitch_target(runtime->rate); snd_emu10k1_ptr_write(emu, CCCA, voice, evoice->epcm->ccca_start_addr | emu10k1_select_interprom(pitch_target) | @@ -753,7 +767,7 @@ emu10k1_pcm_t *epcm; emu10k1_pcm_mixer_t *mix; snd_pcm_runtime_t *runtime = substream->runtime; - int err; + int i, err; epcm = snd_magic_kcalloc(emu10k1_pcm_t, 0, GFP_KERNEL); if (epcm == NULL) @@ -773,8 +787,8 @@ return err; } mix = &emu->pcm_mixer[substream->number]; - mix->send_routing[0] = mix->send_routing[1] = mix->send_routing[2] = - emu->audigy ? 0x03020100 : 0x3210; + for (i = 0; i < 4; i++) + mix->send_routing[0][i] = mix->send_routing[1][i] = mix->send_routing[2][i] = i; memset(&mix->send_volume, 0, sizeof(mix->send_volume)); mix->send_volume[0][0] = mix->send_volume[0][1] = mix->send_volume[1][0] = mix->send_volume[2][1] = 255; diff -Nru a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c --- a/sound/pci/emu10k1/emuproc.c Tue Feb 26 11:57:58 2002 +++ b/sound/pci/emu10k1/emuproc.c Tue Feb 26 11:57:58 2002 @@ -250,6 +250,7 @@ } } emu->proc_entry = entry; + entry = NULL; if ((entry = snd_info_create_card_entry(emu->card, "fx8010_gpr", emu->card->proc_root)) != NULL) { entry->content = SNDRV_INFO_CONTENT_DATA; entry->private_data = emu; @@ -262,6 +263,7 @@ } } emu->proc_entry_fx8010_gpr = entry; + entry = NULL; if (!emu->audigy && (entry = snd_info_create_card_entry(emu->card, "fx8010_tram_data", emu->card->proc_root)) != NULL) { entry->content = SNDRV_INFO_CONTENT_DATA; entry->private_data = emu; @@ -274,6 +276,7 @@ } } emu->proc_entry_fx8010_tram_data = entry; + entry = NULL; if (!emu->audigy && (entry = snd_info_create_card_entry(emu->card, "fx8010_tram_addr", emu->card->proc_root)) != NULL) { entry->content = SNDRV_INFO_CONTENT_DATA; entry->private_data = emu; @@ -286,6 +289,7 @@ } } emu->proc_entry_fx8010_tram_addr = entry; + entry = NULL; if ((entry = snd_info_create_card_entry(emu->card, "fx8010_code", emu->card->proc_root)) != NULL) { entry->content = SNDRV_INFO_CONTENT_DATA; entry->private_data = emu; @@ -298,6 +302,7 @@ } } emu->proc_entry_fx8010_code = entry; + entry = NULL; if ((entry = snd_info_create_card_entry(emu->card, "fx8010_acode", emu->card->proc_root)) != NULL) { entry->content = SNDRV_INFO_CONTENT_TEXT; entry->private_data = emu; diff -Nru a/sound/pci/ens1370.c b/sound/pci/ens1370.c --- a/sound/pci/ens1370.c Tue Feb 26 11:57:58 2002 +++ b/sound/pci/ens1370.c Tue Feb 26 11:57:58 2002 @@ -2049,7 +2049,7 @@ if ((err = pci_module_init(&driver)) < 0) { #ifdef MODULE - snd_printk("Ensoniq AudioPCI soundcard not found or device busy\n"); + printk(KERN_ERR "Ensoniq AudioPCI soundcard not found or device busy\n"); #endif return err; } diff -Nru a/sound/pci/es1938.c b/sound/pci/es1938.c --- a/sound/pci/es1938.c Tue Feb 26 11:58:00 2002 +++ b/sound/pci/es1938.c Tue Feb 26 11:58:00 2002 @@ -1626,7 +1626,7 @@ SLSB_REG(chip, FMLOWADDR), SLSB_REG(chip, FMHIGHADDR), OPL3_HW_OPL3, 1, &opl3) < 0) { - snd_printk("OPL3 not detected at 0x%lx\n", + printk(KERN_ERR "es1938: OPL3 not detected at 0x%lx\n", SLSB_REG(chip, FMLOWADDR)); } else { if ((err = snd_opl3_timer_new(opl3, 0, 1)) < 0) { @@ -1640,7 +1640,7 @@ } if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, chip->mpu_port, 1, chip->irq, 0, &chip->rmidi) < 0) { - snd_printk("unable to initialize MPU-401\n"); + printk(KERN_ERR "es1938: unable to initialize MPU-401\n"); } #ifndef LINUX_2_2 chip->gameport.io = chip->game_port; @@ -1683,7 +1683,7 @@ if ((err = pci_module_init(&driver)) < 0) { #ifdef MODULE - snd_printk("ESS Solo-1 soundcard not found or device busy\n"); + printk(KERN_ERR "ESS Solo-1 soundcard not found or device busy\n"); #endif return err; } diff -Nru a/sound/pci/es1968.c b/sound/pci/es1968.c --- a/sound/pci/es1968.c Tue Feb 26 11:58:00 2002 +++ b/sound/pci/es1968.c Tue Feb 26 11:58:00 2002 @@ -2720,7 +2720,7 @@ if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, chip->io_port + ESM_MPU401_PORT, 1, chip->irq, 0, &chip->rmidi)) < 0) { - printk(KERN_INFO "es1968: skipping MPU-401 MIDI support..\n"); + printk(KERN_WARNING "es1968: skipping MPU-401 MIDI support..\n"); } /* card switches */ @@ -2783,7 +2783,7 @@ if ((err = pci_module_init(&driver)) < 0) { #ifdef MODULE - snd_printk("ESS Maestro soundcard not found or device busy\n"); + printk(KERN_ERR "ESS Maestro soundcard not found or device busy\n"); #endif return err; } @@ -2792,7 +2792,7 @@ leave the speaking emitting an annoying noise, so we catch shutdown events. */ if (register_reboot_notifier(&snd_es1968_nb)) { - snd_printk("reboot notifier registration failed; may make noise at shutdown.\n"); + printk(KERN_ERR "reboot notifier registration failed; may make noise at shutdown.\n"); } #endif return 0; diff -Nru a/sound/pci/fm801.c b/sound/pci/fm801.c --- a/sound/pci/fm801.c Tue Feb 26 11:57:58 2002 +++ b/sound/pci/fm801.c Tue Feb 26 11:57:58 2002 @@ -1104,7 +1104,7 @@ if ((err = pci_module_init(&driver)) < 0) { #ifdef MODULE - snd_printk("ForteMedia FM801 soundcard not found or device busy\n"); + printk(KERN_ERR "ForteMedia FM801 soundcard not found or device busy\n"); #endif return err; } diff -Nru a/sound/pci/ice1712.c b/sound/pci/ice1712.c --- a/sound/pci/ice1712.c Tue Feb 26 11:57:59 2002 +++ b/sound/pci/ice1712.c Tue Feb 26 11:57:59 2002 @@ -1718,7 +1718,7 @@ if (rpcm) *rpcm = pcm; - printk("Consumer PCM code does not work well at the moment --jk\n"); + printk(KERN_WARNING "Consumer PCM code does not work well at the moment --jk\n"); return 0; } @@ -2410,7 +2410,7 @@ ac97.private_data = ice; ac97.private_free = snd_ice1712_mixer_free_ac97; if ((err = snd_ac97_mixer(ice->card, &ac97, &ice->ac97)) < 0) { - snd_printk("ice1712: cannot initialize ac97 for consumer, skipped\n"); + printk(KERN_WARNING "ice1712: cannot initialize ac97 for consumer, skipped\n"); // return err; } else { if ((err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_digmix_route_ac97, ice))) < 0) @@ -2428,7 +2428,7 @@ ac97.private_data = ice; ac97.private_free = snd_ice1712_mixer_free_ac97; if ((err = snd_ac97_mixer(ice->card, &ac97, &ice->ac97)) < 0) { - snd_printk("ice1712: cannot initialize pro ac97, skipped\n"); + printk(KERN_WARNING "ice1712: cannot initialize pro ac97, skipped\n"); // return err; } return 0; @@ -4329,7 +4329,7 @@ if ((err = pci_module_init(&driver)) < 0) { #ifdef MODULE - snd_printk("ICE1712 soundcard not found or device busy\n"); + printk(KERN_ERR "ICE1712 soundcard not found or device busy\n"); #endif return err; } diff -Nru a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c --- a/sound/pci/intel8x0.c Tue Feb 26 11:57:56 2002 +++ b/sound/pci/intel8x0.c Tue Feb 26 11:57:56 2002 @@ -35,6 +35,7 @@ #include #include #include +#include #define SNDRV_GET_ID #include @@ -52,10 +53,24 @@ "{SiS,SI7012}," "{NVidia,NForce Audio}}"); +#define SUPPORT_JOYSTICK 1 +#define SUPPORT_MIDI 1 + static int snd_index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *snd_id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static int snd_enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ static int snd_ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; +#ifdef SUPPORT_JOYSTICK +static int snd_joystick_port[SNDRV_CARDS] = +#ifdef CONFIG_ISA + {0x200}; /* enable as default */ +#else + {0}; /* disabled */ +#endif +#endif +#ifdef SUPPORT_MIDI +static int snd_mpu_port[SNDRV_CARDS]; /* disabled */ +#endif MODULE_PARM(snd_index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(snd_index, "Index value for Intel i8x0 soundcard."); @@ -69,6 +84,16 @@ MODULE_PARM(snd_ac97_clock, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(snd_ac97_clock, "AC'97 codec clock (0 = auto-detect)."); MODULE_PARM_SYNTAX(snd_ac97_clock, SNDRV_ENABLED ",default:0"); +#ifdef SUPPORT_JOYSTICK +MODULE_PARM(snd_joystick_port, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(snd_joystick_port, "Joystick port address for Intel i8x0 soundcard. (0 = disabled)"); +MODULE_PARM_SYNTAX(snd_joystick_port, SNDRV_ENABLED ",allows:{{0},{0x200}},dialog:list"); +#endif +#ifdef SUPPORT_MIDI +MODULE_PARM(snd_mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(snd_mpu_port, "MPU401 port # for Intel i8x0 driver."); +MODULE_PARM_SYNTAX(snd_mpu_port, SNDRV_ENABLED ",allows:{{0},{0x330},{0x300}},dialog:list"); +#endif /* * Direct registers @@ -231,6 +256,8 @@ ac97_t *ac97; ac97_t *ac97sec; + snd_rawmidi_t *rmidi; + spinlock_t reg_lock; spinlock_t ac97_lock; snd_info_entry_t *proc_entry; @@ -256,9 +283,9 @@ { 0x8086, 0x2445, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82801BA */ { 0x8086, 0x2485, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH3 */ { 0x8086, 0x7195, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 440MX */ - { 0x8086, 0x7195, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 440MX */ { 0x1039, 0x7012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_SIS }, /* SI7012 */ { 0x10de, 0x01b1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* NFORCE */ + { 0x764d, 0x1022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD8111 */ { 0, } }; @@ -1087,6 +1114,7 @@ { snd_card_t *card = chip->card; + chip->in_suspend = 1; snd_power_lock(card); if (card->power_state == SNDRV_CTL_POWER_D3hot) goto __skip; @@ -1364,6 +1392,7 @@ { PCI_DEVICE_ID_INTEL_ICH3, "Intel ICH3" }, { PCI_DEVICE_ID_SI_7012, "SiS SI7012" }, { PCI_DEVICE_ID_NVIDIA_MCP_AUDIO, "NVidia NForce" }, + { 0x1022, "AMD-8111" }, { 0, 0 }, }; @@ -1416,6 +1445,16 @@ } } + if (snd_mpu_port[dev] == 0x300 || snd_mpu_port[dev] == 0x330) { + if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_CMIPCI, + snd_mpu_port[dev], 0, + -1, 0, &chip->rmidi)) < 0) { + printk(KERN_ERR "intel8x0: no UART401 device at 0x%x, skipping.\n", snd_mpu_port[dev]); + snd_mpu_port[dev] = 0; + } + } else + snd_mpu_port[dev] = 0; + sprintf(card->longname, "%s at 0x%lx, irq %i", card->shortname, chip->port, chip->irq); @@ -1450,16 +1489,77 @@ #endif }; + +#if defined(SUPPORT_JOYSTICK) || defined(SUPPORT_MIDI) +/* + * initialize joystick/midi addresses + */ + +static int __devinit snd_intel8x0_joystick_probe(struct pci_dev *pci, + const struct pci_device_id *id) +{ + static int dev = 0; + if (dev >= SNDRV_CARDS) + return -ENODEV; + if (!snd_enable[dev]) { + dev++; + return -ENOENT; + } + + if (snd_joystick_port[dev] > 0 || snd_mpu_port[dev] > 0) { + u16 val; + pci_read_config_word(pci, 0xe6, &val); + if (snd_joystick_port[dev] > 0) + val |= 0x100; + if (snd_mpu_port[dev] == 0x300 || snd_mpu_port[dev] == 0x330) + val |= 0x20; + pci_write_config_word(pci, 0xe6, val | 0x100); + + if (snd_mpu_port[dev] == 0x300 || snd_mpu_port[dev] == 0x330) { + u8 b; + pci_read_config_byte(pci, 0xe2, &b); + if (snd_mpu_port[dev] == 0x300) + b |= 0x08; + else + b &= ~0x08; + pci_write_config_byte(pci, 0xe2, b); + } + } + return 0; +} + +static struct pci_device_id snd_intel8x0_joystick_ids[] __devinitdata = { + { 0x8086, 0x2410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* 82801AA */ + { 0x8086, 0x2420, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* 82901AB */ + { 0x8086, 0x2440, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH2 */ + { 0x8086, 0x244c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH2M */ + { 0x8086, 0x248c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH3 */ + // { 0x8086, 0x7195, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* 440MX */ + // { 0x1039, 0x7012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SI7012 */ + { 0x10de, 0x01b2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* NFORCE */ + { 0, } +}; + +static struct pci_driver joystick_driver = { + name: "Intel ICH Joystick", + id_table: snd_intel8x0_joystick_ids, + probe: snd_intel8x0_joystick_probe, +}; +#endif + static int __init alsa_card_intel8x0_init(void) { int err; if ((err = pci_module_init(&driver)) < 0) { #ifdef MODULE - snd_printk("Intel ICH soundcard not found or device busy\n"); + printk(KERN_ERR "Intel ICH soundcard not found or device busy\n"); #endif return err; } +#if defined(SUPPORT_JOYSTICK) || defined(SUPPORT_MIDI) + pci_module_init(&joystick_driver); +#endif return 0; } @@ -1467,6 +1567,9 @@ static void __exit alsa_card_intel8x0_exit(void) { pci_unregister_driver(&driver); +#if defined(SUPPORT_JOYSTICK) || defined(SUPPORT_MIDI) + pci_unregister_driver(&joystick_driver); +#endif } module_init(alsa_card_intel8x0_init) diff -Nru a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c --- a/sound/pci/korg1212/korg1212.c Tue Feb 26 11:57:56 2002 +++ b/sound/pci/korg1212/korg1212.c Tue Feb 26 11:57:56 2002 @@ -1953,27 +1953,27 @@ korg1212->res_iomem = request_mem_region(korg1212->iomem, iomem_size, "korg1212"); if (korg1212->res_iomem == NULL) { - PRINTK("unable to grab region 0x%lx-0x%lx\n", + snd_printk("unable to grab region 0x%lx-0x%lx\n", korg1212->iomem, korg1212->iomem + iomem_size - 1); return -EBUSY; } korg1212->res_ioport = request_region(korg1212->ioport, ioport_size, "korg1212"); if (korg1212->res_ioport == NULL) { - PRINTK("unable to grab region 0x%lx-0x%lx\n", + snd_printk("unable to grab region 0x%lx-0x%lx\n", korg1212->ioport, korg1212->ioport + ioport_size - 1); return -EBUSY; } korg1212->res_iomem2 = request_mem_region(korg1212->iomem2, iomem2_size, "korg1212"); if (korg1212->res_iomem2 == NULL) { - PRINTK("unable to grab region 0x%lx-0x%lx\n", + snd_printk("unable to grab region 0x%lx-0x%lx\n", korg1212->iomem2, korg1212->iomem2 + iomem2_size - 1); return -EBUSY; } if ((korg1212->iobase = (unsigned long) ioremap(korg1212->iomem, iomem_size)) == 0) { - PRINTK("unable to remap memory region 0x%lx-0x%lx\n", korg1212->iobase, + snd_printk("unable to remap memory region 0x%lx-0x%lx\n", korg1212->iobase, korg1212->iobase + iomem_size - 1); return -EBUSY; } @@ -1983,7 +1983,7 @@ "korg1212", (void *) korg1212); if (err) { - PRINTK("unable to grab IRQ %d\n", pci->irq); + snd_printk("unable to grab IRQ %d\n", pci->irq); return -EBUSY; } @@ -2034,7 +2034,7 @@ korg1212->sharedBufferPhy = (unsigned long)phys_addr; if (korg1212->sharedBufferPtr == NULL) { - PRINTK("can not allocate shared buffer memory (%d bytes)\n", sizeof(KorgSharedBuffer)); + snd_printk("can not allocate shared buffer memory (%d bytes)\n", sizeof(KorgSharedBuffer)); return -ENOMEM; } @@ -2050,7 +2050,7 @@ korg1212->PlayDataPhy = (u32)phys_addr; if (korg1212->playDataBufsPtr == NULL) { - PRINTK("can not allocate play data buffer memory (%d bytes)\n", korg1212->DataBufsSize); + snd_printk("can not allocate play data buffer memory (%d bytes)\n", korg1212->DataBufsSize); return -ENOMEM; } @@ -2063,7 +2063,7 @@ korg1212->RecDataPhy = (u32)phys_addr; if (korg1212->recordDataBufsPtr == NULL) { - PRINTK("can not allocate record data buffer memory (%d bytes)\n", korg1212->DataBufsSize); + snd_printk("can not allocate record data buffer memory (%d bytes)\n", korg1212->DataBufsSize); return -ENOMEM; } @@ -2091,7 +2091,7 @@ korg1212->dspMemPhy = (u32)phys_addr; if (korg1212->dspMemPtr == NULL) { - PRINTK("can not allocate dsp code memory (%d bytes)\n", korg1212->dspCodeSize); + snd_printk("can not allocate dsp code memory (%d bytes)\n", korg1212->dspCodeSize); return -ENOMEM; } @@ -2114,7 +2114,7 @@ if (snd_korg1212_downloadDSPCode(korg1212)) return -EBUSY; - PRINTK("dspMemPhy = %08x U[%08x]\n" + printk(KERN_INFO "dspMemPhy = %08x U[%08x]\n" "PlayDataPhy = %08x L[%08x]\n" "RecDataPhy = %08x L[%08x]\n" "VolumeTablePhy = %08x L[%08x]\n" @@ -2312,7 +2312,7 @@ if ((err = pci_module_init(&driver)) < 0) { #ifdef MODULE - PRINTK("No Korg 1212IO cards found\n"); + printk(KERN_ERR "No Korg 1212IO cards found\n"); #endif return err; } diff -Nru a/sound/pci/maestro3.c b/sound/pci/maestro3.c --- a/sound/pci/maestro3.c Tue Feb 26 11:57:56 2002 +++ b/sound/pci/maestro3.c Tue Feb 26 11:57:56 2002 @@ -2676,7 +2676,7 @@ if ((err = pci_module_init(&driver)) < 0) { #ifdef MODULE - snd_printk("Maestro3/Allegro soundcard not found or device busy\n"); + printk(KERN_ERR "Maestro3/Allegro soundcard not found or device busy\n"); #endif return err; } diff -Nru a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c --- a/sound/pci/nm256/nm256.c Tue Feb 26 11:57:58 2002 +++ b/sound/pci/nm256/nm256.c Tue Feb 26 11:57:58 2002 @@ -331,7 +331,7 @@ offset -= chip->buffer_start; #ifdef SNDRV_CONFIG_DEBUG if (offset < 0 || offset >= chip->buffer_size) { - printk("nm256: write_buffer invalid offset = %d size = %d\n", offset, size); + snd_printk("write_buffer invalid offset = %d size = %d\n", offset, size); return; } #endif @@ -1436,10 +1436,10 @@ pval = snd_nm256_readw(chip, NM_MIXER_PRESENCE); if ((pval & NM_PRESENCE_MASK) != NM_PRESENCE_VALUE) { if (! force_load) { - printk(KERN_INFO "nm256: no ac97 is found!\n"); - printk(KERN_INFO " force the driver to load by passing in the module parameter\n"); - printk(KERN_INFO " snd_force_ac97=1\n"); - printk(KERN_INFO " or try sb16 or cs423x drivers instead.\n"); + printk(KERN_ERR "nm256: no ac97 is found!\n"); + printk(KERN_ERR " force the driver to load by passing in the module parameter\n"); + printk(KERN_ERR " snd_force_ac97=1\n"); + printk(KERN_ERR " or try sb16 or cs423x drivers instead.\n"); err = -ENXIO; goto __error; } @@ -1477,8 +1477,8 @@ chip->buffer_start = chip->buffer_end - chip->buffer_size; chip->buffer_addr += chip->buffer_start; - snd_printd("NM256: Mapping port 1 from 0x%x - 0x%x\n", - chip->buffer_start, chip->buffer_end); + printk(KERN_INFO "nm256: Mapping port 1 from 0x%x - 0x%x\n", + chip->buffer_start, chip->buffer_end); chip->res_buffer = request_mem_region(chip->buffer_addr, chip->buffer_size, @@ -1652,7 +1652,7 @@ int err; if ((err = pci_module_init(&driver)) < 0) { #ifdef MODULE - snd_printk("NeoMagic 256 audio soundchip not found or device busy\n"); + printk(KERN_ERR "NeoMagic 256 audio soundchip not found or device busy\n"); #endif return err; } diff -Nru a/sound/pci/rme96.c b/sound/pci/rme96.c --- a/sound/pci/rme96.c Tue Feb 26 11:57:58 2002 +++ b/sound/pci/rme96.c Tue Feb 26 11:57:58 2002 @@ -2486,7 +2486,7 @@ if ((err = pci_module_init(&driver)) < 0) { #ifdef MODULE - snd_printk("No RME Digi96 cards found\n"); + printk(KERN_ERR "No RME Digi96 cards found\n"); #endif return err; } diff -Nru a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c --- a/sound/pci/rme9652/rme9652.c Tue Feb 26 11:57:59 2002 +++ b/sound/pci/rme9652/rme9652.c Tue Feb 26 11:57:59 2002 @@ -392,7 +392,7 @@ if (offset < period_size) { if (offset > rme9652->max_jitter) { if (frag) - printk("Unexpected hw_pointer position (bufid == 0): status: %x offset: %d\n", status, offset); + printk(KERN_ERR "Unexpected hw_pointer position (bufid == 0): status: %x offset: %d\n", status, offset); } else if (!frag) return 0; offset -= rme9652->max_jitter; @@ -401,7 +401,7 @@ } else { if (offset > period_size + rme9652->max_jitter) { if (!frag) - printk("Unexpected hw_pointer position (bufid == 1): status: %x offset: %d\n", status, offset); + printk(KERN_ERR "Unexpected hw_pointer position (bufid == 1): status: %x offset: %d\n", status, offset); } else if (frag) return period_size; offset -= rme9652->max_jitter; @@ -1887,8 +1887,7 @@ #endif } - snd_printk("%s: no buffers available\n", - rme9652->card_name); + printk(KERN_ERR "%s: no buffers available\n", rme9652->card_name); return -ENOMEM; } @@ -1901,24 +1900,16 @@ /* Align to bus-space 64K boundary */ - cb_bus = cb_addr; - cb_bus = (cb_bus + 0xFFFF) & ~0xFFFFl; - - pb_bus = pb_addr; - pb_bus = (pb_bus + 0xFFFF) & ~0xFFFFl; + cb_bus = (cb_addr + 0xFFFF) & ~0xFFFFl; + pb_bus = (pb_addr + 0xFFFF) & ~0xFFFFl; /* Tell the card where it is */ rme9652_write(rme9652, RME9652_rec_buffer, cb_bus); rme9652_write(rme9652, RME9652_play_buffer, pb_bus); -#if 0 // not all architectures have this macro - rme9652->capture_buffer = bus_to_virt(cb_bus); - rme9652->playback_buffer = bus_to_virt(pb_bus); -#else - rme9652->capture_buffer += cb_bus - cb_addr; - rme9652->playback_buffer += pb_bus - pb_addr; -#endif + rme9652->capture_buffer = cb + (cb_bus - cb_addr); + rme9652->playback_buffer = pb + (pb_bus - pb_addr); return 0; } @@ -2732,7 +2723,7 @@ { if (pci_module_init(&driver) < 0) { #ifdef MODULE - snd_printk("RME Digi9652/Digi9636: no cards found\n"); + printk(KERN_ERR "RME Digi9652/Digi9636: no cards found\n"); #endif return -ENODEV; } diff -Nru a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c --- a/sound/pci/sonicvibes.c Tue Feb 26 11:57:57 2002 +++ b/sound/pci/sonicvibes.c Tue Feb 26 11:57:57 2002 @@ -1551,7 +1551,7 @@ if ((err = pci_module_init(&driver)) < 0) { #ifdef MODULE - snd_printk("S3 SonicVibes soundcard not found or device busy\n"); + printk(KERN_ERR "S3 SonicVibes soundcard not found or device busy\n"); #endif return err; } diff -Nru a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c --- a/sound/pci/trident/trident.c Tue Feb 26 11:57:56 2002 +++ b/sound/pci/trident/trident.c Tue Feb 26 11:57:56 2002 @@ -223,7 +223,7 @@ if ((err = pci_module_init(&driver)) < 0) { #ifdef MODULE - snd_printk("Trident 4DWave PCI soundcard not found or device busy\n"); + printk(KERN_ERR "Trident 4DWave PCI soundcard not found or device busy\n"); #endif return err; } diff -Nru a/sound/pci/via686.c b/sound/pci/via686.c --- a/sound/pci/via686.c Tue Feb 26 11:57:58 2002 +++ b/sound/pci/via686.c Tue Feb 26 11:57:58 2002 @@ -246,6 +246,16 @@ return -EIO; } +static void snd_via686a_codec_wait(ac97_t *ac97) +{ + via686a_t *chip = snd_magic_cast(via686a_t, ac97->private_data, return); + int err; + err = snd_via686a_codec_ready(chip, ac97->num); + /* here we need to wait fairly for long time.. */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/2); +} + static void snd_via686a_codec_write(ac97_t *ac97, unsigned short reg, unsigned short val) @@ -811,6 +821,7 @@ ac97.write = snd_via686a_codec_write; ac97.read = snd_via686a_codec_read; ac97.init = snd_via686a_codec_init; + ac97.wait = snd_via686a_codec_wait; ac97.private_data = chip; ac97.private_free = snd_via686a_mixer_free_ac97; ac97.clock = chip->ac97_clock; @@ -1178,7 +1189,7 @@ pci_write_config_byte(pci, 0x43, legacy_cfg); if (legacy & 0x02) { if (check_region(snd_mpu_port[dev], 2)) { - snd_printk("unable to get MPU-401 port at 0x%lx, skipping\n", snd_mpu_port[dev]); + printk(KERN_WARNING "unable to get MPU-401 port at 0x%lx, skipping\n", snd_mpu_port[dev]); legacy &= ~0x02; pci_write_config_byte(pci, 0x42, legacy); goto __skip_mpu; @@ -1187,7 +1198,7 @@ snd_mpu_port[dev], 0, pci->irq, 0, &chip->rmidi) < 0) { - snd_printk("unable to initialize MPU-401 at 0x%lx, skipping\n", snd_mpu_port[dev]); + printk(KERN_WARNING "unable to initialize MPU-401 at 0x%lx, skipping\n", snd_mpu_port[dev]); legacy &= ~0x02; pci_write_config_byte(pci, 0x42, legacy); goto __skip_mpu; @@ -1239,7 +1250,7 @@ if ((err = pci_module_init(&driver)) < 0) { #ifdef MODULE - snd_printk("VIA 82C686A soundcard not found or device busy\n"); + printk(KERN_ERR "VIA 82C686A soundcard not found or device busy\n"); #endif return err; } diff -Nru a/sound/pci/via8233.c b/sound/pci/via8233.c --- a/sound/pci/via8233.c Tue Feb 26 11:57:58 2002 +++ b/sound/pci/via8233.c Tue Feb 26 11:57:58 2002 @@ -877,7 +877,7 @@ if ((err = pci_module_init(&driver)) < 0) { #ifdef MODULE - snd_printk("VIA 8233 soundcard not found or device busy\n"); + printk(KERN_ERR "VIA 8233 soundcard not found or device busy\n"); #endif return err; } diff -Nru a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c --- a/sound/pci/ymfpci/ymfpci.c Tue Feb 26 11:57:59 2002 +++ b/sound/pci/ymfpci/ymfpci.c Tue Feb 26 11:57:59 2002 @@ -197,7 +197,7 @@ if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_YMFPCI, snd_mpu_port[dev], 0, pci->irq, 0, &chip->rawmidi)) < 0) { - printk(KERN_INFO "ymfpci: cannot initialize MPU401 at 0x%lx, skipping...\n", snd_mpu_port[dev]); + printk(KERN_WARNING "ymfpci: cannot initialize MPU401 at 0x%lx, skipping...\n", snd_mpu_port[dev]); } else { legacy_ctrl &= ~0x10; /* disable MPU401 irq */ pci_write_config_word(pci, PCIR_DSXG_LEGACY, legacy_ctrl); @@ -208,7 +208,7 @@ snd_fm_port[dev], snd_fm_port[dev] + 2, OPL3_HW_OPL3, 0, &opl3)) < 0) { - printk(KERN_INFO "ymfpci: cannot initialize FM OPL3 at 0x%lx, skipping...\n", snd_fm_port[dev]); + printk(KERN_WARNING "ymfpci: cannot initialize FM OPL3 at 0x%lx, skipping...\n", snd_fm_port[dev]); } else if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { snd_card_free(card); snd_printk("cannot create opl3 hwdep\n"); @@ -216,7 +216,7 @@ } } if ((err = snd_ymfpci_joystick(chip)) < 0) { - printk(KERN_INFO "ymfpci: cannot initialize joystick, skipping...\n"); + printk(KERN_WARNING "ymfpci: cannot initialize joystick, skipping...\n"); } strcpy(card->driver, str); sprintf(card->shortname, "Yamaha DS-XG PCI (%s)", str); @@ -287,7 +287,7 @@ if ((err = pci_module_init(&driver)) < 0) { #ifdef MODULE - snd_printk("Yamaha DS-XG PCI soundcard not found or device busy\n"); + printk(KERN_ERR "Yamaha DS-XG PCI soundcard not found or device busy\n"); #endif return err; } diff -Nru a/sound/ppc/keywest.c b/sound/ppc/keywest.c --- a/sound/ppc/keywest.c Tue Feb 26 11:57:59 2002 +++ b/sound/ppc/keywest.c Tue Feb 26 11:57:59 2002 @@ -179,7 +179,7 @@ i2c_device = find_compatible_devices("i2c", "keywest"); if (i2c_device == 0) { - snd_printk("No Keywest i2c devices found.\n"); + printk(KERN_ERR "pmac: No Keywest i2c devices found.\n"); return -ENODEV; } diff -Nru a/sound/ppc/powermac.c b/sound/ppc/powermac.c --- a/sound/ppc/powermac.c Tue Feb 26 11:57:59 2002 +++ b/sound/ppc/powermac.c Tue Feb 26 11:57:59 2002 @@ -150,7 +150,7 @@ int err; if ((err = snd_pmac_probe() < 0)) { #ifdef MODULE - snd_printk("no PMac soundchip found\n"); + printk(KERN_ERR "no PMac soundchip found\n"); #endif return err; } diff -Nru a/sound/sound_core.c b/sound/sound_core.c --- a/sound/sound_core.c Tue Feb 26 11:57:59 2002 +++ b/sound/sound_core.c Tue Feb 26 11:57:59 2002 @@ -17,7 +17,7 @@ * plug into this. The fact they dont all go via OSS doesn't mean * they don't have to implement the OSS API. There is a lot of logic * to keeping much of the OSS weight out of the code in a compatibility - * module, but its up to the driver to rember to load it... + * module, but it's up to the driver to rember to load it... * * The code provides a set of functions for registration of devices * by type. This is done rather than providing a single call so that @@ -171,10 +171,10 @@ return r; } - if (r == low) + if (r < SOUND_STEP) sprintf (name_buf, "%s", name); else - sprintf (name_buf, "%s%d", name, (r - low) / SOUND_STEP); + sprintf (name_buf, "%s%d", name, r / SOUND_STEP); s->de = devfs_register (devfs_handle, name_buf, DEVFS_FL_NONE, SOUND_MAJOR, s->unit_minor, S_IFCHR | mode, fops, NULL); @@ -215,7 +215,7 @@ * 15 *16 unused */ -static struct sound_unit *chains[16]; +static struct sound_unit *chains[SOUND_STEP]; /** * register_sound_special - register a special sound node @@ -229,17 +229,22 @@ int register_sound_special(struct file_operations *fops, int unit) { - char *name; + const int chain = unit % (SOUND_STEP-1); + int max_unit = 128 + chain; + const char *name; + char _name[16]; - switch (unit) { + switch (chain) { case 0: name = "mixer"; break; case 1: name = "sequencer"; - break; + if (unit >= SOUND_STEP) + goto __unknown; + max_unit = unit + 1; case 2: - name = "midi00"; + name = "midi"; break; case 3: name = "dsp"; @@ -247,17 +252,11 @@ case 4: name = "audio"; break; - case 5: - name = "unknown5"; - break; - case 6: /* Was once sndstat */ - name = "unknown6"; - break; - case 7: - name = "unknown7"; - break; case 8: name = "sequencer2"; + if (unit >= SOUND_STEP) + goto __unknown; + max_unit = unit + 1; break; case 9: name = "dmmidi"; @@ -265,9 +264,6 @@ case 10: name = "dmfm"; break; - case 11: - name = "unknown11"; - break; case 12: name = "adsp"; break; @@ -278,10 +274,16 @@ name = "admmidi"; break; default: - name = "unknown"; + { + __unknown: + sprintf(_name, "unknown%d", chain); + if (unit >= SOUND_STEP) + strcat(_name, "-"); + name = _name; + } break; } - return sound_insert_unit(&chains[unit&15], fops, -1, unit, unit+1, + return sound_insert_unit(&chains[chain], fops, -1, unit, max_unit, name, S_IRUSR | S_IWUSR); } diff -Nru a/sound/synth/emux/emux_synth.c b/sound/synth/emux/emux_synth.c --- a/sound/synth/emux/emux_synth.c Tue Feb 26 11:57:59 2002 +++ b/sound/synth/emux/emux_synth.c Tue Feb 26 11:57:59 2002 @@ -629,6 +629,25 @@ /* * calculate pitch parameter */ +static unsigned char pan_volumes[256] = { +0x00,0x03,0x06,0x09,0x0c,0x0f,0x12,0x14,0x17,0x1a,0x1d,0x20,0x22,0x25,0x28,0x2a, +0x2d,0x30,0x32,0x35,0x37,0x3a,0x3c,0x3f,0x41,0x44,0x46,0x49,0x4b,0x4d,0x50,0x52, +0x54,0x57,0x59,0x5b,0x5d,0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6f,0x71,0x73,0x75, +0x77,0x79,0x7b,0x7c,0x7e,0x80,0x82,0x84,0x86,0x88,0x89,0x8b,0x8d,0x8f,0x90,0x92, +0x94,0x96,0x97,0x99,0x9a,0x9c,0x9e,0x9f,0xa1,0xa2,0xa4,0xa5,0xa7,0xa8,0xaa,0xab, +0xad,0xae,0xaf,0xb1,0xb2,0xb3,0xb5,0xb6,0xb7,0xb9,0xba,0xbb,0xbc,0xbe,0xbf,0xc0, +0xc1,0xc2,0xc3,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,0xd0,0xd1, +0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdc,0xdd,0xde,0xdf, +0xdf,0xe0,0xe1,0xe2,0xe2,0xe3,0xe4,0xe4,0xe5,0xe6,0xe6,0xe7,0xe8,0xe8,0xe9,0xe9, +0xea,0xeb,0xeb,0xec,0xec,0xed,0xed,0xee,0xee,0xef,0xef,0xf0,0xf0,0xf1,0xf1,0xf1, +0xf2,0xf2,0xf3,0xf3,0xf3,0xf4,0xf4,0xf5,0xf5,0xf5,0xf6,0xf6,0xf6,0xf7,0xf7,0xf7, +0xf7,0xf8,0xf8,0xf8,0xf9,0xf9,0xf9,0xf9,0xf9,0xfa,0xfa,0xfa,0xfa,0xfb,0xfb,0xfb, +0xfb,0xfb,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd, +0xfd,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +}; + static int calc_pan(snd_emux_voice_t *vp) { @@ -646,6 +665,16 @@ } LIMITVALUE(pan, 0, 255); +#if 1 + /* using volume table */ + if (vp->apan != (int)pan_volumes[pan]) { + vp->apan = pan_volumes[pan]; + vp->aaux = pan_volumes[255 - pan]; + return 1; + } + return 0; +#else + /* assuming linear volume */ if (pan != vp->apan) { vp->apan = pan; if (pan == 0) @@ -655,6 +684,7 @@ return 1; } else return 0; +#endif }